PHP + curl, przykładowy kod HTTP POST?


491

Czy ktoś może mi pokazać, jak zrobić curl php z POST HTTP?

Chcę wysłać takie dane:

username=user1, password=passuser1, gender=1

Do www.domain.com

Oczekuję, że curl zwróci odpowiedź jak result=OK. Czy są jakieś przykłady?

Odpowiedzi:


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
nie trzeba używać http_build_query()do obsługi parametrów; wystarczy przekazać tablicę, aby CURLOPT_POSTFIELDSwystarczy.
Raptor,

8
@Raptor udostępniający tablicę bezpośrednio do CURLOPT_POSTFIELDS faktycznie zwijanie się powoduje nieco inny typ POST. (Oczekuje się: 100-kontynuacja)
Oleg Popov

22
Również jeśli wartością CURLOPT_POSTFIELDSjest tablica, Content-Typenagłówek zostanie ustawiony na multipart/form-datazamiast application/x-www-form-urlencoded. php.net/manual/en/function.curl-setopt.php
Chloe

2
Użycie CURLOPT_RETURNTRANSFER oznacza, że ​​curl_exec zwróci odpowiedź jako ciąg, a nie wyśle ​​go.
bnp887

2
Sugeruję używanie truezamiast 1dla CURLOPT_POST.
FluorescentGreen5,

260

Proceduralny

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

Obiektowy

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

Stosowanie

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

Uwaga dodatkowa: najlepiej byłoby stworzyć interfejs wywoływany AdapterInterfacena przykład getResponse()metodą i pozwolić, aby klasa powyżej go zaimplementowała. Następnie zawsze możesz zamienić tę implementację na inny podobny adapter, bez żadnych skutków ubocznych dla twojej aplikacji.

Korzystanie z HTTPS / szyfrowanie ruchu

Zwykle występuje problem z cURL w PHP w systemie operacyjnym Windows. Podczas próby połączenia się z punktem końcowym chronionym https, pojawi się komunikat o błędzie certificate verify failed.

Większość ludzi robi tutaj, aby powiedzieć bibliotece cURL, aby po prostu zignorowała błędy certyfikatu i kontynuowała ( curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). Dzięki temu Twój kod będzie działał, wprowadzasz ogromną lukę w zabezpieczeniach i umożliwiasz złośliwym użytkownikom przeprowadzanie różnych ataków na Twoją aplikację, takich jak atak Man In The Middle lub podobny .

Nigdy, nigdy tego nie rób. Zamiast tego wystarczy zmodyfikować php.iniswój CA Certificateplik i poinformować PHP, gdzie plik ma umożliwić poprawną weryfikację certyfikatów:

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

Najnowsze cacert.pemmożna pobrać z Internetu lub wyodrębnić z ulubionej przeglądarki . Podczas zmiany php.inipowiązanych ustawień pamiętaj o ponownym uruchomieniu serwera.


4
To powinna być naprawdę zaakceptowana odpowiedź, ponieważ najlepszą praktyką byłoby pozwolenie bibliotece HTTP obsługiwać kodowanie zmiennych.
Eric Seastrand,

4
Nie zawsze tak jest. Widziałem serwery sieci Web, które oczekują, że zmienne POST zostaną zakodowane w określony sposób, co spowoduje ich awarię. Wydaje mi się, że http_build_query () jest w tym przypadku bardziej niezawodny niż cURL.
César

4
Specyfikacja HTTP jest dość prosta, jak powinny wyglądać parametry POST. Oprogramowanie serwera sieci i tak powinno być zgodne ze standardami.
emix

1
W ten sposób zmusisz cURL do użycia nieco innego rodzaju testu POST. (Oczekuj: 100-kontynuacja). Sprawdź ten artykuł: support.urbanairship.com/entries/…
Oleg Popov

5
Rozwijając komentarz @ César, dokumentacja PHP wyraźnie stwierdza, co następuje: „Przekazanie tablicy do CURLOPT_POSTFIELDS spowoduje zakodowanie danych jako danych wieloczęściowych / formularzy , natomiast przekazanie ciągu zakodowanego w adresie URL spowoduje zakodowanie danych jako application / x-www-form -urlencoded . ”. Niedawno spędziłem nadmierną ilość czasu, próbując rozwiązać problem, dlaczego wywołanie cURL kończyło się niepowodzeniem na punkcie końcowym innej firmy, aby ostatecznie zdać sobie sprawę, że nie obsługują one danych wieloczęściowych / formularzy.
Jake Z

31

Żywy przykład użycia php curl_exec do zrobienia postu HTTP:

Umieść to w pliku o nazwie 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);
?>

Następnie uruchom go za pomocą polecenia php foobar.php, zrzuca ten rodzaj danych wyjściowych do ekranu:

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

Więc zrobiłeś POST PHP na www.google.com i wysłałeś mu trochę danych.

Gdyby serwer został zaprogramowany do odczytu zmiennych końcowych, mógłby na tej podstawie zdecydować się zrobić coś innego.


$postvars .= $key . $value;powinien $postvars .= $key . $value ."&";czy nie?
Manwal

Patrząc ponownie na tę odpowiedź, możesz również zastąpić niestandardową implementację konwertera ciągów zapytań http_build_query , po prostu podaj jej $fieldstablicę, a wyświetli ciąg zapytania.

Pamiętaj, że powinieneś zakodować swoje dane, aby mogły zostać bezpiecznie przesłane.
wtf8_decode

3
O nie, nie próbuj samodzielnie budować łańcucha postów! użyj tego:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam

3
-1, ponieważ nie uciekasz od swoich post vars. Przykładem OP jest wysyłanie nazw użytkowników i haseł do uwierzytelnienia. Dzięki Twojemu rozwiązaniu użytkownik z hasłem & nigdy nie będzie mógł się zalogować. Komentarz oriadama jest poprawny, ale możesz pominąć http_build_query:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand,

26

Można to łatwo osiągnąć za pomocą:

<?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 + obsługa błędów + ustawianie nagłówków [dzięki @ 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',
]);

Twój kod nie zamknie dojścia i zwolni zasobów, ponieważ zwrócisz curl_close po zgłoszeniu wyjątku. Powinieneś curl_close w końcu bloku.
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
Twój kod nie zamknie dojścia i zwolni zasobów, ponieważ zwrócisz curl_close po zgłoszeniu wyjątku. Powinieneś curl_closewewnątrz finallybloku.
emix

6

Jeśli formularz używa przekierowań, uwierzytelniania, plików cookie, SSL (https) lub czegokolwiek innego niż całkowicie otwarty skrypt oczekujący zmiennych POST, zaczniesz naprawdę zgrzytać zębami. Spójrz na Snoopy , który robi dokładnie to, co masz na myśli, jednocześnie eliminując konieczność ustawiania dużej części kosztów ogólnych.


Jeśli chcesz trzymać się standardowej biblioteki, po prostu spróbuj dodaćcurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
MarkHu

Jedynym minusem jest to, że nadal masz do czynienia z ustawieniem jar pliku cookie i innymi potencjalnymi problemami (np. Czy postępować zgodnie z przekierowaniami, jak radzić sobie z uwierzytelnianiem innym niż HTTP itp.). 6 lat później zaleciłbym bardziej ogólną koncepcję „bezgłowej przeglądarki” zamiast tej konkretnej biblioteki (lub czegokolwiek innego na sourceforge, jak datowany, prawda?) I chociaż ogólnie zajmuję się tylko opcjami curl bezpośrednio, nadal doradzałbym patrząc na bibliotekę przeglądarki bezgłowej, która jest zgodna z PSR-7 (Guzzle jest jedyną, którą znam z ręki), aby uniknąć bólów głowy.
Anthony

3

Prostszą odpowiedzią JEŚLI przekazujesz informacje do swojej witryny, jest użycie zmiennej SESSION. Rozpocznij stronę php:

session_start();

Jeśli w którymś momencie są informacje, które chcesz wygenerować w PHP i przejść do następnej strony w sesji, zamiast używać zmiennej POST, przypisz ją do zmiennej SESSION. Przykład:

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

Następnie na następnej stronie po prostu odwołujesz się do tej zmiennej SESSION. UWAGA: po użyciu upewnij się, że go zniszczyłeś, więc nie będzie się utrzymywał po użyciu:

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

3

Oto kod przykładowy dla PHP + curl http://www.webbotsspidersscreenscrapers.com/DSP_download.php

uwzględnienie w tych bibliotekach uprości rozwój

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

Jeśli spróbujesz zalogować się na stronie za pomocą plików cookie.

Ten kod:

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

Może nie działać, jeśli spróbujesz się zalogować, ponieważ wiele witryn zwraca status 200, ale post nie powiódł się.

Łatwym sposobem sprawdzenia, czy logowanie się powiodło, jest sprawdzenie, czy ponownie ustawia pliki cookie. Jeśli na wyjściu ma ciąg Set-Cookies, oznacza to, że posty nie powiodły się i rozpoczyna nową sesję.

Również post może się powieść, ale zamiast tego można przekierować status 200.

Aby upewnić się, że post się powiódł, spróbuj:

Śledź lokalizację za postem, aby przejść do strony, na której post przekierowuje:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

A następnie sprawdź, czy w żądaniu istnieją nowe pliki cookie:

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

{echo 'post successful'; }

else { echo 'not successful'; }

1

Przykłady przesyłania formularza i surowych danych:

$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);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.