PHP Curl出现403错误的解决办法


Posted in PHP onMay 29, 2014

自己用的小PHP应用,使用curl抓网页下来处理,为了穿墙方便,使用Privoxy作为代理,便于选择哪些网站使用proxy、哪些不用。但今天却遇到了奇怪的问题,访问google baidu这些网站居然都返回403错误,而访问其他的一些网站没事,如果设置为不使用proxy则都能正常访问。

难道google baidu就不让用proxy连接么?显然不可能,所以打开curl的信息输出(curl_setopt($this->mSh, CURLOPT_VERBOSE, 1);)看看,得到以下结果:

*   Trying 127.0.0.1... * connected
* Connected to 127.0.0.1 (127.0.0.1) port 8118 (#0)
* Establish HTTP proxy tunnel to www.baidu.com:80
> CONNECT www.baidu.com:80 HTTP/1.0
Host: www.baidu.com:80
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Proxy-Connection: Keep-Alive
< HTTP/1.0 403 Connection not allowable
< X-Hint: If you read this message interactively, then you know why this happens ,-)
< 
* The requested URL returned error: 403
* Received HTTP code 403 from proxy after CONNECT
* Closing connection #0
... Failed.

可以看到proxy服务器工作正常,的确是baidu返回了403错误,但原因肯定还在我这边。终于,从网上(1of2, 2of2)得到了点启发──我使用的是proxytunnel而非proxy。

在代码中,有这么一句:

 curl_setopt($this->mSh, CURLOPT_HTTPPROXYTUNNEL, true);
 curl_setopt($this->mSh, CURLOPT_PROXY, $phost);

php文档中没有详细说明,不过man curl中有详细解释,两者都是代理,proxytunnel(-p参数)允许其他协议通过http代理传输,而proxy(-x参数)则只能走http协议。所以我猜测,google baidu的服务器和curl的proxytunnel不和,所以返回403。

禁用掉上面2行代码的第一句后,curl访问恢复正常。

比较奇怪的是,几种操作系统下还不一样,一台MAC OSX就要显式的禁用proxytunnel才可以,curl版本:

$ curl --version
curl 7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Protocols: tftp ftp telnet dict ldap http file https ftps 
Features: GSS-Negotiate IPv6 Largefile NTLM SSL libz

而另外一台ubuntu则完全不受影响,怎么都能用,curl版本:
$ curl --version
curl 7.18.2 (i486-pc-linux-gnu) libcurl/7.18.2 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.10
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps 
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

MT主机上的centos也没事,curl版本:
$ curl --version
curl 7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
Protocols: tftp ftp telnet dict ldap http file https ftps 
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

看来不完全是curl版本问题,MAC OSX的确与众不同啊。

还有一个原因也会导致curl返回403错误,如果设置了:

 curl_setopt($ch, CURLOPT_NOBODY, true);

则需要紧跟着设置:
 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');

不然会因为http服务器不允许 HEAD 命令而返回403错误。参考:Trouble with a cURL request in PHP(http://forums.devshed.com/php-development-5/trouble-with-a-curl-request-in-php-445222.html)。MAC OSX上curl之所以特殊,也不排除是这种原因吧。
PHP 相关文章推荐
MySQL的FIND_IN_SET函数使用方法分享
Mar 27 PHP
利用php递归实现无限分类 格式化数组的详解
Jun 08 PHP
php命令行使用方法和命令行参数说明
Apr 08 PHP
php实现分页显示
Nov 03 PHP
php上传图片获取路径及给表单字段赋值的方法
Jan 23 PHP
PHP常用文件操作函数和简单实例分析
Jun 03 PHP
php导出csv文件,可导出前导0实例代码
Nov 16 PHP
PHP7多线程搭建教程
Apr 21 PHP
PHP实现数组转JSon和JSon转数组的方法示例
Jun 14 PHP
PHP面向对象程序设计(OOP)之方法重写(override)操作示例
Dec 21 PHP
详解Laravel服务容器的绑定与解析
Nov 05 PHP
基于php伪静态的实现方法解析
Jul 31 PHP
PHP的foreach中使用引用时需要注意的一个问题和解决方法
May 29 #PHP
神盾加密解密教程(一)PHP变量可用字符
May 28 #PHP
CI框架开发新浪微博登录接口源码完整版
May 28 #PHP
PHP+javascript制作带提示的验证码源码分享
May 28 #PHP
微信支付开发教程(一)微信支付URL配置
May 28 #PHP
php中$美元符号与Zen Coding冲突问题解决方法分享
May 28 #PHP
php轻松实现中英文混排字符串截取
May 28 #PHP
You might like
浅析echo(),print(),print_r(),return之间的区别
2013/11/27 PHP
php实现xml与json之间的相互转换功能实例
2016/07/07 PHP
php链式操作的实现方式分析
2019/08/12 PHP
js 刷新页面的代码小结 推荐
2010/04/02 Javascript
Javascript引用指针使用介绍
2012/11/07 Javascript
ExtJS DOM元素操作经验分享
2013/08/28 Javascript
js简单实现删除记录时的提示效果
2013/12/05 Javascript
JavaScript中的Primitive对象封装介绍
2014/12/31 Javascript
AngularJS中的模块详解
2015/01/29 Javascript
js控制多图左右滚动切换效果代码分享
2015/08/26 Javascript
理解javascript闭包
2015/12/15 Javascript
Javascript技术栈中的四种依赖注入小结
2016/02/27 Javascript
JS显示日历和天气的方法
2016/03/01 Javascript
关于function类中定义变量this的简单说明
2016/05/28 Javascript
Angular懒加载机制刷新后无法回退的快速解决方法
2016/08/30 Javascript
微信js-sdk预览图片接口及从拍照或手机相册中选图接口用法示例
2016/10/13 Javascript
vue的无缝滚动组件vue-seamless-scroll实例
2017/12/18 Javascript
Vue项目数据动态过滤实践及实现思路
2018/09/11 Javascript
java和js实现的洗牌小程序
2019/09/30 Javascript
js函数和this用法实例分析
2020/03/13 Javascript
解决Nuxt使用axios跨域问题
2020/07/06 Javascript
vue 项目引入echarts 添加点击事件操作
2020/09/09 Javascript
python实现通过代理服务器访问远程url的方法
2015/04/29 Python
Python绑定方法与非绑定方法详解
2017/08/18 Python
python导入模块交叉引用的方法
2019/01/19 Python
Python多线程同步---文件读写控制方法
2019/02/12 Python
Scrapy 配置动态代理IP的实现
2020/09/28 Python
mysql的最长数据库名,表名,字段名可以是多长
2014/04/21 面试题
Java面试题:为什么要用Java
2012/05/11 面试题
合同意向书范本
2014/07/30 职场文书
护士工作失误检讨书
2014/09/14 职场文书
党员教师个人对照检查材料(群众路线)
2014/09/26 职场文书
离婚纠纷代理词
2015/05/23 职场文书
教师外出学习心得体会
2016/01/18 职场文书
浏览器常用基本操作之python3+selenium4自动化测试(基础篇3)
2021/05/21 Python
Python集合set()使用的方法详解
2022/03/18 Python