Como envio uma solicitação POST com PHP?


655

Na verdade, eu quero ler o conteúdo que vem após a consulta de pesquisa, quando terminar. O problema é que o URL aceita apenas POSTmétodos e não executa nenhuma ação comGET método ...

Eu tenho que ler todo o conteúdo com a ajuda de domdocumentou file_get_contents(). Existe algum método que me permita enviar parâmetros com o POSTmétodo e depois ler o conteúdo via PHP?

Respostas:


1259

Método sem CURL com 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);

Consulte o manual do PHP para obter mais informações sobre o método e como adicionar cabeçalhos, por exemplo:


64
Vale a pena notar que, se você decidir usar uma matriz para os cabeçalhos, NÃO termine as chaves ou valores com '\ r \ n'. stream_context_create () levará apenas o texto para o primeiro '\ r \ n'
raptor

11
Uma URL pode ser usada como um nome de arquivo file_get_contents()somente se os wrappers fopen tiverem sido ativados. Veja php.net/manual/en/…
Pino

3
@I lovefile_get_contents()
deadlock

14
Existe um motivo específico para não usar CURL?
precisa saber é o seguinte

37
@jvannistelrooy CURL para PHP é uma extensão que pode não existir em todos os ambientes, enquanto file_get_contents()faz parte do núcleo do PHP. Além disso, o uso desnecessário de uma extensão pode ampliar a superfície de ataque do seu aplicativo. Por exemplo, Google php curl cve
Pocketsand 12/10

139

Você pode usar 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
este funcionou para mim porque a página que estou enviando para uma página sem conteúdo, portanto a versão file_get_contents não funcionou.
CommentLuv

9
A solução file_get_contents não funciona nas configurações PHP com allow_url_fopen Off (como na hospedagem compartilhada). Esta versão utiliza a biblioteca de onda e eu acho que é mais "universal", então eu dar-lhe o meu voto
Dayron Gallardo

81
Você não localizou
efreed

4
Embora não seja muito importante, os dados do parâmetro CURLOPT_POSTFIELDS na verdade não precisam ser convertidos em uma string ("urlified"). Citação: "Este parâmetro pode ser passado como uma string codificada em url como 'para1 = val1 & para2 = val2 & ...' ou como uma matriz com o nome do campo como chave e dados do campo como valor. Se value for uma matriz, o Content-Type cabeçalho será definido como multipart / form-data ". Link: php.net/manual/en/function.curl-setopt.php .
Edward

2
Além disso, não há ofensa por escrevê-lo de maneira diferente, mas não sei por que o parâmetro CURLOPT_POST é especificado como um número aqui, pois ele diz que é definido como um booleano na página de manual. Citação: "CURLOPT_POST: TRUE para executar um HTTP POST normal." Link: php.net/manual/en/function.curl-setopt.php .
Edward

68

Eu uso a seguinte função para postar dados usando curl. $ data é uma matriz de campos a serem postados (serão codificados corretamente usando http_build_query). Os dados são codificados usando 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 menciona que http_build_query pode ser omitido, pois o curl codificará corretamente a matriz passada para o parâmetro CURLOPT_POSTFIELDS, mas saiba que, nesse caso, os dados serão codificados usando dados de várias partes / formulário.

Eu uso essa função com APIs que esperam que os dados sejam codificados usando application / x-www-form-urlencoded. É por isso que eu uso http_build_query ().


Passar a matriz para CURLOPT_POSTFIELDS faz com que os dados sejam codificados usando dados de várias partes / formulário, o que pode não ser desejável.
Dima L.

O usuário pediu file_get_contents, então ele precisa de uma solução para alterar o default_stream_context
Radon8472

Para esclarecer: eu acho que @DimaL. está respondendo a um comentário que foi excluído; http_build_queryconverte $dataarray em uma string, evitando a saída como multipart / form-data.
Home

@ Radon8472 - ... CURLOPT_RETURNTRANSFER, trueresulta em $responseconter o conteúdo.
Home

@ToolmakerSteve como eu disse, a pergunta era para file_get_contents e sua solução precisa de CURL o que muitas pessoas não têm. portanto, sua solução talvez esteja funcionando, mas não está respondendo à pergunta de como fazer isso com as funções nativas internas de arquivo / fluxo.
Radon8472 26/04/19

42

Eu recomendo que você use o pacote de código aberto guzzle que é totalmente unidade testada e utiliza as mais recentes práticas de codificação.

Instalando Guzzle

Vá para a linha de comando na pasta do projeto e digite o seguinte comando (supondo que você já tenha o compositor do gerenciador de pacotes instalado). Se precisar de ajuda para instalar o Composer, consulte aqui .

php composer.phar require guzzlehttp/guzzle

Usando o Guzzle para enviar uma solicitação POST

O uso do Guzzle é muito direto, pois usa uma API leve e orientada a objetos:

// 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
Seria útil saber quais vantagens isso tem sobre a solução PHP nativa já postada e a cURL também.
Artfulrobot

9
@artfulrobot: A solução PHP nativa tem muitos problemas (por exemplo, conexão com https, verificação de certificado, etc.pp.), e é por isso que quase todos os desenvolvedores de PHP usam cURL. E por que não usar cURL neste caso? É simples: o Guzzle possui uma interface direta, fácil e leve que abstrai todos os "problemas de manuseio de cURL de baixo nível". Quase todo mundo que desenvolve PHP moderno usa o Composer de qualquer maneira, portanto, usar o Guzzle é realmente muito simples.
Andreas

2
Obrigado, eu sei que o guzzle é popular, no entanto, existem casos de uso em que o compositor causa pesar (por exemplo, desenvolver plugins para projetos de software maiores que já podem usar uma (versão diferente) do guzzle ou outras dependências), por isso é bom saber essas informações para criar uma decisão sobre qual solução será mais robusta
artfulrobot

26

Existe outro método CURL se você estiver indo por esse caminho.

Isso é bastante simples quando você começa a entender como a extensão de curl do PHP funciona, combinando vários sinalizadores com chamadas setopt (). Neste exemplo, tenho uma variável $ xml que contém o XML que preparei para enviar - publicarei o conteúdo disso no método de teste do exemplo.

$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

Primeiro inicializamos a conexão, depois definimos algumas opções usando setopt (). Eles dizem ao PHP que estamos fazendo uma solicitação de postagem e que estamos enviando alguns dados com ele, fornecendo os dados. O sinalizador CURLOPT_RETURNTRANSFER informa ao curl para nos fornecer a saída como o valor de retorno de curl_exec em vez de enviá-lo. Depois fazemos a ligação e fechamos a conexão - o resultado está em $ response.


1
na 3ª chamada curl_setopt (), o primeiro argumento $chnão deve ser $curl, correto?
precisa saber é o seguinte

Você pode usar esse mesmo código para dados POST JSON? Mas substitua $ xml com digamos $ json (onde $ json é provavelmente uma string JSON?)
Neal Davis

24

Se por acaso você estiver usando o Wordpress para desenvolver seu aplicativo (na verdade, é uma maneira conveniente de obter autorização, páginas de informações etc. mesmo para coisas muito simples), use o seguinte trecho:

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

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

Ele usa maneiras diferentes de fazer a solicitação HTTP real, dependendo do que está disponível no servidor da web. Para mais detalhes, consulte a documentação da API HTTP .

Se você não deseja desenvolver um tema ou plug-in personalizado para iniciar o mecanismo do Wordpress, basta fazer o seguinte em um arquivo PHP isolado na raiz do wordpress:

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

// ... your code

Não mostrará nenhum tema ou produzirá HTML, basta cortar com as APIs do Wordpress!


22

Gostaria de acrescentar algumas idéias sobre a resposta baseada em cachos de Fred Tanrikut. Sei que a maioria deles já está escrita nas respostas acima, mas acho que é uma boa ideia mostrar uma resposta que inclua todos eles juntos.

Aqui está a classe que eu escrevi para fazer solicitações HTTP-GET / POST / PUT / DELETE com base em curl, referente a quase todo o corpo da resposta:

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

Melhorias

  • Usando http_build_query para obter a string de consulta de uma matriz de solicitação (você também pode usar a própria matriz, consulte: http://php.net/manual/en/function.curl-setopt.php )
  • Retornando a resposta em vez de repetir. Entre, você pode evitar o retorno removendo a linha curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true); . Depois disso, o valor de retorno é um booleano (true = a solicitação foi bem-sucedida, caso contrário, ocorreu um erro) e a resposta é repetida. Vejo: http://php.net/en/manual/function.curl-exec.php
  • Limpe o fechamento e a exclusão da sessão do manipulador de ondulações usando curl_close . Veja: http://php.net/manual/en/function.curl-close.php
  • Usando valores booleanos para o curl_setopt função vez de usar qualquer número (eu sei que qualquer número que não seja igual a zero também é considerado verdadeiro, mas o uso de true gera um código mais legível, mas essa é apenas a minha opinião).
  • Capacidade de fazer chamadas HTTP-PUT / DELETE (útil para teste de serviço RESTful)

Exemplo de uso

PEGUE

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

POSTAR

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

COLOCAR

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

EXCLUIR

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

Teste

Você também pode fazer alguns testes de serviço interessantes usando esta classe simples.

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

Para mim, ele diz "Erro não capturado: Ligue para o método indefinido HTTPRequester :: HTTPost ()" . Simplesmente colei sua classe no meu arquivo .php. Mais alguma coisa que eu preciso fazer?
LinusGeffarth

1
Você pode postar seu código? É muito difícil adivinhar o que há de errado sem nenhum trecho de código.
Mwatzer

Como eu disse, eu literalmente copiei o seu no meu arquivo php simples e isso me deu esse erro.
LinusGeffarth

1
Ok, agora eu vejo o problema, .. estava errado no exemplo! Você tem que chamar HTTPRequester :: HttpPost () em vez de HTTPRequester :: HTTPost ()
mwatzer

1
Ah É fácil perder isso. Eu tive que ler o seu comentário como 5x antes de ver o P extra . Obrigado!
LinusGeffarth

19

Outra alternativa do método sem ondulação acima é usar as funções de fluxo nativas :

  • stream_context_create():

    Cria e retorna um contexto de fluxo com todas as opções fornecidas nas opções predefinidas.

  • stream_get_contents():

    Idêntico a file_get_contents(), exceto que stream_get_contents() opera em um recurso de fluxo já aberto e retorna o conteúdo restante em uma sequência, até bytes de comprimento máximo e iniciando no deslocamento especificado .

Uma função POST com estes pode ser simplesmente assim:

<?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
Esse método sem CURL funcionou bem para validar o reCAPTCHA do google. Esta resposta converge para este código do google: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Xavi Montero

1
Você não precisa usar fclose()se $fpestiver false. Porque fclose()espera que um recurso seja parâmetro.
Floris

1
@Floris Editou-o agora e, de fato, os documentos fclose mencionam "O ponteiro do arquivo deve ser válido". Obrigado por perceber isso!
CPHPython

8

A melhor maneira de enviar GETou POSTsolicitações PHPé a seguinte:

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

O código é retirado da documentação oficial aqui http://docs.php.net/manual/da/httprequest.send.php


1
@akinuri obrigado por destacar, vou compartilhar o novo.
Imran Zahoor

como fazê-lo em PHP 5x?

@YumYumYum, verifique a resposta do dbau acima para 5x, que usa essa técnica php.net/manual/en/function.stream-context-create.php Ou você sempre pode voltar para a solução padrão de curvatura.
Imran Zahoor

5

Há mais um que você pode usar

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

Clique aqui para mais detalhes


2
Isso depende de uma extensão PECL que a maioria não terá instalada. Nem tenho certeza de que ainda está disponível, pois as páginas de manual foram removidas.
Miken32

5

Eu estava procurando por um problema semelhante e encontrei uma abordagem melhor para fazer isso. Então aqui vai.

Você pode simplesmente colocar a seguinte linha na página de redirecionamento (por exemplo, page1.php).

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

Eu preciso disso para redirecionar solicitações POST para chamadas à API REST . Esta solução é capaz de redirecionar com dados de postagem, bem como valores de cabeçalho personalizados.

Aqui está o link de referência .


1
Isso responde como redirecionar uma solicitação de página não. Como envio uma solicitação POST com PHP? Claro que isso iria encaminhar quaisquer parâmetros post, mas que não é de todo a mesma coisa
Wesley Smith

@ DelightedD0D, Desculpe eu não tive a diferença entre redirect a page request with POST paramvs send POST request. Para mim, o objetivo de ambos é o mesmo, corrija-me se estiver errado.
Arindam Nayak

1
Existe algum método que me permita enviar parâmetros com o método POST e depois ler o conteúdo via PHP? O OP deseja que seu script php construa um conjunto de parâmetros POST e os envie para outra página php e que seu script receba a saída dessa página. Essa solução simplesmente aceita um conjunto de valores já POST e os encaminha para outra página. Eles são bem diferentes.
Wesley Smith #

5

Aqui está usando apenas um comando sem cURL. Super simples.

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

Como o Key2 funciona? qual é o separador entre eles?
Sayed Muhammad Idrees

@Sayedidrees para adicionar key2, você pode inseri-lo como um segundo item da matriz. 'key1' => 'Olá mundo!', 'key2' => 'segundo valor'
Liga

Isso funciona muito bem ao usar com o zapier.
Moxet Jan

3

Experimente o pacote HTTP_Request2 do PEAR para enviar facilmente solicitações POST. Como alternativa, você pode usar as funções curl do PHP ou usar um contexto de fluxo PHP .

HTTP_Request2 também possibilita zombar do servidor , para que você possa testar seu código facilmente


7
Eu gostaria que você o elaborasse, se possível.
Gui Imamura
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.