2008-09-25 164 views
28

我熟悉一些基礎知識,但是我想知道更多關於什麼時候以及爲什麼應該在PHP中使用錯誤處理(包括拋出異常),特別是在活動網站或Web上應用程序。是否可以過度使用,如果是這樣,過度使用是什麼樣子?有沒有不應該使用它的情況?另外,在錯誤處理方面有哪些常見的安全問題?在PHP中處理錯誤

回答

29

有一件事要說,已經說了什麼是最重要的是,你在你的web應用程序中記錄任何錯誤到日誌中。這樣,正如傑夫「編碼恐怖」阿特伍德所建議的那樣,您會知道用戶何時遇到了應用程序問題(而不是「問他們出了什麼問題」)。

要做到這一點,我建議以下類型的基礎設施:

  • 在數據庫中創建一個「崩潰」表和報告錯誤一組包裝類。我建議設置崩潰類別(「阻塞」,「安全」,「PHP錯誤/警告」(與例外)等)。
  • 在所有錯誤處理代碼中,請確保記錄錯誤。一直這樣做取決於你如何建立API(上面的步驟) - 它應該是微不足道的記錄崩潰,如果做得對。

附加題:有時候,你的崩潰將是數據庫級的崩潰:即DB服務器關閉等,如果是這樣的話,你的錯誤日誌基礎設施(上圖)將失敗(您不能崩潰日誌以因爲日誌會嘗試寫入數據庫)。在這種情況下,我會寫故障轉移邏輯在你崩潰包裝類要麼

  • 發送電子郵件給管理員和/或
  • 記錄崩潰的細節,一個純文本文件

所有這些聽起來都像是過火,但相信我,這會影響您的應用程序是否被接受爲「穩定」或「片狀」。這種差異來自於所有應用程序始終如故/崩潰的事實,但那些瞭解應用程序所有問題的開發人員有機會實際修復它。

2

無影響的錯誤會停止腳本,這是一個很好的理由來處理它們。

一般來說,你可以使用try-catch塊來處理錯誤

try 
{ 
    // Code that may error 
} 
catch (Exception $e) 
{ 
    // Do other stuff if there's an error 
} 

如果你想停止出現在頁面上的錯誤或警告消息,那麼你可以像這樣一個@符號前綴通話。

@mysql_query($query); 

使用查詢但它通常是一個好主意,做這樣的事情,所以你有什麼事情的一個更好的主意。

@mysql_query($query) 
    or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />'); 
+2

雖然沒有使用mysql_error()函數存在安全風險? – VirtuosiMedia 2008-09-25 16:39:49

+1

向用戶輸出mysql_error有潛在的風險。 – 2008-09-25 16:47:54

+0

您可以在您的Web應用程序中設置一個標誌,以確定您處於測試環境還是生產環境中;在生產中,不要顯示錯誤,只需記錄它。在測試中,做兩個。 – 2008-09-25 19:19:29

1

不是輸出mysql_error,而是將其存儲在日誌中。這樣您就可以跟蹤錯誤(並且您不依賴用戶報告錯誤),並且可以進入並清除問題。

最好的錯誤處理是對用戶透明的那種,讓你的代碼理清問題,不需要涉及那個用戶傢伙。

2

如果您沒有顯式控制腳本正在處理的數據,則應該使用錯誤處理。我傾向於經常在例如表單驗證等地方使用它。知道如何在代碼中發現容易出錯的地方需要一些練習:一些常見的是在函數調用之後返回一個值,或者在處理來自數據庫查詢的結果時。你絕不應該假設函數的返回將會是你的期望,你應該確保按照預期編寫代碼。你不必使用try/catch塊,儘管它們很有用。很多時候你可以通過簡單的if/else檢查來獲得。

錯誤處理與安全編碼實踐密切相關,因爲存在大量「錯誤」,不會導致腳本簡單崩潰。儘管本身並不嚴格處理錯誤處理,但增加的字節有很多關於安全PHP編程基礎知識的4篇文章系列,您可以找到HERE。在這裏,還有很多其他的問題在關於如mysql_real_escape_stringRegular Expressions這些主題的stackoverflow,這可以非常強大的確認用戶輸入的數據的內容。

1

除了處理錯誤,在你的代碼的時候了,你還可以利用

http://us.php.net/manual/en/function.set-exception-handler.php

http://us.php.net/manual/en/function.set-error-handler.php

我發現,設置自己的異常處理程序特別有用。發生異常時,您可以根據異常類型執行不同的操作。

例如:當mysql_connet調用返回FALSE我拋出一個new DBConnectionException(mysql_error())和處理這是一個「特殊」的方式:記錄錯誤,數據庫連接信息(主機,用戶名,密碼)等,甚至電子郵件的開發團隊,通知他們那些數據庫可能真的有問題

我使用它來補充標準錯誤處理。我不會推薦過度使用這種方法

2

最好的做法恕我直言是使用以下方法:1。 創建錯誤/異常處理程序 2,開始它在應用程序從內有

<?php 
啓動 3.處理所有的錯誤

類調​​試{

public static setAsErrorHandler() { 
     set_error_handler(array(__CLASS__, '__error_handler')); 
    } 

public static function __error_handler($errcode, $errmsg, $errfile, $errline) { 
     if (IN DEV) { 
       print on screen 
      } 
      else if (IN PRO) { 
       log and mail 
      } 
    } 

}

調試:: setAsErrorHandler();

?>

22

粗略地說,錯誤是在PHP中的遺留問題,而例外的是對待錯誤的現代生活方式。最簡單的事情就是設置一個錯誤處理程序,它會拋出一個異常。這樣所有的錯誤都被轉換爲異常,然後你可以簡單地處理一個錯誤處理方案。以下代碼將爲您的錯誤轉換爲例外:

function exceptions_error_handler($severity, $message, $filename, $lineno) { 
    if (error_reporting() == 0) { 
    return; 
    } 
    if (error_reporting() & $severity) { 
    throw new ErrorException($message, 0, $severity, $filename, $lineno); 
    } 
} 
set_error_handler('exceptions_error_handler'); 
error_reporting(E_ALL^E_STRICT); 

儘管有幾種情況,其中代碼是專門設計用於處理錯誤的。例如,在驗證文檔時,schemaValidate method of DomDocument會引發警告。如果您將錯誤轉換爲異常,它將在第一次失敗後停止驗證。有時這是你想要的,但是在驗證文檔時,你可能實際上想要全部失敗。在這種情況下,您可以臨時安裝收集錯誤的錯誤處理程序。這裏有一個小片段,我已經用於上述用途:

class errorhandler_LoggingCaller { 
    protected $errors = array(); 
    function call($callback, $arguments = array()) { 
    set_error_handler(array($this, "onError")); 
    $orig_error_reporting = error_reporting(E_ALL); 
    try { 
     $result = call_user_func_array($callback, $arguments); 
    } catch (Exception $ex) { 
     restore_error_handler(); 
     error_reporting($orig_error_reporting); 
     throw $ex; 
    } 
    restore_error_handler(); 
    error_reporting($orig_error_reporting); 
    return $result; 
    } 
    function onError($severity, $message, $file = null, $line = null) { 
    $this->errors[] = $message; 
    } 
    function getErrors() { 
    return $this->errors; 
    } 
    function hasErrors() { 
    return count($this->errors) > 0; 
    } 
} 

和用例:

$doc = new DomDocument(); 
$doc->load($xml_filename); 
$validation = new errorhandler_LoggingCaller(); 
$validation->call(
    array($doc, 'schemaValidate'), 
    array($xsd_filename)); 
if ($validation->hasErrors()) { 
    var_dump($validation->getErrors()); 
} 
1

用@屏蔽錯誤是非常緩慢的。

0

您還可以使用Google表單來捕獲和分析異常,而無需維護數據庫或公共可訪問的服務器。有一個教程here,解釋過程。