2013-04-14 76 views
4

我想在我的錯誤處理程序中捕獲curl錯誤和警告,以便它們不會將echo編輯給用戶。爲了證明所有的錯誤已經被捕獲,我把$err_start字符串添加到錯誤中。目前這裏是工作(但是簡化)片段的我的代碼(在瀏覽器中運行它,而不是CLI):php curl多錯誤處理程序

<?php 
set_error_handler('handle_errors'); 
test_curl(); 
function handle_errors($error_num, $error_str, $error_file, $error_line) 
{   
    $err_start = 'caught error'; //to prove that the error has been properly caught 
    die("$err_start $error_num, $error_str, $error_file, $error_line<br>"); 
}   
function test_curl() 
{ 
    $curl_multi_handle = curl_multi_init(); 
    $curl_handle1 = curl_init('iamdooooooooooown.com'); 
    curl_setopt($curl_handle1, CURLOPT_RETURNTRANSFER, true); 
    curl_multi_add_handle($curl_multi_handle, $curl_handle1); 
    $still_running = 1; 
    while($still_running > 0) $multi_errors = curl_multi_exec($curl_multi_handle, $still_running); 
    if($multi_errors != CURLM_OK) trigger_error("curl error [$multi_errors]: ".curl_error($curl_multi_handle), E_USER_ERROR); 
    if(strlen(curl_error($curl_handle1))) trigger_error("curl error: [".curl_error($curl_handle1)."]", E_USER_ERROR); 
    $curl_info = curl_getinfo($curl_handle1); //info for individual requests 
    $content = curl_multi_getcontent($curl_handle1); 
    curl_multi_remove_handle($curl_multi_handle, $curl_handle1); 
    curl_close($curl_handle1); 
    curl_multi_close($curl_multi_handle); 
} 
?> 

注意,我完整的代碼有多個並行的請求,但問題仍然用單表現請求如下所示。還要注意,這個代碼片段中顯示的錯誤處理程序是非常基本的 - 我的實際錯誤處理程序不會死在警告或通知上,所以沒有必要在此上學。

現在,如果我嘗試和捲曲主機是目前下跌的話,我成功地捕捉到捲曲的錯誤,我的腳本死:

caught error 256, curl error: [Couldn't resolve host 'iamdooooooooooown.com'], /var/www/proj/test_curl.php, 18 

但是下面的警告沒有被我的錯誤處理函數抓住,正在echo版頁面:

Warning: (null)(): 3 is not a valid cURL handle resource in Unknown on line 0 

我想捕捉到了這個警告在我的錯誤處理程序,這樣我就可以登錄以備日後檢查。

我注意到的一件事是,當curl代碼在函數內部時,警告只會顯示 - 當代碼處於最高範圍級別時,它不會發生。是否有可能在test_curl()函數的範圍內無法訪問其中一個捲曲全局變量(例如CURLM_OK)?

我使用PHP版本5.3.2-1ubuntu4.19

編輯

  • 更新的代碼段充分展示了錯誤
  • 未捕獲的警告僅體現在內部函數或類的方法
+0

你有Xdebug的用'xdebug.scream'設置啓用? –

+0

我不這麼認爲。這是否比'set_error_handler()'捕獲更多的錯誤? – mulllhausen

+0

看看[這個答案](http://stackoverflow.com/questions/10331084/error-logging-in-a-smooth-way/10476589#10476589)。它可能有幫助。 –

回答

7

我不認爲我同意你捕捉錯誤的方式......你可以嘗試

$nodes = array(
     "http://google.com", 
     "http://iamdooooooooooown.com", 
     "https://gokillyourself.com" 
); 

echo "<pre>"; 
print_r(multiplePost($nodes)); 

輸出

Array 
(
    [google.com] => #HTTP-OK 48.52 kb returned 
    [iamdooooooooooown.com] => #HTTP-ERROR 0 for : http://iamdooooooooooown.com 
    [gokillyourself.com] => #HTTP-ERROR 0 for : https://gokillyourself.com 
) 

功能用於

function multiplePost($nodes) { 
    $mh = curl_multi_init(); 
    $curl_array = array(); 
    foreach ($nodes as $i => $url) { 
     $url = trim($url); 
     $curl_array[$i] = curl_init($url); 
     curl_setopt($curl_array[$i], CURLOPT_RETURNTRANSFER, true); 
     curl_setopt($curl_array[$i], CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)'); 
     curl_setopt($curl_array[$i], CURLOPT_CONNECTTIMEOUT, 5); 
     curl_setopt($curl_array[$i], CURLOPT_TIMEOUT, 15); 
     curl_setopt($curl_array[$i], CURLOPT_FOLLOWLOCATION, true); 
     curl_setopt($curl_array[$i], CURLOPT_SSL_VERIFYHOST, 0); 
     curl_setopt($curl_array[$i], CURLOPT_SSL_VERIFYPEER, 0); 
     curl_multi_add_handle($mh, $curl_array[$i]); 
    } 
    $running = NULL; 
    do { 
     usleep(10000); 
     curl_multi_exec($mh, $running); 
    } while ($running > 0); 
    $res = array(); 

    foreach ($nodes as $i => $url) { 
     $domain = parse_url($url, PHP_URL_HOST); 
     $curlErrorCode = curl_errno($curl_array[$i]); 
     if ($curlErrorCode === 0) { 
      $info = curl_getinfo($curl_array[$i]); 
      $info['url'] = trim($info['url']); 
      if ($info['http_code'] == 200) { 
       $content = curl_multi_getcontent($curl_array[$i]); 
       $res[$domain] = sprintf("#HTTP-OK %0.2f kb returned", strlen($content)/1024); 
      } else { 
       $res[$domain] = "#HTTP-ERROR {$info['http_code'] } for : {$info['url']}"; 
      } 
     } else { 
      $res[$domain] = sprintf("#CURL-ERROR %d: %s ", $curlErrorCode, curl_error($curl_array[$i])); 
     } 
     curl_multi_remove_handle($mh, $curl_array[$i]); 
     curl_close($curl_array[$i]); 
     flush(); 
     ob_flush(); 
    } 
    curl_multi_close($mh); 
    return $res; 
} 
+0

謝謝!我顯然期待一個下來的主機返回一個curl錯誤,但正如你的代碼所示,有一個http錯誤,但沒有curl錯誤。根據你的代碼,'curl_error()'只有在curl_errno()不返回'0'時才能被調用。否則'curl_error()似乎打印出不能被抑制的警告。奇怪的是,當主機關閉時,'curl_errno()'不返回52(CURLE_GOT_NOTHING)。乾杯! – mulllhausen

1

有可能這是一個使用php-curl的bug。當以下行被刪除,那麼一切都OK的行爲:

if(strlen(curl_error($curl_handle1))) trigger_error("curl error: [".curl_error($curl_handle1)."]", E_USER_ERROR); 

據我所知,荷蘭國際集團curl主機已關閉以某種方式將curl_error()功能沒有準備被破壞$curl_handle1。爲了解決這個問題(直到修復bug),只需測試curl_getinfo()返回的http_code是否爲0。如果是0則不要使用curl_error功能:

if($multi_errors != CURLM_OK) trigger_error("curl error [$multi_errors]: ".curl_error($curl_multi_handle), E_USER_ERROR); 
$curl_info = curl_getinfo($curl_handle1); //info for individual requests 
$is_up = ($curl_info['http_code'] == 0) ? 0 : 1; 
if($is_up && strlen(curl_error($curl_handle1))) trigger_error("curl error: [".curl_error($curl_handle1)."]", E_USER_ERROR); 

,它不是一個很優雅的解決方案,但它可能對現在要做的。