HTTP-Anforderungen mit file_get_contents, die den Antwortcode erhalten

84

Ich versuche, file_get_contentszusammen mit stream_context_createPOST-Anfragen zu stellen. Mein bisheriger Code:

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

Es funktioniert einwandfrei. Wenn jedoch ein HTTP-Fehler auftritt, wird eine Warnung ausgegeben:

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

und gibt false zurück. Gibt es einen Weg zu:

  • eine Warnung unterdrücken (ich plane, im Fehlerfall meine eigene Ausnahme auszulösen)
  • Erhalten Sie die Fehlerinformationen (mindestens den Antwortcode) aus dem Stream
georg
quelle

Antworten:

147

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
quelle
35
Für diejenigen fragen, die Antwort auf die erste Frage hinzufügen 'ignore_errors' => TRUEzu $options.
georg
3
@georg Sie können auch @am Anfang der Zeile setzen.
FluorescentGreen5
17

Keine der Antworten (einschließlich der von OP akzeptierten) erfüllt tatsächlich die beiden Anforderungen:

  • eine Warnung unterdrücken (ich plane, im Fehlerfall meine eigene Ausnahme auszulösen)
  • Erhalten Sie die Fehlerinformationen (mindestens den Antwortcode) aus dem Stream

Hier ist meine Einstellung:

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

Dies führt zu einer Nichtantwort 200, aber Sie können problemlos von dort aus arbeiten, z. B. eine einfache ResponseKlasse hinzufügen und return new Response((int) $status, $response);wenn dies besser zu Ihrem Anwendungsfall passt.

So führen Sie einen JSON-Vorgang POSTfür einen API-Endpunkt aus:

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

Beachten Sie die Verwendung "ignore_errors" => truein der httpKontextzuordnung. Dadurch wird verhindert, dass die Funktion Fehler für Nicht-2xx-Statuscodes auslöst.

Dies ist höchstwahrscheinlich die "richtige" Menge an Fehlerunterdrückung für die meisten Anwendungsfälle. Ich empfehle nicht, den @Operator zur Fehlerunterdrückung zu verwenden, da dies auch Fehler wie das Übergeben der falschen Argumente unterdrückt, die versehentlich einen Fehler verbergen könnten Code aufrufen.

mindplay.dk
quelle
5

Hinzufügen einiger weiterer Zeilen zur akzeptierten Antwort, um den http-Code zu erhalten

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

Um die Fehlerausgabe auszublenden, sind beide Kommentare in Ordnung. ignore_errors = true oder @ (ich bevorzuge @)

hamboy75
quelle
-1

@file_get_contentsund ignore_errors = truesind nicht dasselbe: der erste gibt nichts zurück; Die zweite Option unterdrückt Fehlermeldungen, gibt jedoch die Serverantwort zurück (z. B. 400 Bad Request).

Ich benutze eine Funktion wie diese:

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

Es werden 200 (Ok) oder 400 (Bad Request) zurückgegeben.

Es funktioniert perfekt und ist einfacher als cURL.

Besen
quelle
Und wie löst das die Frage? Können Sie erklären, wie Sie den Antwortcode erhalten?
Nico Haase
@Nico Was denkst du über meine Lösung?
Besen
Es ist immer noch schlecht, da Sie ein JSON-Ergebnis nicht analysieren und ein zufälliges Feld mit dem Namen lesen status- es hat keine Verbindung zum HTTP-Statuscode für den API-Aufruf
Nico Haase
Es ist offensichtlich, dass die RESTful-API, mit der ich eine Verbindung herstelle, eine JSON-Antwort zurückgibt und dass das, was ich für meinen Zweck wissen muss (200 oder 400), im Feld "Status" enthalten ist. Das ist alles was ich brauche und das ist alles was ich bekomme. Wenn Sie den HTTP-Statuscode kennen müssen, gehen Sie wie folgt vor: return $ http_response_header [0]; Beachten Sie jedoch, dass dies mit @file_get_contents nicht funktioniert.
Besen
Und wie beantwortet dies die ursprüngliche Frage? Warum funktioniert Ihrer Meinung nach $http_response_header[0]eine hochgelobte Antwort nicht file_get_contents?
Nico Haase
-1

Ich gehe auf diese Seite mit einem anderen Problem und poste meine Antwort. Mein Problem war, dass ich nur versucht habe, die Warnmeldung zu unterdrücken und eine benutzerdefinierte Warnmeldung für den Benutzer anzuzeigen. Diese einfache und offensichtliche Lösung hat mir also geholfen:

// Suppress the warning messages
error_reporting(0);

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

Und wenn nötig, schalten Sie die Fehlerberichterstattung danach zurück:

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