Запити HTTP із файлом_get_contents, отримуючи код відповіді


87

Я намагаюся використовувати file_get_contentsразом з stream_context_createдля надсилання запитів POST. Мій код поки:

    $options = array('http' => array(
        'method'  => 'POST',
        'content' => $data,
        'header'  => 
            "Content-Type: text/plain\r\n" .
            "Content-Length: " . strlen($data) . "\r\n"
    ));
    $context  = stream_context_create($options);
    $response = file_get_contents($url, false, $context);

Він працює нормально, однак, коли виникає помилка HTTP, він видає попередження:

file_get_contents(...): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

і повертає false. Чи є спосіб:

  • придушити попередження (я планую видати власний виняток у разі невдачі)
  • отримати інформацію про помилку (принаймні, код відповіді) з потоку

Відповіді:


150

http://php.net/manual/en/reserved.variables.httpresponseheader.php

file_get_contents("http://example.com", false, stream_context_create(['http' => ['ignore_errors' => true]]));
var_dump($http_response_header);

35
Для тих , кому цікаво, відповідь на перше запитання , щоб додати 'ignore_errors' => TRUEдо $options.
georg

3
@georg Ви також можете поставити @на початку рядка.
FluorescentGreen5

19

Жодна з відповідей (включаючи прийняту ОП) насправді не відповідає двом вимогам:

  • придушити попередження (я планую видати власний виняток у разі невдачі)
  • отримати інформацію про помилку (принаймні, код відповіді) з потоку

Ось моя думка:

function fetch(string $method, string $url, string $body, array $headers = []) {
    $context = stream_context_create([
        "http" => [
            // http://docs.php.net/manual/en/context.http.php
            "method"        => $method,
            "header"        => implode("\r\n", $headers),
            "content"       => $body,
            "ignore_errors" => true,
        ],
    ]);

    $response = file_get_contents($url, false, $context);

    /**
     * @var array $http_response_header materializes out of thin air
     */

    $status_line = $http_response_header[0];

    preg_match('{HTTP\/\S*\s(\d{3})}', $status_line, $match);

    $status = $match[1];

    if ($status !== "200") {
        throw new RuntimeException("unexpected response status: {$status_line}\n" . $response);
    }

    return $response;
}

Це призведе до 200відсутності відповіді, але ви можете легко працювати звідти, наприклад, додати простий Responseклас, і return new Response((int) $status, $response);якщо це більше відповідає вашому випадку використання.

Наприклад, щоб зробити JSON POSTдля кінцевої точки API:

$response = fetch(
    "POST",
    "http://example.com/",
    json_encode([
        "foo" => "bar",
    ]),
    [
        "Content-Type: application/json",
        "X-API-Key: 123456789",
    ]
);

Зверніть увагу на використання "ignore_errors" => trueв httpконтекстній карті - це запобіжить появі помилок функції для кодів стану, що не мають значення 2xx.

Це, швидше за все, "правильна" кількість придушення помилок для більшості випадків використання - я не рекомендую використовувати @оператор придушення помилок, оскільки це також придушить помилки, як просто передача помилкових аргументів, які можуть ненавмисно приховати помилку в телефонний код.


5

Додавши ще кілька рядків до прийнятої відповіді, щоб отримати код http

function getHttpCode($http_response_header)
{
    if(is_array($http_response_header))
    {
        $parts=explode(' ',$http_response_header[0]);
        if(count($parts)>1) //HTTP/1.0 <code> <text>
            return intval($parts[1]); //Get code
    }
    return 0;
}

@file_get_contents("http://example.com");
$code=getHttpCode($http_response_header);

щоб приховати вихідні дані про помилку, обидва коментарі нормально, ignore_errors = true або @ (я віддаю перевагу @)


-1

Я переходжу на цю сторінку з якоюсь іншою проблемою, тому публікую свою відповідь. Моя проблема полягала в тому, що я просто намагався придушити попереджувальне сповіщення та показати індивідуальне попереджувальне повідомлення для користувача, тому це просте і очевидне виправлення допомогло мені:

// Suppress the warning messages
error_reporting(0);

$contents = file_get_contents($url);
if ($contents === false) {
  print 'My warning message';
}

А якщо потрібно, поверніть повідомлення про помилки назад після цього:

// Enable warning messages again
error_reporting(-1);

-2

@file_get_contentsі ignore_errors = trueне однакові: перша нічого не повертає; другий придушує повідомлення про помилки, але повертає відповідь сервера (наприклад, 400 поганих запитів).

Я використовую таку функцію:

$result = file_get_contents(
  $url_of_API, 
  false, 
  stream_context_create([
    'http' => [
      'content' => json_encode(['value1' => $value1, 'value2' => $value2]), 
      'header' => 'Authorization: Basic XXXXXXXXXXXXXXX', 
      'ignore_errors' => 1, 
      'method' => 'POST', 
      'timeout' => 10
    ]
  ])
);

return json_decode($result)->status;

Повертає 200 (добре) або 400 (поганий запит).

Це чудово працює, і це простіше, ніж cURL.


І як це вирішує питання? Чи можете ви пояснити, як отримати код відповіді?
Ніко Хаасе

@Nico Що ви думаєте про моє рішення?
Besen

Це все ще погано, оскільки ви аналізуєте результат JSON, а не читаєте випадкове поле з назвою status- воно не має зв’язку з кодом стану HTTP для виклику API
Ніко Хаасе,

Очевидно, що RESTful API, до якого я підключаюся, повертає відповідь JSON і що те, що мені потрібно знати для своєї мети (200 або 400), міститься в полі "статус". Це все, що мені потрібно, і це все, що я отримую. Якщо вам потрібно знати код стану HTTP, просто зробіть це: поверніть $ http_response_header [0]; Але зверніть увагу, що це не працює з @file_get_contents.
Besen

І як це відповідає на вихідне запитання? Чому ви думаєте, що $http_response_header[0], високо оцінена відповідь, не працює file_get_contents?
Ніко Хаасе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.