Permintaan HTTP dengan file_get_contents, mendapatkan kode respons

88

Saya mencoba menggunakan file_get_contentsbersama stream_context_createuntuk membuat permintaan POST. Kode saya sejauh ini:

    $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);

Ini berfungsi dengan baik, namun, ketika kesalahan HTTP terjadi, itu mengeluarkan peringatan:

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

dan mengembalikan false. Apakah ada cara untuk:

  • menekan peringatan (saya berencana untuk membuang pengecualian saya sendiri jika terjadi kegagalan)
  • dapatkan informasi kesalahan (setidaknya, kode respons) dari aliran
georg
sumber

Jawaban:

152

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);
Alles
sumber
35
Bagi mereka bertanya-tanya, jawaban untuk pertanyaan pertama adalah menambahkan 'ignore_errors' => TRUEuntuk $options.
georg
4
@georg Anda juga bisa meletakkan @di awal baris.
FluorescentGreen5
21

Tak satu pun dari jawaban (termasuk yang diterima oleh OP) yang benar-benar memenuhi dua persyaratan:

  • menekan peringatan (saya berencana untuk membuang pengecualian saya sendiri jika terjadi kegagalan)
  • dapatkan informasi kesalahan (setidaknya, kode respons) dari aliran

Ini pendapat saya:

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;
}

Ini akan memunculkan non- 200respons, tetapi Anda dapat dengan mudah bekerja dari sana, misalnya menambahkan Responsekelas sederhana dan return new Response((int) $status, $response);jika itu lebih sesuai dengan kasus penggunaan Anda.

Misalnya, untuk melakukan JSON POSTke titik akhir API:

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

Perhatikan penggunaan "ignore_errors" => truedalam httppeta konteks - ini akan mencegah fungsi dari memberikan kesalahan untuk kode status non-2xx.

Ini kemungkinan besar adalah jumlah error-suppression yang "benar" untuk sebagian besar kasus penggunaan - Saya tidak merekomendasikan penggunaan @operator error-suppression, karena ini juga akan menekan error seperti hanya menyampaikan argumen yang salah, yang dapat secara tidak sengaja menyembunyikan bug di kode panggilan.

mindplay.dk
sumber
5

Menambahkan beberapa baris lagi ke tanggapan yang diterima untuk mendapatkan kode 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);

untuk menyembunyikan keluaran kesalahan, kedua komentar tidak masalah, ignore_errors = true atau @ (Saya lebih suka @)

hamboy75
sumber
-1

Saya membuka halaman ini dengan jenis masalah yang berbeda, jadi saya memposting jawaban saya. Masalah saya adalah saya hanya mencoba untuk menekan pemberitahuan peringatan dan menampilkan pesan peringatan yang disesuaikan untuk pengguna, jadi perbaikan sederhana dan jelas ini membantu saya:

// Suppress the warning messages
error_reporting(0);

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

Dan jika perlu, kembalikan pelaporan kesalahan setelah itu:

// Enable warning messages again
error_reporting(-1);
Kaarel
sumber
-2

@file_get_contentsdan ignore_errors = truetidak sama: yang pertama tidak mengembalikan apa pun; yang kedua menyembunyikan pesan kesalahan, tetapi mengembalikan respons server (mis. 400 Permintaan buruk).

Saya menggunakan fungsi seperti ini:

$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;

Ini mengembalikan 200 (Ok) atau 400 (Permintaan buruk).

Ini bekerja dengan sempurna dan lebih mudah daripada cURL.

Besen
sumber
Dan bagaimana ini menyelesaikan pertanyaan? Bisakah Anda menjelaskan cara mendapatkan kode respons?
Nico Haase
@Nico Apa pendapat Anda tentang solusi saya?
Besen
Ini masih buruk, karena Anda tidak mengurai hasil JSON dan membaca bidang acak bernama status- tidak ada koneksi ke kode status HTTP untuk panggilan API
Nico Haase
Jelas bahwa RESTful API yang saya sambungkan mengembalikan respons JSON dan apa yang perlu saya ketahui untuk tujuan saya (200 atau 400) terdapat dalam bidang "status". Hanya itu yang saya butuhkan dan hanya itu yang saya dapatkan. Jika Anda perlu mengetahui kode status HTTP, cukup lakukan ini: return $ http_response_header [0]; Tetapi perhatikan bahwa itu tidak berfungsi dengan @file_get_contents.
Besen
Dan bagaimana ini menjawab pertanyaan awal? Menurut Anda, mengapa $http_response_header[0]jawaban yang sangat disukai tidak akan berhasil file_get_contents?
Nico Haase