PHP + згортання, зразок коду HTTP POST?


491

Чи може хто-небудь показати мені, як зробити PHP curl з HTTP POST?

Я хочу надіслати такі дані:

username=user1, password=passuser1, gender=1

До www.domain.com

Я очікую, що завиток поверне відповідь на кшталт result=OK. Чи є приклади?

Відповіді:


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
не потрібно використовувати http_build_query()для обробки параметрів; достатньо просто передати масив CURLOPT_POSTFIELDS.
Раптор

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

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

2
Використання CURLOPT_RETURNTRANSFER означає, що curl_exec поверне відповідь як рядок, а не виводить її.
bnp887

2
Я пропоную використовувати trueзамість 1для CURLOPT_POST.
FluorescentGreen5

261

Процедурний

// 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 / шифрування трафіку

Зазвичай у PHP виникає проблема з CURL в операційній системі 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 обробляти кодування ваших змінних.
Eric Seastrand

4
Це не завжди так. Я бачив веб-сервери, які очікують, що змінні POST будуть закодовані певним чином, що призведе до відмови в іншому випадку. Мені здається, що http_build_query () насправді для цього надійніше, ніж CURL.
Сесар

4
Характеристика HTTP досить зрозуміла, як повинні виглядати параметри POST. Програмне забезпечення веб-сервера все одно повинно відповідати стандартам.
емікс

1
Використовуючи цей спосіб, ви змусите cURL використовувати трохи інший тип POST. (Очікуйте: 100-продовження). Перевірте цю статтю: support.urbanairship.com/entries/…
Олег Попов

5
Розширюючись на коментар @ César, документація PHP чітко зазначає наступне: "Передача масиву CURLOPT_POSTFIELDS буде кодувати дані як багаточастинні / форми-дані , а передача рядка з кодовою URL-адресою кодує дані як додаток / x-www-form -урленкодований . ". Нещодавно я витратив непомірну кількість часу, намагаючись вирішити, чому виклик CURL не вдався до сторонньої кінцевої точки, щоб врешті зрозуміти, що вони не підтримують багатосторонні / форми даних.
Джейк 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 ."&";чи ні?
Manwal

Подивившись знову на цю відповідь, ви також можете замінити власну реалізацію конвертера рядків запитів на http_build_query , просто дайте їй $fieldsмасив, і він виведе рядок запиту.

Майте на увазі, що ви повинні кодувати свої дані, щоб вони надійно надходили.
wtf8_decode

3
О ні, не намагайтеся самостійно скласти поштовий рядок! скористайтеся цим:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam

3
-1 тому, що ви не уникаєте своєї посади. Приклад ОП - це надіслати подані користувачем імена та паролі для автентифікації. Користуючись своїм рішенням, користувач із паролем & ніколи не зможе увійти. Коментар 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 Post + Поводження з помилками + Встановити заголовки [завдяки @ 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 всередині остаточного блоку.
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всередині finallyблоку.
emix

6

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


Якщо ви хочете дотримуватися біржової curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
вкладки

Єдиним недоліком є ​​те, що вам все-таки доведеться мати справу зі встановленням файлу cookie та іншими потенційними проблемами (наприклад, чи слідкувати за переспрямуванням, як працювати з аутентифікацією на основі HTTP тощо). Через 6 років я порекомендував би більш загальну концепцію "безголового браузера" замість конкретної бібліотеки (або що-небудь в sourceforge, як датується, правда?) І хоча я, як правило, безпосередньо займаюся варіантами згортання, я б все-таки радив дивлячись на бібліотеку безголівкових браузерів, яка сумісна з PSR-7 (Guzzle - це єдиний, кого я знаю поза рукою), щоб уникнути головних болів.
Ентоні

3

Простіша відповідь, якщо ви передаєте інформацію на свій власний веб-сайт, - це використовувати змінну SESSION. Почніть сторінку з:

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

Якщо ви спробуєте увійти на сайт за допомогою файлів cookie.

Цей код:

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

Може не спрацювати, якщо ви спробуєте увійти, оскільки багато сайтів повертають статус 200, але публікація не є успішною.

Простий спосіб перевірити, чи вдалий пост для входу є перевірити, чи він знову встановлює файли cookie. Якщо у виході є рядок Set-Cookies, це означає, що повідомлення не є успішним, і він починає новий сеанс.

Також публікація може бути успішною, але статус можна переспрямувати замість 200.

Щоб переконатися, що публікація успішна, спробуйте це:

Після публікації слідкуйте за місцем розташування, тож він перейде на сторінку, на яку публікація переспрямовує:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

І ніж перевірити, чи існують у запиті нові файли cookie:

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.