PHP中幾種HTTP請求的實現方法及比較: file_get_contents vs. cURL vs. PECL_HTTP

在PHP中有多種進行HTTP請求的方法, 本文中介紹最常用的三種:

1)  文件流的方式:file_get_contents , 這種方式是PHP自帶的。

2)cURL方式: cURL是PHP的一個第三方庫 , 目前PHP4.0以上都自帶cURL lib.

3) PECL_HTTP 擴展: 這是一個PECL的extension, 需要安裝才能使用

下面分別以一個實際的應用:PayPal的PDT請求爲例, 來分別比較一下這三種方法的優劣:

1. 文件流的方式: PHP的文件流本身就支持HTTP協議,因此我們可以象使用文件一樣來進行HTTP的操作
這種方式適合比較簡單的HTTP GET 或 POST請求, 但對於一些複雜的應用場景中的HTTP 請求還是有些力不從心的。

 if (!isset($_GET["tx"])) {
        header("Location: http://www.cubebackup.com");
        exit() ;
    }

    $post_array = array (
        "cmd" => "_notify-synch",
        "tx" => $_GET["tx"],
        "at" => PDT_IDTOKEN
    );

    $post_string = http_build_query($post_array);

    $opts = array(
        'http' => array(
            'method' => "POST",
            'header' => "Content-Type: application/x-www-form-urlencoded",
            'content'=> $post_string
        )
    );

    $context = stream_context_create($opts);
    $pdt_response = file_get_contents(PAYPALURL, false, $context);

    if ($pdt_response === FALSE) {
        header("Location: http://www.cubebackup.com");
        exit();
    }

    $response_array = preg_split("/\s+/" ,$pdt_response);
    $pdt_data = array();

    if ($response_array[0] === "SUCCESS") {
        foreach ($response_array as $value) {
            $pdt_pair = explode('=', $value);
            if (isset($pdt_pair[1])) {
                $pdt_data[$pdt_pair[0]] = urldecode($pdt_pair[1]);
            }
           //這裏可以對數據進行處理,比如寫入數據庫,或者顯示給用戶等。。  

        }
    } else {
        header("Location: http://www have a peek at this web-site.cubebackup.com");
        exit();
    }

2. 採用curl來處理Paypal PDT 請求

HTTP cURL是基於 libcurl的c語言的類庫封裝而成。 curl/libcurl也是目前最流行的HTTP庫,可以用於多種語言。 我曾經在C++編程中重度使用過curl/libcurl, 無論從功能,性能和編程風格/結構方面, curl都非常出色,尤其是一些複雜的HTTP請求,比如斷點續傳,協同編輯,文件傳輸進度反饋的回調等,cURL都完全沒有問題,而且編程風格非常統一,優雅。

   if (!isset($_GET["tx"])) {
        header("Location: http://www.cubebackup.com");
        exit();
    };

    $post_array = array (
        "cmd" => "_notify-synch",
        "tx" => $_GET["tx"],
        "at" => PDT_IDTOKEN
    );
    $post_data = http_build_query($post_array);

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, PAYPALURL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

    $res = curl_exec($ch);
    curl_close($ch);

    if ($res === FALSE)  {
        error_log("Paypal PDT request failed. ");
        header("Location: http://www.cubebackup.com");
        exit();
    } else {
        $response_array = preg_split("/\s+/" ,$res);

        if ($response_array[0] === "SUCCESS") {
            $pdt_data = array();

            foreach ($response_array as $value) {
                $pdt_pair = explode('=', $value);
                if (isset($pdt_pair[1])) {
                    $pdt_data[urldecode($pdt_pair[0])] = urldecode($pdt_pair[1]);
                }
            }

            //... save pdt_data to db or display to users

        } else {
            //write log
            error_log("Paypal PDT request error, response data is " . $res);
            header("Location: http://www.cubebackup.com");
        }
    }

3. 採用PECL_HTTP來處理同樣的Paypal PDT 請求。 
實際上PECL底層也是基於libcurl來實現的,實現的語言也是c,採用了PECL extension的發佈形式。 目前PECL_HTTP擴展最大的問題是: 大部分的PHP和Linux並沒有自帶該擴展,需要手動自行安裝。 因爲該安裝涉及了重新編譯PHP代碼等工作,因此必須有足夠的權限才能進行,如果你使用的是共享主機,就放棄這個嘗試吧。 另外,不同的系統安裝PECL擴展步驟也有所不同,有的時候,庫的依賴已經其前後順序都會成爲安裝失敗的原因。具體的安裝,請參見: http://php.net/manual/en/install.pecl.php

PECL_HTTP version1 版本有 procedural and OO兩個編程接口, 但 2.0 版本又採用了一個和1.0 完全不兼容的編程接口, 不知道爲什麼, 實在無力吐槽。

實現代碼如下:

  if (!isset($_GET["tx"])) {
        header("Location: http://www.cubebackup.com");
        exit() ;
    }

    $post_string = "cmd=_notify-synch&tx=".$_GET['tx']."&at=".PDT_IDTOKEN;

    if (function_exists('http_post_data') == false ) {
        //PECL http extension 不存在或者安裝有問題
        //採用 CURL 或者 filestream 方式
    }

    $opts= array(
        "redirect" => 10
    );    //因爲該請求有302的redirect,所以設置redirect的次數爲10

    $pdt_response = http_post_data(PAYPALURL, $post_string, $opts);

    if ($pdt_response === FALSE)
    {
        header("Location: http://www.cubebackup.com");
        exit();
    }

    $response_array = preg_split("/\s+/", $pdt_response);

    //下面的代碼和上面的例子相同,就不再寫了 。。。

總結:

1. 目前在PHP平臺上, curl仍然是最好的HTTP庫,沒有之一。 可以解決任何複雜的應用場景中的HTTP 請求
2. 文件流式的HTTP請求比較適合處理簡單的HTTP POST/GET請求,但不適用於複雜的HTTP請求
3. PECL_HTTP擴展寫代碼更加簡潔,省事, 但成熟度不好,編程接口不統一,文檔和實例匱乏。 我個人也沒有使用它做過如斷點續傳等複雜的HTTP 應用,對於其處理複雜HTTP請求的能力也不清楚,爲此我還在stackoverflow上發了個帖子專門詢問一下PECL這個擴展的情況, 得到的答案是: 請用CURL!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章