Come posso inviare una richiesta POST con PHP?


655

In realtà voglio leggere i contenuti che vengono dopo la query di ricerca, quando è fatto. Il problema è che l'URL accetta solo POSTmetodi e non esegue alcuna azione con il GETmetodo ...

Devo leggere tutti i contenuti con l'aiuto di domdocumento file_get_contents(). Esiste un metodo che mi consente di inviare parametri con POSTmetodo e quindi di leggere i contenuti tramite PHP?

Risposte:


1259

Metodo CURL-less con 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);

Consulta il manuale di PHP per ulteriori informazioni sul metodo e su come aggiungere le intestazioni, ad esempio:


64
Vale la pena notare che se si decide di utilizzare un array per le intestazioni, NON terminare le chiavi o i valori con '\ r \ n'. stream_context_create () prenderà il testo solo fino al primo '\ r \ n'
raptor,

11
Un URL può essere utilizzato come nome file file_get_contents()solo se i wrapper fopen sono stati abilitati. Vedi php.net/manual/it/…
Pino il

3
@Io amofile_get_contents()
deadlock

14
C'è un motivo specifico per non usare CURL?
jvannistelrooy,

37
@jvannistelrooy CURL per PHP è un'estensione che potrebbe non esistere in tutti gli ambienti mentre file_get_contents()fa parte del nucleo di PHP. Inoltre, l'utilizzo di un'estensione inutilmente può ampliare la superficie di attacco della tua app. Ad esempio Google php curl cve
Pocketsand,

139

Puoi usare 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;
?>

3
questo ha funzionato per me perché la pagina che sto inviando a una pagina che non ha contenuto, quindi la versione di file_get_contents non ha funzionato.
CommentLuv

9
La soluzione file_get_contents non funziona su configurazioni PHP con allow_url_fopen Off (come nell'hosting condiviso). Questa versione usa la libreria curl e penso che sia la più "universale", quindi ti do il mio voto
Dayron Gallardo,

81
Non hai trovato il sito in cui hai copiato questo esempio di codice da: davidwalsh.name/curl-post
efreed

4
Sebbene non sia molto importante, i dati dei parametri CURLOPT_POSTFIELDS non devono essere convertiti in una stringa ("urized"). Citazione: "Questo parametro può essere passato come una stringa codificata come 'para1 = val1 & para2 = val2 & ...' o come un array con il nome del campo come chiave e dati del campo come valore. Se value è un array, Content-Type l'intestazione sarà impostata su multipart / form-data. " Link: php.net/manual/en/function.curl-setopt.php .
Edward

2
Inoltre, senza offesa per averlo scritto in modo diverso, ma non so perché il parametro CURLOPT_POST sia specificato come un numero qui come dice di impostarlo su un valore booleano nella pagina del manuale. Citazione: "CURLOPT_POST: TRUE per eseguire un normale POST HTTP." Link: php.net/manual/en/function.curl-setopt.php .
Edward

68

Uso la seguente funzione per pubblicare i dati usando l'arricciatura. $ data è un array di campi da pubblicare (sarà codificato correttamente usando http_build_query). I dati vengono codificati utilizzando 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 menziona che http_build_query può essere omesso poiché il ricciolo codificherà correttamente l'array passato al parametro CURLOPT_POSTFIELDS, ma si ricorda che in questo caso i dati verranno codificati usando multipart / form-data.

Uso questa funzione con le API che prevedono la codifica dei dati mediante application / x-www-form-urlencoded. Ecco perché uso http_build_query ().


Il passaggio dell'array a CURLOPT_POSTFIELDS comporta la codifica dei dati utilizzando dati multipart / form che potrebbero non essere desiderabili.
Dima L.,

L'utente ha richiesto file_get_contents, quindi ha bisogno di una soluzione per modificare default_stream_context
Radon8472

Per chiarire: penso che @DimaL. sta rispondendo a un commento che è stato eliminato; http_build_queryconverte l' $dataarray in una stringa, evitando l'output come multipart / form-data.
ToolmakerSteve

@ Radon8472 - ... CURLOPT_RETURNTRANSFER, truerisultati nel $responsecontenere i contenuti.
ToolmakerSteve

@ToolmakerSteve, come ho detto, la domanda era file_get_contentse la tua soluzione ha bisogno di CURL ciò che molte persone non hanno. quindi la tua soluzione sta forse funzionando, ma non risponde alla domanda su come farlo con le funzioni di file / stream incorporate native.
Radon8472,

42

Ti consiglio di usare il guzzle del pacchetto open source che è completamente testato dall'unità e utilizza le ultime pratiche di codifica.

Installazione di Guzzle

Vai alla riga di comando nella cartella del tuo progetto e digita il seguente comando (supponendo che tu abbia già installato il compositore del gestore pacchetti ). Se hai bisogno di aiuto su come installare Composer, dovresti dare un'occhiata qui .

php composer.phar require guzzlehttp/guzzle

Utilizzo di Guzzle per inviare una richiesta POST

L'uso di Guzzle è molto semplice in quanto utilizza un'API orientata agli oggetti leggera:

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

7
Sarebbe utile sapere quali vantaggi ha rispetto alla soluzione PHP nativa già pubblicata e anche a quella cURL.
artfulrobot,

9
@artfulrobot: la soluzione PHP nativa presenta molti problemi (ad es. connessione con https, verifica del certificato, ecc.), motivo per cui quasi tutti gli sviluppatori PHP usano cURL. E perché non usare cURL in questo caso? È semplice: Guzzle ha un'interfaccia semplice, semplice e leggera che consente di eliminare tutti quei "problemi di gestione dei cURL di basso livello". Quasi tutti coloro che sviluppano PHP moderno usano comunque Composer, quindi usare Guzzle è davvero molto semplice.
Andreas,

2
Grazie, so che guzzle è popolare, tuttavia ci sono casi d'uso in cui compositore provoca dolore (ad es. Sviluppo di plugin per progetti software più grandi che potrebbero già utilizzare una (diversa versione) di guzzle o altre dipendenze), quindi è bene conoscere queste informazioni per rendere una decisione su quale soluzione sarà più robusta
artfulrobot il

26

C'è un altro metodo CURL se stai andando in quel modo.

Questo è piuttosto semplice una volta che hai la testa sul modo in cui funziona l'estensione PHP curl, combinando vari flag con chiamate setopt (). In questo esempio ho una variabile $ xml che contiene l'XML che ho preparato per l'invio - pubblicherò il contenuto di questo nel metodo di test dell'esempio.

$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

Inizialmente abbiamo inizializzato la connessione, quindi abbiamo impostato alcune opzioni usando setopt (). Questi dicono a PHP che stiamo facendo una richiesta di posta e che stiamo inviando alcuni dati con esso, fornendo i dati. Il flag CURLOPT_RETURNTRANSFER dice a curl di darci l'output come valore di ritorno di curl_exec anziché emetterlo. Quindi effettuiamo la chiamata e chiudiamo la connessione - il risultato è in $ response.


1
nella chiamata terza curl_setopt (), il primo arg dovrebbe essere $chno $curl, giusto?
jcomeau_ictx,

Puoi usare questo stesso codice per inviare i dati JSON? Ma sostituisci $ xml con diciamo $ json (dove $ json è probabilmente una stringa JSON?)
Neal Davis,

24

Se per caso stai usando Wordpress per sviluppare la tua app (in realtà è un modo conveniente per ottenere autorizzazioni, pagine di informazioni ecc. Anche per cose molto semplici), puoi usare il seguente frammento:

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

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

Utilizza diversi modi per effettuare la richiesta HTTP effettiva, a seconda di ciò che è disponibile sul server web. Per ulteriori dettagli, consultare la documentazione dell'API HTTP .

Se non vuoi sviluppare un tema o plugin personalizzato per avviare il motore di Wordpress, puoi semplicemente fare quanto segue in un file PHP isolato nella radice di wordpress:

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

// ... your code

Non mostrerà alcun tema o non produrrà alcun HTML, basta tagliare via con le API di Wordpress!


22

Vorrei aggiungere alcune riflessioni sulla risposta a base di ricci di Fred Tanrikut. So che molti di loro sono già scritti nelle risposte sopra, ma penso che sia una buona idea mostrare una risposta che li includa tutti insieme.

Ecco la classe che ho scritto per effettuare richieste HTTP-GET / POST / PUT / DELETE in base al ricciolo, concernente solo il corpo della risposta:

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

miglioramenti

  • Utilizzo di http_build_query per estrarre la stringa di query da un array di richieste (è possibile utilizzare anche l'array stesso, quindi consultare: http://php.net/manual/en/function.curl-setopt.php )
  • Restituisce la risposta invece di farla eco. Tra l'altro puoi evitare il ritorno rimuovendo la riga curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true); . Dopodiché il valore restituito è un valore booleano (true = richiesta eseguita correttamente altrimenti si è verificato un errore) e la risposta viene ripetuta. Vedi: http://php.net/en/manual/function.curl-exec.php
  • Pulisci la chiusura della sessione e la cancellazione del gestore ricciolo usando curl_close . Vedi: http://php.net/manual/en/function.curl-close.php
  • Usare valori booleani per la funzione curl_setopt invece di usare qualsiasi numero (so che qualsiasi numero diverso da zero è anche considerato vero, ma l'uso di vero genera un codice più leggibile, ma questa è solo la mia opinione)
  • Possibilità di effettuare chiamate HTTP-PUT / DELETE (utile per il test del servizio RESTful)

Esempio di utilizzo

OTTENERE

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

INVIARE

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

METTERE

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

ELIMINA

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

analisi

Puoi anche fare dei fantastici test di servizio usando questa semplice classe.

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}]');
    }
}

Per me, dice "Errore non rilevato: chiamata al metodo indefinito HTTPRequester :: HTTPost ()" . Ho semplicemente incollato la tua classe nel mio file .php. Qualcos'altro che devo fare?
LinusGeffarth

1
Puoi per favore pubblicare il tuo codice? È piuttosto difficile indovinare cosa c'è che non va senza alcun frammento di codice.
mwatzer,

Come ho detto, ho letteralmente copiato il tuo nel mio semplice file php e questo mi ha dato questo errore.
LinusGeffarth,

1
Ok ora vedo il problema, .. era sbagliato nell'esempio! Devi chiamare HTTPRequester :: HTTPPost () invece di HTTPRequester :: HTTPost ()
mwatzer il

1
Ah. È facile da perdere. Ho dovuto leggere il tuo commento come 5x prima di individuare la P in più . Grazie!
LinusGartharth

20

Un'altra alternativa del metodo senza arricciatura sopra è utilizzare le funzioni di flusso native :

  • stream_context_create():

    Crea e restituisce un contesto di flusso con qualsiasi opzione fornita nelle opzioni predefinite.

  • stream_get_contents():

    Identico a file_get_contents(), tranne che stream_get_contents() opera su una risorsa di flusso già aperta e restituisce i contenuti rimanenti in una stringa, fino a byte di massima lunghezza e a partire dall'offset specificato .

Una funzione POST con questi può essere semplicemente così:

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

1
Questo metodo senza CURL ha funzionato bene per me per convalidare reCAPTCHA da google. Questa risposta converge con questo codice google: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Xavi Montero,

1
Non è necessario utilizzare fclose()se lo $fpè false. Perché si fclose()aspetta che una risorsa sia un parametro.
Floris,

1
@Floris Modificato proprio ora e in effetti il documento fclose menziona "Il puntatore al file deve essere valido". Grazie per averlo notato!
CPHPython,

8

Il modo migliore di inviare GETo POSTrichiedere PHPè come di seguito:

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

Il codice è tratto dalla documentazione ufficiale qui http://docs.php.net/manual/da/httprequest.send.php


1
@akinuri grazie per aver messo in evidenza, ho intenzione di condividere quello nuovo.
Imran Zahoor,

come farlo su PHP 5x?

@YumYumYum per favore controlla la risposta di dbau sopra per 5x che usa questa tecnica php.net/manual/en/function.stream-context-create.php O puoi sempre tornare alla soluzione standard di arricciatura.
Imran Zahoor,

5

Ce n'è ancora uno che puoi usare

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

Clicca qui per i dettagli


2
Questo si basa su un'estensione PECL che la maggior parte non avrà installato. Non sono nemmeno sicuro che sia ancora disponibile, poiché le pagine del manuale sono state rimosse.
miken32,

5

Stavo cercando un problema simile e ho trovato un approccio migliore per farlo. Quindi eccolo qui.

Puoi semplicemente inserire la seguente riga nella pagina di reindirizzamento (ad esempio pagina1.php).

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

Ho bisogno di questo per reindirizzare le richieste POST per le chiamate all'API REST . Questa soluzione è in grado di reindirizzare con i dati dei post e i valori di intestazione personalizzati.

Ecco il link di riferimento .


1
Questo risponde come reindirizzare una richiesta di pagina non Come posso inviare una richiesta POST con PHP? Sicuramente questo inoltrerebbe qualsiasi parametro POST ma non è affatto la stessa cosa
Wesley Smith

@ DelightedD0D, dispiace non ho avuto la differenza tra redirect a page request with POST paramvs send POST request. Per me lo scopo di entrambi è lo stesso, correggimi se sbaglio.
Arindam Nayak

1
Esiste un metodo che mi consente di inviare parametri con il metodo POST e quindi di leggere i contenuti tramite PHP? L'OP vuole che il suo script php costruisca una serie di parametri POST e li invii a un'altra pagina php e che il loro script riceva l'output da quella pagina. Questa soluzione accetterebbe semplicemente un set di valori già POST e li inoltrerebbe a un'altra pagina. Sono piuttosto diversi.
Wesley Smith,

5

Qui sta usando solo un comando senza cURL. Super semplice.

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'
        ])
    ]
]));

Come funzionerà Key2? qual è il separatore tra loro?
Ha detto Muhammad Idrees il

@Sayedidrees per aggiungere key2 è possibile inserirlo come secondo elemento dell'array. 'key1' => 'Hello world!', 'key2' => 'second value'
Liga

Funziona molto bene durante l'utilizzo con zapier.
Moxet,

3

Prova il pacchetto HTTP_Request2 di PEAR per inviare facilmente richieste POST. In alternativa, è possibile utilizzare le funzioni di arricciatura di PHP o utilizzare un contesto di flusso PHP .

HTTP_Request2 consente anche di deridere il server , in modo da poter testare l'unità facilmente il codice


7
Mi piacerebbe vederti per elaborarlo, se possibile.
Gui Imamura,
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.