發送方 send.php
的代碼以下: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
示例:html
<?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);
有些時候腳本產生的臨時小文件,利用普通的上傳方式,則須要先把文件寫入磁盤,再做爲文件上傳。產生了額外的開銷。最好的辦法是直接上傳。
從新實現send.php
代碼以下:web
<?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;
這種方式實現稍顯複雜,但不須要更改處理上傳的代碼,跟第一種磁盤文件的方法同樣。
其餘參考app
深刻淺出php下的文件上傳 提到了一些安全處理的技巧
簡述php中curl的使用curl