您的位置:首页 > 编程语言 > PHP开发

php_curl学习

2012-09-29 15:49 169 查看
<?php
// 本文地址--->http://www.zhurouyoudu.com/index.php/archives/126/http://www.zhurouyoudu.com/index.php/archives/126/I
/*
curl通信
cUrl是一个利用URL语法来传输文件和数据的工具.支持很多协议,例如HTTP,FTP,TELENT等.最爽的是,PHP也支持cURL库.

为什么要用cURL?
大部分时候对于php我们获取网页内容:

$content=file_get_contents("http://www.sgsheg.com");
//or
$lines=file("http://www.sgsheg.org");
//or
readfile("http://www.sgsheg.org");

不过这种做法缺乏灵活性和有效的错误处理.并且,你也不能用它来完成一些高难度任务---比如处理cookie,验证,表单提交,文件上传等.
cURL是一种功能强大的库,支持不同的协议,支持很多不同的协议,选项,能提供URL请求相关的各种细节信息.

基本结构:
在学习复杂的功能前面,可以在PHP中建立cURL请求的基本步骤.

1/初始化
2/设置变量
3/执行并获取结果
4/释放cURL句柄

//1.初始化
$ch=curl_init();

//设置选项,包含URL
curl_setopt($ch,CURLOPT_URL,"http://www.sgsheg.org");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HEADER,0);

//执行并获取HTML文档的内容
$output=curl_exec($ch);

//释放curl句柄
curl_close($ch);

第二步(也就是curl_setopt())最为重要,一切玄妙均在此.

检查错误:
你可以加上一段检查错误的语句(虽然这并不是必需的)
//...
$output=curl_exec($ch);
if($output===FALSE){
echo "cURL Error".curl_error($ch);
}
//....
请注意,比较的时候我们用的是"===FALSE",而非"==FALSE",因为我们得区分空输出和布尔值FASLE,后者才是真正的错误.

获取信息:

这是另一个可选的设置项目,能够在cURL执行后获取这一请求的有关信息.
//....
curl_exec($ch);
$info=curl_getinfo($ch);
echo '获取'.$info['url'].'耗时'.$info['total_time'].'秒';
//.....
返回的数组包含以下的信息

"url"//资源网络地址
"content-type"//HTTP状态码
"http_code"//header的大小
"header_size"//header的大小
"request_size"//请求时的大小
"filetime"//文件创建时间
"ssl_verify_result"//SSL验证结果
"redirect_count"//跳转技术
"total_time"//总耗时
"namelookup_time"//DNS查询耗时
"connect_time"//等待连接耗时
"pretransfer_time"//传输前准备耗时
"size_upload"//上传数据的大小
"size_download"//下载数据的大小
"speed_download"//下载速度
"speed_upload"//上传速度
"download_content_length"//下载内容的长度
"upload_content_length"//上传内容的长度
"starttransfer_time"//开始传输的时间
"redirect_time"//重定向耗时

基于浏览器的重定向
在第一个例子中,我们将提供一段用于侦测服务器是否有基于浏览器的重定向代码.例如,有写网站会根据是否是手机浏览器甚至用户是来自那个国家而重定向网页.

我们用CURLOPT_HTTPHEADER选项来设定我们发送出的HTTP请求头信息(http header),包括user agent信息和默认语言.然后我们看看这些特定的网站是否会把我们重定向到不同的URL

//测试用的URL
$urls=array(
"http://www.cnn.com",
"http://www.mozilla.cn",
"http://www.facebook.com"
);
//测试用的浏览器信息
$browsers=array(
"standard"=>array(
"user_agent"=>"Mozilla/5.0(Window;U;Window NT 6.1;en-US;rv:1.9.1.6)Gecko/20091201 Firefox/3.5.6(.NET CLR3.5.30729)",
"language"=>"en-us,en;q=0.5"
),
"iphone"=>array(
"user_agent"=>"Mozilla/5.0(iphone;U;CPU like Mac OS X;en)AppleWebKit/420+(KHTML,like Gecko)Version/3.0 Mobile/1A537aSafari/419.3",
"language"=>"en"
),
"french"=>array(
"user_agent"=>"Mozilla/4.0(compatible;MSIE 7.0 Window NT 5.1;GTB6;NET CLR 2.0.50727)",
"language"=>'fr,fr-FR;q=0.5'
)

);

foreach($urls as $url){
echo "URL:$url\n";
foreach($browser as $test_name=>$browser){
$ch=curl_init();
//设置url
curl_setopt($ch,CURLOPT_URL,$url);
//设置留啦你去的特定header
curl_setopt($ch,CURLOPT_HTTPHEADER,array(
"User_Agent:{$browser['user_agent']}",
"Accept_Language:{$browser['language']}"
));
//页面内容我们不需要
curl_setopt($ch,CURLOPT_NOBODY,1);
//只需返回HTTP header
curl_setopt($ch,CURLOPT_HEADER,1);
//返回结果,而不是输出它
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$output=curl_exec($ch);
curl_close($ch);

//有重定向的HTTP头信息吗
if(preg_match("!Location:(.*)!",$output,$matches)){
echo "$test_name:redirects to $matches[1]\n";
}else{
echo "$test_name:no redirection\n";
}
}
echo "\n\n";
}

首先,我们建立一组需要测试的URL,接着指定一组要测试的浏览器信息,最后通过循环测试各种URL和浏览器可能产生的情况

因为我们指定了cURL选项,所以返回的输出内容则只包含HTTP头信息(被存在于$output中).利用一个简单的正则,我们检查这个头信息中是否包含了"Location"字样.

运行这段代码:

用POST方法来发送数据:
当发起GET请求的时候,数据可以通过"查询字串(query string)传递给一个URL".例如,在google中搜索时,搜索关键即为URL的查询字符串的一部分.

http://www.google.com/search?q=sgsheg
这种情况下你可能并不需要cURL来模拟.把这个URL丢给"file_get_content()"就能得到相同的结果.

不过有一些HTML表单是用POST方法来提交的.这种表单提交时,数据是通过HTTP请求体(request body)发送,而不是查询字符串.例如,当使用Codeigniter论坛的表单,无论你输入了什么关键字,总是被POST到如下的页面中:

http://codeeigniter.com/forums/do_search/
你可以用php脚本来模拟这种URL请求.首先,新建一个可以接受并显示POST数据的文件,我们给它命名为post_output.php;

print_r($_POST);
接下来,写一段PHP脚本来执行cURL请求.

$url="http://localhost/post_output.php";
$post_data=array(
"foo"=>"bat",
"query"=>"sgsheg",
"action"=>"Submit"
);
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNRANSFER,1);
//我们在POST数据
curl_setopt($ch,CURLOPT_POST,1);
//把POST变量加上
curl_setopt($ch,CURLOPT_POSTFIELDS,$post_data);
$output=curl_exec($ch);
curl_close($ch);
echo $output;

执行代码后应该会得到以下结果:
Array(
[foo]=>bar
[query]=>Nettus
[action]=>Submit
)
这段脚本发送一个POST请求给post_output.php,这个页面$_POST变量并返回,我们利用cURL来捕捉了这个输出.

文件上传
文件上传和前面的POST十分相似,因为所有的文件上传表单都是通过POST方法提交的.

首先新建一个接受文件的页面,命名为upload_output.php;
print_r($_FILES);
以下是真正执行文件上传任务的脚本;

$url="http://localhost/upload_output.php";
$post_data=array(
"foo"=>"bar",
//要上传的本地文件地址
"upload"=>"@C:/wamp/www/test.zip"
);
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$post_data);
$output=curl_exec($ch);
curl_close($ch);
echo $output;

如果你需要上传一个文件,只需要把文件路径像一个post变量,不过要在前面加上@符号.执行脚本会得到如下的输出
Array(
[upload]=>Array(
[name]=>test.zip
[type]=>application/octe-stream
[tmp_name]=>c:\wamp\tmp\php4CCB.tmp
[error]=>0
[size]=>118362
)
)

cURL批处理

cURL还有一个高级特性-批处理句柄(handle).这一特性允许你同时或异步地打开多个URL链接.

下面是来自php.net的示例代码:

//创建两个cURL资源
$ch1=curl_init();
$ch2=curl_init();

//指定的URL和适当的参数
curl_setopt($ch1,CURLOPT_URL,"http://lxr.php.net/");
curl_setopt($ch1,CURLOPT_HEADER,0);
curl_setopt($ch2,CURLOPT_URL,"http://www.php.net/");
curl_setopt($ch2,CURLOPT_HEADER,0);

//创建cURL批处理句柄
$mh=curl_multi_init();
//加上前面两个资源句柄
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);

//预定义一个状态变量
$active=null;

//执行批处理
do{
$mrc=curl_multi_exec($mh,$active);
}while($mrc==CURLM_CALL_MULTI_PERFORM);
while($active && $mrc==CURLM_OK){
if(curl_multi_select($mh)!=-1){

do{
$mrc=curl_multi_exec($mh,$active);
}while($mrc==CURLM_CALL_MULTI_PERFORM);
}
}
//关闭各个句柄
curl_multi_remove_handle($mh,$ch1);
curl_multi_remove_handle($mh,$ch2);
culr_multi_close($mh);

这里要做的是打开多个cURL句柄并指派给一个批处理句柄.然后你需要在一个while循环里等它执行完毕.

这个示例中有连个循环,第一do while循环重复调用了curl_multi_exec();
这个函数是无隔断(non-blocking)的,但尽可能少的执行.它返回一个状态值,只要这个值等于常量CURLM_CALL_MULTI_PERFORM,就代表还有一些刻不容缓的工作要做(例如,把对应URL的Http头信息发送出去).也就是说,我们需要不断调用该函数,直到返回值发生改变.

而接下来的while循环,只在$active变量为true的时继续.这一变量之前作为第二个参数传递给了curl_multi_exec(),代表只要批处理句柄中是否有活动连接.接着,我们调用curl_multi_select(),在活动连接(例如接受服务器响应)出现之前,他都是被屏蔽的.这个函数执行后,我们又会进入另一个do-while,继续下一条URL.

wordpress连接查询器
想象一下你有一个很庞大的博客,这些文章中有很多外部网站链接.一段时间以后,因为这样的那样的原因,这些链接相当数量都失效了.要么是被和谐了,要么是整个站点被功夫网了...

我们下面建立一个脚本,分析所有链接,找出打不开或者是404页面,并生成一个报告.

//CONFIG
$db_host="localhost";
$db_user="root";
$db_pass="";
$db_name="wordpress";
$excluded_domains=array(
'localhost','www.mydomain.com'
);
$max_connections=10;
//初始化一些变量
$url_list=array();
$working_urls=array();
$dead_urls=array();
$not_found_urls=array();
$active=null;

//连接到Mysql
if(!mysql_connect($db_host,$db_user,$db_pass)){
die('Could not connect:'.mysql_error());
}
if(!mysql_select_db($db_name)){
die('Could not select db'.mysql_error());
}

//找出所有含有链接的文章
$q="SELECT post_connect FROM wp_posts
WHERE post_content LIKE %href=%'
AND post_status='publish'
AND post_type='post'";
$r=mysql_query($q) or die(mysql_error());
while($d=mysql_fetch_assoc($r)){
//用正则匹配
if(preg_match_all("!href=\"(.*?)\"!",$d['post_content'],$matches)){
foreach($matches[1] as $url){
//exclude some domains
$tmp=parse_url($url);
if(in_array($tmp['host'],$excluded_domains)){
continue;
}
//store the url
$url_list[]=$url;
}
}
}
//移除重定向
$url_list=array_values(array_unique($url_list));
if(!$url_list){
die('No URL to check');
}

我们要配置好数据库,一系列要排除的域名$excluded_domains.以及最大的并发连接数$max_connections,然后,连接数据库,获取文章和包含的链接,把她们收集到一个数组中$url_list中.

//1.批处理
$mh=curl_multi_init();
//2.加入需批处理的URL
for($i=0;$i<$max_connections;$i++){
add_url_multi_handle($mh,$url_list);
}
//初始处理
do{
$mrc=curl_multi_exec($mh,$active);

}while($mrc==CURLM_CALL_MULTI_PERFORM);

//主循环
while($active && $mrc==CURLM_OK){
//有活动的链接
if(curl_multi_select($mh) != -1){
//干活
do{
$mrc=curl_multi_exec($mh,$active);
}while($mrc==CURLM_CALL_MULTI_PERFORM);
//有信息否
if($mhinfo=curl_multi_info_read($mh)){
//意味着连接正常结束
//从curl句柄获取信息
$chinfo=curl_getinfo($mhinfo['handle']);

//死链吗
if($chinfo['http_code']){
$dead_urls[]=$chinfo['url'];
//10 405了吗

}else if($chinfo['http_code']==404){
$not_found_urls[]=$chinfo['url'];
//还能用吗

}else{
$working_urls[]=$chinfo['url'];
}
//移除句柄
curl_multi_remove_handle($mh,$mhinfo['handle'];
curl_close($mhinfo['handle']);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: