Requêtes HTTP avec file_get_contents, obtention du code de réponse

87

J'essaye d'utiliser file_get_contentsavec stream_context_createpour faire des demandes POST. Mon code jusqu'à présent:

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

Cela fonctionne bien, cependant, lorsqu'une erreur HTTP se produit, il crache un avertissement:

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

et renvoie false. Existe-t-il un moyen de:

  • supprimer un avertissement (je prévois de lancer ma propre exception en cas d'échec)
  • obtenir les informations d'erreur (au moins, le code de réponse) du flux
Georg
la source

Réponses:

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);
Alles
la source
35
Pour ceux qui se demandent, la réponse à la première question est d'ajouter 'ignore_errors' => TRUEà $options.
georg
3
@georg Vous pouvez également mettre @au début de la ligne.
FluorescentGreen5
19

Aucune des réponses (y compris celle acceptée par OP) ne satisfait réellement aux deux exigences:

  • supprimer un avertissement (je prévois de lancer ma propre exception en cas d'échec)
  • obtenir les informations d'erreur (au moins, le code de réponse) du flux

Voici ma prise:

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

Cela entraînera une non- 200réponse, mais vous pouvez facilement travailler à partir de là, par exemple ajouter une Responseclasse simple et return new Response((int) $status, $response);si cela correspond mieux à votre cas d'utilisation.

Par exemple, pour effectuer un JSON POSTsur un point de terminaison d'API:

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

Notez l'utilisation de "ignore_errors" => truedans la httpcarte de contexte - cela empêchera la fonction de générer des erreurs pour les codes d'état non-2xx.

Il s'agit probablement de la "bonne" quantité de suppression d'erreurs pour la plupart des cas d'utilisation - je ne recommande pas d'utiliser l' @opérateur de suppression d'erreurs, car cela supprimera également des erreurs telles que le simple passage de mauvais arguments, ce qui pourrait masquer par inadvertance un bogue dans code d'appel.

mindplay.dk
la source
5

Ajout de quelques lignes supplémentaires à la réponse acceptée pour obtenir le code 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);

pour masquer la sortie d'erreur, les deux commentaires sont ok, ignore_errors = true ou @ (je préfère @)

hamboy75
la source
-1

Je vais sur cette page avec une sorte de problème différent, donc poster ma réponse. Mon problème était que j'essayais simplement de supprimer la notification d'avertissement et d'afficher un message d'avertissement personnalisé pour l'utilisateur, donc cette solution simple et évidente m'a aidé:

// Suppress the warning messages
error_reporting(0);

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

Et si nécessaire, réactivez le rapport d'erreur après cela:

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

@file_get_contentset ignore_errors = truene sont pas les mêmes: le premier ne renvoie rien; le second supprime les messages d'erreur, mais renvoie la réponse du serveur (par exemple 400 Bad request).

J'utilise une fonction comme celle-ci:

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

Il renvoie 200 (Ok) ou 400 (Mauvaise demande).

Cela fonctionne parfaitement et c'est plus facile que cURL.

Besen
la source
Et comment cela résout-il la question? Pouvez-vous expliquer comment obtenir le code de réponse?
Nico Haase
@Nico Que pensez-vous de ma solution?
Besen
C'est toujours mauvais, car vous analysez un résultat JSON non et lisez un champ aléatoire nommé status- il n'a pas de connexion avec le code d'état HTTP pour l'appel d'API
Nico Haase
Il est évident que l'API RESTful à laquelle je me connecte renvoie une réponse JSON et que ce que j'ai besoin de savoir pour mon objectif (200 ou 400) est contenu dans le champ "status". C'est tout ce dont j'ai besoin et c'est tout ce que j'ai. Si vous avez besoin de connaître le code d'état HTTP, procédez comme suit: return $ http_response_header [0]; Mais notez que cela ne fonctionne pas avec @file_get_contents.
Besen
Et comment cela répond-il à la question initiale? Pourquoi pensez-vous que $http_response_header[0], une réponse hautement votée, ne fonctionne pas avec file_get_contents?
Nico Haase