手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表Tag:curl

转:2011-10-12 PHP重用curl句柄, CURLOPT_HTTPGET的BUG

转的文章。主要是因为经常会用curl来抓取数据。而且几乎是http_get和http_post混用。但我没遇上这个BUG。不清楚以后会不会遇上,所以我先记录一下,以防万一遇到时候不知道怎么做。

原文地址来自:http://www.ideawu.net/blog/archives/622.html

重用一个CURL句柄时, 发现curl_setopt($ch, CURLOPT_HTTPGET, TRUE) 不起作用. 期望在调用这条语句之后发起请求, 应该发送的是GET, 但看服务器log, 却使用了和前一次请求相同的HTTP方法.

PHP脚本:

<?php $url = 'http://www.ideawu.net/';  $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_exec($ch);  curl_setopt($ch, CURLOPT_HTTPGET, true); // 错误! BUG curl_exec($ch);  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); // 正确 curl_exec($ch); ?>

web server log:

124.127.130.50 "2011-10-12 18:55:09" "POST / HTTP/1.1" 200 3516 "-" www.ideawu.net 124.127.130.50 "2011-10-12 18:55:09" "POST / HTTP/1.1" 200 3516 "-" www.ideawu.net 124.127.130.50 "2011-10-12 18:55:09" "GET / HTTP/1.1" 200 3516 "-" www.ideawu.net

这个BUG目前还没找到相关的资料.

补充: 不仅仅是CURLOPT_HTTPGET, CURLOPT_POST也有同样的问题. 所以, 结论是: 只有CURLOPT_CUSTOMREQUEST才是正确的方法.

 

Tags: curl

开发中的几件事

开发中又遇到一些事情,于是记录一下
1、CURL的问题
    curl在安全模式下或者设定了open_basedir的情况下,如果使用了OPT_FOLLOWLOCATION,会导致无返回值。这个理由很多,但FOLLOWLOCATION这个参数是用于目标网址会多次跳转而使用,还可以设置最大跳转次数,因此,如果你要抓取的对象有多次跳转,这个参数就非设不可(真纠结,实在不行就file_get_contents了,它自动支持多次跳转,但不如curl更可控一些)
    具体关于CURL的一些常用参数,可以看这里:

http://opensuse.iteye.com/blog/349829
  1. curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);       
  2. //HTTP协议的版本号  
  3. curl_setopt($ch, CURLOPT_NOPROGRESS, 1);                             
  4. //如果你不会PHP为CURL传输显示一个进程条,设置这个选项为一个非零值。注意:PHP自动设置这个选项为非零值,你应该仅仅为了调试的目的来改变这个选项。  
  5. curl_setopt($ch, CURLOPT_NOBODY, 0);  
  6. //如果你不想在输出中包含body部分,设置这个选项为一个非零值。  
  7. curl_setopt($ch, CURLOPT_HTTPGET, 1);  
  8. //设置HTTP请求的方法为GET  
  9. curl_setopt($ch, CURLOPT_ENCODING, ”);  
  10. //设置HTTP请求头中可接受的压缩格式  
  11. curl_setopt($ch, CURLOPT_COOKIEFILE, 1);  
  12. //传递一个包含cookie数据的文件的名字的字符串。这个cookie文件可以是Netscape格式,或是堆存在文件中的HTTP风格的头。  
  13. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);  
  14. //设置这个选项为一个非零值(象 “Location: “)的头,服务器会把它当做HTTP头的一部分发送(注意这是递归的,PHP将发送形如 “Location: “的头)。  
  15. curl_setopt($ch, CURLOPT_MAXREDIRS, 3);  
  16. //最多可以进行几次HTTP重定向,一般和curl_followlocation联用  
  17. curl_setopt($ch, CURLOPT_USERAGENT, ‘Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)’);  
  18. //在HTTP请求中包含一个”user-agent”头的字符串  
  19. $http_header = array();  
  20. $http_header[] = ‘Connection: Keep-Alive’;  
  21. $http_header[] = ‘Pragma: no-cache’;  
  22. $http_header[] = ‘Cache-Control: no-cache’;  
  23. $http_header[] = ‘Accept: */*’;  
  24. $http_header[] = ‘Host: ‘.$url_ary['host'];  
  25. curl_setopt($ch, CURLOPT_HTTPHEADER, $http_header);  
  26. //一个数组格式的HTTP头文件格式  
  27. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
  28. //将curl_exec的返回值转换成一个字符串,而不是直接输出出来  
  29. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);  
  30. //设置一个长整形数,作为最大延续多少秒  
  31. curl_setopt($ch, CURLOPT_REFERER, $url);  
  32. //在HTTP请求中包含一个”referer”头的字符串  
  33. curl_setopt($ch, CURLOPT_URL, $url);  
  34. //这是你想用PHP取回的URL地址。你也可以在用curl_init()函数初始化时设置这个选项  


2、命令下行指定用户组来执行命令
最偷懒的方法就是:su www -c 'php xxx.php'

3、hightman遇到的Javascript函数parseInt(''),返回NaN,这个让我想起有个人做了一个PPT,来说明JS中的一些特殊问题,它的地址是:http://neatstudio.com/show-1987-1.shtml

4、PHP的header跳转
大家都知道header("Location:http://xxx.xxx.com");在这个之后如果你file_put_contents内容去一个文件,还是会被执行的,于是我们习惯性的在header跳转后继续处理一些内容,即不影响跳转,也可以完成一些内容性的处理。
但尝试了一下,如果是header()下面跟上sleep(10);你会发现header不会即刻跳转了,会等10秒后再跳转。
因此,现在了解header跳转还是会受原有代码的影响的。

5、HTML5的a标签属性ping
ping的属性说的很好,当a有href属性时,如果有ping属性,会在跳转链接时候,自动ping网站(ping标签中的对应网站),但测试了一下之后发现。居然没用。查看了一下资料,我操:

6.6 Changes from 4 March 2010 to 24 June 2010

  • The ping attribute has been removed from the W3C version of HTML5.

我郁闷啊。。。

-------EOF------

Tags: curl

snoopy的缺陷与CURL的强大

在使用PHP进行POST和GET的时候,如果为了简单的应用,大多情况下,我们都采用了fsockopen,于是snoopy就成了我们的最佳选择。可惜,并非所有POST都可以通过snoopy来完成。毕竟,在snoopy中,POST的方式,即类似FORM的entype只支持两种 :application/x-www-form-urlencoded和multipart/form-data,一个是针对FORM中的变量,一个是针对文件上传。一般来说这两种足够了。但昨天发现了一个问题。那就是。。。http://www.baidu.com/search/blogsearch_help.html#n7
baidu和google其他一样,都提供了blogsearch的ping服务,因此,你发表博客后,可以通知一下百度,你的博客更新了。
于是昨天尝试着用snoopy来进行POST发送。结果。。。一直失败,提示无法连接80端口,再看一下百度的说明:

XML/HTML代码
  1. ping-service对非POST方法请求返回HTTP_METHOD_NOT_ALLOWED(405)错误代码,对超大错误包返回 HTTP_REQUEST_ENTITY_TOO_LARGE(413)错误代码,对非“text/xml”请求包返回 HTTP_UNSUPPORTED_MEDIA_TYPE(415)错误代码。  
  2. 其他情况返回HTTP_OK(200)代码,xml-rpc响应http包体为一个xml文档,含有一个int值,0表示推送成功,其他值表示推送失败,目前只有0和1。  

而snoopy在连接的时候是需要先fsockopen,打开80端口的连接后才能发送数据。。。所以,死活连接不上了。最后,用了curl。。。短短几行代码就解决了。。
事实上,即使snoopy能够连接上百度的ping服务,也没有办法提交,因为$snoopy->submit()方法的第二个参数必须是数组。众所周知,FORM提交都是由name对应着value的。snoopy正是这样操作的,他无法直接把一个字符串不对应name就提交。。。

以下是curl代码:

XML/HTML代码
  1. set_time_limit( 0 );  
  2. $url = "http://ping.baidu.com/ping/RPC2";  
  3. $data = '<?xml version="1.0" encoding="UTF-8"?>  
  4. <methodCall>  
  5. <methodName>weblogUpdates.extendedPing</methodName>  
  6. <params>  
  7. <param>  
  8. <value><string>百度的空间</string></value>  
  9. </param>  
  10. <param>  
  11. <value><string>http://hi.baidu.com/baidu/</string></value>  
  12. </param>  
  13. <param>  
  14. <value><string>http://hi.baidu.com/baidu/blog/item/5e8b10d574e971cd50da4b74.html</string></value>  
  15. </param>  
  16. <param>  
  17. <value><string>http://hi.baidu.com/baidu/rss</string></value>  
  18. </param>  
  19. </params>  
  20. </methodCall>';  
  21.   
  22.   
  23.   
  24. $header[]="Content-Type: text/xml; charset=utf-8";  
  25.   
  26. $ch = curl_init();  
  27. curl_setopt($ch, CURLOPT_URL, $url);  
  28. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);  
  29. curl_setopt($ch, CURLOPT_POST, 1);  
  30. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);  
  31. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
  32. curl_setopt($ch, CURLOPT_HEADER, 0);  
  33. $res = curl_exec($ch);  
  34. curl_close($ch);   
  35. echo '<pre>';  
  36. print_r( htmlspecialchars($res) );  
  37. echo '</pre>';  

Tags: snoopy, curl

使用CURL函数发送数据时的注意事项

PHP函数库里面,提到CURL,恐怕很多人都会翘起大拇指吧,确实,这个函数库太牛叉了

CURL其实是调用的CURL的lib,随着PHP版本的升高,curl所需的lib版本也随之提高。

关于CURL所必须的类库和安装说明,手册上有详细介绍:

XML/HTML代码
  1. Requirements  
  2.   
  3. In order to use PHP's cURL functions you need to install the libcurl package. PHP requires that you use libcurl 7.0.2-beta or higher. In PHP 4.2.3, you will need libcurl version 7.9.0 or higher. From PHP 4.3.0, you will need a libcurl version that's 7.9.8 or higher. PHP 5.0.0 requires a libcurl version 7.10.5 or greater.  
  4.   
  5. Installation  
  6.   
  7. To use PHP's cURL support you must also compile PHP --with-curl[=DIR] where DIR is the location of the directory containing the lib and include directories. In the "include" directory there should be a folder named "curl" which should contain the easy.h and curl.h files. There should be a file named libcurl.a located in the "lib" directory. Beginning with PHP 4.3.0 you can configure PHP to use cURL for URL streams --with-curlwrappers.   
  8.   
  9. Note to Win32 Users: In order to enable this module on a Windows environment, libeay32.dll and ssleay32.dll must be present in your PATH.   
  10. You don't need libcurl.dll from the cURL site.   

然后在使用的时候也很方便,只需要初始化一下,设置一下postfields或者GET啥啥的,最后exec一下就行了。关键是别忘了close.

例子代码如下:

PHP代码
  1. $ch = curl_init("http://www.example.com/");  
  2. $fp = fopen("example_homepage.txt""w");  
  3.   
  4. curl_setopt($ch, CURLOPT_FILE, $fp);  
  5. curl_setopt($ch, CURLOPT_HEADER, 0);  
  6.   
  7. curl_exec($ch);  
  8. curl_close($ch);  
  9. fclose($fp);  

以上例子代码有点特殊,是因为他把网页内容进行了下载,同时生成一个文件。这是默认调用GET的方法。

其实,CURL更多的是用来处理POST数据、上传文件等功能

例子如下:

PHP代码
  1. <?   
  2. /*  
  3. * Author: Ron  
  4. * Released: August 4, 2007  
  5. * Description: An example of the disguise_curl() function in order to grab contents from a website while remaining fully camouflaged by using a fake user agent and fake headers.  
  6. */   
  7.   
  8. $url = 'http://www.ericgiguere.com/tools/http-header-viewer.html';   
  9.   
  10. // disguises the curl using fake headers and a fake user agent.   
  11. function disguise_curl($url)   
  12. {   
  13.   $curl = curl_init();   
  14.   
  15.   // Setup headers - I used the same headers from Firefox version 2.0.0.6   
  16.   // below was split up because php.net said the line was too long. :/   
  17.   $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";   
  18.   $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";   
  19.   $header[] = "Cache-Control: max-age=0";   
  20.   $header[] = "Connection: keep-alive";   
  21.   $header[] = "Keep-Alive: 300";   
  22.   $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";   
  23.   $header[] = "Accept-Language: en-us,en;q=0.5";   
  24.   $header[] = "Pragma: "// browsers keep this blank.   
  25.   
  26.   curl_setopt($curl, CURLOPT_URL, $url);   
  27.   curl_setopt($curl, CURLOPT_USERAGENT, 'Googlebot/2.1 (+http://www.google.com/bot.html)');   
  28.   curl_setopt($curl, CURLOPT_HTTPHEADER, $header);   
  29.   curl_setopt($curl, CURLOPT_REFERER, 'http://www.google.com');   
  30.   curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');   
  31.   curl_setopt($curl, CURLOPT_AUTOREFERER, true);   
  32.   curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);   
  33.   curl_setopt($curl, CURLOPT_TIMEOUT, 10);   
  34.   
  35.   $html = curl_exec($curl); // execute the curl command   
  36.   curl_close($curl); // close the connection   
  37.   
  38.   return $html// and finally, return $html   
  39. }   
  40.   
  41. // uses the function and displays the text off the website   
  42. $text = disguise_curl($url);   
  43. echo $text;   
  44. ?>   

上面是一个比较完整的实现。特别需要注意的是header头部的发送,最初看手册的时候,我一以为CURLOPT_HTTPHEADER所需的数组是键值对应的,即:

PHP代码
  1. $header = array('Keep-Alive'=>'300');  

现实的残酷告诉我,不应该这么用,而是象上面的例子那样,每条header为数组的一个记录。

切记切记啊

Tags: curl, curlopt, httpheader, libcurl, charset