Comment envoyer une requête POST avec PHP?

655

En fait, je veux lire le contenu qui vient après la requête de recherche, quand elle est terminée. Le problème est que l'URL n'accepte que les POSTméthodes et n'entreprend aucune action avec la GETméthode ...

Je dois lire tout le contenu à l'aide de domdocumentou file_get_contents(). Y a-t-il une méthode qui me permettra d'envoyer des paramètres avec la POSTméthode puis de lire le contenu via PHP?

Fred Tanrikut
la source

Réponses:

1259

Méthode sans CURL avec PHP5:

$url = 'http://server.com/path';
$data = array('key1' => 'value1', 'key2' => 'value2');

// use key 'http' even if you send the request to https://...
$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'method'  => 'POST',
        'content' => http_build_query($data)
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }

var_dump($result);

Voir le manuel PHP pour plus d'informations sur la méthode et comment ajouter des en-têtes, par exemple:

dbau
la source
64
Il convient de noter que si vous décidez d'utiliser un tableau pour les en-têtes, ne terminez PAS les clés ou les valeurs par «\ r \ n». stream_context_create () ne prendra le texte que jusqu'au premier '\ r \ n'
raptor
11
Une URL peut être utilisée comme nom de fichier file_get_contents()uniquement si les wrappers fopen ont été activés. Voir php.net/manual/en/…
Pino
3
@I lovefile_get_contents()
deadlock
14
Y a-t-il une raison spécifique pour ne pas utiliser CURL?
jvannistelrooy
37
@jvannistelrooy CURL for PHP est une extension qui peut ne pas exister dans tous les environnements alors qu'elle file_get_contents()fait partie du noyau de PHP. De plus, l'utilisation d'une extension inutilement peut élargir la surface d'attaque de votre application. Par exemple, Google php curl cve
Pockets et
139

Vous pouvez utiliser cURL :

<?php
//The url you wish to send the POST request to
$url = $file_name;

//The data you want to send via POST
$fields = [
    '__VIEWSTATE '      => $state,
    '__EVENTVALIDATION' => $valid,
    'btnSubmit'         => 'Submit'
];

//url-ify the data for the POST
$fields_string = http_build_query($fields);

//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);

//So that curl_exec returns the contents of the cURL; rather than echoing it
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); 

//execute post
$result = curl_exec($ch);
echo $result;
?>
Fred Tanrikut
la source
3
celui-ci a fonctionné pour moi parce que la page que j'envoie à une page qui n'a pas de contenu donc la version file_get_contents n'a pas fonctionné.
CommentLuv
9
La solution file_get_contents ne fonctionne pas sur les configurations PHP avec allow_url_fopen Off (comme dans l'hébergement mutualisé). Cette version utilise la bibliothèque curl et je pense qu'elle est la plus "universelle" donc je vous donne mon vote
Dayron Gallardo
81
Vous n'avez pas site où vous avez copié cet exemple de code à partir de: davidwalsh.name/curl-post
efreed
4
Bien que cela ne soit pas très important, les données du paramètre CURLOPT_POSTFIELDS n'ont en fait pas besoin d'être converties en chaîne ("urlified"). Quote: "Ce paramètre peut être transmis sous la forme d'une chaîne codée en url comme" para1 = val1 & para2 = val2 & ... "ou sous forme de tableau avec le nom de champ comme clé et les données de champ comme valeur. Si la valeur est un tableau, le Content-Type l'en-tête sera défini sur multipart / form-data. " Lien: php.net/manual/en/function.curl-setopt.php .
Edward
2
En outre, aucune infraction pour l'écrire différemment, mais je ne sais pas pourquoi le paramètre CURLOPT_POST est spécifié sous forme de nombre ici, comme il est dit de le définir sur un booléen sur la page de manuel. Citation: "CURLOPT_POST: VRAI pour faire un POST HTTP régulier." Lien: php.net/manual/en/function.curl-setopt.php .
Edward
68

J'utilise la fonction suivante pour publier des données en utilisant curl. $ data est un tableau de champs à publier (sera correctement encodé en utilisant http_build_query). Les données sont encodées en utilisant application / x-www-form-urlencoded.

function httpPost($url, $data)
{
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($curl);
    curl_close($curl);
    return $response;
}

@Edward mentionne que http_build_query peut être omis car curl encodera correctement le tableau passé au paramètre CURLOPT_POSTFIELDS, mais sachez que dans ce cas, les données seront encodées à l'aide de multipart / form-data.

J'utilise cette fonction avec des API qui s'attendent à ce que les données soient encodées en utilisant application / x-www-form-urlencoded. C'est pourquoi j'utilise http_build_query ().

Dima L.
la source
Le passage du tableau à CURLOPT_POSTFIELDS entraîne le codage des données à l'aide de données en plusieurs parties / de formulaire qui peuvent ne pas être souhaitables.
Dima L.
L'utilisateur a demandé file_get_contents, il a donc besoin d'une solution pour changer le default_stream_context
Radon8472
Pour clarifier: je pense à @DimaL. répond à un commentaire qui a été supprimé; http_build_queryconvertit le $datatableau en une chaîne, en évitant la sortie sous forme de parties / données de formulaire.
ToolmakerSteve
@ Radon8472 - ... CURLOPT_RETURNTRANSFER, truerésulte en $responsecontenant le contenu.
ToolmakerSteve
@ToolmakerSteve comme je l'ai dit, la question était pour file_get_contentset votre solution a besoin de CURL ce que beaucoup de gens n'ont pas. donc votre solution fonctionne peut-être, mais elle ne répond pas à la question de savoir comment le faire avec les fonctions natives de fichier / flux intégré.
Radon8472 du
42

Je vous recommande d'utiliser le package open-source Guzzle qui est entièrement testé et l' unité utilise les dernières pratiques de codage.

Installation de Guzzle

Accédez à la ligne de commande dans votre dossier de projet et tapez la commande suivante (en supposant que vous avez déjà installé le gestionnaire de package composer ). Si vous avez besoin d'aide pour installer Composer, vous devriez jeter un œil ici .

php composer.phar require guzzlehttp/guzzle

Utilisation de Guzzle pour envoyer une demande POST

L'utilisation de Guzzle est très simple car il utilise une API orientée objet légère:

// Initialize Guzzle client
$client = new GuzzleHttp\Client();

// Create a POST request
$response = $client->request(
    'POST',
    'http://example.org/',
    [
        'form_params' => [
            'key1' => 'value1',
            'key2' => 'value2'
        ]
    ]
);

// Parse the response object, e.g. read the headers, body, etc.
$headers = $response->getHeaders();
$body = $response->getBody();

// Output headers and body for debugging purposes
var_dump($headers, $body);
Andreas
la source
7
Il serait utile de savoir quels avantages cela présente par rapport à la solution PHP native déjà publiée, et la solution cURL également.
artfulrobot
9
@artfulrobot: La solution PHP native a beaucoup de problèmes (par exemple, connexion avec https, vérification de certificat, etc.pp.), c'est pourquoi presque tous les développeurs PHP utilisent cURL. Et pourquoi ne pas utiliser cURL dans ce cas? C'est simple: Guzzle a une interface simple, simple et légère qui résume tous ces "problèmes de gestion des cURL de bas niveau". Presque tout le monde qui développe PHP moderne utilise de toute façon Composer, donc utiliser Guzzle est vraiment très simple.
Andreas
2
Merci, je sais que guzzle est populaire, mais il existe des cas d'utilisation lorsque le compositeur cause du chagrin (par exemple, développer des plugins pour des projets logiciels plus importants qui pourraient déjà utiliser une (version différente) de guzzle ou d'autres dépendances), il est donc bon de connaître ces informations pour faire une décision sur la solution qui sera la plus robuste
artfulrobot
26

Il y a une autre méthode CURL si vous allez dans ce sens.

C'est assez simple une fois que vous avez compris comment fonctionne l'extension PHP curl, en combinant divers indicateurs avec des appels setopt (). Dans cet exemple, j'ai une variable $ xml qui contient le XML que j'ai préparé pour envoyer - je vais publier le contenu de cela dans la méthode de test de l'exemple.

$url = 'http://api.example.com/services/xmlrpc/';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
//process $response

Nous avons d'abord initialisé la connexion, puis nous avons défini certaines options à l'aide de setopt (). Ceux-ci indiquent à PHP que nous faisons une demande de publication et que nous envoyons des données avec, fournissant les données. L'indicateur CURLOPT_RETURNTRANSFER indique à curl de nous donner la sortie comme valeur de retour de curl_exec plutôt que de la sortir. Ensuite, nous faisons l'appel et fermons la connexion - le résultat est en réponse $.

Josip Ivic
la source
1
dans le 3ème appel curl_setopt (), le premier argument ne devrait $chpas être $curl, correct?
jcomeau_ictx
Pouvez-vous utiliser ce même code pour POSTER des données JSON? Mais remplacez $ xml par say $ json (où $ json est probablement une chaîne JSON?)
Neal Davis
24

Si par hasard vous utilisez Wordpress pour développer votre application (c'est en fait un moyen pratique d'obtenir une autorisation, des pages d'informations, etc., même pour des choses très simples), vous pouvez utiliser l'extrait de code suivant:

$response = wp_remote_post( $url, array('body' => $parameters));

if ( is_wp_error( $response ) ) {
    // $response->get_error_message()
} else {
    // $response['body']
}

Il utilise différentes façons de faire la demande HTTP réelle, selon ce qui est disponible sur le serveur Web. Pour plus de détails, consultez la documentation de l'API HTTP .

Si vous ne souhaitez pas développer un thème ou un plugin personnalisé pour démarrer le moteur Wordpress, vous pouvez simplement faire ce qui suit dans un fichier PHP isolé dans la racine wordpress:

require_once( dirname(__FILE__) . '/wp-load.php' );

// ... your code

Il ne montrera aucun thème ou ne produira aucun HTML, il suffit de pirater avec les API Wordpress!


la source
22

Je voudrais ajouter quelques réflexions sur la réponse en boucle de Fred Tanrikut. Je sais que la plupart d'entre eux sont déjà écrits dans les réponses ci-dessus, mais je pense que c'est une bonne idée de montrer une réponse qui les inclut tous ensemble.

Voici la classe que j'ai écrite pour faire des requêtes HTTP-GET / POST / PUT / DELETE basées sur curl, concernant à peu près le corps de la réponse:

class HTTPRequester {
    /**
     * @description Make HTTP-GET call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPGet($url, array $params) {
        $query = http_build_query($params); 
        $ch    = curl_init($url.'?'.$query);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    /**
     * @description Make HTTP-POST call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPPost($url, array $params) {
        $query = http_build_query($params);
        $ch    = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    /**
     * @description Make HTTP-PUT call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPPut($url, array $params) {
        $query = \http_build_query($params);
        $ch    = \curl_init();
        \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
        \curl_setopt($ch, \CURLOPT_HEADER, false);
        \curl_setopt($ch, \CURLOPT_URL, $url);
        \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'PUT');
        \curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
        $response = \curl_exec($ch);
        \curl_close($ch);
        return $response;
    }
    /**
     * @category Make HTTP-DELETE call
     * @param    $url
     * @param    array $params
     * @return   HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPDelete($url, array $params) {
        $query = \http_build_query($params);
        $ch    = \curl_init();
        \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
        \curl_setopt($ch, \CURLOPT_HEADER, false);
        \curl_setopt($ch, \CURLOPT_URL, $url);
        \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'DELETE');
        \curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
        $response = \curl_exec($ch);
        \curl_close($ch);
        return $response;
    }
}

Améliorations

  • Utiliser http_build_query pour extraire la chaîne de requête d'un tableau de requêtes (vous pouvez également utiliser le tableau lui-même, donc voir: http://php.net/manual/en/function.curl-setopt.php )
  • Renvoyer la réponse au lieu de l'écho. Btw vous pouvez éviter le retour en supprimant la ligne curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true); . Après cela, la valeur de retour est un booléen (true = la demande a réussi sinon une erreur s'est produite) et la réponse est répercutée. Voir: http://php.net/en/manual/function.curl-exec.php
  • Nettoyez la fermeture de session et la suppression du curl-handler en utilisant curl_close . Voir: http://php.net/manual/en/function.curl-close.php
  • Utiliser des valeurs booléennes pour la fonction curl_setopt au lieu d'utiliser n'importe quel nombre (je sais que tout nombre différent de zéro est également considéré comme vrai, mais l'utilisation de true génère un code plus lisible, mais c'est juste mon opinion)
  • Possibilité de faire des appels HTTP-PUT / DELETE (utile pour les tests de service RESTful)

Exemple d'utilisation

AVOIR

$response = HTTPRequester::HTTPGet("http://localhost/service/foobar.php", array("getParam" => "foobar"));

PUBLIER

$response = HTTPRequester::HTTPPost("http://localhost/service/foobar.php", array("postParam" => "foobar"));

METTRE

$response = HTTPRequester::HTTPPut("http://localhost/service/foobar.php", array("putParam" => "foobar"));

SUPPRIMER

$response = HTTPRequester::HTTPDelete("http://localhost/service/foobar.php", array("deleteParam" => "foobar"));

Essai

Vous pouvez également effectuer des tests de service intéressants en utilisant cette classe simple.

class HTTPRequesterCase extends TestCase {
    /**
     * @description test static method HTTPGet
     */
    public function testHTTPGet() {
        $requestArr = array("getLicenses" => 1);
        $url        = "http://localhost/project/req/licenseService.php";
        $this->assertEquals(HTTPRequester::HTTPGet($url, $requestArr), '[{"error":false,"val":["NONE","AGPL","GPLv3"]}]');
    }
    /**
     * @description test static method HTTPPost
     */
    public function testHTTPPost() {
        $requestArr = array("addPerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPPost($url, $requestArr), '[{"error":false}]');
    }
    /**
     * @description test static method HTTPPut
     */
    public function testHTTPPut() {
        $requestArr = array("updatePerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPPut($url, $requestArr), '[{"error":false}]');
    }
    /**
     * @description test static method HTTPDelete
     */
    public function testHTTPDelete() {
        $requestArr = array("deletePerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPDelete($url, $requestArr), '[{"error":false}]');
    }
}
mwatzer
la source
Pour moi, il dit "Erreur non interceptée: appel à la méthode non définie HTTPRequester :: HTTPost ()" . J'ai simplement collé votre classe dans mon fichier .php. Autre chose que je dois faire?
LinusGeffarth
1
Pouvez-vous s'il vous plaît poster votre code? Il est assez difficile de deviner ce qui ne va pas sans aucun extrait de code.
mwatzer
Comme je l'ai dit, j'ai littéralement copié le vôtre dans mon fichier php ordinaire et cela m'a donné cette erreur.
LinusGeffarth
1
Ok maintenant je vois le problème, .. c'était faux dans l'exemple! Vous devez appeler HTTPRequester :: HTTPPost () au lieu de HTTPRequester :: HTTPost ()
mwatzer
1
Ah. Celui-là est facile à manquer. J'ai dû lire votre commentaire comme 5x avant de repérer le P supplémentaire . Merci!
LinusGeffarth
20

Une autre alternative de la méthode sans boucle ci- dessus consiste à utiliser les fonctions de flux natives :

  • stream_context_create():

    Crée et renvoie un contexte de flux avec toutes les options fournies dans les options prédéfinies.

  • stream_get_contents():

    Identique à file_get_contents(), sauf qu'il stream_get_contents() fonctionne sur une ressource de flux déjà ouverte et renvoie le contenu restant dans une chaîne, jusqu'à maxlength octets et en commençant à l' offset spécifié .

Une fonction POST avec ceux-ci peut simplement être comme ceci:

<?php

function post_request($url, array $params) {
  $query_content = http_build_query($params);
  $fp = fopen($url, 'r', FALSE, // do not use_include_path
    stream_context_create([
    'http' => [
      'header'  => [ // header array does not need '\r\n'
        'Content-type: application/x-www-form-urlencoded',
        'Content-Length: ' . strlen($query_content)
      ],
      'method'  => 'POST',
      'content' => $query_content
    ]
  ]));
  if ($fp === FALSE) {
    return json_encode(['error' => 'Failed to get contents...']);
  }
  $result = stream_get_contents($fp); // no maxlength/offset
  fclose($fp);
  return $result;
}
CPHPython
la source
1
Cette méthode sans CURL a bien fonctionné pour moi pour valider reCAPTCHA de Google. Cette réponse converge avec ce code google: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Xavi Montero
1
Vous n'avez pas à utiliser fclose()si $fpc'est le cas false. Parce que fclose()attend une ressource est un paramètre.
Floris
1
@Floris l'a édité tout à l'heure et en effet la documentation de fclose mentionne "Le pointeur de fichier doit être valide". Merci de l'avoir remarqué!
CPHPython
8

La meilleure façon d'envoyer GETou de POSTdemander avec PHPest la suivante:

<?php
    $r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
    $r->setOptions(array('cookies' => array('lang' => 'de')));
    $r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));

    try {
        echo $r->send()->getBody();
    } catch (HttpException $ex) {
        echo $ex;
    }
?>

Le code est tiré de la documentation officielle ici http://docs.php.net/manual/da/httprequest.send.php

Imran Zahoor
la source
1
@akinuri merci d'avoir mis en évidence, je vais partager le nouveau.
Imran Zahoor le
comment faire sur PHP 5x?
@YumYumYum veuillez vérifier la réponse de dbau ci-dessus pour 5x qui utilise cette technique php.net/manual/en/function.stream-context-create.php Ou vous pouvez toujours revenir à la solution de curl standard.
Imran Zahoor
5

Il y en a un de plus que vous pouvez utiliser

<?php
$fields = array(
    'name' => 'mike',
    'pass' => 'se_ret'
);
$files = array(
    array(
        'name' => 'uimg',
        'type' => 'image/jpeg',
        'file' => './profile.jpg',
    )
);

$response = http_post_fields("http://www.example.com/", $fields, $files);
?>

Cliquez ici pour plus de détails

Code
la source
2
Cela repose sur une extension PECL que la plupart n'auront pas installée. Je ne suis même pas sûr qu'il soit toujours disponible, car les pages de manuel ont été supprimées.
miken32
5

Je cherchais un problème similaire et j'ai trouvé une meilleure approche pour le faire. Alors voilà.

Vous pouvez simplement mettre la ligne suivante sur la page de redirection (par exemple page1.php).

header("Location: URL", TRUE, 307); // Replace URL with to be redirected URL, e.g. final.php

J'en ai besoin pour rediriger les demandes POST pour les appels d'API REST . Cette solution est capable de rediriger avec des données de publication ainsi que des valeurs d'en-tête personnalisées.

Voici le lien de référence .

Arindam Nayak
la source
1
Cela explique comment rediriger une demande de page et non Comment envoyer une demande POST avec PHP? Bien sûr, cela transmettrait tous les paramètres POST, mais ce n'est pas du tout la même chose
Wesley Smith
@ DelightedD0D, Désolé je n'ai pas la différence entre redirect a page request with POST paramvs send POST request. Pour moi, le but des deux est le même, corrigez-moi si je me trompe.
Arindam Nayak
1
Y a-t-il une méthode qui me permettra d'envoyer des paramètres avec la méthode POST puis de lire le contenu via PHP? L'OP veut que leur script php construise un ensemble de paramètres POST et les envoie à une autre page php et que leur script reçoive la sortie de cette page. Cette solution accepterait simplement un ensemble de valeurs déjà POSTé et les transmettrait à une autre page. Ils sont assez différents.
Wesley Smith
5

Voici en utilisant une seule commande sans cURL. Super simple.

echo file_get_contents('https://www.server.com', false, stream_context_create([
    'http' => [
        'method' => 'POST',
        'header'  => "Content-type: application/x-www-form-urlencoded",
        'content' => http_build_query([
            'key1' => 'Hello world!', 'key2' => 'second value'
        ])
    ]
]));
Liga
la source
Comment fonctionnera le Key2? quel est le séparateur entre eux?
Sayed Muhammad Idrees
@Sayedidrees pour ajouter key2, vous pouvez le saisir comme deuxième élément du tableau. 'key1' => 'Hello world!', 'key2' => 'second value'
Liga
Cela fonctionne très bien lors de l'utilisation avec zapier.
Moxet
3

Essayez le package HTTP_Request2 de PEAR pour envoyer facilement des requêtes POST. Alternativement, vous pouvez utiliser les fonctions curl de PHP ou utiliser un contexte de flux PHP .

HTTP_Request2 permet également de simuler le serveur , vous pouvez donc tester facilement votre code

cweiske
la source
7
J'aimerais que vous l'élaboriez, si possible.
Gui Imamura du