代码之家  ›  专栏  ›  技术社区  ›  Bemmu

当cURL数据>1024时,PHP HTTP POST失败

  •  12
  • Bemmu  · 技术社区  · 17 年前

    注:解决方案在末尾

    如果我尝试执行超过1024个字符的HTTP POST,它将失败。为什么?下面是一个最小的例子:

    recipient.php:

    <?php
    if (strlen(file_get_contents('php://input')) > 1000
        || strlen($HTTP_RAW_POST_DATA) > 1000) {
     echo "This was a triumph.";
    }
    ?>
    

    sender.php:

    <?php
    function try_to_post($char_count) {
     $url = 'http://gpx3quaa.joyent.us/test/recipient.php';
     $post_data = str_repeat('x', $char_count);
     $c = curl_init();
     curl_setopt_array($c,
                        array(  CURLOPT_URL => $url,
                                CURLOPT_HEADER => false,
                                CURLOPT_CONNECTTIMEOUT => 999,
                                CURLOPT_RETURNTRANSFER => true,
                                CURLOPT_POST => 1,
                                CURLOPT_POSTFIELDS => $post_data
                        )
     );
     $result = curl_exec($c);
     echo "{$result}\n";
     curl_close($c);
    }
    
    for ($i=1020;$i<1030;$i++) {
     echo "Trying {$i} - ";
     try_to_post($i);
    }
    ?>
    

    输出:

    Trying 1020 - This was a triumph.
    Trying 1021 - This was a triumph.
    Trying 1022 - This was a triumph.
    Trying 1023 - This was a triumph.
    Trying 1024 - This was a triumph.
    Trying 1025 - 
    Trying 1026 - 
    Trying 1027 - 
    Trying 1028 - 
    Trying 1029 - 
    

    配置:

    PHP Version 5.2.6
    libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3 libidn/1.8
    lighttpd-1.4.19
    

    解决方案

    为cURL添加以下选项:

    curl_setopt($ch,CURLOPT_HTTPHEADER,array("Expect:"));
    

    原因似乎是,任何超过1024个字符的POST都会导致发送“Expect:100 continue”HTTP标头,而Lighttpd 1.4.*不支持它。我找到了一个问题: http://redmine.lighttpd.net/issues/show/1017

    他们说它在1.5中工作。

    4 回复  |  直到 17 年前
        1
  •  22
  •   pilif    17 年前

    你可以通过设置一个显式的请求头来说服PHP的curl后端停止执行100-continue操作:

    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
    

    这样,您就可以发布请求,无论您想要多长时间,curl都不会进行双阶段发布。

    I have 的常用口语形式 blogged about this 大约两年前。

        2
  •  3
  •   Paul Dixon    17 年前

    第一个想法。..

    手册页 curl_setopt 关于CURLOPT_POSTFIELDS的评论

    在HTTP“post”中发布的完整数据 操作。要发布文件,请在前面添加 文件名中带有@,并使用完整路径。 这可以作为 url编码字符串 'para1=val1&para2=val2&…”或作为一个 以字段名为键的数组 字段数据作为值。"

    可能是你的值被当作是url编码的,因此看起来像一个没有值的大长名称。某个地方决定截断这个名字。

    也许你可以把它改成这样

    $post_data = "data=".str_repeat('x', $char_count);
    

    事实证明,这太容易了,问题有点深。那么,如何调试呢?

    确切了解CURL向服务器发送的内容

    另一种调试策略可能是制定一个实现相同功能的curl命令行,并让它在发出HTTP请求时输出详细信息。

    手动测试服务器

    您可以通过手动执行请求来从等式中删除服务器,例如通过telnet连接到服务器上的端口80并向其发送请求>1024个字符

    POST /test/recipient.php HTTP/1.0
    Host: gpx3quaa.joyent.us
    Content-Length:1028
    
    xxxxx(I put 1028 chars here, no point copying them all here!)
    

    我收到了这个回复

    HTTP/1.0 200 OK
    Connection: close
    Content-type: text/html; charset=UTF-8
    Content-Length: 19
    Date: Tue, 20 Jan 2009 21:35:16 GMT
    Server: lighttpd/1.4.19
    
    This was a triumph.Connection closed by foreign host.
    

    所以至少你现在知道这一切都在客户端,可能在某个地方有一些CURL选项或配置设置:(

    最终答案!

    这个问题引起了我的兴趣,所以我深入研究了

    如果你使用 CURLOPT_VERBOSE=>true ,你会看到CURL在较大的帖子上发送了一个额外的标题: Expect: 100-Continue 。你的lighttpd服务器似乎不喜欢这样。

    您可以通过强制CURL使用HTTP/1.0来阻止它这样做 CURLOPT_HTTP_VERSION=>CURL_HTTP_VERSION_1_0 在curlsetto选项数组中。

        3
  •  0
  •   Louis Louis    17 年前

    我在使用SSL v3的IIS服务器上也遇到了类似的问题。

    当CURLOPT_POSTFIELDS大于1024时,我一直收到以下cURL错误:

    52 - SSL read: error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number, errno 0
    

    添加CURLOPT_HTTPHEADER:“Expect:”为我解决了这个问题。

    非常感谢你的帖子!

        4
  •  0
  •   Furicane    15 年前

    检查是否启用了Suhosin补丁。默认情况下,它会在达到一定数量的索引后切断POST数据。您可以在Suhosin配置中绕过它。

    推荐文章