PHP + curl, exemple de code HTTP POST?

491

Quelqu'un peut-il me montrer comment faire une boucle php avec un HTTP POST?

Je souhaite envoyer des données comme celle-ci:

username=user1, password=passuser1, gender=1

À www.domain.com

Je m'attends à ce que la boucle renvoie une réponse comme result=OK. Y a-t-il des exemples?

mysqllearner
la source

Réponses:

841
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,"http://www.example.com/tester.phtml");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
            "postvar1=value1&postvar2=value2&postvar3=value3");

// In real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS, 
//          http_build_query(array('postvar1' => 'value1')));

// Receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$server_output = curl_exec($ch);

curl_close ($ch);

// Further processing ...
if ($server_output == "OK") { ... } else { ... }
?>
miku
la source
47
pas besoin d'utiliser http_build_query()pour gérer les paramètres; il suffit de passer le tableau à CURLOPT_POSTFIELDSest suffisant.
Raptor
8
@Raptor fournissant un tableau directement à CURLOPT_POSTFIELDS en fait curl crée un type de POST légèrement différent. (Attendu: 100-continue)
Oleg Popov
22
De plus, si la valeur de CURLOPT_POSTFIELDSest un tableau, l'en- Content-Typetête sera défini sur au multipart/form-datalieu de application/x-www-form-urlencoded. php.net/manual/en/function.curl-setopt.php
Chloé
2
L'utilisation de CURLOPT_RETURNTRANSFER signifie que curl_exec renverra la réponse sous forme de chaîne plutôt que de la sortir.
bnp887
2
Je suggère d'utiliser trueau lieu de 1pour CURLOPT_POST.
FluorescentGreen5
261

De procédure

// set post fields
$post = [
    'username' => 'user1',
    'password' => 'passuser1',
    'gender'   => 1,
];

$ch = curl_init('http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

// execute!
$response = curl_exec($ch);

// close the connection, release resources used
curl_close($ch);

// do anything you want with your response
var_dump($response);

Orienté objet

<?php

// mutatis mutandis
namespace MyApp\Http;

class CurlPost
{
    private $url;
    private $options;

    /**
     * @param string $url     Request URL
     * @param array  $options cURL options
     */
    public function __construct($url, array $options = [])
    {
        $this->url = $url;
        $this->options = $options;
    }

    /**
     * Get the response
     * @return string
     * @throws \RuntimeException On cURL error
     */
    public function __invoke(array $post)
    {
        $ch = curl_init($this->url);

        foreach ($this->options as $key => $val) {
            curl_setopt($ch, $key, $val);
        }

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

        $response = curl_exec($ch);
        $error    = curl_error($ch);
        $errno    = curl_errno($ch);

        if (is_resource($ch)) {
            curl_close($ch);
        }

        if (0 !== $errno) {
            throw new \RuntimeException($error, $errno);
        }

        return $response;
    }
}

Usage

// create curl object
$curl = new \MyApp\Http\CurlPost('http://www.example.com');

try {
    // execute the request
    echo $curl([
        'username' => 'user1',
        'password' => 'passuser1',
        'gender'   => 1,
    ]);
} catch (\RuntimeException $ex) {
    // catch errors
    die(sprintf('Http error %s with code %d', $ex->getMessage(), $ex->getCode()));
}

Note latérale ici: il serait préférable de créer une sorte d'interface appelée AdapterInterfacepar exemple avec la getResponse()méthode et de laisser la classe ci-dessus l'implémenter. Ensuite, vous pouvez toujours échanger cette implémentation avec un autre adaptateur de votre choix, sans aucun effet secondaire sur votre application.

Utilisation de HTTPS / chiffrement du trafic

Habituellement, il y a un problème avec cURL en PHP sous le système d'exploitation Windows. En essayant de vous connecter à un point de terminaison protégé par https, vous obtiendrez une erreur vous le disant certificate verify failed.

Ce que la plupart des gens font ici, c'est de dire à la bibliothèque cURL d'ignorer simplement les erreurs de certificat et de continuer ( curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). Comme cela fera fonctionner votre code, vous introduisez un énorme trou de sécurité et permettez aux utilisateurs malveillants d'effectuer diverses attaques sur votre application comme l' attaque Man In The Middle ou autre.

Ne fais jamais ça. Au lieu de cela, il vous suffit de modifier votre php.iniet de dire à PHP où se trouve votre CA Certificatefichier pour le laisser vérifier correctement les certificats:

; modify the absolute path to the cacert.pem file
curl.cainfo=c:\php\cacert.pem

Les dernières cacert.pempeuvent être téléchargées sur Internet ou extraites de votre navigateur préféré . Lorsque vous modifiez php.inides paramètres associés, n'oubliez pas de redémarrer votre serveur Web.

emix
la source
4
Cela devrait vraiment être la réponse acceptée, car la meilleure pratique serait de laisser la bibliothèque HTTP gérer l'encodage de vos variables.
Eric Seastrand
4
Ce n'est pas toujours le cas. J'ai vu des serveurs Web qui s'attendent à ce que les variables POST soient encodées d'une certaine manière, ce qui entraînerait leur échec dans le cas contraire. Il me semble que http_build_query () est en fait plus fiable que cURL pour cela.
César
4
La spécification HTTP est assez simple sur la façon dont les paramètres POST devraient ressembler. Le logiciel du serveur Web doit de toute façon être conforme aux normes.
emix
1
En utilisant cette méthode, vous forcerez cURL à utiliser un type de POST légèrement différent. (Attendez-vous à: 100-continuer). Consultez cet article: support.urbanairship.com/entries/…
Oleg Popov
5
Développant le commentaire de @ César, la documentation PHP note explicitement ce qui suit: "Le passage d'un tableau à CURLOPT_POSTFIELDS codera les données en tant que multipart / form-data , tandis que le passage d'une chaîne codée URL codera les données en tant qu'application / x-www-form -urlencoded . ". J'ai récemment passé un temps excessif à essayer de résoudre les raisons pour lesquelles un appel cURL échouait sur un point de terminaison tiers pour finalement réaliser qu'ils ne prenaient pas en charge les données de formulaire / multipart.
Jake Z
31

Un exemple en direct d'utilisation de php curl_exec pour faire un post HTTP:

Mettez ceci dans un fichier appelé foobar.php:

<?php
  $ch = curl_init();
  $skipper = "luxury assault recreational vehicle";
  $fields = array( 'penguins'=>$skipper, 'bestpony'=>'rainbowdash');
  $postvars = '';
  foreach($fields as $key=>$value) {
    $postvars .= $key . "=" . $value . "&";
  }
  $url = "http://www.google.com";
  curl_setopt($ch,CURLOPT_URL,$url);
  curl_setopt($ch,CURLOPT_POST, 1);                //0 for a get request
  curl_setopt($ch,CURLOPT_POSTFIELDS,$postvars);
  curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,3);
  curl_setopt($ch,CURLOPT_TIMEOUT, 20);
  $response = curl_exec($ch);
  print "curl response is:" . $response;
  curl_close ($ch);
?>

Ensuite, exécutez-le avec la commande php foobar.php, il vide ce type de sortie à l'écran:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Title</title>

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<body>
  A mountain of content...
</body>
</html>

Vous avez donc effectué un POST PHP sur www.google.com et lui avez envoyé des données.

Si le serveur avait été programmé pour lire les variables de post, il pourrait décider de faire quelque chose de différent en fonction de cela.

Eric Leschinski
la source
$postvars .= $key . $value;devrait $postvars .= $key . $value ."&";ou non?
Manwal
En examinant à nouveau cette réponse, vous pouvez également remplacer votre implémentation de convertisseur de chaîne de requête personnalisée par http_build_query , donnez-lui simplement le $fieldstableau et il produira une chaîne de requête.
Sachez que vous devez coder vos données afin qu'elles soient soumises en toute sécurité.
wtf8_decode
3
Oh non, n'essayez pas de construire la chaîne de message vous-même! utiliser ceci:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam
3
-1 parce que vous n'échappez pas à vos post-var. L'exemple du PO envoie des noms d'utilisateur et des mots de passe soumis par l'utilisateur pour l'authentification. Avec votre solution, un utilisateur avec un & dans son mot de passe ne pourra jamais se connecter. Le commentaire de oriadam est correct, mais vous pouvez laisser de côté http_build_querycomme:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand
26

Il est facilement accessible avec:

<?php

$post = [
    'username' => 'user1',
    'password' => 'passuser1',
    'gender'   => 1,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.domain.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$response = curl_exec($ch);
var_export($response);
V. Kovpak
la source
13

Curl Post + Gestion des erreurs + Définir les en-têtes [merci à @ mantas-d]:

function curlPost($url, $data=NULL, $headers = NULL) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    if(!empty($data)){
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }

    if (!empty($headers)) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }

    $response = curl_exec($ch);

    if (curl_error($ch)) {
        trigger_error('Curl Error:' . curl_error($ch));
    }

    curl_close($ch);
    return $response;
}


curlPost('google.com', [
    'username' => 'admin',
    'password' => '12345',
]);
MSS
la source
Votre code ne fermera pas le handle et les ressources libres, car vous curl_close après avoir levé une exception. Vous devez curl_close à l'intérieur d'un bloc finally.
emix
7
curlPost('google.com', [
    'username' => 'admin',
    'password' => '12345',
]);


function curlPost($url, $data) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    $response = curl_exec($ch);
    $error = curl_error($ch);
    curl_close($ch);
    if ($error !== '') {
        throw new \Exception($error);
    }

    return $response;
}
Mantas D
la source
1
Votre code ne fermera pas le handle et les ressources libres, car vous curl_close après avoir levé une exception. Vous devriez à l' curl_closeintérieur d'un finallybloc.
emix
6

Si le formulaire utilise des redirections, une authentification, des cookies, SSL (https) ou autre chose qu'un script totalement ouvert qui attend des variables POST, vous allez commencer à grincer des dents très rapidement. Jetez un œil à Snoopy , qui fait exactement ce que vous avez en tête tout en supprimant la nécessité de configurer une grande partie des frais généraux.

Anthony
la source
Si vous voulez vous en tenir à la curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
bibliothèque de
Le seul inconvénient est que vous devez toujours gérer la configuration d'un pot de cookies et d'autres problèmes potentiels (comme suivre les redirections, comment gérer l'authentification non basée sur HTTP, etc.). 6 ans plus tard, je recommanderais le concept plus générique de "navigateur sans tête" au lieu de cette bibliothèque spécifique (ou quoi que ce soit sur sourceforge, quelle date, non?) Et même si je ne traite généralement que des options de curl, je conseillerais en regardant une bibliothèque de navigateur sans tête compatible PSR-7 (Guzzle est la seule que je connaisse de l'extérieur) pour éviter les maux de tête.
Anthony
3

Une réponse plus simple SI vous transmettez des informations à votre propre site Web est d'utiliser une variable SESSION. Commencez la page php avec:

session_start();

Si, à un moment donné, vous souhaitez générer des informations en PHP et passer à la page suivante de la session, au lieu d'utiliser une variable POST, affectez-la à une variable SESSION. Exemple:

$_SESSION['message']='www.'.$_GET['school'].'.edu was not found.  Please try again.'

Ensuite, sur la page suivante, vous référencez simplement cette variable SESSION. REMARQUE: après l'avoir utilisé, assurez-vous de le détruire, afin qu'il ne persiste pas après son utilisation:

if (isset($_SESSION['message'])) {echo $_SESSION['message']; unset($_SESSION['message']);}
user2532795
la source
3

Voici du code standard pour PHP + curl http://www.webbotsspidersscreenscrapers.com/DSP_download.php

inclure dans ces bibliothèques simplifiera le développement

<?php
# Initialization
include("LIB_http.php");
include("LIB_parse.php");
$product_array=array();
$product_count=0;

# Download the target (store) web page
$target = "http://www.tellmewhenitchanges.com/buyair";
$web_page = http_get($target, "");
    ...
?>
AzizSM
la source
2

Si vous essayez de vous connecter sur le site avec des cookies.

Ce code:

if ($server_output == "OK") { ... } else { ... }

Peut ne pas fonctionner si vous essayez de vous connecter, car de nombreux sites renvoient le statut 200, mais la publication échoue.

Un moyen facile de vérifier si la connexion est réussie est de vérifier s'il réinstalle les cookies. Si en sortie ont une chaîne Set-Cookies, cela signifie que les publications ne réussissent pas et que la nouvelle session démarre.

La publication peut également réussir, mais le statut peut être redirigé à la place 200.

Pour être sûr que le message est réussi, essayez ceci:

Suivez l'emplacement après le message, il ira donc à la page vers laquelle le message est redirigé:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Et puis vérifiez si de nouveaux cookies existent dans la demande:

if (!preg_match('/^Set-Cookie:\s*([^;]*)/mi', $server_output)) 

{echo 'post successful'; }

else { echo 'not successful'; }
Atanas Atanasov
la source
1

Exemples d'envoi de formulaire et de données brutes :

$curlHandler = curl_init();

curl_setopt_array($curlHandler, [
    CURLOPT_URL => 'https://postman-echo.com/post',
    CURLOPT_RETURNTRANSFER => true,

    /**
     * Specify POST method
     */
    CURLOPT_POST => true,

    /**
     * Specify array of form fields
     */
    CURLOPT_POSTFIELDS => [
        'foo' => 'bar',
        'baz' => 'biz',
    ],
]);

$response = curl_exec($curlHandler);

curl_close($curlHandler);

echo($response);
Serhii Andriichuk
la source