磁盘io php,PHP CURL如何处理上传内存中文件,避免磁盘IO开销
普通的CURL上傳磁盤文件的方式
發送方 send.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示例:
$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://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手冊中的代碼
$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協議的請求。
如果自己構造這段請求,便不再局限于文件的形式了。
/**
* 參考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;
這種方式實現稍顯復雜,但不需要更改處理上傳的代碼,跟第一種磁盤文件的方法一樣。
其他參考
總結
以上是生活随笔為你收集整理的磁盘io php,PHP CURL如何处理上传内存中文件,避免磁盘IO开销的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为WATCH Ultimate非凡大师
- 下一篇: centos 6.5 openldap