PHP 的 cURL 扩展库使用详解

1,566 阅读5分钟
原文链接: www.jianshu.com

在还没有接触curl的时候,相信大家在获取网页内容的时,使用得最多的一个函数就是:file_get_contents(),但是它的可控制性不够灵活,无法处理错误情况,对于各种复杂情况的采集更是显得有点无能为力。因此,本文将为你介绍另外一种工具:cURL的使用方法,在后面也还会给出相关的几个案例,这些都是你使用file_get_contents()无法做到的。

一、cURL库的介绍

为了更好的理解下面的内容,这里先给出一个curl的最简单的案例

入门案例:

$url = "http://nosee123.com/test_post.php";

$ch = curl_init($url); //初始化一个cURL会话

curl_exec($ch);   //执行一个cURL会话

curl_close($ch);   //关闭一个cURL会话

该案例的执行结果就是把$url的网页内容输出到你的浏览器上,其实这个案例的效果和使用file_get_contents()的结果是一样的,这是因为它没有设置任何的参数。但cURL的功能远远不止这些,下面我们开始讲解cURL更详细的使用方法。

cURL是一个可以使用URL的语法模拟浏览器来传输数据的工具库(libcurl库),libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。

注意:在使用cURL库之前,记得要先将你的配置文件(php.ini)中打开的你cURL模块,可以使用phpinfo()查看curl模块是否开启,如没有开启就直接使用相关的方法则会报错。

二、使用基本步骤

使用 cURL 函数的基本思想是先使用curl_init() 初始化 cURL会话,接着可以通过 curl_setopt() 设置需要的全部选项,然后使用 curl_exec()来执行会话,当执行完会话后使用curl_close()关闭会话。

简单来说,使用cURL完成简单的请求主要分为以下四个步骤:

//(1)初始化cURL

$url = "http://nosee123.com/test_post.php";

$ch = curl_init($url); //初始化一个cURL会话

//(2)设置URL和相应的选项

//将curl_exec()获取的信息以字符串返回,而不是直接输出。

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

//(3)抓取URL并把它传递给浏览器

//由于步骤2对CURLOPT_RETURNTRANSFER的设置,curl_exec()不会直接输出内容

$str = curl_exec($ch); //执行一个cURL会话

//(4)关闭cURL资源,并且释放系统资源

curl_close($ch); //关闭一个cURL会话

echo $str; //输出步骤3获取的页面内容

上面的4个步骤将会把获取到的网页内容输出,这是使用cURL最基本的四个步骤。

三、curl_setopt常用参数

cURL之所以强大,只要是体现在它的第二个步骤中。你可以通过curl_setopt灵活地设置请求选项,更多的参数设置查看官网:php.net/manual/zh/f…

官方上罗列的是所有的参数列表,全部都记住也没有什么必要。然而实际开发中,我们常用的也就来来去去那几个,所以在这我也顺便把常用的几个都详细讲讲,这样也方便我们更好的快速的用到实际开发中。但建议有时间的话最好把官网上的都看一篇,这样至少自己心里也有个底,知道里面有些什么方法,当真正需要的时候也方便过来查找。

curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);//将curl_exec()获取的信息以字符串返回,而不是直接输出。

curl_setopt($ch, CURLOPT_HEADER,false);//不输出头文件,如果设为true,获得的网页源代码最前边会带有'HTTP/1.1 200 OK'等内容

curl_setopt($ch, CURLOPT_FILE, $fp);//设置输出文件,默认为STDOUT (浏览器)。

curl_setopt($ch, CURLOPT_POST, 1);// 设置请求为post类型

curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);// 添加post数据到请求中

四、cURL常用函数

除了上面基本的4个步骤用到的4个函数,cURL还提供了其他很多实用的函数,如curl_error、curl_getinfo等。

获取curl请求的具体信息: curl_getinfo()

在执行一个cURL请求后,你也可以使用curl_getinfo获取该请求的具体信息:

curl_exec($ch);

$curl_info= curl_getinfo($ch);

echo "收到的http回复的code为: {$curl_info['http_code']}";

上述$curl_info是一个关联数组,可以从中获取很多的具体请求信息。

参考:php.net/manual/zh/f…

错误处理:curl_error()

$response = curl_exec($ch);

if ($response === FALSE) {

echo "cURL 具体出错信息: " . curl_error($ch);

}

注意了,在做上述判断时务必要使用===,因为请求的回复可能是空字符串,curl在请求出错的情况下回返回FALSE值,所以我们必须使用===,而不是==

参考:php.net/manual/zh/f…

五、实用案例

案例1:使用curl发送post请求

$url = "http://nosee123.com/test_post.php";

$post_data = array (

"name" => "nosee",

"url" => "http://www.nosee123.com",

"action" => "Submit"

);

$ch = curl_init($url );

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_HEADER, false);

curl_setopt($ch, CURLOPT_POST, 1);// 设置请求为post类型

curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);// 添加post数据到请求中

$str = curl_exec($ch);// 执行post请求,获得回复

curl_close($ch);

echo $str ;

案例2:将获取到的内容输出到文件(文件下载)

$url = "http://nosee123.com/86-1.zip"; //远程服务器上要下载的文件

$fp = fopen("output.zip", "w"); //打开一个本地文件指针资源

$ch = curl_init($url); //初始化一个cURL会话

curl_setopt($ch, CURLOPT_FILE, $fp); //设置输出文件,默认为STDOUT (浏览器)。

$str = curl_exec($ch); //执行一个cURL会话

if ($str === FALSE) {

echo "cURL 具体出错信息: " . curl_error($ch);

}

curl_close($ch); //关闭一个cURL会话

fclose($fp); //关闭一个已打开的文件指针

案例3:文件上传

PHP使用CURL上传文件只需发送一个POST请求就可以了,在请求中设置某个字段为需要上传的文件全路径,并且以“@”开头,然后使用CURL把该变量以POST方式发送到服务器,在服务端即可以从超级全局变量$_FILES中取到相应的上传文件信息。需要注意的是,上传文件的变量不是存在着$_POST中,而是在$_FILES中。

以下代码是存在我本地服务器的脚本:

$url = "http://nosee123.com/test_post.php";

$post_data = array (

//要上传的本地的文件地址

"attachment" => "@D:/web/www/wp70/readme.html""

);

//初始化cURL会话

$ch = curl_init();

//设置请求的url

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_HEADER, false);

//设置为post请求类型

curl_setopt($ch, CURLOPT_POST, 1);

curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);//重点!下面详细讲解

//设置具体的post数据

curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);

$response = curl_exec($ch);

if ($response === FALSE) {

echo "cURL 具体出错信息: " . curl_error($ch);

}

curl_close($ch);

print_r($response);

我的远程服务端处理请求的脚本文件:test_post.php  如下:

//首先使用var_export将$_FILES变量输出到标准输出

echo var_export($_FILES,true);

//然后使用file_get_contents读取$_FILES[‘attachment’][‘tmp_name’]所指文件的内容,并输出到标准输出

echo file_get_contents($_FILES['attachment']['tmp_name']);

//然后把$_FILES[‘attachment’][‘tmp_name’]所指文件自制到当前目录的log_copy.txt文件中

copy($_FILES['attachment']['tmp_name'], "./testdata_copy.txt");

可以看到$_FILES变量中有一个attachment数组,对应到上传文件描述信息,其中name和type分别表示名称和类型。tmp_name比较关键,服务端在接收到上传文件之后,会把文件写在一个临时文件中,这个临时文件的名字就是tmp_name的值,这也是为什么我们读取该文件可以获取一testdata.txt的文件内容。一般在服务端接收到上传文件后都需要立即读取该文件或者把文件复制到别外一个文件中,因为tmp_name所指的临时文件在服务端脚本执行完毕后会被删除掉,test_post.php脚本的最后一行就是把临时文件复制到我们的目标文件中。

还有一个重点问题,这个问题也是折腾了我整整一天的,因为一开始我的请求代码里面没有加curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);这一段代码,上传文件一直失败,@后面的文件地址无法被解析。一直到最后我才发现了那是因为php版本兼容性的问题。对于PHP5.6及以上的版本是不会直接识别@绑定的后面的地址,那要怎么解决这个兼容性问题呢?有两种解决方法:

1)就如我上面的代码,使用配置参数 CURLOPT_SAFE_UPLOAD ,在 PHP5.5中默认值是 false ,而在 PHP5.6中已经默认为 true 了。 所以只需要增加一行强制设置为 false 就行,如下:

curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);

注意:该参数的设置顺序,必须在设置 CURLOPT_POSTFIELDS 参数之前才有效哦!!!

2)使用 CURLFile 类来处理文件

在上面代码的基础上,把变量$post_data修改为如下代码即可:

$post_data = array (

"attachment" => new CURLFile("D:/web/www/wp70/readme.html")

);

详细参考官方文档:php.net/manual/zh/c…

案例4:发送json数据

$posturl='http://nosee123.com/test_json.php';

$array=array ('key'=>'abc','phone'=>'18813912321','userid'=>'1234321');

$jsoninfo = json_encode($array);  //把数组进行json编码

//模拟post请求

$ch = curl_init();//初始化curl

if ( $ch === FALSE ){

return 'ERROR: Sorry , you cannot open curl. --- nosee';

}

curl_setopt($ch, CURLOPT_URL,$posturl); //抓取指定网页

curl_setopt($ch, CURLOPT_HEADER, 0);    //设置header

//这一步为最关键!!设置head头的请求数据格式为json

curl_setopt($ch, CURLOPT_HTTPHEADER, array(

"Content-type:application/json;charset=utf-8",

"Content-Length: " . strlen($jsoninfo)

));

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上

curl_setopt($ch, CURLOPT_POST, 1);   //post提交方式

curl_setopt($ch, CURLOPT_POSTFIELDS, $jsoninfo); //添加请求的json数据

$data = curl_exec($ch);   //运行curl 返回请求的json数据

$json = json_decode($data);  //把json数据转为php的对象类型

curl_close($ch);   //关闭curl

使用用curl传输json数据的实际案例可查看我的上一篇文章:使用php接入图灵机器人的方法

向图灵机器人的API提交json数据的POST请求中,本人使用的就是这个方法。


更多cURL的案例和使用方法可查看官方文档,地址如下:

php.net/manual/zh/b…

感谢阅读