Heim >Backend-Entwicklung >PHP-Tutorial >200分CURL设置HTTPHEADER上传文件问题!

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

WBOY
WBOYOriginal
2016-06-23 13:52:352454Durchsuche

哪位大侠有使用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>
Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn