普通的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. list extend 和 append
  2. 百度Apollo发布中国首个自动驾驶安全报告,L3级别产品2020年量产上市
  3. 几十条业务线日志系统如何收集处理?
  4. 阿里云系列——3.企业网站备案步骤---2018-1-4
  5. “笨方法”学习Python笔记(1)-Windows下的准备
  6. 数据分析:主成分分析(PCA)1
  7. Hadoop中通过ToolRunner和Configured实现直接读取命令行动态出入reduce task数量,jar文件等...
  8. Android APK反编译 apktool使用教程
  9. JS 无法清除Cookie的解决方法
  10. halcon python缺陷检测_Halcon学习笔记之缺陷检测(一)
  11. 转 C#对多个集合和数组的操作(合并,去重,判断)
  12. 数据科学入门与实战:玩转pandas之六时间序列
  13. 录入成绩编程平均java_java 学习第二天小练习
  14. c++ xml 解析“后直接跟值问题
  15. aehyok.com的成长之路一——开篇
  16. Hive 实用的第三方 UDF 收集
  17. android斗鱼app源代码,android文件管理器源码、斗鱼直播源码、企业级erp源码等
  18. Listary -- 高效率办公软件
  19. android打飞机游戏素材,微信打飞机游戏素材
  20. 网络安全中的数据挖掘技术(一)

热门文章

  1. web渗透之文件包含漏洞-学习笔记分享
  2. JavaScript中的数组常用方法总结
  3. java游戏倒计时代码怎么用,Java实现倒计时代码
  4. 企业该如何使用.icu域名?
  5. 【JVM学习】Java内存管理一
  6. 顶尖程序员不同于常人的5个区别
  7. 安卓APP修改 生成的图标和app名称
  8. 阿尔法编程平台python答案_阿尔法编程python答案
  9. Adobe Photoshop CC 2018之ps反向抠图
  10. windows下从ibd文件恢复表数据(InnoDB)