PHP cURL 函数 curl类库

406 阅读5分钟

概述

PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。

libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。

PHP中使用cURL实现Get和Post请求的方法

这些函数在PHP 4.0.2中被引入。

需求

为了使用PHP的cURL函数,你需要安装 » libcurl包。

PHP需要使用libcurl 7.0.2-beta 或者更高版本。在PHP 4.2.3 里使用cURL,你需要安装7.9.0或更高版本的libcurl。从PHP 4.3.0开始你需要安装7.9.0或更高版本的libcurl。从PHP 5.0.0开始你需要安装7.10.5或更高版本的libcurl。

安装

要使用PHP的cURL支持你必须在编译PHP时加上–with-curl[=DIR] 选项,DIR为包含lib和include的目录路径。在include目录中必须有一个名为curl,包含了easy.h和curl.h的文件夹。lib文件夹里应该有一个名为libcurl.a的文件。对于PHP 4.3.0你可以配置–with-curlwrappers 使cURL使用URL流。

注意: Win32用户注意 要在Windows环境下使用这个模块,libeay32.dll和ssleay32.dll必须放到PATH环境变量包含的目录下。 不用cURL网站上的libcurl.dll。

PHP cURL 函数
以下包含了PHP cURL函数列表:

函数描述
curl_close()关闭一个cURL会话。
curl_copy_handle()复制一个cURL句柄和它的所有选项。
curl_errno()返回最后一次的错误号。
curl_error()返回一个保护当前会话最近一次错误的字符串。
curl_escape()返回转义字符串,对给定的字符串进行URL编码。
curl_exec()执行一个cURL会话。
curl_file_create()创建一个 CURLFile 对象。
curl_getinfo()获取一个cURL连接资源句柄的信息。
curl_init()初始化一个cURL会话。
curl_multi_add_handle()向curl批处理会话中添加单独的curl句柄。
curl_multi_close()关闭一组cURL句柄。
curl_multi_exec()运行当前 cURL 句柄的子连接。
curl_multi_getcontent()如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流。
curl_multi_info_read()获取当前解析的cURL的相关传输信息。
curl_multi_init()返回一个新cURL批处理句柄。
curl_multi_remove_handle()移除curl批处理句柄资源中的某个句柄资源。
curl_multi_select()等待所有cURL批处理中的活动连接。
curl_multi_setopt()设置一个批处理cURL传输选项。
curl_multi_strerror()返回描述错误码的字符串文本。
curl_pause()暂停及恢复连接。
curl_reset()重置libcurl的会话句柄的所有选项。
curl_setopt_array()为cURL传输会话批量设置选项。
curl_setopt()设置一个cURL传输选项。
curl_share_close()关闭cURL共享句柄。
curl_share_init()初始化cURL共享句柄。
curl_share_setopt()设置一个共享句柄的cURL传输选项。
curl_strerror()返回错误代码的字符串描述。
curl_unescape()解码URL编码后的字符串。
curl_version()获取cURL版本信息。

实例:

/*
模拟get请求
$url 链接
$headerArray  请求头
*/
function geturl($url,$headerArray =array("Content-type:application/json;","Accept:application/json")){
	 
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch,CURLOPT_HTTPHEADER,$headerArray);
        $output = curl_exec($ch);
        curl_close($ch);
        $output = json_decode($output,true);
        return $output;
}

/*
模拟post请求
$url 链接
$headerArray  请求头
$data 请求数据
*/
function posturl($url,$data, $headerArray =array("Content-type:application/json;charset='utf-8'","Accept:application/json")){
        $data  = json_encode($data);    
      
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl,CURLOPT_HTTPHEADER,$headerArray);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return json_decode($outputtrue);
}

/*
模拟PUT请求
put=更新;
$url 链接
$headerArray  请求头
$data 请求数据
*/
function puturl($url,$data){
    $data = json_encode($data);
    $ch = curl_init(); //初始化CURL句柄 
    curl_setopt($ch, CURLOPT_URL, $url); //设置请求的URL
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type:application/json'));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); //设为TRUE把curl_exec()结果转化为字串,而不是直接输出 
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST,"PUT"); //设置请求方式
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);//设置提交的字符串
    $output = curl_exec($ch);
    curl_close($ch);
    return json_decode($output,true);
}
/*
模拟DELETE 请求
DELETE =删除;
$url 链接
$headerArray  请求头
$data 请求数据
*/
function delurl($url,$data){
    $data  = json_encode($data);
    $ch = curl_init();
    curl_setopt ($ch,CURLOPT_URL,$put_url);
    curl_setopt ($ch, CURLOPT_HTTPHEADER, array('Content-type:application/json'));
    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, "DELETE");   
    curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
    $output = curl_exec($ch);
    curl_close($ch);
    $output = json_decode($output,true);
}
/*
模拟PATCH请求
PATCH=Http的【RFC2616】原本定义用于上传数据的方法只有POST和PUT,但是考虑到两者的不足,就增加了PATCH方法。;
$url 链接
$headerArray  请求头
$data 请求数据
*/
function patchurl($url,$data){
    $data  = json_encode($data);
    $ch = curl_init();
    curl_setopt ($ch,CURLOPT_URL,$url);
    curl_setopt ($ch, CURLOPT_HTTPHEADER, array('Content-type:application/json'));
    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, "PATCH");  
    curl_setopt($ch, CURLOPT_POSTFIELDS,$data);     //20170611修改接口,用/id的方式传递,直接写在url中了
    $output = curl_exec($ch);
    curl_close($ch);
    $output = json_decode($output);
    return $output;
}

会给我们返回的信息
在这里插入图片描述

  • 类名称:curl
  • 1.支持单个get,post请求
  • 2.支持多个目标未登录get请求
  • 3.支持单个目标并行多个get,post请求
  • 4.支持ajax请求
  • 5.支持自定义header请求
  • 6.支持自定义编码数据请求(该情况比较特殊)
  • 7.支持代理登陆
  • 8.支持自定义来路
  • 9.支持自定义超时
  • 10.支持文件上传
<?php
/**
 * 类名称:curl
 * 1.支持单个get,post请求
 * 2.支持多个目标未登录get请求
 * 3.支持单个目标并行多个get,post请求
 * 4.支持ajax请求
 * 5.支持自定义header请求
 * 6.支持自定义编码数据请求(该情况比较特殊)
 * 7.支持代理登陆
 * 8.支持自定义来路
 * 9.支持自定义超时
 * 10.支持文件上传
 */

/**
 * demo1 get 请求
 * curl()->get("http://www.baidu.com")->body();
 */

/**
 * demo2 post请求 
 * curl()->post("http://www.xxx.com/say.php",array(
 *      'data' => array(
 *                  'title' => 'test title',
 *                  'content' => 'test content',
 *              ),
 * ))->body();
 */

/**
 * demo3 post请求 ajax请求 并设置cookie
 * curl()->post("http://www.xxx.com/save.php",array(
 *      'data' => array(
 *              'username' => 'test',
 *              'password' => 'test'
 *             ),
 *      'cookie_file' => '/tmp/cookie.txt',
 *      'ajax' => 1,
 * ))->body();
 */

/***
 * demo4 批处理get请求
 * curl()->get(array(
 *  'http://www.xxx.com/test1.php?aaa=111',
 *  'http://www.xxx.com/test2.php?aaa=222',
 *  'http://www.xxx.com/test3.php?aaa=333',
 * ))->body();
 */

/***
 * demo5 批处理post请求 post请求,目前只支持单个网站的批处理post请求
 * curl()->post(array(
 *  'http://www.xxx.com/test1.php',
 *  'http://www.xxx.com/test2.php',
 *  'http://www.xxx.com/test3.php',
 * ),array(
 *   'data' => array(
 *        array(
 *              'uid' => 'aabbccdd',
 *        ),
 *        array(
 *              'uid' => 'eeeeeeee',
 *        ),
 *        array(
 *              'uid' => 'ffffffff',
 *        ),
 *   ),
 *   'cookie_file' => '/tmp/cookie.txt'
 * ))->body();
 */

/**
 * demo6 文件上传
 * curl()->post('填写url地址',array(
 *       'files' => array(
 *          'pic' => '/tmp/a.gif' ,
 *       ),
 *   ))->body();
 */

/**
 * 其他方法未一一列举,可查看源码进行测试
 */

class Curl {
    
    //单例对象
    private static $ins = null;
    
    //请求结果
    private $body = null;
    
    //cookie文件
    private $cookieFile = null;
    
    //支持的请求方法
    private $method = array('get','post');
  
    //禁用初始化方法
    final private function __construct()
    {        
    }
    
    /**
     * 单例化对象
     */
    public static function exec()
    {
        if (self::$ins) {
            return self::$ins;
        }
        return self::$ins = new self();
    }
    
    /**
     * 禁止克隆对象
     */
    public function __clone()
    {
        throw new curlException('错误:不能克隆对象');
    }
    
    /**
     * 调用不存在的方法被调用
     */
    public function __call($method, $args)
    {
        if(!in_array($method,$this->method)) {
            throw new curlException("错误:不支持{$method}方法,支持的方法有" 
                . join(',',$this->method));
        }
        return $this->request($method, $args);
    }
    
    /**
     * 返回执行结果
     */
    public function body() 
    {
        return $this->body;
    }

    /**
     * 执行请求
     * @param type $method
     * @param type $args
     * @return 返回对象本身
     */
    private function request($method, $args) 
    {

        if (isset($args[1]['multi'])) {
            $this->body = $this->multiExecCurl($method, $args);
        } else {
            $this->body = $this->execCurl($method, $args);
        }
        return $this;
    }
    
    /**
     * curl 批处理请求
     * @param type $method
     * @param type $args
     * @return type
     */
    public function multiExecCurl($method, $args)
    {
        $urls      = isset($args[0])            ? $args[0]            : "";
        $data      = isset($args[1]['data'])    ? $args[1]['data']    : "";
        $ajax      = isset($args[1]['ajax'])    ? $args[1]['ajax']    : "";
        $timeout   = isset($args[1]['timeout']) ? $args[1]['timeout'] : 30;
        $referer   = isset($args[1]['referer']) ? $args[1]['referer'] : "";
        $proxy     = isset($args[1]['proxy'])   ? $args[1]['proxy']   : "";
        $headers   = isset($args[1]['headers']) ? $args[1]['headers'] : "";
        
        if (!is_array($urls) || (is_array($urls) && empty($urls))) {
            throw new curlException("错误信息:批处理url必须是数组并且不能为空");
        }
        
        //创建批处理cURL句柄 
        $queue   = curl_multi_init();
        
        //取得cookie文件路径
        if(!$this->cookieFile) {
            $this->cookieFile = isset($args[1]['cookie_file']) 
                    ? $args[1]['cookie_file'] : "";
        }
        
        //如果未获取到浏览器环境信息,就手动指定一个
        $userAgent = isset($_SERVER['HTTP_USER_AGENT']) 
                        ? $_SERVER['HTTP_USER_AGENT'] 
                            : 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:23.0) '
                                .'Gecko/20100101 Firefox/23.0';

        //设置CURL OPT选项
        $options = array(  
                    CURLOPT_TIMEOUT        => $timeout,  //超时
                    CURLOPT_RETURNTRANSFER => 1,         //输出数据流
                    CURLOPT_HEADER         => 0,         //禁止头文件数据流输出
                    CURLOPT_FOLLOWLOCATION => 1,         //自动跳转追踪
                    CURLOPT_AUTOREFERER    => 1,         //自动设置来路信息
                    CURLOPT_SSL_VERIFYPEER => 0,         //认证证书检查
                    CURLOPT_SSL_VERIFYHOST => 0,         //检查SSL加密算法
                    CURLOPT_HEADER         => 0,         //禁止头文件输出
                    CURLOPT_NOSIGNAL       => 1,         //忽略php所有的传递信号
                    CURLOPT_USERAGENT      => $userAgent,//浏览器环境字符串
        			CURLOPT_IPRESOLVE	   => CURL_IPRESOLVE_V4, //ipv4寻址方式
                    CURLOPT_ENCODING       => 'gzip',    //解析使用gzip压缩的网页	
                   );  
        
         //检测是否存在代理请求
         if (is_array($proxy) && !empty($proxy)) {
            
            $options[CURLOPT_PROXY]        = $proxy['host'];
            $options[CURLOPT_PROXYPORT]    = $proxy['port'];
            
            $options[CURLOPT_PROXYUSERPWD] = 
                                        $proxy['user'] . ':' . $proxy['pass'];
        }
        
        //header选项
        $headerOptions = array();
        
        //模拟AJAX请求 
        if ($ajax) {
            $headerOptions['X-Requested-With']  = 'XMLHttpRequest';
        }
        
        if ($this->cookieFile) {
            $options[CURLOPT_COOKIEFILE] = $this->cookieFile;
            $options[CURLOPT_COOKIEJAR]  =  $this->cookieFile;
        }

        if ($referer) {
            $options[CURLOPT_REFERER] = $referer;
        }
        
        if (!empty($headerOptions)) {
            $options[CURLOPT_HTTPHEADER] = $headerOptions;
        }
        
        //循环的进行初始化一个cURL会话
        foreach ($urls as  $k => $url) {     
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);          
            
            if ($method == 'post') {
                //发送一个常规的POST请求,
                //类型为:application/x-www-form-urlencoded,就像表单提交的一样
                $options[CURLOPT_POST]       = 1;
                
                //使用HTTP协议中的"POST"操作来发送数据,支持键值对数组定义
                //注意:即使不使用http_build_query也能自动编码
                $options[CURLOPT_POSTFIELDS] = $data[$k]; 
            }
            
            curl_setopt_array($ch,$options);
            curl_multi_add_handle($queue, $ch);
        }

        //初始化变量
        $responses = array();
        $active    = null;

        //循环运行当前 cURL 句柄的子连接
        do {
            while (($code = curl_multi_exec($queue, 
                    $active)) == CURLM_CALL_MULTI_PERFORM);

            if ($code != CURLM_OK) { 
                break;
            }

            //循环获取当前解析的cURL的相关传输信息
            while ($done = curl_multi_info_read($queue)) {

                //获取最后一次传输的相关信息
                $info = curl_getinfo($done['handle']);

                //从最后一次传输的相关信息中找 http_code 等于200
                if ($info['http_code'] == 200) {
                    //如果设置了CURLOPT_RETURNTRANSFER,获取的输出的文本流
                    $responses[] = curl_multi_getcontent($done['handle']);
                }

                //移除curl批处理句柄资源中的某个句柄资源
                curl_multi_remove_handle($queue, $done['handle']);

                //关闭某个批处理句柄会话
                curl_close($done['handle']);
            }

            if ($active > 0) {
                //等待所有cURL批处理中的活动连接
                curl_multi_select($queue, 0.5);
            }

        } while ($active);

        //关闭一组cURL句柄
        curl_multi_close($queue);

        //返回结果
        return $responses;
    }
    
    /**
     * curl 单句柄请求
     * @param type $method
     * @param type $args
     * @return type
     */
    private function execCurl($method, $args)
    {
        //解析参数
        $url       = isset($args[0])            ? $args[0]            : "";
        $multi     = isset($args[1]['multi'])   ? $args[1]['multi']   : "";
        $data      = isset($args[1]['data'])    ? $args[1]['data']    : "";
        $ajax      = isset($args[1]['ajax'])    ? $args[1]['ajax']    : "";
        $timeout   = isset($args[1]['timeout']) ? $args[1]['timeout'] : 30;
        $files     = isset($args[1]['files'])   ? $args[1]['files']   : "";
        $referer   = isset($args[1]['referer']) ? $args[1]['referer'] : "";
        $proxy     = isset($args[1]['proxy'])   ? $args[1]['proxy']   : "";
        $headers   = isset($args[1]['headers']) ? $args[1]['headers'] : "";
        
        //如果环境变量的浏览器信息不存在,就是用手动设置的浏览器信息
        $userAgent = isset($_SERVER['HTTP_USER_AGENT'])?
            $_SERVER['HTTP_USER_AGENT']:
                'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:23.0) 
                    Gecko/20100101 Firefox/23.0';
        
        //检测url必须参数 不能为空
        if (!$url) {
            throw new curlException("错误:curl请求地址不能为空");
        }
        
        //设置curl选项
        $options = array(
                        CURLOPT_URL            => $url,      //目标url
                        CURLOPT_TIMEOUT        => $timeout,  //超时
                        CURLOPT_RETURNTRANSFER => 1,         //输出数据流
                        CURLOPT_FOLLOWLOCATION => 1,         //自动跳转追踪
                        CURLOPT_AUTOREFERER    => 1,         //自动设置来路信息
                        CURLOPT_SSL_VERIFYPEER => 0,         //认证证书检查
                        CURLOPT_SSL_VERIFYHOST => 0,         //检查SSL加密算法
                        CURLOPT_HEADER         => 0,         //禁止头文件输出
                        CURLOPT_NOSIGNAL       => 1,         //忽略所有传递的信号
                        CURLOPT_USERAGENT      => $userAgent,//浏览器环境字符串
                        CURLOPT_IPRESOLVE      => CURL_IPRESOLVE_V4, //ipv4寻址方式
                        CURLOPT_ENCODING       => 'gzip',    //解析使用gzip压缩的网页    
                   );  
        
        //获取cookie文件地址路径
        if(!$this->cookieFile) {
            $this->cookieFile = isset($args[1]['cookie_file']) 
                    ? $args[1]['cookie_file'] : "";
        }
        
        //设置代理 必须是数组并且非空
        if (is_array($proxy) && !empty($proxy)) {   
            $options[CURLOPT_PROXY]        = $proxy['host'];
            $options[CURLOPT_PROXYPORT]    = $proxy['port'];   
            $options[CURLOPT_PROXYUSERPWD] = 
                                        $proxy['user'] . ':' . $proxy['pass'];
        }
        
        //检测是否未启用自定义urlencode编码
        if (!isset($args[1]['build'])) { 
            if ($data && $method == "post" && is_array($data)) {
                $data = http_build_query($data, '', '&');
            }
        }
        
        //检测是否含有上传文件
        if ($files && $method == "post" && is_array($files)) {
            foreach ($files as $k => $v) {
                $files[$k] = '@' . $v;
            }

            parse_str($data, $data);
            $data = $data + $files;
        }
        
        //检测判断是否是post请求
        if ($method == 'post') {
            //发送一个常规的POST请求
            $options[CURLOPT_POST]       = 1; 
            
            //使用HTTP协议中的"POST"操作来发送数据,支持键值对数组定义
            $options[CURLOPT_POSTFIELDS] = $data; 
        }
        
        //初始化header数组
        $headerOptions = array();
        
        //检测是否是ajax提交
        if ($ajax) {
            $headerOptions['X-Requested-With']  = 'XMLHttpRequest';
        }
        
       
        //设置cookie
        if ($this->cookieFile) {
            $options[CURLOPT_COOKIEFILE] = $this->cookieFile;
            $options[CURLOPT_COOKIEJAR]  = $this->cookieFile;
        }

        //设置来路
        if ($referer) {
            $options[CURLOPT_REFERER] = $referer;
        }
        
        //合并header
        if (!empty($headers) && is_array($headers)) {
            foreach ($headers as $k => $v) {
                $headerOptions[$k] = $v;
            }
        }
        
        //转换header选项为浏览器header格式
        if (!empty($headerOptions) && is_array($headerOptions)) {
            $array = array();
            
            foreach($headerOptions as $k => $v) {
                $array[] = $k . ": " . $v;
            }
            
            $options[CURLOPT_HTTPHEADER] = $array;
        }
        
        //创建curl句柄
        $ch = curl_init();
        
        //设置curl选项
        curl_setopt_array($ch, $options);
        
        //获取返回内容
        $content = curl_exec($ch);
        
        //关闭curl句柄
        curl_close($ch);
        
        //返回内容
        return $content;

    }
    
    /**
     * 对一个对象进行字符串echo输出
     * 自动调用__toString方法
     * @return type
     */
    public function __toString()
    {
        return $this->body();
    }
    
}

class curlException extends Exception {}

//curl方法不存在就设置一个curl方法
if (!function_exists('curl')) {
    function curl() {
        return curl::exec();
    }
}

\