考虑 PHP 5.0~5.6 各版本兼容性的 cURL 文件上传
最近做的一个需求,要通过PHP调用cURL,以multipart/form-data
格式上传文件。踩坑若干,够一篇文章了。
重要警告
没事不要读PHP的官方中文文档!版本跟不上坑死你!
不同版本PHP之间cURL的区别
PHP的cURL支持通过给CURL_POSTFIELDS
传递关联数组(而不是字符串)来生成multipart/form-data
的POST请求。
传统上,PHP的cURL支持通过在数组数据中,使用“@
+文件全路径”的语法附加文件,供cURL读取上传。这与命令行直接调用cURL程序的语法是一致的:
curl_setopt(ch, CURLOPT_POSTFIELDS, array( 'file' => '@'.realpath('p_w_picpath.png'),
));
equals
$ curl -F "file=@/absolute/path/to/p_w_picpath.png" <url>
但PHP从5.5开始引入了新的CURLFile类用来指向文件。CURLFile类也可以详细定义MIME类型、文件名等可能出现在multipart/form-data数据中的附加信息。PHP推荐使用CURLFile替代旧的@
语法:
curl_setopt(ch, CURLOPT_POSTFIELDS, [ 'file' => new CURLFile(realpath('p_w_picpath.png')),
]);
PHP 5.5另外引入了CURL_SAFE_UPLOAD
选项,可以强制PHP的cURL模块拒绝旧的@
语法,仅接受CURLFile式的文件。5.5的默认值为false,5.6的默认值为true。
但是坑的一点在于:@
语法在5.5就已经被打了deprecated,在5.6中就直接被删除了(会产生 ErorException: The usage of the @filename
API for file uploading is deprecated. Please use the CURLFile class instead)。
对于PHP 5.6+而言,手动设置CURL_SAFE_UPLOAD
为false是毫无意义的。根本不是字面意义理解的“设置成false,就能开启旧的unsafe的方式”——旧的方式已经作为废弃语法彻底不存在了。PHP 5.6+ == CURLFile only,不要有任何的幻想。
我的部署环境是5.4(仅@
语法),但开发环境是5.6(仅CURLFile)。都没有压在5.5这个两者都支持过渡版本上,结果就是必须写出带有环境判断的两套代码。
现在问题来了……(挖掘机滚远点!)
环境判断:小心魔法数字!
我见过这种环境判断的代码:
if (version_compare(phpversion(), '5.4.0') >= 0)
我对这种代码的评价只有一个字:屎。
这个判断掉入了典型的魔法数字陷阱。版本号莫名其妙的出现在代码之中,不查半天PHP手册和更新历史,很难明白作者被卡在了哪个功能的变更上。
代码应该回归本源。我们的实际需求其实是:有CURLFile就优先采用,没有再退化到传统@
语法。那么代码就来了:
if (class_exists('\CURLFile')) { $field = array('fieldname' => new \CURLFile(realpath($filepath)));
} else { $field = array('fieldname' => '@' . realpath($filepath));
}
建议明确指定的退化选项
从可靠的角度,推荐指定CURL_SAFE_UPLOAD
的值,明确告知php是容忍还是禁止旧的@
语法。注意在低版本PHP中CURLOPT_SAFE_UPLOAD
常量本身可能不存在,需要判断:
if (class_exists('\CURLFile')) {curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true); } else { if (defined('CURLOPT_SAFE_UPLOAD')) {curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);} }
cURL选项设置的顺序
不管是curl_setopt()
单发还是curl_setopt_array()
批量,cURL的选项总是设置一个生效一个,而设置好的选项立刻就会影响cURL在设置后续选项时的行为。
例如CURLOPT_SAFE_UPLOAD
就和CURLOPT_POSTFIELDS
的行为有关。如果先设置CURLOPT_POSTFIELDS
再设置CURLOPT_SAFE_UPLOAD
,那么后者的约束作用就不会生效。因为设置前者时cURL就已经把数据实际的识读处理完毕了!
cURL有那么几个选项存在这种坑,务必小心。还好这种存在“依赖关系”的选项不多,机制也不复杂,简单处理即可。我的方法是先批量设置所有的选项,然后直到curl_exec()
的前一刻才用curl_setopt()
单发设置CURLOPT_POSTFIELDS
。
实际上在curl_setopt_array()
用的数组中,保证CURLOPT_POSTFIELDS
的位置在后边也是可靠的。PHP的关联数组是有顺序保障的,我们也可以假设curl_setopt_array()
内部的执行顺序一定是从头到尾按顺序[注A]
,所以尽可放心。
我的做法只是在代码表现上加个多余的保险,突出强调顺序的重要性防以后手贱。
命名空间
PHP 5.2或以下的版本没有命名空间。代码中用到了空间分隔符\
就会引发解析器错误。要照顾PHP 5.2其实容易想,放弃命名空间即可。
要注意的反倒是有命名空间的PHP 5.3+。无论是调用CURLFile还是用class_exists()
判断CURLFile的存在性,都推荐写成\CURLFile
明确指定顶层空间,防止代码包裹在命名空间内的时候崩掉。
http://segmentfault.com/a/1190000000725185
转载于:https://blog.51cto.com/332374363/1715181
考虑 PHP 5.0~5.6 各版本兼容性的 cURL 文件上传相关推荐
- php curl post 文件_php curl文件上传$_FILES为空,只有$_POST有值,如何兼容php5.0~5.6各版本...
PHP 5.5以下用@,php5.5 @已被弃用,但勉强还能用,php5.6直接删除了@用法,必须得用new CURLFile(realpath('image.png'))这种方式才行了.关键我这还没 ...
- 【Servlet3.0新特性】第03节_文件上传
这是一个Web Project 首先是web.xml <?xml version="1.0" encoding="UTF-8"?> <web- ...
- php5.4 curl,PHP5.0~5.6 各版本兼容性cURL文件上传功能实例分析
本文实例分析了PHP5.0~5.6 各版本兼容性cURL文件上传功能.分享给大家供大家参考,具体如下: 最近做的一个需求,要通过PHP调用cURL,以multipart/form-data格式上传文件 ...
- django 快速实现文件上传(django2.0)
django2.0 快速实现文件上传 本操作环境: 虚拟环境:django2.0 python3.5(应该python3.6都可以使用) window10 1.创建项目与应用(项目和应用都是自己制定的 ...
- ewebeditor文件上传漏洞2.8.0版本(漏洞复现)
漏洞概述 ewebeditor 是常用的网站后台编辑器,此编辑器有asp等版本. 登陆后台之后,可以通过修改上传文件白名单的方法,任意文件上传. 漏洞危害等级 高危 影响版本 v2.8.0 漏洞复现 ...
- 00截断上传绕过_【文件上传与解析】文件上传与解析漏洞总结v1.0
点击上方"公众号" 可以订阅哦! Hello,各位小伙伴晚上好~ 这里是依旧勤劳写公众号的小编~ 今天本公众号将推出一个新的模块,那就是漏洞知识点总结模块!!!(此处应有掌声~) ...
- struts2.0实现文件上传
首先,引入jar包.除了 Struts2.0的几个核心jar包外,还需要额外引入commons-fileupload.jar和commons-io.jar. 引入这两个包的时候,似乎版本也是一个比较重 ...
- Spring MVC-09循序渐进之文件上传(基于Servlet3.0+内置功能)
概述 测试 源码 概述 Spring MVC-09循序渐进之文件上传(基于Apache Commons FileUpload) 上篇博文我们说了基于Apache Commons FileUpload的 ...
- vc++ 6.0 创建程序快捷方式的一个例子源码_漏洞复现:phpcms v9.6.0任意文件上传漏洞(CVE201814399)...
文章说明 漏洞复现是为了学习漏洞利用所写,漏洞都是互联网上以流传已久的各种漏洞的利用及原理,用来增强自己见识,培养自己动手能力,有兴趣的朋友可自行搭建环境练习.源码下载连接在文章最后. 漏洞说明 PH ...
最新文章
- SpringBoot实现万能文件在线预览,已开源,真香!!!
- Postgres-XL部署记录(一)
- Could not find com.android.support.constraint:constraint-layout的问题解决
- 谷歌首款Tensor手机芯片,全是AI炫技,性能一笔带过
- Python 列表count()函数元素次数统计
- [NOIP]数字三角形
- python怎么创建变量_Python中通过函数对象创建全局变量
- 程序员:请不要对我的代码指手画脚!
- 基于matlab的高等数学,基于MATLAB的高等数学问题求解
- 来给罗永浩和王自如打个分(上)
- springbootBBS问答社区系统的设计与实现毕业设计源码121007
- 新年第一天 | 恶补新一季《黑镜》的同时,营长又深入扒了扒它那擅长机器学习的新爸爸是如何赚钱的
- 2007第一天上班想哭
- Tableau-热力图
- Qgis教程12:动态展示
- Bill Gekas儿童摄影作品欣赏
- MYSQL主从部署(Censo:6)
- 如何用Sonic云真机打王者
- NPN求解三极管电路或电容恒流放电详解,三极管工作在放大区,基极控制集电极电流,针对电荷泵电容恒流放电控制,因为电荷泵输出恒定电流给快充手机锂电池充电
- Facebook新财报:不惧“隐私门“事件影响,广告业务依然增长强劲
热门文章
- mysql登录、导入导出、用户权限、事务操作汇总大全
- 敏捷的项目启动-尽早启动!
- 吐血整理《计算机网络五层协议之物理层(下)》
- 数据库之关系模型的组成,特点以及完整性约束
- python属性使用教程_Python对象的属性访问过程详解
- 神策营销云:「在线教育」行业,如何借“运营工具”玩转微信生态?
- PPT 下载 | 神策数据孙文亮:客户全生命周期管理从方法到实践全解析
- 洛谷 P2048 [NOI2010]超级钢琴(优先队列,RMQ)
- 使用spring-rabbit测试RabbitMQ消息确认(发送确认,接收确认)
- 001——数组(一)数组知识及foreach函数应用