PHP + curl, HTTP POST пример кода?


491

Может кто-нибудь показать мне, как сделать php curl с HTTP POST?

Я хочу отправить данные так:

username=user1, password=passuser1, gender=1

к www.domain.com

Я ожидаю, что локон возвратит ответ как result=OK. Есть ли примеры?

Ответы:


842
<?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
нет необходимости использовать http_build_query()для обработки параметров; достаточно просто передать массив в CURLOPT_POSTFIELDS.
Raptor

8
@Raptor, предоставляющий массив непосредственно в CURLOPT_POSTFIELDS, фактически curl делает немного другой тип POST. (Ожидание: 100-продолжение)
Олег Попов

22
Также, если значение CURLOPT_POSTFIELDSявляется массивом, Content-Typeзаголовок будет установлен multipart/form-dataвместо application/x-www-form-urlencoded. php.net/manual/en/function.curl-setopt.php
Хлоя

2
Использование CURLOPT_RETURNTRANSFER означает, что curl_exec будет возвращать ответ в виде строки, а не выводить ее.
bnp887

2
Я предлагаю использовать trueвместо 1для CURLOPT_POST.
FluorescentGreen5

262

процедурный

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

Объектно-ориентированный

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

Применение

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

Заметьте здесь: лучше было бы создать некоторый интерфейс, вызываемый, AdapterInterfaceнапример, с getResponse()методом, и позволить классу выше реализовать его. Затем вы всегда можете поменять эту реализацию с другим адаптером по вашему вкусу, без каких-либо побочных эффектов для вашего приложения.

Использование HTTPS / шифрование трафика

Обычно есть проблема с cURL в PHP под операционной системой Windows. При попытке подключения к защищенной https конечной точке вы получите сообщение об ошибке certificate verify failed.

Здесь большинство людей говорят библиотеке cURL просто игнорировать ошибки сертификата и продолжить ( curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). Поскольку это заставит ваш код работать, вы создадите огромную дыру в безопасности и дадите злоумышленникам возможность выполнять различные атаки на ваше приложение, например, Man In The Middle. атака или тому подобное.

Никогда, никогда не делай этого. Вместо этого вам просто нужно изменить свой php.iniи сообщить PHP, где находится ваш CA Certificateфайл, чтобы он мог правильно проверять сертификаты:

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

Последние cacert.pemмогут быть загружены из Интернета или извлечены из вашего любимого браузера . При изменении любых php.iniсвязанных настроек не забудьте перезапустить ваш веб-сервер.


4
Это действительно должен быть принятый ответ, потому что наилучшей практикой будет позволить библиотеке HTTP обрабатывать кодирование ваших переменных.
Эрик Сеастранд,

4
Это не всегда так. Я видел веб-серверы, которые ожидают, что переменные POST будут закодированы определенным образом, в противном случае они будут сбои. Мне кажется, что http_build_query () на самом деле более надежен, чем cURL для этого.
Сезар

4
Спецификация HTTP довольно проста в том, как должны выглядеть параметры POST. В любом случае программное обеспечение веб-сервера должно соответствовать стандартам.
emix

1
Используя этот способ, вы заставите cURL использовать немного другой тип POST. (Ожидание: 100-продолжение). Проверьте эту статью: support.urbanairship.com/entries/…
Олег Попов

5
Расширяя комментарий @ César, документация PHP явно отмечает следующее: «Передача массива в CURLOPT_POSTFIELDS будет кодировать данные как multipart / form-data , в то время как передача строки в кодировке URL будет кодировать данные как application / x-www-form. - закодированный . Недавно я потратил слишком много времени, пытаясь выяснить причину сбоя вызова cURL на сторонней конечной точке, чтобы в итоге понять, что они не поддерживают multipart / form-data.
Джейк Z

31

Пример использования php curl_exec для создания HTTP-сообщения:

Поместите это в файл с именем 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);
?>

Затем запустите его с помощью команды php foobar.php, он выведет этот вид вывода на экран:

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

Итак, вы сделали PHP POST на www.google.com и отправили ему некоторые данные.

Если бы сервер был запрограммирован на чтение в переменных записи, он мог бы решить сделать что-то другое, основываясь на этом.


$postvars .= $key . $value;должен $postvars .= $key . $value ."&";или нет?
Манвал

Посмотрев еще раз на этот ответ, вы также можете заменить свою собственную реализацию конвертера строки запроса на http_build_query , просто передайте ему $fieldsмассив, и он выведет строку запроса.

Помните, что вы должны закодировать свои данные для того, чтобы они были безопасно переданы.
wtf8_decode

3
О, нет, не пытайтесь создать строку поста самостоятельно! используйте это:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
Ориадам

3
-1 потому что вы не избегаете своих постов. Пример OP - отправка пользовательских имен и паролей для аутентификации. С вашим решением пользователь с паролем & в своем пароле никогда не сможет войти в систему. Комментарий oriadam верен, но вы можете оставить его http_build_queryкак:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand

26

Это может быть легко достигнуто с помощью:

<?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 + Обработка ошибок + Установка заголовков [спасибо @ 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',
]);

Ваш код не закроет дескриптор и освободит ресурсы, потому что вы curl_close после создания исключения. Вы должны curl_close внутри блока 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
Ваш код не закроет дескриптор и освободит ресурсы, потому что вы curl_close после создания исключения. Вы должны curl_closeвнутри finallyблока.
emix

6

Если форма использует перенаправления, аутентификацию, файлы cookie, SSL (https) или что-то еще, кроме полностью открытого скрипта, ожидающего переменные POST, вы начнете очень быстро скрежетать зубами. Взгляните на Snoopy , который делает именно то, что вы имеете в виду, устраняя необходимость в настройке большого количества накладных расходов.


Если вы хотите придерживаться стандартной curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
библиотеки

Единственным недостатком является то, что вам все еще приходится иметь дело с установкой файла cookie и другими потенциальными проблемами (например, следует ли выполнять перенаправления, как обращаться с аутентификацией не на основе HTTP и т. Д.). Спустя 6 лет я бы порекомендовал более общую концепцию «безголового браузера» вместо этой конкретной библиотеки (или что-нибудь о sourceforge, как устарело, верно?). И хотя я обычно просто имею дело с опциями curl напрямую, я бы все же посоветовал глядя на библиотеку безголовых браузеров, которая совместима с PSR-7 (Guzzle - единственная, которую я знаю, не знаю), чтобы избежать головной боли.
Энтони

3

Более простой ответ, если вы передаете информацию на свой сайт, - это использовать переменную SESSION. Начните php-страницу с:

session_start();

Если в какой-то момент есть информация, которую вы хотите сгенерировать в PHP и перейти на следующую страницу в сеансе, вместо использования переменной POST, присвойте ее переменной SESSION. Пример:

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

Затем на следующей странице вы просто ссылаетесь на эту переменную SESSION. ПРИМЕЧАНИЕ: после использования убедитесь, что вы уничтожили его, чтобы он не сохранялся после его использования:

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

3

Вот примерный код для PHP + curl http://www.webbotsspidersscreenscrapers.com/DSP_download.php

включение в эти библиотеки упростит разработку

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

Если вы попытаетесь войти на сайт с помощью куки.

Этот код:

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

Может не работать, если вы попытаетесь войти в систему, потому что многие сайты возвращают статус 200, но сообщение не успешно.

Простой способ проверить, успешна ли запись для входа в систему, - проверить, не устанавливает ли она файлы cookie снова. Если в выводе есть строка Set-Cookies, это означает, что сообщения не успешны, и начинается новый сеанс.

Также сообщение может быть успешным, но статус может быть перенаправлен вместо 200.

Чтобы убедиться, что сообщение успешно, попробуйте это:

Следуйте за местоположением после сообщения, так что оно перейдет на страницу, на которую оно будет перенаправлено:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

И затем проверьте, существуют ли новые куки в запросе:

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

{echo 'post successful'; }

else { echo 'not successful'; }

1

Примеры отправки формы и необработанных данных:

$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);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.