給新手的建議:這個函式與「tail」搭配使用效果很好,tail 是一個 Unix 指令,可以即時監看日誌檔。Windows 也有 Tail 的版本,例如 Tail for Win32 或 Kiwi Log Viewer。
同時使用 error_log() 和 tail 來檢視 php_error.log,您就可以在除錯程式碼時不必太擔心除錯訊息會顯示在螢幕上,以及可能會被誰看到。
進一步說明:當您設定了兩個螢幕時,效果會更好。一個用於瀏覽器和 IDE,另一個用於即時檢視日誌檔的更新。
(PHP 4, PHP 5, PHP 7, PHP 8)
error_log — 傳送錯誤訊息到已定義的錯誤處理常式
$message
,$message_type
= 0,$destination
= null
,$additional_headers
= null
將錯誤訊息傳送到網路伺服器的錯誤日誌或檔案。
message
應記錄的錯誤訊息。
message_type
指定錯誤訊息的傳送位置。可能的訊息類型如下:
0 |
message 會被傳送到 PHP 的系統記錄器,使用作業系統的系統記錄機制或檔案,具體取決於 error_log 設定指令的設定。這是預設選項。 |
1 |
message 會以電子郵件的形式傳送到 destination 參數指定的地址。這是唯一使用第四個參數 additional_headers 的訊息類型。 |
2 | 不再是一個選項。 |
3 |
message 會被附加到檔案 destination 。系統不會自動在 message 字串的結尾新增換行符號。 |
4 |
message 會直接傳送到 SAPI 記錄處理程式。 |
destination
目的地。其含義取決於 message_type
參數,如上所述。
additional_headers
額外的標頭。當 message_type
參數設定為 1
時使用。此訊息類型使用與 mail() 相同的內部函式。
版本 | 說明 |
---|---|
8.0.0 |
destination 和 additional_headers 現在可以為 null。 |
範例 #1 error_log() 範例
<?php
// 如果無法連線到資料庫,則透過伺服器日誌發送通知。
if (!Ora_Logon($username, $password)) {
error_log("Oracle 資料庫無法使用!", 0);
}
// 如果 FOO 用盡,則透過電子郵件通知管理員
if (!($foo = allocate_new_foo())) {
error_log("嚴重問題,FOO 已用盡!", 1,
"operator@example.com");
}
// 呼叫 error_log() 的另一種方式:
error_log("您出錯了!", 3, "/var/tmp/my-errors.log");
?>
error_log() 不是二進位安全的。 message
將會被空字元截斷。
message
不應包含空字元。請注意,message
可能會被送到檔案、郵件、系統日誌等。在呼叫 error_log() 之前,請使用適當的轉換/跳脫函式,例如 base64_encode()、rawurlencode() 或 addslashes()。
給新手的建議:這個函式與「tail」搭配使用效果很好,tail 是一個 Unix 指令,可以即時監看日誌檔。Windows 也有 Tail 的版本,例如 Tail for Win32 或 Kiwi Log Viewer。
同時使用 error_log() 和 tail 來檢視 php_error.log,您就可以在除錯程式碼時不必太擔心除錯訊息會顯示在螢幕上,以及可能會被誰看到。
進一步說明:當您設定了兩個螢幕時,效果會更好。一個用於瀏覽器和 IDE,另一個用於即時檢視日誌檔的更新。
不要嘗試在 error_log() 中輸出過大的文字;
如果您嘗試輸出大量的文字,它會在大約 8000 個字元處截斷文字(對於合理的大量字串,< 32K 個字元),或者(對於極其大量的字串,大約 160 萬個字元)完全當機,甚至不會拋出任何錯誤(我甚至將它放在 try/catch 中,也沒有從 catch 中得到任何結果)。
我在嘗試除錯 `wp_remote_get();` 的回應時遇到了這個問題,我所有的 `error_log()` 都正常運作,除了一個... (-_-)
經過大約一天的除錯,我終於找到了原因,這就是我寫這篇文章的原因。
顯然回應的內容超過 160 萬個字元(或位元組?(無論 `strlen()` 返回什麼))。
如果您有一個長度未知的字串,請使用以下方法
`$start_index = 0;`
`$end_index = 8000;`
`error_log( substr( $output_text , $start_index , $end_index ) );`
`$message` 參數的最大長度有限制。
預設值似乎是 1024,但可以透過調整執行時設定值 `'log_errors_max_len'` 來更改。
更多細節請參考這裡
https://php.dev.org.tw/manual/en/errorfunc.configuration.php
注意!如果多個腳本共用同一個日誌檔,但以不同的使用者身分執行,則首先記錄錯誤的腳本將擁有該檔案,而以不同使用者身分執行的 `error_log()` 呼叫將*無聲無息地*失敗!
沒有比試圖找出為什麼所有 `error_log` 呼叫實際上都沒有寫入,結果卻發現是由於*無聲無息的*權限被拒絕錯誤更令人沮喪的事情了!
如果您從命令列執行 PHP,系統日誌似乎是 stderr,而且 stderr 通常是 stdout。這表示如果您使用自訂錯誤同時顯示錯誤並將其記錄到系統日誌,則命令列使用者將會看到相同的錯誤報告兩次。
訊息類型 3 接受相對路徑作為目的地,但要注意的是,根目錄是由呼叫 `error_log()` 的上下文決定的,而上下文可能會改變,因此程式碼中的一個 `error_log()` 實例可能會導致在不同位置建立多個日誌檔。
在 WordPress 環境中,根目錄在許多情況下會是網站的根目錄,但在 AJAX 呼叫中會是 `/wp-admin/`,而在其他情況下會是外掛程式的目錄。如果您希望所有輸出都寫入同一個檔案,請使用絕對路徑。
當使用 `error_log` 發送電子郵件時,並非所有 `extra_headers` 字串的元素都以相同的方式處理。「From:」和「Reply-To:」標頭值將會取代預設的標頭值。「Subject:」標頭值則不會:它們會被*新增*到郵件標頭中,但不會取代預設值,導致郵件訊息具有兩個「Subject」欄位。
<?php
error_log("sometext", 1, "zigzag@my.domain",
"Subject: Foo\nFrom: Rizzlas@my.domain\n");
?>
---------------%<-----------------------
收件者:zigzag@my.domain
信封收件者:zigzag@my.domain
日期:2003 年 3 月 28 日,星期五,13:29:02 -0500
寄件者:Rizzlas@my.domain
主旨:PHP error_log 訊息
主旨:Foo
遞送日期:2003 年 3 月 28 日,星期五,13:29:03 -0500
sometext
---------------%<---------------------
文件說明:「此訊息類型使用與 mail() 相同的內部函式。」
mail() 也無法根據 extra_header 資料設定「主旨」欄位,而是採用單獨的引數來指定「主旨:」字串。
php v.4.2.3, SunOS 5.8
在 *nix 系統上,您可以使用「tail」和「grep」輕鬆篩選傳送到 error_log() 的訊息。這使得在開發過程中輕鬆查看除錯訊息。
請務必使用唯一字串「標記」您的錯誤訊息,以便您可以使用「grep」進行篩選。
在您的程式碼中:
error_log("DevSys1 - FirstName: $FirstName - LastName: $Lastname");
在您的命令列上:
tail -f /var/log/httpd/error_log | grep DevSys1
在此範例中,我們將 Apache 記錄輸出透過管道傳送到 grep (STDIN),它會為您篩選輸出,僅顯示包含「DevSys1」的訊息。
「-f」選項表示「追蹤」,它會將所有新的記錄項目串流到您的終端機或後續的任何管道命令,在本例中為「grep」。
「如果您從命令列執行 PHP,系統日誌似乎是 stderr。」
實際上,如果 PHP 無法寫入日誌檔,它似乎會記錄到 stderr。命令列 PHP 會回到 stderr,因為日誌檔(通常)只能由網路伺服器寫入。
在 Windows 上記錄到 Apache 時,error_log 和 trigger_error 都會在訊息前面產生 Apache 錯誤狀態。如果您只想記錄資訊,這很不好。但是,您可以簡單地記錄到 stderr,但您必須自行組合所有訊息。
LogToApache($Message) {
$stderr = fopen('php://stderr', 'w');
fwrite($stderr,$Message);
fclose($stderr);
}
嗨!
發佈「HTML」郵件內文的另一個技巧。只需在 extra_header 字串中加入「Content-Type: text/html; charset=ISO-8859-1」。當然,您可以根據您的國家/地區、環境或內容設定字元集。
例如:Error_log("<html><h2>stuff</h2></html>",1,"eat@joe.com","subject :lunch\nContent-Type: text/html; charset=ISO-8859-1");
好好享受吧!
如果在 error_log 檔案中找不到您的項目
當您在不產生任何輸出的腳本中使用 error_log 時,這表示您在腳本執行期間看不到任何內容,並且當您想知道為什麼 error_log 檔案中沒有產生任何 error_log 項目時,原因可能是:
- 您沒有在 php.ini 中設定 error_log 輸出
- 腳本有語法錯誤,因此沒有執行
請注意,由於典型的電子郵件未加密,使用此函數通過電子郵件發送有關錯誤的數據可能會被視為安全風險。風險程度取決於您發送的信息量和類型,但僅僅在發生錯誤時發送電子郵件(即使無法讀取)本身就可能暗示觀察您網站的資深駭客,他們已成功導致錯誤發生。
當然,大多數開源支持者都會同意,透過隱匿來維護安全性是最薄弱的安全性。這只是您應該記住的事情。
當然,無論您做什麼,請確保此類電子郵件不包含敏感的用戶數據。
<?php
//多行錯誤日誌類別
// ersin güvenç 2008 eguvenc@gmail.com
//斷行請使用 "\n" 而非 '\n'
類別 log {
//
const USER_ERROR_DIR = '/home/site/error_log/Site_User_errors.log';
const GENERAL_ERROR_DIR = '/home/site/error_log/Site_General_errors.log';
/*
使用者錯誤...
*/
public function user($msg,$username)
{
$date = date('d.m.Y h:i:s');
$log = $msg." | 日期: ".$date." | 使用者: ".$username."\n";
error_log($log, 3, self::USER_ERROR_DIR);
}
/*
一般錯誤...
*/
public function general($msg)
{
$date = date('d.m.Y h:i:s');
$log = $msg." | 日期: ".$date."\n";
error_log($msg." | 日期: ".$date, 3, self::GENERAL_ERROR_DIR);
}
}
$log = new log();
$log->user($msg,$username); //用於使用者錯誤
//$log->general($msg); //用於一般錯誤
?>
如果您遇到日誌檔案權限問題 *卻沒有任何提示*
最好不要設定 error_log 指令,這樣錯誤就會寫入您目前虛擬主機的 Apache 日誌檔案中。
當 error_log() 意外使用 stdout 時,您應該檢查 CLI 環境中 php.ini 的 error_log 值是否為空。 這麼簡單的操作或許就能恢復預期的行為。
<?php ini_set('error_log', 'error_log'); ?>
// 美觀的紀錄資訊函式
<?php
function logger($log, $clear = true){
file_put_contents('/path/log/logger.log', (is_object($log) || is_array($log) || is_resource($log) ? json_encode($log, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : $log), (!$clear) ? FILE_APPEND : 0);
}