PHP CURL如何处理上传内存中文件,避免磁盘IO开销
普通的CURL上传磁盘文件的方式
发送方 send.php
的代码如下:
<?php
$target_url = "http://localhost/upload.php";
$filename = realpath("test.txt");
/*
* 第一种写法,但是在5.5以上版本不推荐使用
* @$filename 是文件路径,必须有
* filename=test.txt 是接收方收到的文件名,为空时 则取 filename 文件路径中的 basename部分
* type=text/plain 文档类型,可以为空
*/
/*
$post_data = array(
'extra_info' => '123456',
'file_contents' => "@$filename;filename=test.txt;type=text/plain",
);
*/
/*
* 第二种写法,推荐新版本php中使用
* CURLFile参数解释
* @$filename 需要上传的文件,建议使用绝对路径
* @$mimetype: 默认是 application/octet-stream,此处留空
* @$postname: 接收方$_FILES数组中的文件名,此处为 test.txt
*/
$file = new CURLFile($filename, '', 'test.txt');
$post_data = array(
'extra_info' => '123456',
'file_contents' => $file,
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
处理上传文件的代码upload.php
示例:
<?php
$upload_dir = realpath('./') . '/';
$uploadfile = $upload_dir . basename($_FILES['file_contents']['name']);
echo '
<
pre>';
if(move_uploaded_file($_FILES['file_contents']['tmp_name'], $uploadfile)) {
echo 'ok!';
} else {
echo 'failed!';
}
//调试信息
var_dump($_FILES);
var_dump($_POST);
利用 PUT 方法上传内存中的文件
有些时候脚本产生的临时小文件,利用普通的上传方式,则需要先把文件写入磁盘,再作为文件上传。产生了额外的开销。最好的办法是直接上传。
重新实现send.php
代码如下:
<?php
/**
* php://temp 会在内存量达到预定义的限制后(默认是 2MB)存入临时文件中。
*/
$fh = fopen('php://temp', 'rw+');
$string = 'test';
fwrite($fh, $string);
rewind($fh);
$ch = curl_init('http://localhost/putfile.php');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($string));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
fclose($fh);
没有用 php://memory
,会报错 Warning: curl_setopt(): cannot represent a stream of type MEMORY as a STDIO FILE*
暂无好的解决方案
处理上传的文件的脚本也需要修改下:
<?php
//修改自PHP手册中的代码
$putdata = fopen("php://input", "r");
/* Open a file for writing */
$fp = fopen("myputfile.txt", "w");
/* Read the data 1 KB at a time
and write to the file */
while ($data = fread($putdata, 1024))
fwrite($fp, $data);
/* Close the streams */
fclose($fp);
fclose($putdata);
这个方法,适合上传小于2MB的文件,否则还是会生成临时文件。当然该参数可以通过php.ini
修改
自己构造请求的主体 实现任意大小文件的直接内存上传
通过CURL 上传文件,不管是磁盘文件还是内存中的字符串也好,其实都是基于HTTP协议的请求。
如果自己构造这段请求,便不再局限于文件的形式了。
<?php
/**
* 参考rfc1867协议 第6部分的 examples 中的格式 : http://www.ietf.org/rfc/rfc1867.txt
* 如下:第一行是header 中的(省略了其他header),其他部分是主体部分
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
* 或
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y
--BbC04y
Content-disposition: attachment; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--BbC04y
Content-disposition: attachment; filename="file2.gif"
Content-type: image/gif
Content-Transfer-Encoding: binary
...contents of file2.gif...
--BbC04y--
--AaB03x--
* CURL POST,对 CURLOPT_POSTFIELDS 的设置,倘若是字符串可以解释为主体部分
*/
//生成分隔符
$delimiter = '-------------' . uniqid();
//需要上传的文件数组
$fileFields = array(
'file1' => array(
'name' => 'test1.txt',
'type' => 'text/plain',
'content' => '...this is my file content...'
),
'file2' => array(
'name' => 'test.txt',
'type' => 'text/plain',
'content' => '... this is my two file'
),
);
//后端接受的$_POST的数组值
$postFields = array(
'myname' => 'joe',
);
//@var $data 保存主体的字符串
$data = '';
//先将post的普通数据生成主体字符串
foreach ($postFields as $name => $content) {
$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="' . $name . '"';
//multipart/form-data 不需要urlencode,参见 http:stackoverflow.com/questions/6603928/should-i-url-encode-post-data
$data .= "\r\n\r\n" . $content . "\r\n";
}
//将上传的文件生成主体字符串
foreach ($fileFields as $name => $file) {
$data .= "--" . $delimiter . "\r\n";
$data .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $file['name'] . "\" \r\n";
$data .= 'Content-Type: ' . $file['type'] . "\r\n\r\n";//多了个文档类型
$data .= $file['content'] . "\r\n";
}
//主体结束的分隔符
$data .= "--" . $delimiter . "--";
$target_url = "http://localhost/upload.php";
$handle = curl_init($target_url);
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_HTTPHEADER , array(
'Content-Type: multipart/form-data; boundary=' . $delimiter,
'Content-Length: ' . strlen($data))
);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($handle);
curl_close($handle);
//echo $result;
这种方式实现稍显复杂,但不需要更改处理上传的代码,跟第一种磁盘文件的方法一样。
其他参考
深入浅出php下的文件上传 提到了一些安全处理的技巧
简述php中curl的使用
PHP CURL如何处理上传内存中文件,避免磁盘IO开销相关推荐
- 磁盘io php,PHP CURL如何处理上传内存中文件,避免磁盘IO开销
普通的CURL上传磁盘文件的方式 发送方 send.php的代码如下: $target_url = "http://localhost/upload.php"; $filename ...
- linux下上传系统中文件到gitHub
linux下上传系统中文件到gitHub 一: 1系统下生成公钥 #ssh-keygen 一路回车即可 2对公钥进行复制 #cat .shh/id_rsa.pub 3将公钥复制到github中 首先要 ...
- curl post json_curl 模拟 GETPOST 请求,以及 curl post 上传文件
curl 模拟 GETPOST 请求,以及 curl post 上传文件 一般情况下,我们调试数据接口,都会使用一个 postman 的工具,但是这个工具还是有点大了.事实上,我们在调试一些小功能的时 ...
- curl 模拟 GET\POST 请求,以及 curl post 上传文件
curl 模拟 GET\POST 请求,以及 curl post 上传文件 一般情况下,我们调试数据接口,都会使用一个 postman 的工具,但是这个工具还是有点大了.事实上,我们在调试一些小功能的 ...
- thinkphp如何一次性的上传多个文件,在文件域中可以多选?
可以做到类似于某度网盘的样式吗? 文件夹的命名, 可以用单数, 也可以用复数, 在同一个项目中, 只要统一就好了. 毕竟项目开发不同于英语写作. 建议使用缩写, 不管是不是缩写都用单数, 这样简洁,容 ...
- asp.net 2.0中允许一次上传多个文件的设计
在asp.net 2.0中,可以结合dhtml来实现在用户上传完一个文件后,再点"继续上传",而动态增加上传文件框 首先是前台的页面 <script language=&qu ...
- 如何在Linux中使用sFTP上传或下载文件与文件夹
如何在Linux中使用sFTP上传或下载文件与文件夹 sFTP(安全文件传输程序)是一种安全的交互式文件传输程序,其工作方式与 FTP(文件传输协议)类似. 然而,sFTP 比 FTP 更安全;它通过 ...
- linux curl t上传文件,curl 命令行上传文件
现在nginx大行其道,一般在机器上装个nginx 简答配置下就可以做upload用了.主要需求是开发那边需要运维这边投递一些app_log和一些history log.下面讲解下直接用curl命令上 ...
- leaflet使用L.KML.js插件上传本地kml文件到leaflet中
发现网上的案例都是加载项目assets内的kml文件,而实际的需求是:用户需要上传自己计算机上的kml文件,找了半天没找到案例,最后终于研究出来了,喜欢的点赞支持! 1.网上案例使用 L.KML.js ...
最新文章
- SQ_20200326_Z-TEK主动式USB-5m延长线对于Intel Realsense D435掉线情况测试
- leetcode910. 最小差值 II(贪心)
- jQuery之load方法
- php label,HTML的label标签
- primefaces教程_Primefaces,带有JPA的Spring 4(Hibernate 4 / EclipseLink)示例教程
- 打印机显示rpg服务器不可用,网络打印机“RPC服务器不可用”的终极解决办法
- 在mysql中productname_ASP如何读出数据库里的英文符号.....%rs(ProductName)% 其是ProductName=10×26wood...
- 联想小新13pro锐龙版网卡_诠释极致性价比 联想小新Pro 13标压锐龙版笔记本评测...
- 可用等式为:html+java=jsp表示jsp[8]._在 JSP 中 , 对 jsp:setProperty 标记描述正确的是 ()_学小易找答案...
- Altium Designer 20查找指定元器件
- smbd of samba-3.0.23b internal
- 达梦数据库key文件更换
- 唠唠 U盘格式 (Normal:FAT32 NTFS exFAT)以及U盘格式化选什么格式好???
- 使用requests.get()爬取猫眼电影数据,返回值与网页源代码不一致
- 敏涵控股集团:以匠心致敬品质 用效益回馈社会
- 【NOIP2015提高组】信息传递
- 格隆汇笔记-黄勇演讲
- 小忽视大问题:4.8通过 Apple 登录
- FLUENT提供了9个湍流模型,教你如何选择
- EXCEL函数vlookup视频教程