Mengatur Curl's Timeout di PHP

230

Saya menjalankan permintaan ikal pada basis data eXist melalui php. Dataset sangat besar, dan sebagai hasilnya, database secara konsisten membutuhkan waktu lama untuk mengembalikan respons XML. Untuk memperbaikinya, kami menyiapkan permintaan ikal, dengan apa yang seharusnya menjadi batas waktu yang lama.

$ch = curl_init();
$headers["Content-Length"] = strlen($postString);
$headers["User-Agent"] = "Curl/1.0";

curl_setopt($ch, CURLOPT_URL, $requestUrl);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'admin:');
curl_setopt($ch,CURLOPT_TIMEOUT,1000);
$response = curl_exec($ch);
curl_close($ch);

Namun, permintaan ikal secara konsisten berakhir sebelum permintaan selesai (<1000 ketika diminta melalui browser). Adakah yang tahu apakah ini cara yang tepat untuk mengatur batas waktu dalam ikal?

Moki
sumber

Jawaban:

346

Lihat dokumentasi: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- Jumlah detik untuk menunggu saat mencoba terhubung. Gunakan 0 untuk menunggu tanpa batas.
CURLOPT_TIMEOUT- Jumlah maksimum detik untuk memungkinkan fungsi cURL dijalankan.

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout in seconds

juga jangan lupa untuk memperbesar waktu pelaksanaan skrip php sendiri:

set_time_limit(0);// to infinity for example
msangel
sumber
13
Anda tidak perlu set_time_limit(0);jika skrip berjalan di konsol.
CONvid19
6
@PedroLobito yang Anda sebutkan adalah konfigurasi default dari php on cli, tetapi ada kemungkinan bahwa ini mungkin telah dimodifikasi.
cherouvim
4
@cherouvim jelas benar di sini (hanya berlari php -d max_execution_time=1 -r 'while(true){$r=1*1;}'atau melakukan sesuatu untuk mengamati bahwa cli tidak memiliki bendera 'selalu tak terbatas' sihir.
Wrikken
@Pedro Lobito Anda tidak perlu set_time_limit(0)jika Anda tidak menggunakannya di dalam lingkaran.
Viktor Joras
58

Hmm, menurut saya seperti CURLOPT_TIMEOUTmendefinisikan jumlah waktu yang harus dijalankan oleh setiap fungsi CURL. Saya pikir Anda harus benar-benar melihat CURLOPT_CONNECTTIMEOUTsebaliknya, karena itu memberi tahu CURL jumlah waktu maksimum untuk menunggu koneksi selesai.

Chad Birch
sumber
Sementara dokumen dalam PHP katakan CURLOPT_TIMEOUTtentang berapa lama fungsi tersebut, dokumen pustaka ikal yang mendasarinya sepertinya mengatakan itu tentang berapa lama permintaan, yang merupakan perbedaan yang menarik - tidak yakin cara membaca yang mana!
fideloper
Saya pikir di sini adalah interpretasi terbaik: stackoverflow.com/questions/27776129/…
fideloper
33

Ada kekhasan dengan ini yang mungkin relevan bagi sebagian orang ... Dari komentar PHP docs.

Jika Anda ingin cURL untuk kehabisan waktu dalam waktu kurang dari satu detik, Anda dapat menggunakan CURLOPT_TIMEOUT_MS, meskipun ada bug / "fitur" pada "Unix-like systems" yang menyebabkan libcurl segera kehabisan waktu jika nilainya <1000 ms dengan kesalahan "cURL Kesalahan (28): Batas waktu tercapai ". Penjelasan untuk perilaku ini adalah:

"Jika libcurl dibangun untuk menggunakan penyelesai nama sistem standar, bagian dari transfer itu masih akan menggunakan resolusi sepersekian detik untuk waktu habis dengan batas waktu minimum yang diizinkan satu detik."

Apa artinya ini bagi pengembang PHP adalah "Anda tidak dapat menggunakan fungsi ini tanpa mengujinya terlebih dahulu, karena Anda tidak bisa memastikan apakah libcurl menggunakan pemecah nama sistem standar (tapi Anda bisa yakin itu)"

Masalahnya adalah pada (Li | U) nix, ketika libcurl menggunakan resolver nama standar, SIGALRM dinaikkan selama resolusi nama yang menurut libcurl adalah alarm batas waktu.

Solusinya adalah menonaktifkan sinyal menggunakan CURLOPT_NOSIGNAL. Berikut ini contoh skrip yang meminta dirinya menyebabkan penundaan 10 detik sehingga Anda dapat menguji batas waktu:

if (!isset($_GET['foo'])) {
    // Client
    $ch = curl_init('http://localhost/test/test_timeout.php?foo=bar');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
    $data = curl_exec($ch);
    $curl_errno = curl_errno($ch);
    $curl_error = curl_error($ch);
    curl_close($ch);

    if ($curl_errno > 0) {
        echo "cURL Error ($curl_errno): $curl_error\n";
    } else {
        echo "Data received: $data\n";
    }
} else {
    // Server
    sleep(10);
    echo "Done.";
}

Dari http://www.php.net/manual/en/function.curl-setopt.php#104597

Simon Timur
sumber
Halo, kode ini berfungsi tetapi file sumbernya 7MB dan ini hanya 52KB untuk saya, apa yang salah? URL adalah sesuatu seperti webserver.tld / folder / download / ...
Muflix
@Simon East dapat tolong bantu saya stackoverflow.com/questions/30861112/…
Nathan Srivi
Perlu dicatat bahwa Anda mengharapkan kesalahan batas waktu dengan skrip ini
kmoney12
30

Kode Anda menetapkan batas waktu hingga 1000 detik . Untuk milidetik, gunakan CURLOPT_TIMEOUT_MS.

Matt Humphreys
sumber
13

Anda perlu memastikan batas waktu antara Anda dan file. Dalam hal ini PHP dan Curl.

Untuk memberi tahu Curl agar tidak pernah kehabisan waktu saat transfer masih aktif, Anda harus mengatur CURLOPT_TIMEOUTke 0, sebagai ganti 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

Di PHP, sekali lagi, Anda harus menghapus batas waktu atau PHP sendiri (setelah 30 detik secara default) akan mematikan skrip bersama permintaan Curl. Ini saja harus memperbaiki masalah Anda .
Selain itu, jika Anda memerlukan integritas data, Anda bisa menambahkan lapisan keamanan dengan menggunakan ignore_user_abort:

# The maximum execution time, in seconds. If set to zero, no time limit is imposed.
set_time_limit(0);

# Make sure to keep alive the script when a client disconnect.
ignore_user_abort(true);

Pemutusan klien akan mengganggu pelaksanaan skrip dan kemungkinan merusak data,
misalnya. permintaan basis data non-transisional, membangun file konfigurasi, ecc., sementara dalam kasus Anda itu akan mengunduh sebagian file ... dan Anda mungkin, atau tidak, peduli dengan hal ini.

Menjawab pertanyaan lama ini karena utas ini ada di urutan teratas pada pencarian mesin CURL_TIMEOUT.

Marco
sumber
8

Anda tidak dapat menjalankan permintaan dari browser, itu akan kehabisan waktu menunggu server menjalankan permintaan CURL untuk merespons. Browser mungkin kehabisan waktu dalam 1-2 menit, batas waktu jaringan default.

Anda perlu menjalankannya dari baris perintah / terminal.

Brent Baisley
sumber
2
+1 - batas waktu mungkin eksternal untuk curl. Anda benar-benar dapat bekerja di sekitar batas waktu browser dengan memastikan untuk mengeluarkan sesuatu secara berkala; browser umumnya mengatur ulang batas waktu mereka setiap kali mereka menerima lebih banyak data. Tapi itu retas; berjalan melalui CLI (hampir?) selalu lebih disukai.
Frank Farmer
3

Jika Anda menggunakan PHP sebagai aplikasi fastCGI maka pastikan Anda memeriksa pengaturan batas waktu fastCGI. Lihat: PHP curl put 500 error

wbinky
sumber