curl不支持这种方式,你需要自己构造数据包。我研究过

解决方案 »

  1.   

    http://cn.php.net/fsockopen
    CTRL + F搜索boundary,例子好好看看,构建一个文件上传的http请求头即可,按理说CURL构建同样的请求头应该也没问题。
      

  2.   

    总结一下项目中用到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); 
      

  3.   


    貌似没看到使用了CURLOPT_HTTPHEADER
      

  4.   


    谢谢,CURL不支持这种上传方法吗?
      

  5.   

    可能是比较复杂吧,所以 curl 提供了 '@'.文件名 的方式。把构造头和数据的工作留给了自己但 curl 依然提供了 CURLOPT_UPLOAD 来表示上传文件,但实际上使用了 PUT 请求
    只适合向 ftp 上传文件
    在 php 中,要从 php://input 读取使用 #5 给出的代码,会产生 无法识别的请求 这样的错误,注释掉文件上传的那段,依然报这个错。不知是什么原因
    但对比 curl PUT 方式的数据报,似乎也没有什么差异
      

  6.   

    知道了,这样写就可以!$contents =<<< 'TEXT'
    数据报中应该是
    Content-Disposition: form-data; name="userfile"; filename="file_name"
    Content-Type: 文档类型文件内容这样的格式,我只实现了文件名部分,文档类型不知道如何实现。
    这样上传后就取不到 type 的值curl_upload_server.php
    <xmp>
    <?php
    print_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;
      

  7.   

    原来这样就有 type了$varname = 'my';
    $name = '3.txt';
    $type = 'text/plain';
    $key = <<< TEXT
    $varname"; filename="$name
    Content-Type: $typeTEXT;
    $fields[$key] = $contents;注意:我是在 win 下的,linux 下要将 \n 换成 \r\n
    没办法,早年的 sun 是拼不过 ms 的,现在也不行吧?一直以为上传的文件类型是 php 识别的,却原来是浏览器提供的
      

  8.   


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

  9.   

    #10 就是
    curl_upload_server.php 就是测试用服务器端
    <xmp>
    <?php
    print_r($_FILES);echo "文件内容:\n";
    $p = current($_FILES);
    readfile($p['tmp_name']);
      

  10.   

    本帖最后由 xuzuning 于 2012-04-10 13:19:42 编辑
      

  11.   

    http文件上传协议,主要是那个boundary,这个东西就是标识一个文件的内容和类型以及各种上传参数的token,其它和普通的POST提交也没啥区别。fsockopen来写http请求就比较直白,用curl的话模拟对应的请求头和body就好了。
    <?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;
    ?>upload.php
    <?php print_r($_FILES);?>结果
    HTTP/1.1 200 OK
    Server: nginx/0.8.54
    Date: Tue, 10 Apr 2012 05:22:01 GMT
    Content-Type: text/html
    Connection: close
    X-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
            ))
      

  12.   


    非常感谢,CURL部分的代码我这边测试成功了,我再加一百分
      

  13.   

    #14 服务器端
    #15 客户端#14 中的 $contents 是待上传的文件内容
      

  14.   

    上次好像看到你问的是一个文件切分多份,然后上传,如果是这样的话,你要要做的只是用boundary标识多个上传内容区块。比如
    $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";
      

  15.   

    to #21
    你这样做是不行的,应该使用 curl_multi 并发
    不然把一个文件拆成几个,一次性传出,再在服务器端组装。有什么意义?
      

  16.   

    说的也是哈,不过curl_multi的并发,对于请求不同的url后获取数据比较有意义,就是说是并行请求不同的url获取http返回。如果往同一url请求,要么就一次请求,要么就分发多次请求,多次请求有个性能消耗在于每次都要scoket连接/销毁,但是能控制请求字节数。
      

  17.   

    忘了如果服务器支持keep-alive的话,无需进行多次socket create,呵呵
      

  18.   


    嗯,基本上都支持keep-alive了
      

  19.   

    CSDN的编辑器还是没改进,同时回复多个还需要手动复制代码
      

  20.   


    照着PHP手册里去做反而没成功
      

  21.   

    是吗?你不如用wireshark,smartsniff等工具查看http请求格式(firebug或者chrome自带的F12应该也可以),执行一次上传文件动作,然后观察文件上传时的http请求格式。
      

  22.   

    贴个post的socket代码:
    我测试过的备份!http://webinno.cn/blog/article/view/40
      

  23.   

    CURLOPT_HEADERFUNCTION这个参数可以设置HTTP协议回调,你可以参考下
      

  24.   

    curl只要你设置些参数,然后他自己会生成协议头提交服务器