PHP中几种HTTP请求的实现方法及比较: file_get_contents vs. cURL vs. PECL_HTTP

By | 2014/07/21

前一篇文章中介绍了 PHP中的对象复制以及深拷贝浅拷贝的问题,这里我们来探讨一下PHP中的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!

欢迎大家对这个问题进行讨论。

One thought on “PHP中几种HTTP请求的实现方法及比较: file_get_contents vs. cURL vs. PECL_HTTP

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.