PHP + curl, codice di esempio HTTP POST?


491

Qualcuno può mostrarmi come fare un ricciolo php con un POST HTTP?

Voglio inviare dati come questo:

username=user1, password=passuser1, gender=1

Per www.domain.com

Mi aspetto che il ricciolo restituisca una risposta simile result=OK. Ci sono degli esempi?

Risposte:


840
<?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 { ... }
?>

47
non è necessario utilizzare http_build_query()per gestire i parametri; è sufficiente passare l'array a CURLOPT_POSTFIELDS.
Raptor

8
@Raptor fornisce array direttamente a CURLOPT_POSTFIELDS in realtà arricciatura rende leggermente diverso il tipo di POST. (Aspettatevi: 100-continua)
Oleg Popov,

22
Anche se il valore di CURLOPT_POSTFIELDS è un array, l' Content-Typeintestazione verrà impostata su multipart/form-datainvece di application/x-www-form-urlencoded. php.net/manual/en/function.curl-setopt.php
Chloe

2
L'uso di CURLOPT_RETURNTRANSFER significa che curl_exec restituirà la risposta come una stringa anziché emetterla.
bnp887,

2
Suggerisco di utilizzare trueinvece di1 per CURLOPT_POST.
FluorescentGreen5

261

Procedurale

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

Orientato agli oggetti

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

uso

// 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()));
}

Nota a margine qui: sarebbe meglio creare una sorta di interfaccia chiamata AdapterInterfacead esempio con il getResponse()metodo e lasciare che la classe sopra lo implementasse. Quindi puoi sempre scambiare questa implementazione con un altro adattatore di tuo gradimento, senza effetti collaterali per la tua applicazione.

Utilizzo del traffico HTTPS / crittografato

Di solito c'è un problema con cURL in PHP con il sistema operativo Windows. Durante il tentativo di connettersi a un endpoint protetto https, verrà visualizzato un errore certificate verify failed.

Quello che la maggior parte delle persone fa qui è dire alla libreria cURL di ignorare semplicemente gli errori del certificato e continue ( curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). Poiché questo farà funzionare il tuo codice, introduci un enorme buco nella sicurezza e consenti agli utenti malintenzionati di eseguire vari attacchi alla tua app come l' attacco Man In The Middle o simili.

Mai e poi mai. Invece, devi semplicemente modificare il tuo php.inie dire a PHP dove si trova il tuo CA Certificatefile per permettergli di verificare correttamente i certificati:

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

Le ultime cacert.pempossono essere scaricate da Internet o estratte dal tuo browser preferito . Quando si cambia qualsiasiphp.ini impostazioni correlate, ricordarsi di riavviare il server Web.


4
Questa dovrebbe davvero essere la risposta accettata, poiché la migliore pratica sarebbe quella di consentire alla libreria HTTP di gestire la codifica delle variabili.
Eric Seastrand,

4
Questo non è sempre il caso. Ho visto server Web che si aspettano che le variabili POST vengano codificate in un certo modo, causando altrimenti errori. Mi sembra che http_build_query () sia effettivamente più affidabile di cURL per questo.
César,

4
Le specifiche HTTP sono piuttosto semplici su come dovrebbero apparire i parametri POST. Il software del server web dovrebbe comunque essere conforme agli standard.
emix

1
Usando questo modo forzerai cURL a usare un tipo di POST leggermente diverso. (Aspettatevi: 100-continua). Controlla questo articolo: support.urbanairship.com/entries/…
Oleg Popov,

5
Espandendo il commento di @ César, la documentazione di PHP nota esplicitamente quanto segue: "Il passaggio di un array a CURLOPT_POSTFIELDS codificherà i dati come multipart / form-data , mentre il passaggio di una stringa con codifica URL codificherà i dati come application / x-www-form codificato ". Di recente ho trascorso una quantità eccessiva di tempo cercando di risolvere il motivo per cui una chiamata cURL non andava a buon fine su un endpoint di terze parti solo per rendermi conto alla fine che non supportavano multipart / form-data.
Jake Z,

31

Un esempio live dell'utilizzo di php curl_exec per eseguire un post HTTP:

Mettilo in un file chiamato 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);
?>

Quindi eseguilo con il comando php foobar.php, scarica questo tipo di output sullo schermo:

<!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>

Quindi hai inviato un PHP POST a www.google.com e gli hai inviato alcuni dati.

Se il server fosse stato programmato per leggere nelle variabili post, avrebbe potuto decidere di fare qualcosa di diverso in base a quello.


$postvars .= $key . $value;dovrebbe $postvars .= $key . $value ."&";o no?
Manwal,

Guardando di nuovo questa risposta, è anche possibile sostituire l'implementazione del convertitore di stringhe di query personalizzate con http_build_query , assegnargli semplicemente l' $fieldsarray e verrà generata una stringa di query.

Tieni presente che devi codificare i tuoi dati affinché possano essere inviati in modo sicuro.
wtf8_decode

3
Oh no, non provare a creare tu stesso la stringa post! usa questo:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam,

3
-1 perché non stai sfuggendo ai tuoi post vars. L'esempio del PO sta inviando nomi utente e password inviati dall'utente per l'autenticazione. Con la tua soluzione, un utente con un & nella sua password non sarà mai in grado di accedere. Il commento di oriadam è corretto, ma puoi lasciarlo fuori http_build_querycome:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand

26

È facilmente raggiungibile con:

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

13

Curl Post + Gestione errori + Imposta intestazioni [grazie a @ 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',
]);

Il tuo codice non chiuderà l'handle e libererà risorse, perché curl_close dopo aver lanciato un'eccezione. Dovresti curl_close all'interno di un blocco 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;
}

1
Il tuo codice non chiuderà l'handle e libererà risorse, perché curl_close dopo aver lanciato un'eccezione. Dovresti entrare curl_closein un finallyblocco.
emix

6

Se il modulo utilizza reindirizzamenti, autenticazione, cookie, SSL (https) o qualsiasi altra cosa diversa da uno script totalmente aperto in attesa di variabili POST, inizierai a digrignare i denti molto rapidamente. Dai un'occhiata a Snoopy , che fa esattamente quello che hai in mente rimuovendo la necessità di impostare un sacco di spese generali.


Se vuoi rimanere con la lib di scorta, prova ad aggiungerecurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
MarkHu il

L'unico aspetto negativo è che devi ancora gestire l'impostazione di un cookie jar e altri potenziali problemi (come se seguire i reindirizzamenti, come gestire l'autenticazione non basata su HTTP, ecc.). 6 anni dopo, consiglierei il concetto più generico di "browser senza testa" invece di quella libreria specifica (o qualsiasi cosa su sourceforge, con quale data, giusto?) E mentre generalmente mi occupo solo direttamente delle opzioni di arricciatura, consiglierei comunque guardando una libreria di browser senza testa compatibile con PSR-7 (Guzzle è l'unico che conosco a mani nude) per evitare mal di testa.
Anthony,

3

Una risposta più semplice SE si stanno trasmettendo informazioni al proprio sito Web è utilizzare una variabile SESSIONE. Inizia pagina php con:

session_start();

Se ad un certo punto ci sono informazioni che vuoi generare in PHP e passare alla pagina successiva nella sessione, invece di usare una variabile POST, assegnale a una variabile SESSION. Esempio:

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

Quindi nella pagina successiva fai semplicemente riferimento a questa variabile SESSION. NOTA: dopo averlo usato, assicurati di distruggerlo, quindi non persiste dopo l'uso:

if (isset($_SESSION['message'])) {echo $_SESSION['message']; unset($_SESSION['message']);}

3

Ecco un po 'di codice boilerplate per PHP + curl http://www.webbotsspidersscreenscrapers.com/DSP_download.php

includere in queste librerie semplificherà lo sviluppo

<?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, "");
    ...
?>

2

Se si tenta di accedere al sito con i cookie.

Questo codice:

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

Potrebbe non funzionare se si tenta di accedere, poiché molti siti restituiscono lo stato 200, ma il post non ha esito positivo.

Un modo semplice per verificare se il post di accesso ha esito positivo è verificare se i cookie vengono nuovamente impostati. Se nell'output ha una stringa Set-Cookies, ciò significa che i post non hanno esito positivo e avvia una nuova sessione.

Anche il post può avere esito positivo, ma è possibile reindirizzare lo stato invece 200.

Per essere sicuro che il post abbia successo, prova questo:

Segui la posizione dopo il post, quindi andrà alla pagina in cui il post reindirizza a:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

E poi controlla se i nuovi cookie esistono nella richiesta:

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

{echo 'post successful'; }

else { echo 'not successful'; }

1

Esempi di invio di moduli e dati grezzi :

$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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.