PHP + curl, código de exemplo HTTP POST?

491

Alguém pode me mostrar como fazer um php curl com um HTTP POST?

Quero enviar dados como este:

username=user1, password=passuser1, gender=1

Para www.domain.com

Espero que o cacho retorne uma resposta como result=OK. Existem exemplos?

mysqllearner
fonte

Respostas:

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 { ... }
?>
miku
fonte
47
não há necessidade de usar http_build_query()para manipular parâmetros; basta passar a matriz para o CURLOPT_POSTFIELDSsuficiente.
Raptor
8
O @Raptor, que fornece o array diretamente para CURLOPT_POSTFIELDS, na verdade curl, cria um tipo ligeiramente diferente de POST. (Esperado: 100-continuar)
Oleg Popov
22
Além disso, se o valor de CURLOPT_POSTFIELDSfor uma matriz, o Content-Typecabeçalho será definido como em multipart/form-datavez de application/x-www-form-urlencoded. php.net/manual/en/function.curl-setopt.php
Chloe
2
Usar CURLOPT_RETURNTRANSFER significa que curl_exec retornará a resposta como uma sequência em vez de enviá-la.
bnp887
2
Sugiro usar em truevez de 1para CURLOPT_POST.
FluorescentGreen5
261

Procedural

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

Orientado a Objeto

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

Uso

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

Nota lateral aqui: seria melhor criar algum tipo de interface chamada, AdapterInterfacepor exemplo, com getResponse()method e deixar a classe acima implementá-la. Então você sempre pode trocar essa implementação por outro adaptador do seu gosto, sem efeitos colaterais para o seu aplicativo.

Usando HTTPS / criptografando tráfego

Geralmente, há um problema com o cURL no PHP no sistema operacional Windows. Ao tentar conectar-se a um endpoint protegido por https, você receberá um erro dizendo isso certificate verify failed.

O que a maioria das pessoas faz aqui é dizer à biblioteca cURL para simplesmente ignorar erros de certificado e continuar ( curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). Como isso fará com que seu código funcione, você introduz uma enorme falha de segurança e permite que usuários mal-intencionados realizem vários ataques ao seu aplicativo, como o ataque Man In The Middle ou algo assim.

Nunca, nunca faça isso. Em vez disso, basta modificar php.inie informar ao PHP onde seu CA Certificatearquivo está para permitir que ele verifique os certificados corretamente:

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

O mais recente cacert.pempode ser baixado da Internet ou extraído do seu navegador favorito . Ao alterar php.inias configurações relacionadas, lembre-se de reiniciar o servidor da web.

emix
fonte
4
Essa deve ser realmente a resposta aceita, porque a melhor prática seria deixar a biblioteca HTTP manipular a codificação de suas variáveis.
Eric Seastrand
4
Isso não é sempre o caso. Vi servidores da Web que esperam que as variáveis ​​POST sejam codificadas de uma certa maneira, causando a falha de outra maneira. Parece-me que http_build_query () é realmente mais confiável que cURL para isso.
César
4
A especificação HTTP é bastante direta sobre a aparência dos parâmetros POST. O software do servidor da web deve estar em conformidade com os padrões de qualquer maneira.
Emix
1
Ao usar desta maneira, você forçará o cURL a usar um tipo ligeiramente diferente de POST. (Espere: 100 continuações). Verifique este artigo: support.urbanairship.com/entries/…
Oleg Popov
5
Expandindo o comentário de @ César, a documentação do PHP observa explicitamente o seguinte: "Passar uma matriz para CURLOPT_POSTFIELDS codificará os dados como multipart / form-data , enquanto passar uma string codificada em URL codificará os dados como application / x-www-form -urlencoded . ". Recentemente, passei uma quantidade excessiva de tempo tentando solucionar por que uma chamada cURL estava falhando em um terminal de terceiros apenas para finalmente perceber que eles não suportavam dados de várias partes / formulário.
Jake Z
31

Um exemplo ao vivo do uso do php curl_exec para fazer uma postagem HTTP:

Coloque isso em um arquivo chamado 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);
?>

Em seguida, execute-o com o comando php foobar.php, ele despeja esse tipo de saída na tela:

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

Então você fez um PHP POST para www.google.com e enviou alguns dados.

Se o servidor tivesse sido programado para ler as variáveis ​​de postagem, ele poderia decidir fazer algo diferente com base nisso.

Eric Leschinski
fonte
$postvars .= $key . $value;deveria $postvars .= $key . $value ."&";ou não?
Manwal
Olhando novamente para esta resposta, você também pode substituir a implementação do conversor de cadeia de consulta personalizada por http_build_query , basta fornecer a $fieldsmatriz e ela produzirá uma cadeia de consulta.
Esteja ciente de que você deve codificar seus dados para que sejam enviados com segurança.
Wtf8_decode
3
Oh não, não tente construir a string do post você mesmo! use isto:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam 29/09/2015
3
-1 porque você não está escapando dos seus pós-vars. O exemplo do OP está enviando nomes de usuário e senhas enviados pelo usuário para autenticação. Com sua solução, um usuário com um e em sua senha nunca será capaz de fazer logon no comentário de oriadam está correto, mas você pode deixar de fora. http_build_queryComo:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand
26

Pode ser facilmente alcançado com:

<?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);
V. Kovpak
fonte
13

Pós-ondulação + tratamento de erros + definir cabeçalhos [graças a @ 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',
]);
MSS
fonte
Seu código não fecha o identificador e libera recursos, porque você enrola_close após lançar uma exceção. Você deve enrolar_close dentro de um bloco finalmente.
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;
}
Mantas D
fonte
1
Seu código não fecha o identificador e libera recursos, porque você enrola_close após lançar uma exceção. Você deve curl_closedentro de um finallybloco.
Emix
6

Se o formulário estiver usando redirecionamentos, autenticação, cookies, SSL (https) ou qualquer outra coisa que não seja um script totalmente aberto esperando variáveis ​​POST, você começará a ranger muito rápido. Dê uma olhada no Snoopy , que faz exatamente o que você tem em mente e elimina a necessidade de configurar muitas despesas gerais.

Anthony
fonte
Se você quiser ficar com o estoque lib, apenas tente adicionarcurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
MarkHu
A única desvantagem é que você ainda precisa lidar com a configuração de um pote de cookies e outros possíveis problemas (como seguir redirecionamentos, como lidar com autenticação não baseada em HTTP, etc.). Seis anos depois, eu recomendaria o conceito mais genérico de um "navegador sem cabeça" em vez daquela biblioteca específica (ou qualquer coisa no sourceforge, como datada, certo?) olhando para uma biblioteca de navegadores sem cabeça compatível com PSR-7 (Guzzle é o único que conheço de imediato) para evitar dores de cabeça.
Anthony
3

Uma resposta mais simples se você estiver passando informações para o seu próprio site é usar uma variável SESSION. Comece a página php com:

session_start();

Se em algum momento houver informações que você deseja gerar no PHP e passar para a próxima página da sessão, em vez de usar uma variável POST, atribua-a a uma variável SESSION. Exemplo:

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

Então, na próxima página, você simplesmente faz referência a essa variável SESSION. NOTA: depois de usá-lo, certifique-se de destruí-lo, para que ele não persista depois de ser usado:

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

Aqui estão alguns códigos padrão para o PHP + curl http://www.webbotsspidersscreenscrapers.com/DSP_download.php

incluir nessas bibliotecas simplificará o desenvolvimento

<?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, "");
    ...
?>
AzizSM
fonte
2

Se você tentar fazer login no site com cookies.

Este código:

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

Pode não funcionar se você tentar fazer login, porque muitos sites retornam o status 200, mas a postagem não é bem-sucedida.

Uma maneira fácil de verificar se a postagem de login foi bem-sucedida é verificar se está configurando cookies novamente. Se na saída houver uma sequência de Set-Cookies, isso significa que as postagens não são bem-sucedidas e inicia uma nova sessão.

Além disso, a postagem pode ser bem-sucedida, mas o status pode ser redirecionado em vez de 200.

Para garantir que a postagem seja bem-sucedida, tente o seguinte:

Siga o local após a postagem, para que ela vá para a página para a qual a postagem é redirecionada:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

E depois verifique se existem novos cookies na solicitação:

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

{echo 'post successful'; }

else { echo 'not successful'; }
Atanas Atanasov
fonte
1

Exemplos de envio de formulário e dados brutos :

$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);
Serhii Andriichuk
fonte