Как отправить запрос POST с помощью PHP?

655

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

Я должен прочитать все содержимое с помощью domdocumentили file_get_contents(). Есть ли метод, который позволит мне отправить параметры с POSTметодом, а затем прочитать содержимое через PHP?

Фред Танрикут
источник

Ответы:

1259

Метод без 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 для получения дополнительной информации о методе и о том, как добавить заголовки, например:

dbau
источник
64
Стоит отметить, что если вы решите использовать массив для заголовков, НЕ заканчивайте ключи или значения символом '\ r \ n'. stream_context_create () будет принимать текст только до первого '\ r \ n'
raptor
11
URL может использоваться в качестве имени файла file_get_contents()только в том случае, если были включены обертки fopen. Смотрите php.net/manual/en/…
Pino
3
@ Я люблюfile_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
Решение file_get_contents не работает в конфигурациях PHP с отключенным параметром allow_url_fopen (как в случае общего хостинга). В этой версии используется библиотека curl, и я думаю, что она наиболее «универсальна», поэтому я отдаю вам свой голос
Дайрон Галлардо
81
Вы не нашли
efreed
4
Хотя это не очень важно, данные параметра CURLOPT_POSTFIELDS на самом деле не нужно преобразовывать в строку («urlified»). Цитата: «Этот параметр может быть передан в виде строки, закодированной в формате urlen, например« para1 = val1 & para2 = val2 & ... », или в виде массива с именем поля в качестве ключа и данными поля в качестве значения. Если значение является массивом, Content-Type заголовок будет установлен в multipart / form-data. " Ссылка: 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). Данные кодируются с использованием 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 упоминает, что http_build_query может быть опущен, так как curl будет правильно кодировать массив, переданный параметру CURLOPT_POSTFIELDS, но имейте в виду, что в этом случае данные будут кодироваться с использованием multipart / form-data.

Я использую эту функцию с API, которые ожидают, что данные будут закодированы с использованием application / x-www-form-urlencoded. Вот почему я использую http_build_query ().

Дима Л.
источник
Передача массива в CURLOPT_POSTFIELDS приводит к тому, что данные кодируются с использованием multipart / form-data, что может быть нежелательно.
Дима Л.
Пользователь запросил file_get_contents, поэтому ему нужно решение для изменения default_stream_context
Radon8472
Чтобы уточнить: я думаю, @DimaL. отвечает на комментарий, который был удален; http_build_queryпреобразует $dataмассив в строку, избегая вывода в виде multipart / form-data.
ToolmakerSteve
@ Radon8472 - ... CURLOPT_RETURNTRANSFER, trueприводит $responseсодержащий содержимое.
ToolmakerSteve
@ ToolmakerSteve, как я уже сказал, вопрос был, file_get_contentsи ваше решение нуждается в CURL, чего нет у многих людей. поэтому ваше решение, возможно, работает, но оно не отвечает на вопрос, как это сделать с помощью встроенных встроенных файловых / потоковых функций.
Radon8472
42

Я рекомендую вам использовать пакетную утилиту с открытым исходным кодом, которая полностью протестирована модульно и использует новейшие методы кодирования.

Установка жрет

Перейти к командной строке в вашей папке проекта и введите следующую команду (если у вас уже есть менеджер пакетов композитор установлен). Если вам нужна помощь в установке Composer, вы должны посмотреть здесь .

php composer.phar require guzzlehttp/guzzle

Использование Guzzle для отправки запроса POST

Использование 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);
Andreas
источник
7
Было бы полезно узнать, какие преимущества это имеет по сравнению с уже опубликованным нативным решением PHP, а также cURL.
artfulrobot
9
@artfulrobot: нативное PHP-решение имеет множество проблем (например, соединение с https, проверка сертификата и т. п.), поэтому почти каждый разработчик PHP использует cURL. И почему бы не использовать cURL в этом случае? Все просто: Guzzle имеет простой, легкий и легкий интерфейс, который устраняет все эти «проблемы с низкоуровневой обработкой cURL». В любом случае, почти все, кто разрабатывает современный PHP, используют Composer, поэтому использовать Guzzle просто.
Андреас
2
Спасибо, я знаю, что guzzle популярно, однако бывают случаи, когда композитор вызывает горе (например, разработка плагинов для больших программных проектов, которые могут уже использовать (другую версию) guzzle или другие зависимости), поэтому полезно знать эту информацию, чтобы решение о том, какое решение будет наиболее надежным
artfulrobot
26

Есть другой метод CURL, если вы идете по этому пути.

Это довольно просто, как только вы поймете, как работает расширение PHP curl, комбинируя различные флаги с вызовами 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-запроса, в зависимости от того, что доступно на веб-сервере. Для получения дополнительной информации см. Документацию HTTP API .

Если вы не хотите разрабатывать собственную тему или плагин для запуска движка 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 )
  • Возвращать ответ, а не повторять его. Кстати, вы можете избежать возврата, удалив строку curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 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"));

ПОСЛЕ

$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}]');
    }
}
mwatzer
источник
Для меня это говорит "Uncaught Error: вызов неопределенного метода HTTPRequester :: HTTPost ()" . Я просто вставил ваш класс в мой файл .php. Что-нибудь еще мне нужно сделать?
LinusGeffarth
1
Можете ли вы опубликовать свой код? Довольно сложно догадаться, что не так без какого-либо фрагмента кода.
mwatzer
Как я уже сказал, я буквально скопировал ваш файл в мой обычный php-файл, и это дало мне эту ошибку.
LinusGeffarth
1
Хорошо, теперь я вижу проблему, это было неправильно в примере! Вы должны вызвать HTTPRequester :: HTTPPost () вместо HTTPRequester :: HTTPost ()
mwatzer
1
Ах. Это легко пропустить. Я должен был прочитать свой комментарий , как 5x , прежде чем я заметил дополнительный P . Спасибо!
LinusGeffarth
20

Другая альтернатива из завитка менее метода выше , чтобы использовать нативные потоковые функции:

  • 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;
}
CPHPython
источник
1
Этот метод без CURL работал хорошо для меня, чтобы проверить reCAPTCHA от Google. Этот ответ сходится с этим кодом Google: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Хави Монтеро,
1
Вам не нужно использовать, fclose()если $fpесть false. Потому fclose()что ожидает ресурс является параметром.
Флорис
1
@Floris Отредактировал это только сейчас, и действительно, fclose docs упоминает "Указатель файла должен быть действительным". Спасибо, что заметили это!
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 выше для 5x, который использует эту технику 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

Я искал похожую проблему и нашел лучший подход для этого. Так что вот так.

Вы можете просто поместить следующую строку на странице перенаправления (скажем, page1.php).

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

Это нужно для перенаправления запросов POST на вызовы REST API. Это решение может перенаправлять с данными поста, а также с пользовательскими значениями заголовка.

Вот ссылка ссылка .

Ариндам Наяк
источник
1
Это ответ, как перенаправить запрос страницы не Как отправить запрос POST с PHP? Конечно, это перешло бы любые параметры POST, но это совсем не одно и то же
Уэсли Смит
@ DelightedD0D, К сожалению , я не получить разницу между redirect a page request with POST paramпротив send POST request. Для меня цель обоих одинакова, поправьте меня, если я ошибаюсь.
Ариндам Наяк
1
Есть ли метод, который позволит мне отправлять параметры с методом POST, а затем читать содержимое через PHP? OP хочет, чтобы их 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'
        ])
    ]
]));
Liga
источник
Как будет работать Key2? что за сепаратор между ними?
сказал Мухаммед Идриес
@ Сказал, что для добавления ключа 2 вы можете ввести его как второй элемент массива. 'key1' => 'Hello world!', 'key2' => 'second value'
Лига
Это работает очень хорошо при использовании с Zapier.
Моксет
3

Попробуйте пакет PEAR HTTP_Request2 , чтобы легко отправлять запросы POST. Кроме того, вы можете использовать функции curl в PHP или использовать потоковый контекст PHP .

HTTP_Request2 также позволяет макетировать сервер , поэтому вы можете легко тестировать свой код

cweiske
источник
7
Я хотел бы видеть вас, чтобы уточнить это, если это возможно.
Ги Имамура