【问题标题】:PHP - curl_exec hangsPHP - curl_exec 挂起
【发布时间】:2011-09-12 14:58:22
【问题描述】:

我对下面的 php 函数有一个奇怪的问题。不幸的是,这是那些特殊的“仅限生产”案例之一。

function requestPost($url, $data)
{
        set_time_limit(60);
        $output = array();
        $curlSession = curl_init();

        if($curlSession == false)
                syslog(LOG_INFO,"Falied to create a curl sessions");

        // Set the URL
        curl_setopt ($curlSession, CURLOPT_URL, $url);
        // No headers, please
        curl_setopt ($curlSession, CURLOPT_HEADER, 0);
        // It's a POST request
        curl_setopt ($curlSession, CURLOPT_POST, 1);
        // Set the fields for the POST
        curl_setopt ($curlSession, CURLOPT_POSTFIELDS, $data);
        // Return it direct, don't print it out
        curl_setopt($curlSession, CURLOPT_RETURNTRANSFER,1);
        // This connection will timeout in 30 seconds
        curl_setopt($curlSession, CURLOPT_TIMEOUT,30);
        //The next two lines must be present for the kit to work with newer version of cURL
        //You should remove them if you have any problems in earlier versions of cURL
        curl_setopt($curlSession, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curlSession, CURLOPT_SSL_VERIFYHOST, 1);

        //Send the request and store the result in an array
        syslog(LOG_INFO,"base.php::requestPost() :  BEFORE SENDING CURL ");

        $rawresponse = curl_exec($curlSession);

}
PHP 5.3.6 (cli) (built: Mar 17 2011 21:19:28) 
curl Version          : 7.20.1
NSS Version           : 3.12.9
apr Version           : 1.4.5
Php Version           : 5.3.6

这似乎随机挂在 curl_exec 上。我不是 php 开发人员,所以我不知道从哪里开始。

我注意到,当 curl 请求“挂起”时,在停止 httpd 守护程序时它会尝试发送这些请求,因此它们可能会被缓冲或卡在 httpd 服务器中。任何指针将不胜感激。

编辑:我设法从 Web 服务器中获取堆栈跟踪。

(gdb) where
#0  0x00c15416 in __kernel_vsyscall ()
#1  0x002f522c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libpthread.so.0
#2  0x00a73a9d in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libc.so.6
#3  0x00b9b869 in PR_WaitCondVar () from /lib/libnspr4.so
#4  0x00809c0f in NSSRWLock_LockWrite_Util () from /usr/lib/libnssutil3.so
#5  0x05e9ae0e in ?? () from /usr/lib/libnss3.so
#6  0x05ebd014 in ?? () from /usr/lib/libnss3.so
#7  0x05ebd60d in ?? () from /usr/lib/libnss3.so
#8  0x05eb0506 in SECMOD_LoadModule () from /usr/lib/libnss3.so
#9  0x05eb047f in SECMOD_LoadModule () from /usr/lib/libnss3.so
#10 0x05e7c007 in ?? () from /usr/lib/libnss3.so
#11 0x05e7c95e in NSS_Initialize () from /usr/lib/libnss3.so
#12 0x008e8609 in ?? () from /usr/lib/libcurl.so.4
#13 0x008e9215 in Curl_nss_connect () from /usr/lib/libcurl.so.4
#14 0x008df9a3 in Curl_ssl_connect () from /usr/lib/libcurl.so.4
#15 0x008bc1fa in Curl_http_connect () from /usr/lib/libcurl.so.4
#16 0x008c44c6 in Curl_protocol_connect () from /usr/lib/libcurl.so.4
#17 0x008c5075 in ?? () from /usr/lib/libcurl.so.4
#18 0x008c58cf in Curl_async_resolved () from /usr/lib/libcurl.so.4
#19 0x008d1b2f in Curl_perform () from /usr/lib/libcurl.so.4
#20 0x008d2a74 in curl_easy_perform () from /usr/lib/libcurl.so.4
#21 0x006b4693 in ?? () from /usr/lib/php/modules/curl.so
#22 0x056e4ac9 in ?? () from /etc/httpd/modules/libphp5.so
#23 0x056bb87e in execute () from /etc/httpd/modules/libphp5.so
#24 0x05693a66 in zend_execute_scripts () from /etc/httpd/modules/libphp5.so
#25 0x05639cb6 in php_execute_script () from /etc/httpd/modules/libphp5.so
#26 0x057236b3 in ?? () from /etc/httpd/modules/libphp5.so
#27 0x00dc6421 in ap_run_handler ()
#28 0x00dca166 in ap_invoke_handler ()
#29 0x00dd6fa8 in ap_process_request ()
#30 0x00dd39e8 in ?? ()
#31 0x00dcec71 in ap_run_process_connection ()
#32 0x00ddc44a in ?? ()
#33 0x00ddc7ee in ?? ()
#34 0x00ddd793 in ap_mpm_run ()
#35 0x00db0ab2 in main ()

它似乎陷入了 pthread_condition 等待状态。有人有线索吗 ? 通过命令行每次都成功执行相同的请求;所以它确实指向图书馆。

编辑:

以下是它永远不会发出的呼叫。

* About to connect() to live.sagepay.com port 443 (#0)
*   Trying x.x.x.x... * connected
* Connected to live.sagepay.com (x.x.x.x) port 443 (#0)
* warning: ignoring unsupported value (1) of ssl.verifyhost
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using SSL_RSA_WITH_RC4_128_MD5
* Server certificate:
*       subject: CN=live.sagepay.com,OU="Member, VeriSign Trust Network",OU=Authenticated by VeriSign,OU=Terms of use at www.verisign.co.uk/rpa (c)05,OU=Sage,O=Sage (UK) Limited,L=Newcastle Upon Tyne,ST=TYNE AND WEAR,C=GB,serialNumber=x.x.x,OID.x.x.x=Private Organization,OID.x.x.x.x=GB
*       start date: Mar 05 00:00:00 2011 GMT
*       expire date: Mar 04 23:59:59 2013 GMT
*       common name: live.sagepay.com
*       issuer: CN=VeriSign Class 3 Extended Validation SSL SGC CA,OU=Terms of use at https://www.verisign.com/rpa (c)06,OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US
> POST /gateway/service/vspserver-register.vsp HTTP/1.1^M
Host: live.sagepay.com^M
Accept: */*^M
Content-Length: 664^M
Content-Type: application/x-www-form-urlencoded^M
^M
< HTTP/1.1 200 OK^M
< Date: Wed, 15 Jun 2011 16:11:43 GMT^M
< Server: Microsoft-IIS/6.0^M
< X-Powered-By: ASP.NET^M
< Content-Language: en-GB^M
< Content-Length: 276^M
< Set-Cookie: NSC_wjq-tbhfqbz-dpn-ofx=xxxx;expires=Wed, 15-Jun-2011 16:48:26 GMT;path=/;secure;httponly^M
< ^M
* Connection #0 to host live.sagepay.com left intact

编辑: 问题出在 NSS 上,使用 OpenSSL 重新编译 curl 和一些依赖项(libssh2),到目前为止它似乎工作正常。

干杯!

【问题讨论】:

  • 你连接的是什么网址?如果您正在访问动态页面,您可能只是在等待远程服务器创建和提供内容。
  • 它指向一个电子商务供应商,如贝宝。这是一个 https 链接。
  • 在您停止守护进程之前进程会挂起多长时间?你说它随机挂起,你的意思是某些网址不挂起,还是某些帖子数据不挂起?或者,给定相同的 url 和数据,有时会挂起,有时会成功?
  • 嗨,本,很抱歉延迟回来。它随机挂起相同的数据/网址。成功时的响应是即时的。

标签: php curl libcurl apache


【解决方案1】:

如果curl_exec 挂起,则可能是由于 DNS 问题或重定向循环。也就是说,功能可能没有问题,但是你请求的网络路由没有问题。可能是 localhost 循环的死锁。 干杯!

【讨论】:

    【解决方案2】:

    NSS 比 OpenSSL 或 GnuTLS 更严格。 Fedora/RHEL curl 默认使用 NSS over OpenSSL,并且可以捕获在 OSX、Ubuntu 等上使用 curl 不会出现的错误。

    这里是 NSS 错误代码列表http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslerr.html

    [root@mybox ~]# curl -k -v -E /etc/mycert.pem https://127.0.0.1/
    * About to connect() to 127.0.0.1 port 443 (#0)
    *   Trying 127.0.0.1... connected
    * Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
    * Initializing NSS with certpath: sql:/etc/pki/nssdb
    * warning: ignoring value of ssl.verifyhost
    * NSS error -8054
    * Closing connection #0
    * SSL connect error
    curl: (35) SSL connect error
    

    【讨论】:

      【解决方案3】:

      问题是 NSS。我用 OpenSSL 重新编译了 curl,到目前为止它没有显示任何问题。

      干杯!

      【讨论】:

        【解决方案4】:

        您是否尝试过安装不同版本的 apache 和 php?你在包管理器中有它们吗?如果没有,尝试手动编译最新的apache、php和curl,看看是否得到相同的结果。

        【讨论】:

        • 这也是我打算做的事情,我尝试了一些可以让我安全降级的存储库,在 httpd 的情况下,链条很深,可以玩。谢谢!
        • 螺丝二进制文件。手动编译它们。
        • 不幸的是,我上次使用 httpd 做同样事情的经历并不顺利,但是是的,现在似乎是时候拿起武器了 :)
        【解决方案5】:

        堆栈跟踪清楚地表明,您在构建 libcurl 以用于 SSL 的 NSS 加密库中确实发生了中断。

        自从您使用 libcurl 版本以来,libcurl 已经获得了许多与 NSS 相关的修复,并且您可能也没有使用最新的 NSS。我强烈建议您在解决这个问题之前考虑升级到最新最好的版本。

        要调试此问题,我建议您尝试使用同一服务器的 curl 命令行重复此问题,并充分利用 --trace-ascii 命令。

        【讨论】:

        • 感谢您的回复。不幸的是,我已经为 FC 13 更新了所有库。我实际上正在考虑降级 :( 每次都通过命令行成功请求相同的请求,因此它确实指出了其中一个依赖库。
        • 我宁愿说它指向 PHP 环境中的某些东西,因为命令行工具使用相同的 libcurl 和 NSS 库...
        • 这是一条至关重要的信息。干杯!将尝试降级 php 并与它搏斗。
        • 线路面临严重丢包是否会导致此类问题?据我了解,高层应该负责重新传输..干杯!
        【解决方案6】:

        在脚本末尾添加以下内容以获取失败原因

        if( $rawresponse === false )
            syslog( LOG_INFO , "base.php::requestPost() : ".curl_error($curlSession) );
        

        编辑 1

        这可能是 curl 的内部问题。首先检查所有服务器运行时是否是最新的(至少是 php、php-curl 和 apache)。检查他们所有的日志...... 然后我会建议比较几个生产环境或开发/测试环境之间的结果。

        最后尝试缩小可以重现您的问题的最小测试用例并发布测试用例的完整代码。

        【讨论】:

        • 不幸的是,它根本不是来自 curl_exec 调用。有没有办法调试函数本身?作为生产环境;我可能缺少几个选项。
        • 我不知道有什么方法可以调试 libcurl 的内部,除了低级 C 调试。请参阅上面的更新。您也可以尝试网络跟踪(wireshark 或 tcpdump),但我怀疑它会解决您的问题。
        • 不幸的是,这只是生产环境中的“罕见”之一。我试图将我能想到的单个库同步。
        猜你喜欢
        • 2011-10-09
        • 1970-01-01
        • 2013-07-19
        • 2015-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-11
        相关资源
        最近更新 更多