Comment obtenir le corps d'un POST en php?

273

Je soumets en tant que POST à ​​une page php ce qui suit:

{a:1}

Il s'agit du corps de la demande (une demande POST).
En php, que dois-je faire pour extraire cette valeur?

var_dump($_POST); 

n'est pas la solution, ne fonctionne pas.

Itay Moav -Malimovka
la source
23
Il s'agit d'une question utile pour les personnes souhaitant créer des API RESTful. La plupart ne savent pas comment accéder aux données d'entrée brutes soumises à leurs scripts car elles ne sont pas disponibles via le $_POSTsuperglobal. Cela est également (particulièrement) vrai dans le cas des requêtes PUT, car PHP n'a pas de superglobal correspondant.
rdlowrey
1
Il convient de noter que le nom $ _POST est trompeur, car aucun type de données provenant d'une demande POST ne sera présent, mais uniquement lorsque le type de contenu est application / x-www-form-urlencoded ou multipart / form-data
Petruza

Réponses:

549

Pour accéder au corps d'entité d'une demande POST ou PUT (ou à toute autre méthode HTTP):

$entityBody = file_get_contents('php://input');

De plus, la STDINconstante est un flux déjà ouvert vers php://input, vous pouvez donc également faire:

$entityBody = stream_get_contents(STDIN);

À partir de l' entrée manuelle PHP sur les documents de flux d'E / S :

php: // input est un flux en lecture seule qui vous permet de lire les données brutes du corps de la requête. Dans le cas des requêtes POST, il est préférable d'utiliser l' entrée php: // au lieu de $HTTP_RAW_POST_DATAcela car cela ne dépend pas de directives php.ini spéciales. De plus, pour les cas où il $HTTP_RAW_POST_DATAn'est pas renseigné par défaut, il s'agit d'une alternative potentiellement moins gourmande en mémoire à l'activation de always_populate_raw_post_data. php: // entrée n'est pas disponible avec enctype = "multipart / form-data".

Plus précisément, vous voudrez noter que le php://inputflux, quelle que soit la façon dont vous y accédez dans un SAPI Web, n'est pas recherché . Cela signifie qu'il ne peut être lu qu'une seule fois. Si vous travaillez dans un environnement où de grands corps d'entités HTTP sont régulièrement téléchargés, vous souhaiterez peut-être conserver l'entrée sous sa forme de flux (plutôt que de la mettre en mémoire tampon comme dans le premier exemple ci-dessus).

Pour maintenir la ressource de flux, quelque chose comme ceci peut être utile:

<?php

function detectRequestBody() {
    $rawInput = fopen('php://input', 'r');
    $tempStream = fopen('php://temp', 'r+');
    stream_copy_to_stream($rawInput, $tempStream);
    rewind($tempStream);

    return $tempStream;
}

php://tempvous permet de gérer la consommation de mémoire car il basculera de manière transparente vers le stockage du système de fichiers après le stockage d'une certaine quantité de données (2 Mo par défaut). Cette taille peut être manipulée dans le fichier php.ini ou en ajoutant /maxmemory:NN, où NNest la quantité maximale de données à conserver en mémoire avant d'utiliser un fichier temporaire, en octets.

Bien sûr, à moins d'avoir une très bonne raison de rechercher sur le flux d'entrée, vous ne devriez pas avoir besoin de cette fonctionnalité dans une application Web. La lecture du corps de l'entité de demande HTTP une fois suffit généralement - ne laissez pas les clients attendre toute la journée pendant que votre application trouve quoi faire.

Notez que l'entrée php: // n'est pas disponible pour les demandes spécifiant un en- Content-Type: multipart/form-datatête ( enctype="multipart/form-data"dans les formulaires HTML). Cela résulte du fait que PHP a déjà analysé les données du formulaire dans le $_POSTsuperglobal.

rdlowrey
la source
17
Veuillez noter que afaics, le flux STDIN n'est pas disponible sur les systèmes exécutant PHP utilisant CGI, c'est-à-dire via mod_fcgid ou mod_fastcgi etc.
scy
mais, je transmets une variable (sous forme de données de formulaire) à la demande, comment puis-je accéder à la valeur spécifiée, je transmets grant_type = mot de passe et nom d'utilisateur = utilisateur et mot de passe = passer en tant que corps de données de formulaire avec la demande, comment vais-je obtenir grant_type de "$ entityBody "
Anvar Pk
selon mon test, ceci php://inputest également vide pour le application/x-www-form-urlencodedtype de contenu (en plus multipart/form-data)
YakovL
6
Pour développer la réponse de @ scy: STDIN n'est pas disponible, mais l' php://inputest. Ainsi, alors que les configurations CGI (rapides) stream_get_contents(STDIN)ne fonctionneront pas, elles le file_get_contents("php://input")seront.
Sinus Mackowaty
16

retourne la valeur dans le tableau

 $data = json_decode(file_get_contents('php://input'), true);
umesh bhanderi
la source
Dans ce scénario, vous devez maintenant parcourir le $datatableau associatif pour vérifier si chaque valeur est codée comme vous le souhaitez. La façon de voir les choses de «flux vers type de données» peut être simpliste, mais elle peut ne pas être aussi efficace que de traiter le codage sous la «forme de flux» à l'aide d'un filtre de flux. Si vous ne gérez pas les problèmes d'encodage et que vous désinfectez et validez simplement, il vous manque une étape.
Anthony Rutledge
13

Une raison possible pour un vide $_POSTest que la demande ne l'est pas POST, ou POSTplus ... Elle peut avoir commencé en tant que publication, mais a rencontré un 301ou 302rediriger quelque part, qui est basculé vers GET!

Inspectez $_SERVER['REQUEST_METHOD']pour vérifier si c'est le cas.

Voir https://stackoverflow.com/a/19422232/109787 pour une bonne discussion sur la raison pour laquelle cela ne devrait pas se produire, mais se produit toujours.

Legolas
la source
1
Cette question a été posée dans le cadre du développement d'une plateforme api REST.
Itay Moav -Malimovka
Je ne sais pas ce que tu veux dire? Une API REST pourrait tout aussi bien trouver des redirections sur son chemin, c'est le problème que j'ai eu.
Legolas
Je voulais dire quand j'ai posé la question, je n'essayais pas de résoudre un bogue, mais plutôt d'essayer de comprendre comment le développer.
Itay Moav -Malimovka
3
cette allusion m'a sauvé la journée. le serveur de réception a été reconfiguré pour rediriger vers https qui a cassé certains clients API.
DesertEagle
En fait, ma demande était, POSTmais après inspection, elle montrait que c'était le cas GET. Une fois que j'ai ajouté un /à la fin de mon URL, il a commencé à afficher POST. Bizarre!
zackygaurav
4

Vérifiez la $HTTP_RAW_POST_DATAvariable

linepogl
la source
7
La méthode préférée pour accéder aux données POST brutes est php://input. $HTTP_RAW_POST_DATAn'est pas disponible avec enctype="multipart/form-data".
nullité
38
Cette fonctionnalité a été obsolète en PHP 5.6.0 et supprimée en PHP 7.0.0.
Charles
3

Si vous avez installé l'extension HTTP PECL, vous pouvez utiliser la http_get_request_body()fonction pour obtenir les données du corps sous forme de chaîne.

shivanshu patel
la source
la fonction n'existe pas.
Rick
2

Si vous avez installé l'extension pecl / http , vous pouvez également utiliser ceci:

$request = new http\Env\Request();
$request->getBody();
spinkus
la source
2
function getPost()
{
    if(!empty($_POST))
    {
        // when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
        // NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
        return $_POST;
    }

    // when using application/json as the HTTP Content-Type in the request 
    $post = json_decode(file_get_contents('php://input'), true);
    if(json_last_error() == JSON_ERROR_NONE)
    {
        return $post;
    }

    return [];
}

print_r(getPost());
Hatzegopteryx
la source
Ce peu de logique qui manque est un test de la valeur trouvée dans l'en-tête Content-Type. Il ne suit pas que juste parce que $ _POST est vide que JSON doit avoir été soumis, ou que si json_last_error() == JSON_ERROR_NONEest false, qu'un tableau vide doit être retourné. Que faire si quelqu'un a soumis du XML ou du YAML? Ajoutez un test pour le Content-Type et continuez à partir de là.
Anthony Rutledge
De plus, la méthode de requête HTTP peut prendre en compte la détermination de l'acceptation des données d'entrée. Voir le $_SERVERsuperglobal pour les valeurs utiles à vérifier.
Anthony Rutledge