PHP5.0~5.6 各版本兼容性cURL文件上传功能实例分析


Posted in PHP onMay 11, 2018

本文实例分析了PHP5.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('image.png'),
));

equals

$ curl -F "file=@/absolute/path/to/image.png" <url>

但PHP从5.5开始引入了新的CURLFile类用来指向文件。CURLFile类也可以详细定义MIME类型、文件名等可能出现在multipart/form-data数据中的附加信息。PHP推荐使用CURLFile替代旧的@语法:

curl_setopt(ch, CURLOPT_POSTFIELDS, [
  'file' => new CURLFile(realpath('image.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()内部的执行顺序一定是从头到尾按顺序(好吧我知道assume不是件好事,不过有些实在过分浅显的事实,就容我下个最低限度的断言吧),所以尽可放心。

我的做法只是在代码表现上加个多余的保险,突出强调顺序的重要性防以后手贱。

命名空间

PHP 5.2或以下的版本没有命名空间。代码中用到了空间分隔符\就会引发解析器错误。要照顾PHP 5.2其实容易想,放弃命名空间即可。

要注意的反倒是有命名空间的PHP 5.3+。无论是调用CURLFile还是用class_exists()判断CURLFile的存在性,都推荐写成\CURLFile明确指定顶层空间,防止代码包裹在命名空间内的时候崩掉。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
多文件上载系统完整版
Oct 09 PHP
MySql中正则表达式的使用方法描述
Jul 30 PHP
PHP实现异步调用方法研究与分享
Oct 27 PHP
PHP生成随机用户名和密码的实现代码
Feb 27 PHP
简单的php数据库操作类代码(增,删,改,查)
Apr 08 PHP
php中AES加密解密的例子小结
Feb 18 PHP
php无限遍历目录示例
Feb 21 PHP
php使用正则表达式提取字符串中尖括号、小括号、中括号、大括号中的字符串
Apr 05 PHP
PHP实现文件上传与下载实例与总结
Mar 13 PHP
PHP实现的激活用户注册验证邮箱功能示例
Jun 06 PHP
PHP实现的大文件切割与合并功能示例
Apr 10 PHP
360搜索引擎自动收录php改写方案
Apr 28 PHP
PHP7基于curl实现的上传图片功能
May 11 #PHP
关于ThinkPHP中的异常处理详解
May 11 #PHP
PHP基于递归算法解决兔子生兔子问题
May 11 #PHP
PHP7如何开启Opcode打造强悍性能详解
May 11 #PHP
laravel项目利用twemproxy部署redis集群的完整步骤
May 11 #PHP
PHP实现搜索时记住状态的方法示例
May 11 #PHP
PHP实现压缩图片尺寸并转为jpg格式的方法示例
May 10 #PHP
You might like
php Try Catch异常测试
2009/03/01 PHP
php简单对象与数组的转换函数代码(php多层数组和对象的转换)
2011/05/18 PHP
使用php发送有附件的电子邮件-(PHPMailer使用的实例分析)
2013/04/26 PHP
Ajax+PHP快速上手及简单应用说明
2013/07/24 PHP
php缓存技术详细总结
2013/08/07 PHP
PHP微框架Dispatch简介
2014/06/12 PHP
PHP删除指定目录中的所有目录及文件的方法
2015/02/26 PHP
PHP中的自动加载操作实现方法详解
2019/08/06 PHP
Mac系统下搭建Nginx+php-fpm实例讲解
2020/12/15 PHP
jquery animate实现鼠标放上去显示离开隐藏效果
2013/07/21 Javascript
jQuery调用ajax请求的常见方法汇总
2015/03/24 Javascript
jQuery 1.9.1源码分析系列(十五)之动画处理
2015/12/03 Javascript
jQuery实现鼠标滑过图片移动特效
2016/12/08 Javascript
JS对象是否拥有某属性如何判断
2017/02/03 Javascript
详解AngularJS controller调用factory
2017/05/19 Javascript
BootStrap自定义popover,点击区域隐藏功能的实现
2018/01/23 Javascript
深入剖析Node.js cluster模块
2018/05/23 Javascript
vue实现登录、注册、退出、跳转等功能
2020/12/23 Vue.js
[01:01:22]VGJ.S vs OG 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
python 类详解及简单实例
2017/03/24 Python
python 绘制拟合曲线并加指定点标识的实现
2019/07/10 Python
Python中zip()函数的简单用法举例
2019/09/02 Python
Oakley官网:运动太阳镜、雪镜和服装
2016/09/30 全球购物
Hello Molly美国:女性时尚在线
2019/08/26 全球购物
JACK & JONES荷兰官网:男士服装和鞋子
2021/03/07 全球购物
名词解释WEB SERVICE,SOAP,UDDI,WSDL,JAXP,JAXM;JSWDL开发包的介绍。
2012/10/27 面试题
艺术设计专业个人求职信范文
2013/12/11 职场文书
平面网站制作专科生的自我评价分享
2013/12/11 职场文书
中医专业职业生涯规划书范文
2014/01/04 职场文书
一月红领巾广播稿
2014/02/11 职场文书
工伤事故证明
2014/10/20 职场文书
优秀大学生自荐信
2015/03/26 职场文书
刮痧观后感
2015/06/05 职场文书
狂人日记读书笔记
2015/06/30 职场文书
详解MySQL主从复制及读写分离
2021/05/07 MySQL
总结python多进程multiprocessing的相关知识
2021/06/29 Python