首頁 >後端開發 >php教程 >200分CURL设置HTTPHEADER上传文件问题!

200分CURL设置HTTPHEADER上传文件问题!

WBOY
WBOY原創
2016-06-23 13:52:352453瀏覽

哪位大侠有使用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<xmp><?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;

原来这样就有 type了

$varname = 'my';$name = '3.txt';$type = 'text/plain';$key = <<< TEXT$varname"; filename="$nameContent-Type: $typeTEXT;$fields[$key] = $contents;

注意:我是在 win 下的,linux 下要将 \n 换成 \r\n
没办法,早年的 sun 是拼不过 ms 的,现在也不行吧?

一直以为上传的文件类型是 php 识别的,却原来是浏览器提供的

原来这样就有 type了PHP code
$varname = 'my';
$name = '3.txt';
$type = 'text/plain';
$key =  $varname"; filename="$name
Content-Type: $type

TEXT;
$fields[$key] = $contents;


注意:我是在 win 下的,linux 下……



很感谢,有没有比较完整的CURL 通过拼接HTTPHEADER信息上传的POST示例呢?

#10 就是
curl_upload_server.php 就是测试用服务器端

<br> <?php <br /> print_r($_FILES); <br> <br> echo "文件内容:\n"; <br> $p = current($_FILES); <br> readfile($p['tmp_name']); <br> <p class="sougouAnswer"> 完整的代码 <pre class="sycode" name="code">$contents =&lt;&lt;&lt; 'TEXT'数据报中应该是Content-Disposition: form-data; name=&quot;userfile&quot;; filename=&quot;file_name&quot;Content-Type: 文档类型文件内容这样的格式以下是服务器端代码curl_upload_server.php&lt;xmp&gt;&lt;?phpprint_r($_FILES); //检查上传信息echo &quot;文件内容:\n&quot;;$p = current($_FILES);readfile($p['tmp_name']); //输出上传的文件TEXT;$varname = 'my';$name = '3.txt';$type = 'text/plain';$key = &quot;$varname\&quot;; filename=\&quot;$name\r\nContent-Type: $type\r\n&quot;;$fields[$key] = $contents;$ch = curl_init(); curl_setopt($ch, CURLOPT_URL,&quot;http://localhost/curl_upload_server.php&quot;); 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">&lt;?php//what file you want to upload$uploadFile = file_get_contents(&quot;/var/www/index.html&quot;);//content boundary $boundary = md5(time());$postStr = &quot;&quot;;$postStr .=&quot;--&quot;.$boundary.&quot;\r\n&quot;;$postStr .=&quot;Content-Disposition: form-data; name=\&quot;uptxt\&quot;; filename=\&quot;index.html\&quot;\r\n&quot;;$postStr .=&quot;Content-Type: text/html\r\n\r\n&quot;;$postStr .=$uploadFile.&quot;\r\n&quot;;$postStr .=&quot;--&quot;.$boundary.&quot;\r\n&quot;; /** use fsockopen to set upload http header and body **/$fp = fsockopen(&quot;localhost&quot;,&quot;80&quot;,$errer,$errno,1);fwrite($fp,&quot;POST /upload.php HTTP/1.0\r\n&quot;);fwrite($fp,&quot;Content-Type: multipart/form-data; boundary=&quot;.$boundary.&quot;\r\n&quot;);fwrite($fp,&quot;Content-length:&quot;.strlen($postStr).&quot;\r\n\r\n&quot;);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( &quot;Content-Type: multipart/form-data; boundary=&quot;.$boundary));curl_setopt($cl,CURLOPT_POSTFIELDS,$postStr);curl_setopt($cl,CURLOPT_RETURNTRANSFER,true);$content = curl_exec($cl);curl_close($cl);echo $content;?&gt;</pre> <br> <br> upload.php <br> <pre class="sycode" name="code">&lt;?php print_r($_FILES);?&gt;</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] =&gt; Array ( [name] =&gt; index.html [type] =&gt; text/html [tmp_name] =&gt; /tmp/phpKHfxkY [error] =&gt; 0 [size] =&gt; 344 ))Array( [uptxt] =&gt; Array ( [name] =&gt; index.html [type] =&gt; text/html [tmp_name] =&gt; /tmp/phpB0se13 [error] =&gt; 0 [size] =&gt; 344 ))</pre> <br> <br> <br> <br> </p> <p class="sougouAnswer"> </p> <p class="yy"> 完整的代码PHP code <br> $contents = 数据报中应该是 <br> Content-Disposition: form-data; name="userfile"; filename="file_name" <br> Content-Type: 文档类型 <br> <br> 文件内容 <br> <br> 这样的格式 <br> 以下是服务器端代码 <br> curl_upload_server.php <br> </p> <xmp> <br> <?php <br /> print_r(…… <br> <br> 没有client? <p class="sougouAnswer"> </p> <p class="yy"> 完整的代码PHP code <br> $contents = 数据报中应该是 <br> Content-Disposition: form-data; name="userfile"; filename="file_name" <br> Content-Type: 文档类型 <br> <br> 文件内容 <br> <br> 这样的格式 <br> 以下是服务器端代码 <br> curl_upload_server.php <br> </p> <xmp> <br> <?php <br /> print_r(…… <br> <br> 最好能分开发一下,谢谢 <p class="sougouAnswer"> </p> <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 class="sougouAnswer"> #14 服务器端 <br> #15 客户端 <br> <br> #14 中的 $contents 是待上传的文件内容 </p> <p class="sougouAnswer"> 上次好像看到你问的是一个文件切分多份,然后上传,如果是这样的话,你要要做的只是用boundary标识多个上传内容区块。比如 <br> <pre class="sycode" name="code">$boundary = md5(time());$postStr = &quot;&quot;;$postStr .=&quot;--&quot;.$boundary.&quot;\r\n&quot;;$postStr .=&quot;Content-Disposition: form-data; name=\&quot;uptxt[]\&quot;; filename=\&quot;index_1.html\&quot;\r\n&quot;;$postStr .=&quot;Content-Type: text/html\r\n\r\n&quot;;$postStr .=$uploadFile.&quot;\r\n&quot;; #这里是部分文件内容$postStr .=&quot;--&quot;.$boundary.&quot;\r\n&quot;;$postStr .=&quot;--&quot;.$boundary.&quot;\r\n&quot;;$postStr .=&quot;Content-Disposition: form-data; name=\&quot;uptxt[]\&quot;; filename=\&quot;index_2.html\&quot;\r\n&quot;; $postStr .=&quot;Content-Type: text/html\r\n\r\n&quot;;$postStr .=$uploadFile.&quot;\r\n&quot;;#这里是部分文件内容$postStr .=&quot;--&quot;.$boundary.&quot;\r\n&quot;;</pre> <br> </p> <p class="sougouAnswer"> 收藏了! </p> <p class="sougouAnswer"> to #21 <br> 你这样做是不行的,应该使用 curl_multi 并发 <br> 不然把一个文件拆成几个, 一次性传出,再在服务器端组装。有什么意义? <br> </p> <p class="sougouAnswer"> </p> <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 class="sougouAnswer"> </p> <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 class="sougouAnswer"> </p> <p class="yy"> to #21 <br> 你这样做是不行的,应该使用 curl_multi 并发 <br> 不然把一个文件拆成几个,一次性传出,再在服务器端组装。有什么意义? </p> <br> 说的也是哈,不过curl_multi的并发,对于请求不同的url后获取数据比较有意义,就是说是并行请求不同的url获取http返回。如果往同一url请求,要么就一次请求,要么就分发多次请求,多次请求有个性能消耗在于每次都要scoket连接/销毁,但是能控制请求字节数。 <p class="sougouAnswer"> </p> <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 class="sougouAnswer"> 一路上传不能充分利用网络资源,多路并发可使上传速度加快 <br> </p> <p class="sougouAnswer"> </p> <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 class="sougouAnswer"> </p> <p class="yy"> 一路上传不能充分利用网络资源,多路并发可使上传速度加快 </p> <br> <br> 嗯,网络利用率更高 <p class="sougouAnswer"> CSDN的编辑器还是没改进,同时回复多个还需要手动复制代码。。。 </p> <p class="sougouAnswer"> 嗯,服务器可开多线程/进程处理你的并发上传请求,这是快的缘故。 </p> <p class="sougouAnswer"> 只要资源够,多开几路并无大碍,至多大部被阻塞了,就相当于单路 <br> 设计成多路传输的好处还有,当某段数据传输失败时,可以重传这段。 <br> 这是单路传输设计做不到的 </p> <p class="sougouAnswer"> </p> <p class="yy"> http://cn.php.net/fsockopen <br> CTRL + F搜索boundary,例子好好看看,构建一个文件上传的http请求头即可,按理说CURL构建同样的请求头应该也没问题。 </p> <br> <br> 照着PHP手册里去做反而没成功 <p class="sougouAnswer"> </p> <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 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"> 我也要一份 </p>
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn