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

本文实例分析了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 curl用法总结》、《PHP网络编程技巧总结》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《PHP数据结构与算法教程》、《php程序设计算法总结》及《PHP运算与运算符用法总结》

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

您可能感兴趣的文章:

  • PHP7基于curl实现的上传图片功能
  • php curl上传、下载、https登陆实现代码
  • PHP使用curl模拟post上传及接收文件的方法
  • php实现curl模拟ftp上传的方法
  • php curl 上传文件代码实例
  • PHP基于CURL进行POST数据上传实例
  • PHP7 新特性详细介绍
  • 浅析PHP7新功能及语法变化总结
  • 可兼容php5与php7的cURL文件上传功能实例分析
(0)

相关推荐

  • php curl上传、下载、https登陆实现代码

    1.curl下载 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "ftp://127.0.0.1/downtest.txt"); curl_setopt($ch, CURLOPT_HEADER,0); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_TIMEOUT,300); //设置用户名和密码 curl_setopt($ch, CURLOPT

  • PHP使用curl模拟post上传及接收文件的方法

    本文实例讲述了PHP使用curl模拟post上传及接收文件的方法.分享给大家供大家参考,具体如下: public function Action_Upload(){ $this->path_config(); exit(); $furl="@d:\develop\JMFrameworkWithDemo.rar"; $url= "http://localhost/DemoIndex/curl_pos/"; $this->upload_file_to_cdn

  • 浅析PHP7新功能及语法变化总结

    标量类型声明 有两种模式: 强制 (默认) 和 严格模式. 现在可以使用下列类型参数(无论用强制模式还是严格模式): 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool).在旧版中,函数的参数声明只能是(Array $arr).(CLassName $obj)等,基本类型比如Int,String等是不能够被声明的 <?php function check(int $bool){ var_dump($bool); } check(1); check(tr

  • 可兼容php5与php7的cURL文件上传功能实例分析

    本文实例讲述了可兼容php5与php7的cURL文件上传功能.分享给大家供大家参考,具体如下: 为啥要写这个示例 最近修改一个项目,需要通过cURL上传文件. 记得之前做过类似实现的,于是翻出来之前的代码,使用的是"@"前缀方式. 但同样的方法现在不行了!后来发现,是版本兼容问题. 奔着开源分享的精神,同时避免自己遗忘,于是写了下面的示例程序. 示例程序 特别说明: 共3个文件,都放在web根目录的test目录下,同时保证该目录可写.上传的图片也会保存在该目录. 如果要将程序文件放在其

  • php实现curl模拟ftp上传的方法

    本文实例讲述了php实现curl模拟ftp上传的方法.分享给大家供大家参考.具体如下: <?php function upload($dir,$src,$dest) { $ch = curl_init(); $fp = fopen($src, 'r'); curl_setopt($ch, CURLOPT_URL, 'ftp://user:pwd@host/interpretation/'.$dir .'/'. $dest); curl_setopt($ch, CURLOPT_UPLOAD, 1)

  • PHP7基于curl实现的上传图片功能

    本文实例讲述了PHP7基于curl实现的上传图片功能.分享给大家供大家参考,具体如下: 根据php版本不同,curl模拟表单上传的方法不同 php5.5之前 $curl = curl_init(); if (defined('CURLOPT_SAFE_UPLOAD')) { curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false); } $data = array('file' => '@' . realpath($path));//'@' 符号告诉服务器为上

  • PHP基于CURL进行POST数据上传实例

    本文实例讲述了PHP基于CURL进行POST数据上传的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: ////二维码 $QRCode_URL="https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$ACC_TOKEN;    $data ='{"expire_seconds": 1800, "action_name": "QR_SCENE&q

  • php curl 上传文件代码实例

    假设server端上传文件处理脚本upload.php: 复制代码 代码如下: <?php    print_r($_POST);  print_r($_FILES); 1.使用 CURL 默认的方法 复制代码 代码如下: //如果php文件是utf8编码,系统是GBK编码,那么就需要转下编码,要不然Php在系统中找不到这个文件    $file = realpath(mb_convert_encoding('测试图片.JPG','GBK','utf8'));    $file = realpa

  • PHP7 新特性详细介绍

    PHP 的学习新特性 最近做的项目使用了 php7,但感觉有很多新特性没有用起来.就想总结一下,一些可能会用到的新特性.之前使用的环境是 php5.4,所有也会有 php5.5 和 php5.6 的特性总结进来,这里只列出我觉得在项目中可能用到的特性,主要内容来自 php手册的附录. Generators (PHP 5 >= 5.5.0, PHP 7) 通过添加 yield 关键字支持了 generators,Generators 提供了一个更简单的方法实现迭代器,不需要实现 Iterator

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

    本文实例分析了PHP5.0~5.6 各版本兼容性cURL文件上传功能.分享给大家供大家参考,具体如下: 最近做的一个需求,要通过PHP调用cURL,以multipart/form-data格式上传文件.踩坑若干,够一篇文章了. 重要警告 没事不要读PHP的官方中文文档!版本跟不上坑死你! 不同版本PHP之间cURL的区别 PHP的cURL支持通过给CURL_POSTFIELDS传递关联数组(而不是字符串)来生成multipart/form-data的POST请求. 传统上,PHP的cURL支持通

  • Servlet3.0实现文件上传的方法

    Servlet 实现文件上传 所谓文件上传就是将本地的文件发送到服务器中保存.例如我们向百度网盘中上传本地的资源或者我们将写好的博客上传到服务器等等就是典型的文件上传. Servlet 3.0 上次完成文件下载功能使用的是 Servlet 2.5,但是想要完成文件上传,那么继续使用 Servlet 2.5 肯定不是一个好的选择,因此我们使用 Servlet 3.0 来完成文件上传.下面我来简单介绍一下 Servlet 3.0 的新特性: 1.新增的注解支持 该版本新增了若干注解,用于简化 Ser

  • layui(1.0.9)文件上传upload,前后端的实例代码

    因为公司还在使用老版本的layui,文件上传在新版本中全部重写了,这里记录下老版本layui的文件上传. 前端代码:(引入layui相关包) <input type="file" lay-type="file" id="xxxxx" name="file" class="layui-upload-file"> 这里可以参考layui官方文档,有一点需要注意,name属性是必需的,当你选择好文件后

  • ASP的chr(0)文件上传漏洞原理和解决方法介绍

    我们在用ASP开发文件上传功能的时候,为了防止用户上传木马程序,常常会限制一些文件的上传,常用的方法是判断一下上传文件的扩展名是否符合规定,可以用right字符串函数取出上传文件的文件名的后四位,这样很容易就能判断了,但是这里面有一个漏洞,非常危险,就是chr(0)漏洞,详情请接着往下看. 一.首先解释下什么是chr(0)? 在ASP中可以用chr()函数调用ASCII码,其中chr(0)表示调用的是一个结束字符,简单的说当一个字符串中包含chr(0)字符时,只能输出chr(0)前面的字符,ch

  • Servlet3.0学习总结之基于Servlet3.0的文件上传实例

    在Servlet2.5中,我们要实现文件上传功能时,一般都需要借助第三方开源组件,例如Apache的commons-fileupload组件,在Servlet3.0中提供了对文件上传的原生支持,我们不需要借助任何第三方上传组件,直接使用Servlet3.0提供的API就能够实现文件上传功能了. 一.使用Servlet3.0提供的API实现文件上传 1.1.编写上传页面 <%@ page language="java" pageEncoding="UTF-8"%

  • CentOS 7.x编译安装Nginx1.10.3+MySQL5.7.16+PHP5.2 5.3 5.4 5.5 5.6 7.0 7.1多版本全能环境

    前传: 1.CentOS 7.3.1611系统安装配置图解教程 http://www.osyunwei.com/archives/10003.html 2.CentOS服务器初始化设置 http://www.osyunwei.com/archives/9034.html 准备篇 一.防火墙配置 CentOS 7.x默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewalld.service #停止firew

  • Windows下的PHP5.0安装配制详解

    PHP5包括以下一些重要的特征: ·支持新的对象模型和许多新特点的Zend引擎. ·完全重新编写了XML支持,扩展性能围绕着优秀的libxml2库(http://www.xmlsoft.org/). ·新的SimpleXML扩展,PHP对象轻松访问操作. ·全新的内建SOAP扩展,支持Web服务的交换. ·增加命名为MySQLi的了MySQL的扩展,支持MySQL4.1及以后版本的功能. ·绑定SQLite数据库. ·极大地改进流的设计,包括通过流操作底层的socket 首先,点这里下载PHP5

  • 解决PHP4.0 和 PHP5.0类构造函数的兼容问题

    在 PHP5.0 以上版本里,还兼容了 4.0 版本的构造函数的定义规则.如果同时定义了4.0的构造函数和 __construct()函数,则__construct() 函数优先.为了使类代码同时兼容 PHP4.0 和 5.0,可以采取以下的方式: 复制代码 代码如下: <?phpclass MyClass { function __construct() { //for PHP5.0  echo 'this is class2 construct'; } // 为了使类代码同时兼容 PHP4.

  • Windows下的PHP5.0详解

    PHP5包括以下一些重要的特征:  ·支持新的对象模型和许多新特点的Zend引擎. ·完全重新编写了XML支持,扩展性能围绕着优秀的libxml2库(http://www.xmlsoft.org/). ·新的SimpleXML扩展,PHP对象轻松访问操作. ·全新的内建SOAP扩展,支持Web服务的交换. ·增加命名为MySQLi的了MySQL的扩展,支持MySQL4.1及以后版本的功能. ·绑定SQLite数据库. ·极大地改进流的设计,包括通过流操作底层的socket 首先,点这里下载PHP

随机推荐