Як надіслати запит на пошту з PHP?


656

Насправді я хочу прочитати вміст, який надходить після пошукового запиту, коли він буде виконаний. Проблема полягає в тому, що URL-адреса приймає лише POSTметоди, і вона не вживає ніяких дій із GETметодом ...

Я повинен прочитати весь вміст за допомогою domdocumentабо file_get_contents(). Чи є якийсь метод, який дозволить мені надсилати параметри POSTметодом, а потім читати вміст через PHP?

Відповіді:


1260

Метод без CURL з 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);

Дивіться посібник PHP для отримання додаткової інформації про метод та способи додавання заголовків, наприклад:


64
Варто зазначити, що якщо ви вирішили використовувати масив для заголовків, НЕ закінчуйте клавіші або значення на "\ r \ n". stream_context_create () буде приймати текст лише до першого '\ r \ n'
raptor

11
URL-адреса може використовуватися як ім'я файлу, file_get_contents()лише якщо ввімкнено обгортки fopen. Дивіться php.net/manual/en/…
Піно

3
@ I lovefile_get_contents()
тупик

14
Чи є конкретна причина не використовувати CURL?
jvannistelrooy

37
@jvannistelrooy CURL для PHP - це розширення, яке може існувати не у всіх середовищах, тоді як file_get_contents()є частиною ядра PHP. Крім того, використання розширення без необхідності може розширити поверхню атаки вашої програми. Наприклад, Google php curl cve
Pocketsand

139

Ви можете використовувати 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
ця працювала для мене, тому що сторінка, яку я надсилаю на сторінку, яка не має вмісту, тому версія file_get_contents не працювала.
CommentLuv

9
рішення_файл_get_contents не працює в конфігураціях PHP з дозволом_url_fopen Off (як у спільному хостингу). Ця версія використовує бібліотеку curl, і я вважаю, що вона найбільш "універсальна", тому я віддаю вам свій голос
Дейрон Галлардо,


4
Хоча це не дуже важливо, дані параметра CURLOPT_POSTFIELDS насправді не потрібно перетворювати на рядок ("урлифицированный"). Цитата: "Цей параметр може бути переданий у вигляді рядка, що кодується urlencoded, наприклад" para1 = val1 & para2 = val2 & ... ", або як масив із назвою поля як ключовим, а дані поля - як значення. Якщо значення - це масив, тип Content-Type заголовок буде встановлено на багаточастинні / форми-дані. " Посилання: php.net/manual/en/function.curl-setopt.php .
Едвард

2
Крім того, не буде ображеним, якщо записати його по-іншому, але я не знаю, чому параметр CURLOPT_POST вказаний як число тут, як він говорить, щоб встановити його як булеве на сторінці керівництва. Цитата: "CURLOPT_POST: TRUE робити звичайний HTTP POST." Посилання: php.net/manual/en/function.curl-setopt.php .
Едвард

68

Я використовую наступну функцію для розміщення даних за допомогою curl. $ data - це масив полів для публікації (буде правильно закодовано за допомогою http_build_query). Дані кодуються за допомогою програми / 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 зазначає, що http_build_query може бути пропущено, оскільки curl буде правильно кодувати масив, переданий параметру CURLOPT_POSTFIELDS, але слід зазначити, що в цьому випадку дані будуть кодуватися за допомогою даних multipart / form-data.

Я використовую цю функцію з API, які очікують, що дані будуть закодовані за допомогою програми / x-www-form-urlencoded. Ось чому я використовую http_build_query ().


Передача масиву в CURLOPT_POSTFIELDS спричиняє кодування даних за допомогою багаточастинних / форм-даних, що може бути небажаним.
Діма Л.

Користувач запитав файл_get_contents, тому йому потрібно рішення про зміну default_stream_context
Radon8472,

Для уточнення: я думаю @DimaL. відповідає на коментар, який було видалено; http_build_queryперетворює $dataмасив у рядок, уникаючи виведення у вигляді багаточастинних / форм-даних.
ToolmakerSteve

@ Radon8472 - ... CURLOPT_RETURNTRANSFER, trueпризводить $responseдо вмісту вмісту.
ToolmakerSteve

@ToolmakerSteve, як я вже сказав, було питання, і для file_get_contentsвашого рішення потрібно CURL те, що у багатьох людей немає. тож ваше рішення, можливо, працює, але це не відповідає на питання, як це зробити за допомогою вбудованих функцій файлу / потоку.
Radon8472

42

Я рекомендую вам використовувати загадку з відкритим кодом, яка повністю перевірена і використовує новітні методи кодування.

Встановлення Guzzle

Перейдіть до командного рядка в папці проекту та введіть наступну команду (якщо припустити, що у вас вже встановлений композитор менеджера пакунків ). Якщо вам потрібна допомога, як встановити Composer, ви повинні подивитися тут .

php composer.phar require guzzlehttp/guzzle

Використання Guzzle для надсилання запиту на пошту

Використання Guzzle дуже прямо вперед, оскільки він використовує об'єктно орієнтований API:

// 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
Було б корисно знати, які переваги це має над вже опублікованим нативним рішенням PHP, а також CURL.
artfulrobot

9
@artfulrobot: У рідного PHP-рішення виникає безліч проблем (наприклад, підключення до https, перевірка сертифікатів тощо). Ось чому майже кожен розробник PHP використовує cURL. І чому б не використовувати cURL в цьому випадку? Це просто: Guzzle має простий, легкий, легкий інтерфейс, який дозволяє усунути всі "низькі рівні роботи з CURL". Практично кожен, хто розробляє сучасний PHP, так чи інакше використовує Composer, тому використовувати Guzzle просто дуже просто.
Андреас

2
Дякую, я знаю, що загадка популярна, проте є випадки, коли композитор викликає горе (наприклад, розробку плагінів для великих програмних проектів, які вже можуть використовувати (іншу версію) guzzle чи інші залежності), тому добре знати цю інформацію, щоб зробити рішення про те, яке рішення буде найбільш надійним
artfulrobot

26

Є інший метод CURL, якщо ви йдете цим шляхом.

Це досить просто, як тільки ви обернетесь навколо того, як працює розширення curl PHP, поєднуючи різні прапори з дзвінками setopt (). У цьому прикладі у мене є змінна $ xml, яка містить вміст XML, який я підготовив надіслати - я збираюся розмістити вміст цього тестового методу.

$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

Спочатку ми ініціалізували з'єднання, потім встановили деякі параметри за допомогою setopt (). Вони говорять PHP, що ми робимо запит на пошту і що ми надсилаємо деякі дані разом з ними, надаючи дані. Прапор CURLOPT_RETURNTRANSFER повідомляє curl, щоб нам виводити як повернене значення curl_exec, а не виводити його. Потім робимо дзвінок і закриваємо з'єднання - результат у $ response.


1
у виклику третього curl_setopt (), то перший аргумент повинен бути $chНЕ $curl, правильно?
jcomeau_ictx

Чи можете ви використовувати цей самий код для надсилання даних JSON? Але замініть $ xml на скажіть $ json (де $ json - це, мабуть, рядок JSON?)
Ніл Девіс,

24

Якщо ви випадково використовуєте Wordpress для розробки свого додатка (це фактично зручний спосіб отримати авторизацію, інформаційні сторінки тощо навіть для дуже простих речей), ви можете скористатися наступним фрагментом:

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

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

Він використовує різні способи створення фактичного запиту HTTP, залежно від того, що є на веб-сервері. Докладніше див. У документації API HTTP .

Якщо ви не хочете розробити власну тему чи плагін, щоб запустити механізм Wordpress, ви можете просто зробити наступне в ізольованому файлі PHP в корені Wordpress:

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

// ... your code

Він не показуватиме будь-яку тему чи виводити будь-який HTML, просто злому API-програм Wordpress!


22

Я хотів би додати кілька думок щодо відповіді Фреда Танрікута на основі завитка. Я знаю, що більшість із них уже написані у відповідях вище, але я думаю, що це гарна ідея показати відповідь, яка включає їх усіх разом.

Ось клас, який я написав для того, щоб робити запити HTTP-GET / POST / PUT / DELETE на основі curl, що стосуються лише тіла відповіді:

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

Поліпшення

  • Використовуючи http_build_query для отримання рядка запиту з масиву запитів. (Ви також можете використовувати сам масив, тому дивіться: http://php.net/manual/en/function.curl-setopt.php )
  • Повернення відповіді, а не повторення. Btw ви можете уникнути повернення, видаливши рядок curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true); . Після цього значення повернення є булевим (true = запит був успішним, інакше сталася помилка), і відповідь лунає. Подивитися: http://php.net/en/manual/function.curl-exec.php
  • Очистіть закриття сеансу та видалення обробника curl за допомогою curl_close . Подивитися: http://php.net/manual/en/function.curl-close.php
  • Використання булевих значень для curl_setopt замість використання будь-якого числа. (Я знаю, що будь-яке число, яке не дорівнює нулю, також вважається істинним, але використання true створює більш читабельний код, але це лише моя думка)
  • Можливість здійснювати дзвінки HTTP-PUT / DELETE (корисно для тестування послуг RESTful)

Приклад використання

ЗАРАЗ

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

POST

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

ПУТ

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

УДАЛИТИ

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

Тестування

Ви також можете зробити кілька класних сервісних тестів, скориставшись цим простим класом.

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

Для мене в ньому написано "Uncaught Error: Call to undefined method HTTPRequester :: HTTPost ()" . Я просто вставив ваш клас у мій .php файл. Що ще мені потрібно зробити?
LinusGeffarth

1
Чи можете ви опублікувати свій код? Досить важко здогадатися, що трапилося без фрагмента коду.
mwatzer

Як я вже говорив, я буквально скопіював ваш у мій звичайний файл php, і це дало мені цю помилку.
LinusGeffarth

1
Ок, тепер я бачу проблему, .. це було неправильно в прикладі! Ви повинні зателефонувати HTTPRequester :: HTTPPost () замість HTTPRequester :: HTTPost ()
mwatzer

1
Ага. Це легко пропустити. Я повинен був прочитати свій коментар , як 5x , перш ніж я помітив додатковий P . Дякую!
ЛінусГеффарт

19

Інша альтернатива з завитка менш методу вище , щоб використовувати нативні потокові функції:

  • stream_context_create():

    Створює та повертає контекст потоку з будь-якими параметрами, що надаються у попередньо встановлених параметрах .

  • stream_get_contents():

    Ідентично file_get_contents(), за винятком того, що stream_get_contents() працює на вже відкритому ресурсі потоку і повертає залишок вмісту в рядку, до байтів максимальної довжини і починаючи з заданого зміщення .

Функція POST з ними може бути просто такою:

<?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
Цей метод, що не відповідає CURL, добре працював для перевірки реCAPTCHA від Google. Ця відповідь збігається з цим кодом google: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Xavi Montero

1
Вам не доведеться користуватися, fclose()якщо $fpє false. Тому що fclose()очікує, що ресурс - це параметр.
Флоріс

1
@Floris Відредагував це саме зараз, і справді в документах fclose згадується "Покажчик файлу повинен бути дійсним". Дякую, що помітили це!
CPHPython

8

Кращий спосіб надсилання GETабо POSTзапитів за допомогою PHPнаступного:

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

Код взято з офіційної документації тут http://docs.php.net/manual/da/httprequest.send.php


1
@akinuri дякую за виділення, я збираюся поділитися новим.
Імран

як це зробити на PHP 5x?

@YumYumYum, будь ласка, перегляньте відповідь dbau вище на 5 разів, яка використовує цю техніку php.net/manual/en/function.stream-context-create.php Або ви завжди можете повернутися до стандартного рішення для завитків.
Імран

5

Є ще один, який ви можете використовувати

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

Натисніть тут, щоб отримати детальну інформацію


2
Це покладається на розширення PECL, яке більшість не буде встановлено. Навіть не впевнений, що він все ще доступний, оскільки сторінки з інструкціями були видалені.
miken32

5

Я шукав подібну проблему і знайшов кращий підхід до цього. Отож ось це йде.

Ви можете просто поставити наступний рядок на сторінку перенаправлення (скажімо, сторінку1.php).

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

Мені потрібно це для переадресації запитів POST на дзвінки API REST . Це рішення здатне перенаправляти з даними публікації, а також спеціальними значеннями заголовків.

Ось посилання на посилання .


1
Це відповідає на те, як перенаправити запит на сторінку, а не Як надіслати запит POST за допомогою PHP? Впевнений, що це переправить будь-які параметри POST, але це зовсім не те саме
Wesley Smith

@ DelightedD0D, К жаль , я не отримати різницю між redirect a page request with POST paramпроти send POST request. Для мене мета обох однакова, виправте мене, якщо я помиляюся.
Аріндам Наяк

1
Чи є якийсь метод, який дозволить мені надсилати параметри методом POST, а потім читати вміст через PHP? ОП хоче, щоб їхній скрипт php сконструював набір параметрів POST та надіслав їх на іншу сторінку php та щоб їх сценарій отримав вихід з цієї сторінки. Це рішення просто приймає вже встановлений набір значень і пересилає їх на іншу сторінку. Вони досить різні.
Веслі Сміт

5

Тут використовується лише одна команда без CURL. Супер просто.

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

Як буде працювати Key2? що між ними сепаратор?
Сейед Мухаммед Ідріс

@Sayedidrees для додавання key2 ви можете ввести його як другий елемент масиву. 'key1' => 'Привіт, світ!', 'key2' => 'друге значення'
Ліга

Це дуже добре працює під час використання з zapier.
Moxet

3

Спробуйте пакет HTTP_Request2 PEAR для легкого надсилання запитів POST. Крім того, ви можете використовувати функції curl PHP або використовувати контекст потоку PHP .

HTTP_Request2 також дає змогу знущатися над сервером , тому ви можете легко протестувати код


7
Я хотів би, щоб ви докладно розробили це, якщо це можливо.
Gui Imamura
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.