哪位大俠有使用CURL設定HTTPHEADER來上傳檔案的經驗?
求指點
PS:不是 '@'.檔案名稱,而是Content-Type: application/octet-stream
回複討論(解決方案)
curl不支援這種方式,你需要自己構造資料包。我研究過
curl不支援這種方式,你需要自己構造資料包。我研究過
是否有樣本?
http://cn.php.net/fsockopen
CTRL + F搜尋boundary,例子好好看看,構建一個檔案上傳的http要求標頭即可,按理說CURL構建同樣的要求標頭應該也沒問題。
總結一下項目中用到curl的幾種方式
1. php curl的預設調用方法,get方式訪問url
Java代碼
....
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //設定http頭
curl_setopt($ch, CURLOPT_ENCODING, "gzip" ); //設定為用戶端支援gzip壓縮
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30 ); //設定串連等待時間
curl_setopt($ch, CURLOPT_URL, $url );
curl_exec( $ch );
if ($error = curl_error($ch) ) {
//出錯處理
return -1;
}
fclose($fp);
$curl_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); //擷取http傳回值
if( $curl_code == 200 ) {
//正常訪問url
}
//異常
....
....
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //設定http頭
curl_setopt($ch, CURLOPT_ENCODING, "gzip" ); //設定為用戶端支援gzip壓縮
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30 ); //設定串連等待時間
curl_setopt($ch, CURLOPT_URL, $url );
curl_exec( $ch );
if ($error = curl_error($ch) ) {
//出錯處理
return -1;
}
fclose($fp);
$curl_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); //擷取http傳回值
if( $curl_code == 200 ) {
//正常訪問url
}
//異常
....
2. 設定http header支援curl訪問lighttpd伺服器
Java代碼
$header[]= 'Expect:';
$header[]= 'Expect:';
3. 設定curl,只擷取http header,不擷取body:
Java代碼
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
或者只擷取body:
Java代碼
curl_setopt($ch, CURLOPT_HEADER, 0); // make sure we get the body
curl_setopt($ch, CURLOPT_NOBODY, 0);
curl_setopt($ch, CURLOPT_HEADER, 0); // make sure we get the body
curl_setopt($ch, CURLOPT_NOBODY, 0);
4. 訪問虛擬機器主機,需設定Host
$header[]= 'Host: '.$host;
5. 使用post, put, delete等REStful方式訪問url
post:
curl_setopt($ch, CURLOPT_POST, 1 );
put, delete:
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); //或者PUT,需要伺服器支援這些方法。
6. 儲存下載內容為檔案
curl_setopt($ch, CURLOPT_FILE, $fp);
總結一下項目中用到curl的幾種方式
1. php curl的預設調用方法,get方式訪問url
Java代碼
....
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //設定http頭
curl_setopt($ch, CURLOPT_ENCO……
貌似沒看到使用了CURLOPT_HTTPHEADER
http://cn.php.net/fsockopen
CTRL + F搜尋boundary,例子好好看看,構建一個檔案上傳的http要求標頭即可,按理說CURL構建同樣的要求標頭應該也沒問題。
謝謝,CURL不支援這種上傳方法嗎?
可能是比較複雜吧,所以 curl 提供了 '@'.檔案名稱 的方式。把構造頭和資料的工作留給了自己
但 curl 依然提供了 CURLOPT_UPLOAD 來表示上傳檔案,但實際上使用了 PUT 請求
只適合向 ftp 上傳檔案
在 php 中,要從 php://input 讀取
使用 #5 給出的代碼,會產生 無法識別的請求 這樣的錯誤,注釋掉檔案上傳的那段,依然報這個錯。不知是什麼原因
但對比 curl PUT 方式的資料報,似乎也沒有什麼差異
知道了,這樣寫就可以!
$contents =<<< 'TEXT'資料報中應該是Content-Disposition: form-data; name="userfile"; filename="file_name"Content-Type: 文件類型檔案內容這樣的格式,我只實現了檔案名稱部分,文件類型不知道如何?。這樣上傳後就取不到 type 的值curl_upload_server.php<?phpprint_r($_FILES);echo "檔案內容:\n";$p = current($_FILES);readfile($p['tmp_name']);TEXT;$fields['f"; filename="x.x'] = $contents; //這個關聯鍵的寫法很怪異吧?$ch = curl_init(); curl_setopt($ch, CURLOPT_URL,"http://localhost/curl_upload_server.php"); curl_setopt($ch, CURLOPT_POST, 1 );curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$s = curl_exec ($ch); curl_close ($ch); echo $s;</pre> </p> <p class="sougouAnswer"> 原來這樣就有 type了 <pre class="sycode" name="code">$varname = 'my';$name = '3.txt';$type = 'text/plain';$key = <<< TEXT$varname"; filename="$nameContent-Type: $typeTEXT;$fields[$key] = $contents;</pre> <br /> 注意:我是在 win 下的,linux 下要將 \n 換成 \r\n <br /> 沒辦法,早年的 sun 是拼不過 ms 的,現在也不行吧? <br /> <br /> 一直以為上傳的檔案類型是 php 識別的,卻原來是瀏覽器提供的 </p> <p class="sougouAnswer"> <p class="yy"> 原來這樣就有 type了PHP code <br /> $varname = 'my'; <br /> $name = '3.txt'; <br /> $type = 'text/plain'; <br /> $key = <<< TEXT <br /> $varname"; filename="$name <br /> Content-Type: $type <br /> <br /> TEXT; <br /> $fields[$key] = $contents; <br /> <br /> <br /> 注意:我是在 win 下的,linux 下…… </p> <br /> <br /> 很感謝,有沒有比較完整的CURL 通過拼接HTTPHEADER資訊上傳的POST樣本呢? </p> <p class="sougouAnswer"> #10 就是 <br /> curl_upload_server.php 就是測試用伺服器端 <br /> <xmp> <br /> <?php <br /> print_r($_FILES); <br /> <br /> echo "檔案內容:\n"; <br /> $p = current($_FILES); <br /> readfile($p['tmp_name']); <br /> </p> <p class="sougouAnswer"> 完整的代碼 <pre class="sycode" name="code">$contents =<<< 'TEXT'資料報中應該是Content-Disposition: form-data; name="userfile"; filename="file_name"Content-Type: 文件類型檔案內容這樣的格式以下是伺服器端代碼curl_upload_server.php<xmp><?phpprint_r($_FILES); //檢查上傳資訊echo "檔案內容:\n";$p = current($_FILES);readfile($p['tmp_name']); //輸出上傳的檔案TEXT;$varname = 'my';$name = '3.txt';$type = 'text/plain';$key = "$varname\"; filename=\"$name\r\nContent-Type: $type\r\n";$fields[$key] = $contents;$ch = curl_init(); curl_setopt($ch, CURLOPT_URL,"http://localhost/curl_upload_server.php"); curl_setopt($ch, CURLOPT_POST, 1 );curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$s = curl_exec ($ch); curl_close ($ch); echo $s;</pre> </p> <p class="sougouAnswer"> http檔案上傳協議,主要是那個boundary,這個東西就是標識一個檔案的內容和類型以及各種上傳參數的token,其它和普通的POST提交也沒啥區別。 <br /> <br /> fsockopen來寫http請求就比較直白,用curl的話類比對應的要求標頭和body就好了。 <br /> <pre class="sycode" name="code"><?php//what file you want to upload$uploadFile = file_get_contents("/var/www/index.html");//content boundary $boundary = md5(time());$postStr = "";$postStr .="--".$boundary."\r\n";$postStr .="Content-Disposition: form-data; name=\"uptxt\"; filename=\"index.html\"\r\n";$postStr .="Content-Type: text/html\r\n\r\n";$postStr .=$uploadFile."\r\n";$postStr .="--".$boundary."\r\n"; /** use fsockopen to set upload http header and body **/$fp = fsockopen("localhost","80",$errer,$errno,1);fwrite($fp,"POST /upload.php HTTP/1.0\r\n");fwrite($fp,"Content-Type: multipart/form-data; boundary=".$boundary."\r\n");fwrite($fp,"Content-length:".strlen($postStr)."\r\n\r\n");fwrite($fp,$postStr);while (!feof($fp)){ echo fgets($fp, 128);}fclose($fp);/** use curl instead **/$cl = curl_init('http://localhost/upload.php');$boundary = md5(time());curl_setopt($cl,CURLOPT_POST,true);curl_setopt($cl,CURLOPT_HTTPHEADER,array( "Content-Type: multipart/form-data; boundary=".$boundary));curl_setopt($cl,CURLOPT_POSTFIELDS,$postStr);curl_setopt($cl,CURLOPT_RETURNTRANSFER,true);$content = curl_exec($cl);curl_close($cl);echo $content;?></pre> <br /> <br /> upload.php <br /> <pre class="sycode" name="code"><?php print_r($_FILES);?></pre> <br /> <br /> 結果 <br /> <pre class="sycode" name="code">HTTP/1.1 200 OKServer: nginx/0.8.54Date: Tue, 10 Apr 2012 05:22:01 GMTContent-Type: text/htmlConnection: closeX-Powered-By: PHP/5.3.10Array( [uptxt] => Array ( [name] => index.html [type] => text/html [tmp_name] => /tmp/phpKHfxkY [error] => 0 [size] => 344 ))Array( [uptxt] => Array ( [name] => index.html [type] => text/html [tmp_name] => /tmp/phpB0se13 [error] => 0 [size] => 344 ))</pre> <br /> <br /> <br /> <br /> </p> <p class="sougouAnswer"> <p class="yy"> 完整的代碼PHP code <br /> $contents =<<< 'TEXT' <br /> 資料報中應該是 <br /> Content-Disposition: form-data; name="userfile"; filename="file_name" <br /> Content-Type: 文件類型 <br /> <br /> 檔案內容 <br /> <br /> 這樣的格式 <br /> 以下是伺服器端代碼 <br /> curl_upload_server.php <br /> <xmp> <br /> <?php <br /> print_r(…… </p> <br /> <br /> 沒有client? </p> <p class="sougouAnswer"> <p class="yy"> 完整的代碼PHP code <br /> $contents =<<< 'TEXT' <br /> 資料報中應該是 <br /> Content-Disposition: form-data; name="userfile"; filename="file_name" <br /> Content-Type: 文件類型 <br /> <br /> 檔案內容 <br /> <br /> 這樣的格式 <br /> 以下是伺服器端代碼 <br /> curl_upload_server.php <br /> <xmp> <br /> <?php <br /> print_r(…… </p> <br /> <br /> 最好能分開發一下,謝謝 </p> <p class="sougouAnswer"> <p class="yy"> http檔案上傳協議,主要是那個boundary,這個東西就是標識一個檔案的內容和類型以及各種上傳參數的token,其它和普通的POST提交也沒啥區別。 <br /> <br /> fsockopen來寫http請求就比較直白,用curl的話類比對應的要求標頭和body就好了。 <br /> PHP code <br /> <?php <br /> //what file you want to upload <br /> $uploadFile = file_get_…… </p> <br /> <br /> 非常感謝,CURL部分的代碼我這邊測試成功了,我再加一百分 </p> <p class="sougouAnswer"> #14 伺服器端 <br /> #15 用戶端 <br /> <br /> #14 中的 $contents 是待上傳的檔案內容 </p> <p class="sougouAnswer"> 上次好像看到你問的是一個檔案切分多份,然後上傳,如果是這樣的話,你要要做的只是用boundary標識多個上傳內容區塊。比如 <br /> <pre class="sycode" name="code">$boundary = md5(time());$postStr = "";$postStr .="--".$boundary."\r\n";$postStr .="Content-Disposition: form-data; name=\"uptxt[]\"; filename=\"index_1.html\"\r\n";$postStr .="Content-Type: text/html\r\n\r\n";$postStr .=$uploadFile."\r\n"; #這裡是部分檔案內容$postStr .="--".$boundary."\r\n";$postStr .="--".$boundary."\r\n";$postStr .="Content-Disposition: form-data; name=\"uptxt[]\"; filename=\"index_2.html\"\r\n"; $postStr .="Content-Type: text/html\r\n\r\n";$postStr .=$uploadFile."\r\n";#這裡是部分檔案內容$postStr .="--".$boundary."\r\n";</pre> <br /> </p> <p class="sougouAnswer"> 收藏了! </p> <p class="sougouAnswer"> to #21 <br /> 你這樣做是不行的,應該使用 curl_multi 並發 <br /> 不然把一個檔案拆成幾個, 一次性傳出,再在伺服器端組裝。有什麼意義? <br /> </p> <p class="sougouAnswer"> <p class="yy"> 上次好像看到你問的是一個檔案切分多份,然後上傳,如果是這樣的話,你要要做的只是用boundary標識多個上傳內容區塊。比如 <br /> PHP code <br /> $boundary = md5(time()); <br /> $postStr = ""; <br /> $postStr .="--".$boundary."\r\n"; <br /> $postStr .="Content-Disposition: form-data; name=…… </p> <br /> <br /> 我用了個迴圈來做 </p> <p class="sougouAnswer"> <p class="yy"> 引用 21 樓 的回複: <br /> <br /> 上次好像看到你問的是一個檔案切分多份,然後上傳,如果是這樣的話,你要要做的只是用boundary標識多個上傳內容區塊。比如 <br /> PHP code <br /> $boundary = md5(time()); <br /> $postStr = ""; <br /> $postStr .="--".$boundary."\r\n"; <br /> $postStr .="Content-Dispositi…… </p> <br /> <br /> 感謝,curl_multi很有用 </p> <p class="sougouAnswer"> <p class="yy"> to #21 <br /> 你這樣做是不行的,應該使用 curl_multi 並發 <br /> 不然把一個檔案拆成幾個,一次性傳出,再在伺服器端組裝。有什麼意義? </p> <br /> 說的也是哈,不過curl_multi的並發,對於請求不同的url後擷取資料比較有意義,就是說是並行請求不同的url擷取http返回。如果往同一url請求,要麼就一次請求,要麼就分發多次請求,多次請求有個效能消耗在於每次都要scoket串連/銷毀,但是能控制請求位元組數。 </p> <p class="sougouAnswer"> <p class="yy"> 引用 23 樓 的回複: <br /> <br /> to #21 <br /> 你這樣做是不行的,應該使用 curl_multi 並發 <br /> 不然把一個檔案拆成幾個,一次性傳出,再在伺服器端組裝。有什麼意義? <br /> <br /> 說的也是哈,不過curl_multi的並發,對於請求不同的url後擷取資料比較有意義,就是說是並行請求不同的url擷取http返回。如果往同一url請求,要麼就一次請求,要麼就分發多次請求,多次請求有個效能消耗在於每…… </p> <br /> 忘了如果伺服器支援keep-alive的話,無需進行多次socket create,呵呵 </p> <p class="sougouAnswer"> 一路上傳不能充分利用網路資源,多路並發可使上傳速度加快 <br /> </p> <p class="sougouAnswer"> <p class="yy"> 引用 26 樓 的回複: <br /> <br /> 引用 23 樓 的回複: <br /> <br /> to #21 <br /> 你這樣做是不行的,應該使用 curl_multi 並發 <br /> 不然把一個檔案拆成幾個,一次性傳出,再在伺服器端組裝。有什麼意義? <br /> <br /> 說的也是哈,不過curl_multi的並發,對於請求不同的url後擷取資料比較有意義,就是說是並行請求不同的url擷取http返回。如果往同一url請求,要麼就一次請求,要麼就分發多…… </p> <br /> <br /> 嗯,基本上都支援keep-alive了 </p> <p class="sougouAnswer"> <p class="yy"> 一路上傳不能充分利用網路資源,多路並發可使上傳速度加快 </p> <br /> <br /> 嗯,網路利用率更高 </p> <p class="sougouAnswer"> CSDN的編輯器還是沒改進,同時回複多個還需要手動複製代碼。。。 </p> <p class="sougouAnswer"> 嗯,伺服器可開多線程/進程處理你的並發上傳請求,這是快的緣故。 </p> <p class="sougouAnswer"> 只要資源夠,多開幾路並無大礙,至多大部被阻塞了,就相當於單路 <br /> 設計成多路傳輸的好處還有,當某段資料轉送失敗時,可以重傳這段。 <br /> 這是單路傳輸設計做不到的 </p> <p class="sougouAnswer"> <p class="yy"> http://cn.php.net/fsockopen <br /> CTRL + F搜尋boundary,例子好好看看,構建一個檔案上傳的http要求標頭即可,按理說CURL構建同樣的要求標頭應該也沒問題。 </p> <br /> <br /> 照著PHP手冊裡去做反而沒成功 </p> <p class="sougouAnswer"> <p class="yy"> 引用 5 樓 的回複: <br /> <br /> http://cn.php.net/fsockopen <br /> CTRL + F搜尋boundary,例子好好看看,構建一個檔案上傳的http要求標頭即可,按理說CURL構建同樣的要求標頭應該也沒問題。 <br /> <br /> <br /> 照著PHP手冊裡去做反而沒成功 </p> <br /> 是嗎?你不如用wireshark,smartsniff等工具查看http請求格式(firebug或者chrome內建的F12應該也可以),執行一次上傳檔案動作,然後觀察檔案上傳時的http請求格式。 </p> <p class="sougouAnswer"> 貼個post的socket代碼: <br /> 我測試過的備份! <br /> <br /> http://webinno.cn/blog/article/view/40 <br /> <br /> </p> <p class="sougouAnswer"> CURLOPT_HEADERFUNCTION這個參數可以設定HTTP協議回調,你可以參考下 </p> <p class="sougouAnswer"> curl只要你設定些參數,然後他自己會產生協議頭提交伺服器 </p> <p class="sougouAnswer"> 謝謝大家! </p> <p class="sougouAnswer"> 我只用過Content-Type提供下載. </p> <p class="sougouAnswer"> 不錯!!!!!! </p> <p class="sougouAnswer"> 我也要一份<li ><i class="layui-icon">