PHP + curl, mã HTTP POST mẫu?


491

Bất cứ ai có thể chỉ cho tôi làm thế nào để thực hiện một curl php với HTTP POST?

Tôi muốn gửi dữ liệu như thế này:

username=user1, password=passuser1, gender=1

Đến www.domain.com

Tôi mong đợi các curl sẽ trả lời như thế nào result=OK. Có ví dụ nào không?

Câu trả lời:


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
không cần sử dụng http_build_query()để xử lý các tham số; Chỉ cần vượt qua các mảng CURLOPT_POSTFIELDSlà đủ.
Raptor

8
@Raptor cung cấp mảng trực tiếp cho CURLOPT_POSTFIELDS thực sự làm cho kiểu POST hơi khác. (Mong đợi: 100-tiếp tục)
Oleg Popov

22
Ngoài ra nếu giá trị của CURLOPT_POSTFIELDSmột mảng, Content-Typetiêu đề sẽ được đặt thành multipart/form-datathay vì application/x-www-form-urlencoded. php.net/manual/en/feft.curl-setopt.php
Chloe

2
Sử dụng CURLOPT_RETURNTRANSFER có nghĩa là curl_exec sẽ trả về phản hồi dưới dạng chuỗi thay vì xuất ra.
bnp887

2
Tôi đề nghị sử dụng truethay vì 1cho CURLOPT_POST.
Huỳnh

261

Thủ tục

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

Hướng đối tượng

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

Sử dụng

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

Lưu ý bên ở đây: tốt nhất là tạo một loại giao diện được gọi là AdapterInterfaceví dụ với getResponse()phương thức và để lớp bên trên thực hiện nó. Sau đó, bạn luôn có thể trao đổi việc thực hiện này với một bộ điều hợp khác mà bạn muốn, mà không có bất kỳ tác dụng phụ nào cho ứng dụng của bạn.

Sử dụng HTTPS / mã hóa lưu lượng

Thông thường có vấn đề với cURL trong PHP trong hệ điều hành Windows. Trong khi cố gắng kết nối với điểm cuối được bảo vệ https, bạn sẽ gặp lỗi cho bạn biết điều đó certificate verify failed.

Điều mà hầu hết mọi người làm ở đây là nói với thư viện cURL chỉ cần bỏ qua các lỗi chứng chỉ và tiếp tục ( curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). Vì điều này sẽ làm cho mã của bạn hoạt động, bạn giới thiệu lỗ hổng bảo mật khổng lồ và cho phép người dùng độc hại thực hiện các cuộc tấn công khác nhau trên ứng dụng của bạn như tấn công Man In The Middle hoặc như vậy.

Không bao giờ, bao giờ làm điều đó. Thay vào đó, bạn chỉ cần sửa đổi php.inivà cho PHP biết CA Certificatetệp của bạn ở đâu để cho phép xác minh chứng chỉ chính xác:

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

Bản mới nhất cacert.pemcó thể được tải xuống từ Internet hoặc trích xuất từ ​​trình duyệt yêu thích của bạn . Khi thay đổi bất kỳ php.inicài đặt liên quan nào, hãy nhớ khởi động lại máy chủ web của bạn.


4
Đây thực sự phải là câu trả lời được chấp nhận, bởi vì cách thực hành tốt nhất là để thư viện HTTP xử lý mã hóa các biến của bạn.
Eric Seastrand

4
Đây không phải là luôn luôn như vậy. Tôi đã thấy các máy chủ web hy vọng các biến POST được mã hóa theo một cách nhất định, khiến chúng bị lỗi khác. Dường như với tôi rằng http_build_query () thực sự đáng tin cậy hơn cURL cho việc này.
César

4
Thông số HTTP khá đơn giản về cách các tham số POST sẽ trông như thế nào. Phần mềm máy chủ web phải tuân thủ các tiêu chuẩn.
emix 15/03/2016

1
Bằng cách này, bạn sẽ buộc cURL sử dụng loại POST hơi khác. (Mong đợi: 100-tiếp tục). Kiểm tra bài viết này: support.urbanairship.com/entries/ từ
Oleg Popov

5
Mở rộng trên nhận xét của @ César, tài liệu PHP ghi chú rõ ràng như sau: "Truyền một mảng cho CURLOPT_POSTFIELDS sẽ mã hóa dữ liệu dưới dạng nhiều dữ liệu / biểu mẫu , trong khi truyền chuỗi mã hóa URL sẽ mã hóa dữ liệu dưới dạng ứng dụng / x-www -được mã hóa . ". Gần đây tôi đã dành một lượng thời gian không đáng có để cố gắng khắc phục lý do tại sao cuộc gọi cURL không thành công ở điểm cuối của bên thứ ba để cuối cùng nhận ra rằng họ không hỗ trợ đa dữ liệu / biểu mẫu.
Jake Z

31

Một ví dụ trực tiếp về việc sử dụng php curl_exec để thực hiện một bài đăng HTTP:

Đặt cái này trong một tệp có tên 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);
?>

Sau đó chạy nó bằng lệnh php foobar.php, nó loại loại đầu ra này ra màn hình:

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

Vì vậy, bạn đã làm một POST PHP cho www.google.com và gửi cho nó một số dữ liệu.

Nếu máy chủ được lập trình để đọc các biến bài, nó có thể quyết định làm một cái gì đó khác nhau dựa trên điều đó.


$postvars .= $key . $value;Có nên $postvars .= $key . $value ."&";hay không?
Manwal

Nhìn lại câu trả lời này, bạn cũng có thể thay thế triển khai trình chuyển đổi chuỗi truy vấn tùy chỉnh của mình bằng http_build_query , chỉ cần cung cấp cho nó $fieldsmảng và nó sẽ xuất ra một chuỗi truy vấn.

Xin lưu ý rằng bạn nên mã hóa dữ liệu của mình để dữ liệu được gửi an toàn.
wtf8_decode

3
Ồ không đừng cố gắng tự xây dựng chuỗi bài viết! sử dụng cái này:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
oriadam

3
-1 bởi vì bạn không thoát khỏi bài đăng của bạn. Ví dụ của OP đang gửi tên người dùng và mật khẩu do người dùng gửi để xác thực. Với giải pháp của bạn, người dùng có mật khẩu & mật khẩu của họ sẽ không bao giờ có thể đăng nhập. Nhận xét của oriadam là chính xác, nhưng bạn có thể bỏ qua http_build_querynhư:curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Eric Seastrand

26

Có thể dễ dàng tiếp cận với:

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

Bài đăng Curl + Xử lý lỗi + Đặt tiêu đề [cảm ơn @ 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',
]);

Mã của bạn sẽ không đóng tay cầm và tài nguyên miễn phí, vì bạn curl_c Đóng sau khi ném ngoại lệ. Bạn nên curl_c Đóng bên trong một khối cuối cùng.
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
Mã của bạn sẽ không đóng tay cầm và tài nguyên miễn phí, vì bạn curl_c Đóng sau khi ném ngoại lệ. Bạn nên curl_closebên trong một finallykhối.
emix

6

Nếu biểu mẫu đang sử dụng chuyển hướng, xác thực, cookie, SSL (https) hoặc bất kỳ thứ gì khác ngoài tập lệnh mở hoàn toàn mong đợi các biến POST, bạn sẽ bắt đầu nghiến răng thật nhanh. Hãy xem Snoopy , nơi thực hiện chính xác những gì bạn có trong đầu trong khi loại bỏ nhu cầu thiết lập nhiều chi phí.


Nếu bạn muốn gắn bó với lib stock, chỉ cần thử thêmcurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
MarkHu

Nhược điểm duy nhất là bạn vẫn phải xử lý cài đặt lọ cookie và các vấn đề tiềm ẩn khác (như có nên theo dõi chuyển hướng hay không, cách xử lý xác thực không dựa trên HTTP, v.v.). 6 năm sau, tôi sẽ đề xuất khái niệm chung hơn về "trình duyệt không đầu" thay vì thư viện cụ thể đó (hoặc bất cứ thứ gì trên sourceforge, ngày tháng, phải không?) Và trong khi tôi thường chỉ giải quyết trực tiếp các tùy chọn cuộn tròn, tôi vẫn sẽ khuyên nhìn vào một thư viện trình duyệt không đầu tương thích với PSR-7 (Guheads là người duy nhất tôi biết ngoài tầm tay) để tránh đau đầu.
Anthony

3

Một câu trả lời đơn giản hơn NẾU bạn đang truyền thông tin đến trang web của riêng bạn là sử dụng biến SESSION. Bắt đầu trang php với:

session_start();

Nếu tại một thời điểm nào đó có thông tin bạn muốn tạo trong PHP và chuyển đến trang tiếp theo trong phiên, thay vì sử dụng biến POST, hãy gán nó cho biến SESSION. Thí dụ:

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

Sau đó, trên trang tiếp theo, bạn chỉ cần tham khảo biến SESSION này. LƯU Ý: sau khi bạn sử dụng, hãy chắc chắn rằng bạn phá hủy nó, để nó không tồn tại sau khi được sử dụng:

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

3

Dưới đây là một số mã soạn sẵn cho PHP + curl http: //www.webbotsspiderssc Greenscrapers.com/DSP_doad.php

bao gồm trong các thư viện sẽ đơn giản hóa sự phát triển

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

Nếu bạn cố gắng đăng nhập trên trang web với cookie.

Mã này:

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

Có thể không hoạt động nếu bạn cố gắng đăng nhập, vì nhiều trang web trả về trạng thái 200, nhưng bài đăng không thành công.

Cách dễ dàng để kiểm tra xem bài đăng nhập có thành công hay không là kiểm tra xem nó có đặt lại cookie không. Nếu trong đầu ra có chuỗi Set-Cookies, điều này có nghĩa là các bài đăng không thành công và nó bắt đầu phiên mới.

Ngoài ra bài viết có thể thành công, nhưng trạng thái có thể được chuyển hướng thay vì 200.

Để chắc chắn bài viết thành công hãy thử điều này:

Theo dõi vị trí sau bài đăng, vì vậy nó sẽ đi đến trang nơi bài đăng chuyển hướng đến:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

Và hơn kiểm tra nếu cookie mới tồn tại trong yêu cầu:

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

{echo 'post successful'; }

else { echo 'not successful'; }

1

Ví dụ về gửi mẫu và dữ liệu thô :

$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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.