Подтвердить что ты не робот

PHP - зависание curl_exec

У меня возникла странная проблема с приведенной ниже функцией 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 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, поэтому я понятия не имею, с чего начать.

Я заметил, что, когда запросы на завивание "зависают", при остановке демона httpd он пытается отправить эти запросы, поэтому может показаться, что они получают буферизацию или застревание на сервере httpd. Любые указатели будут оценены.

Изменить: мне удалось получить трассировку стека из веб-сервера.

(gdb) where
#0  0x00c15416 in __kernel_vsyscall ()
#1  0x002f522c in [email protected]@GLIBC_2.3.2 () from /lib/libpthread.so.0
#2  0x00a73a9d in [email protected]@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. У кого-нибудь есть ключ? Один и тот же запрос успешно выполняется каждый раз через командную строку; поэтому он указывает на библиотеки.

Edit:

Ниже приведен вызов, из которого он никогда не выходит.

* 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

Edit: Проблема заключалась в NSS, перекомпилированном скручивании с OpenSSL и еще нескольких обручах для зависимостей (libssh2) и, похоже, до сих пор работает нормально.

Ура!

4b9b3361

Ответ 1

Проблема была NSS. Я перекомпилировал curl с OpenSSL и до сих пор не обнаружил никаких проблем.

Ура!

Ответ 2

добавьте следующее в конец script, чтобы получить причину сбоя

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

РЕДАКТИРОВАТЬ 1

Это может быть внутренняя проблема завитка. Перед проверкой все время выполнения сервера обновляется (по крайней мере, php, php-curl и apache). Проверьте все их журналы..... Затем я бы рекомендовал сравнивать результаты между несколькими производственными средами или средой dev/test.

Наконец, попробуйте сузить минимальный тестовый файл, который может воспроизвести вашу проблему и опубликовать полный код для тестового примера.

Ответ 3

Трассировка стека ясно показывает, что разрыв произошел в криптографической библиотеке NSS, созданной вашей libcurl для использования в SSL.

libcurl имеет множество исправлений, связанных с NSS, с версии libcurl, которую вы используете, и, возможно, вы не используете самую последнюю версию NSS. Я настоятельно рекомендую вам рассмотреть возможность обновления до самого последнего и самого большого, прежде чем вы вытащите все свои волосы из этой проблемы.

Чтобы отладить эту проблему, я бы рекомендовал вам попробовать повторить ее с помощью командной строки curl с того же сервера и эффективно использовать команду -trace-ascii.

Ответ 4

Вы пытались установить другую версию apache и php? Есть ли у вас в диспетчере пакетов? Если нет, попробуйте выполнить компиляцию последних apache, php и curl вручную и посмотреть, получится ли у вас тот же результат.

Ответ 5

NSS более строгая, чем OpenSSL или GnuTLS. Коррекция Fedora/RHEL по умолчанию использует NSS поверх OpenSSL и может ловить ошибки, которые не возникают с помощью curl на OSX, Ubuntu и т.д.

Здесь приведен список кодов ошибок NSS http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslerr.html

[[email protected] ~]# 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

Ответ 6

Если curl_exec зависает, это может быть из-за проблемы DNS или цикла перенаправления. Другими словами, в функции может быть ничего плохого, но с сетевым маршрутом вашего запроса. Может быть тупиком с циклом localhost. Ура!