Bootstrap

PHP curl请求接口并获取数据-----详解

      最近因为调用Ping++支付的原因,可是把我给难为到了,主要还是自己自我解决问题的能力不太强,下面试报错信息:

其实根据报错的信息可以找到错误的路程,最终定在了AppiRequestor.php文件中的第316行,本人一直不明白为啥本地就是一直报错,看了大神的解决思路就发现了原来是Curl抓取的问题,恍然大悟,此时才明白,自己之所以找不到解决之法归根结底还是因为对于这个curl的使用不太了解,今天就给自己总结一下,也希望能帮助到你们!

 

PHP手册---搜索CURL的使用,点击查看手册使用详解

一般分为四步:

Step1: curl_init()初始化

    curl_init(【String $url】):参数可以为空,单独初始化一个cURl资源,要是有参数,则代表curl_setopt()中的CUTLOPT_URL选      项被设置成这个值,也可以手动使用curl_setopt()函数设置这个值,成功返回cURL句柄,失败返回false,

Step2:curl_setopt()设置cURL传输选项

     bool curl_setopt ( resource $ch , int $option , mixed $value ) //option 需要设置的CURLOPT_XXX选项;value为值

    其中主要有几个常用的选项设置:

     CURLOPT_HEADER: 启用时会将头文件信息作为输出流输出; 一般为false

     CURLOPT_RETURNTRANSER:TRUE时将curl_exec()获取的信息以字符串返回,而不是直接输出

     CURLOPT_SSL_VERIFYPEER: FALSE指禁用cURL验证对等证书,像微信开发中一般https访问的需要设置这个选项

     CURLOPT_SSL_VERIFYHOST : 设置了不做服务器端的认证,那么客户端也不需要认证,为false

     CURLOPT_POST: true时指定发送post请求,不设置默认为get方式

     CURLOPT_POSTFIELDS: 设置了post方式请求,那么就要处理post请求的数据,,这个在使用curl_setopt()设置选项的时         候会多一个参数,$data,它就是post发送的参数

Step3:curl_exec()执行cURL回话

    它是在初始化一个cURL回话后并全部选项被设置后调用

     curl_exec($ch) //$ch是初始化的cURL资源

Step4:curl_close() 关闭资源

    curl_close($ch) //关闭cURL资源,并且释放系统资源

 

下面试封好的方法,仅供参考使用

1.分开设置curl_setopt参数

public static function https_request($curl, $data=null, $https=true, $method='post'){
    $ch = curl_init();//初始化
    curl_setopt($ch, CURLOPT_URL, $curl);//设置访问的URL
    curl_setopt($ch, CURLOPT_HEADER, false);//设置不需要头信息
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//只获取页面内容,但不输出
    if($https){
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//不做服务器认证
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不做客户端认证
    }
    if($method == 'post'){
        curl_setopt($ch, CURLOPT_POST, true);//设置请求是POST方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);//设置POST请求的数据
    }
    $str = curl_exec($ch);//执行访问,返回结果
    curl_close($ch);//关闭curl,释放资源
    return $str;
}


此方法通用于微信公众号的开发使用当中,http和https两种协议都支持

2.直接数组的形式设置curl_setopt参数,使用curl_setopt_array()方法

private function _curlRequest($method, $absUrl, $headers, $params)
{
    $curl = curl_init();
    $method = strtolower($method);
    $opts = array();
    $dataToBeSign = '';
    $requestTime = null;
    if ($method === 'get' || $method === 'delete') {
        if ($method === 'get') {
            $opts[CURLOPT_HTTPGET] = 1;
        } else {
            $opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
        }
        $dataToBeSign .= parse_url($absUrl, PHP_URL_PATH);
        if (count($params) > 0) {
            $encoded = self::encode($params);
            $absUrl = "$absUrl?$encoded";
            $dataToBeSign .= '?' . $encoded;
        }
        $requestTime = time();
    } elseif ($method === 'post' || $method === 'put') {
        if ($method === 'post') {
            $opts[CURLOPT_POST] = 1;
        } else {
            $opts[CURLOPT_CUSTOMREQUEST] = 'PUT';
        }
        $rawRequestBody = $params !== null ? json_encode($params) : '';
        $opts[CURLOPT_POSTFIELDS] = $rawRequestBody;
        $dataToBeSign .= $rawRequestBody;
        if ($this->_signOpts !== null) {
            if (isset($this->_signOpts['uri']) && $this->_signOpts['uri']) {
                $dataToBeSign .= parse_url($absUrl, PHP_URL_PATH);
            }
            if (isset($this->_signOpts['time']) && $this->_signOpts['time']) {
                $requestTime = time();
            }
        }
    } else {
        throw new Error\Api("Unrecognized method $method");
    }

    $absUrl = Util\Util::utf8($absUrl);
    $opts[CURLOPT_URL] = $absUrl;         //设置路径,也可以在curl_init()初始化回话的时候
    $opts[CURLOPT_RETURNTRANSFER] = true; //true代表将curl_exec()获取的信息以字符串返回,而不是直接输出
    $opts[CURLOPT_CONNECTTIMEOUT] = 30;   //在尝试连接时等待的秒数。设置为0,则无限等待
    $opts[CURLOPT_TIMEOUT] = 80;          //允许 cURL 函数执行的最长秒数
    $opts[CURLOPT_HTTPHEADER] = $headers; //设置 HTTP 头字段的数组。格式: array('Content-type: text/plain','Content-                              length: 100')

    $opts[CURLOPT_SSL_VERIFYPEER] = false; //FALSE禁止 cURL 验证对等证书

    if (!Pingpp::$verifySslCerts) {
        $opts[CURLOPT_SSL_VERIFYPEER] = false;
    }

    curl_setopt_array($curl, $opts);
    $rbody = curl_exec($curl);

    if (!defined('CURLE_SSL_CACERT_BADFILE')) {
        define('CURLE_SSL_CACERT_BADFILE', 77);  // constant not defined in PHP
    }

    $errno = curl_errno($curl);
    if ($errno == CURLE_SSL_CACERT ||
        $errno == CURLE_SSL_PEER_CERTIFICATE ||
        $errno == CURLE_SSL_CACERT_BADFILE) {
            array_push(
                $headers,
                'X-Pingpp-Client-Info: {"ca":"using Pingpp-supplied CA bundle"}'
            );
            $cert = $this->caBundle();
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($curl, CURLOPT_CAINFO, $cert);
            $rbody = curl_exec($curl);
        }

    if ($rbody === false) {
        $errno = curl_errno($curl);
        $message = curl_error($curl);
        curl_close($curl);
        $this->handleCurlError($errno, $message);
    }

    $rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);
    return array($rbody, $rcode);
}

 

注意:在封装的时候一定要考虑到post的方式,以及HTTPS协议的情况,一个使用 CURLOPT_POST 给curl_setopt()设置参数,另一个使用 CURLOPT_SSL_VERIFYPEER 给curl_setopt()设置参数

 

;