普通的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开销相关推荐

  1. 磁盘io php,PHP CURL如何处理上传内存中文件,避免磁盘IO开销

    普通的CURL上传磁盘文件的方式 发送方 send.php的代码如下: $target_url = "http://localhost/upload.php"; $filename ...

  2. linux下上传系统中文件到gitHub

    linux下上传系统中文件到gitHub 一: 1系统下生成公钥 #ssh-keygen 一路回车即可 2对公钥进行复制 #cat .shh/id_rsa.pub 3将公钥复制到github中 首先要 ...

  3. curl post json_curl 模拟 GETPOST 请求,以及 curl post 上传文件

    curl 模拟 GETPOST 请求,以及 curl post 上传文件 一般情况下,我们调试数据接口,都会使用一个 postman 的工具,但是这个工具还是有点大了.事实上,我们在调试一些小功能的时 ...

  4. curl 模拟 GET\POST 请求,以及 curl post 上传文件

    curl 模拟 GET\POST 请求,以及 curl post 上传文件 一般情况下,我们调试数据接口,都会使用一个 postman 的工具,但是这个工具还是有点大了.事实上,我们在调试一些小功能的 ...

  5. thinkphp如何一次性的上传多个文件,在文件域中可以多选?

    可以做到类似于某度网盘的样式吗? 文件夹的命名, 可以用单数, 也可以用复数, 在同一个项目中, 只要统一就好了. 毕竟项目开发不同于英语写作. 建议使用缩写, 不管是不是缩写都用单数, 这样简洁,容 ...

  6. asp.net 2.0中允许一次上传多个文件的设计

    在asp.net 2.0中,可以结合dhtml来实现在用户上传完一个文件后,再点"继续上传",而动态增加上传文件框 首先是前台的页面 <script language=&qu ...

  7. 如何在Linux中使用sFTP上传或下载文件与文件夹

    如何在Linux中使用sFTP上传或下载文件与文件夹 sFTP(安全文件传输程序)是一种安全的交互式文件传输程序,其工作方式与 FTP(文件传输协议)类似. 然而,sFTP 比 FTP 更安全;它通过 ...

  8. linux curl t上传文件,curl 命令行上传文件

    现在nginx大行其道,一般在机器上装个nginx 简答配置下就可以做upload用了.主要需求是开发那边需要运维这边投递一些app_log和一些history log.下面讲解下直接用curl命令上 ...

  9. leaflet使用L.KML.js插件上传本地kml文件到leaflet中

    发现网上的案例都是加载项目assets内的kml文件,而实际的需求是:用户需要上传自己计算机上的kml文件,找了半天没找到案例,最后终于研究出来了,喜欢的点赞支持! 1.网上案例使用 L.KML.js ...

最新文章

  1. SQ_20200326_Z-TEK主动式USB-5m延长线对于Intel Realsense D435掉线情况测试
  2. leetcode910. 最小差值 II(贪心)
  3. jQuery之load方法
  4. php label,HTML的label标签
  5. primefaces教程_Primefaces,带有JPA的Spring 4(Hibernate 4 / EclipseLink)示例教程
  6. 打印机显示rpg服务器不可用,网络打印机“RPC服务器不可用”的终极解决办法
  7. 在mysql中productname_ASP如何读出数据库里的英文符号.....%rs(ProductName)% 其是ProductName=10×26wood...
  8. 联想小新13pro锐龙版网卡_诠释极致性价比 联想小新Pro 13标压锐龙版笔记本评测...
  9. 可用等式为:html+java=jsp表示jsp[8]._在 JSP 中 , 对 jsp:setProperty 标记描述正确的是 ()_学小易找答案...
  10. Altium Designer 20查找指定元器件
  11. smbd of samba-3.0.23b internal
  12. 达梦数据库key文件更换
  13. 唠唠 U盘格式 (Normal:FAT32 NTFS exFAT)以及U盘格式化选什么格式好???
  14. 使用requests.get()爬取猫眼电影数据,返回值与网页源代码不一致
  15. 敏涵控股集团:以匠心致敬品质 用效益回馈社会
  16. 【NOIP2015提高组】信息传递
  17. 格隆汇笔记-黄勇演讲
  18. 小忽视大问题:4.8通过 Apple 登录
  19. FLUENT提供了9个湍流模型,教你如何选择
  20. EXCEL函数vlookup视频教程

热门文章

  1. TPGS-folate (TPGS-FA);维生素E琥珀酸酯PEG-叶酸;科研实验用
  2. Java多类合作实例1汽车和修理厂
  3. 2016年6月全球浏览器市场份额:Chrome继续蚕食市场份额
  4. 使用JavaScript合并数组
  5. 飞絮季消防安全不可忽视,这些防火知识要牢记
  6. Singleton 模式
  7. 【芯片应用】具有看门狗功能的超低功耗系统计时器TPL5010
  8. 广告数据分析工具如何对各行业的广告投放进行分析?
  9. python 递归 写平方_Python递归函数如何写?正确的Python递归函数用法
  10. 8.3 Nagios监控安装配置与添加监控服务器