PHP開發基礎教學之Error

一、問題引入

在之前我們寫程式碼的時候常常會看到:函數名寫錯了,忘加分號了,函數被重新定義了都會報各種不同樣的錯。

在開發中,顯示錯誤對我們的開發非常有利。因為,顯示錯誤後能幫我們快速定位錯誤、解決問題。

而在生產環境(即公網)給其他人訪問的的網站、微網站、手機網站、手機介面... ...等等。

如果錯誤顯示出來了,就容易暴露:

  • 伺服器的檔案路徑和檔案儲存規範

  • 有些人喜歡用個人名稱命名,透過社會工程學可以反向推理出密碼

  • 有時還會暴露mysql資料庫伺服器的位址
    ... ... 等等

上面這些資訊特別容易被網路上別有用心的一些人給利用。

例如下面這段程式碼,我們不加分號就全面暴露了我們的伺服器端檔案存放路徑、框架資訊等。如下:

<?php
$fp = fopen('abc.txt','a+')
fwrite($fp,'abc');
fclose($fp);
?>

報錯了:

 59.png

#錯誤提示中文翻譯過來為:
解析錯誤:語法錯誤。意外發生在/home/vagrant/Code/Laravel/public/index.php 檔案的第5行fwrite附近。

在本章中,我們來嘗試解決這個問題


#二、禁止顯示錯誤

在php .ini設定檔中。我們可以控制php的錯誤顯示狀態。

php.ini中有一個專門的設定項:

display_errors

這個選項設定是否將錯誤訊息輸出到網頁,或是對用戶隱藏而不顯示。

這個值的狀態為on 或 off,也可以設為1 或0。

display_error的值設為0或off則不在頁面中顯示錯誤,如果設為1或on則顯示錯誤訊息。

問題:如果沒有修改伺服器php.ini的狀態權限怎麼辦?

可以使用ini_set。

<?php
ini_set('display_errors' , 0 );
?>

上面的程式碼也相當於修改了php.ini中display_errors的值。不過,僅僅在目前php程式碼中生效。

問題:想取得php.ini的設定項目狀態怎麼辦?

可以使用ini_get(參數項) 來得到參數的值。

實例:

<?php
echo '服务器中display_errors的状态为' . ini_get('display_errors');
?>

附註:修改完php.ini文件,需要重新啟動伺服器。


三、錯誤回報等級

#1.錯誤類型

##php大家最常見的錯誤顯示:


60.png


在在上面的幾種型別中:

  • error最嚴重,必須要解決。不然程式無法繼續向下執行

  •  warning也很重要。通也必須解決。如果明確的,故意的可以不用處理。

  •  notice 你可以不用管。但是在有些公司,專案標準特別高。在高標準要求的項目中也必須解決。因為,notice會影響PHP的執行效率。通常發生在函數未定義等。

  • parse錯誤,是指語法錯誤寫錯了,必須解決

  • 代表全部類型的所有錯誤

其它根據上面擴展出來的另外一些需要了解的錯誤項:


61.png


在學習過程中,上面的類型了解即可。因為基本上不會遇到,遇到了大家去查一下或查一下手冊就清楚了。

2.error_reporting 報告錯誤類型

error_reporting 是指錯誤報告。在php.ini中也有這樣一個參數。這個參數。決定了PHP引擎記錄、報告、顯示哪些錯誤類型。

1)、 在php.ini中error_reporting參數

如若error_reporting參數設定為0。整個PHP引擎發出錯誤均不會顯示、輸出、記錄。在下一章將要講到的日誌記錄中,也不會記錄。

如果我們想顯示所有錯誤可以寫上:

error_reporting = E_ALL

想要顯示所有錯誤但排除提示,可以將這個參數寫成:

error_reporting = E_ALL & ~ E_NOTICE

顯示所有錯誤,但排除提示、相容性和未來相容性。可寫為:

error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED

2)、在某些情況下我們無權限操作php.ini文件,又想要控制error_reporting怎麼辦呢?

在執行的xxxx.php檔案中開始處,我們可以使用error_reporting()函數達到目標。

示範程式碼如下:

<?php
//关闭了所有的错误显示
error_reporting(0);
//显示所有错误
//error_reporting(E_ALL);
//显示所有错误,但不显示提示
//error_reporting(E_ALL & ~ E_NOTICE);
?>

上面的程式碼你可以試試,故意寫錯程式碼看看。在目前文件中也會不會顯示指定的錯誤。

[擴充、了解知識點]: @ 符是我們之前學過的單行不顯示錯誤,請不用或少用@符。

我們拿讀取一個不存在的文件,這樣的php程式碼來示範實作過程:

<?php
//读取一个不存在的adsaf.txt文件,用@符抑制错误
@$fp = fopen('adsaf.txt','r');
?>
@符效率较低,它在php内核中的实现过程是:
<?php
//关闭错误
error_reporting(0);
 
//读取一个不存在的文件,显示错误
 
//显示错误
error_reporting(E_ALL & ~ E_NOTICE);
?>

四、錯誤記錄日誌

在某些公司裡面,有專門的日誌收集系統。日誌收集系統會在背後默默的幫你收集錯誤、警告、提示。

也有些公司沒有專門的日誌收集系統,透過檔案來伺服器當中的運行日誌。

其中:PHP的錯誤,警告這些是必須要收集的。

那麼問題來了-不讓使用者看到,設定好錯誤報告等級好,如何將錯誤收集到日誌系統呢?

這裡有需要使用到php.ini的相關設定項。這兩個配置項為:


62.png


說明:

  • # 在表格中的log_errors和log_errors_max_len非常好理解。

  •  而error_log 指定將錯誤存在什麼路徑上。配置項目中的syslog可能有點不太好理解。 syslog是指系統來記錄。 windows系統在電腦的日誌收集器裡面。 linux預設在:/etc/syslog.conf

[擴充] 了解知識點。若Linux系統啟動或修改了日誌收集。可能儲存在第三方專用的日誌收集伺服器中。

此外,PHP還為我們專門準備了一個自訂的錯誤日誌函數:

bool error_log ( string $錯誤訊息[, int $錯誤訊息類型= 0 [, string $存儲目標]] )

這個函數可以把錯誤訊息傳送到web伺服器的錯誤日誌,或是到一個檔案裡。

常用的錯誤訊息類型:


63.png


範例:

<?php
//无法连接到数据库服务器,直接记录到php.ini 中的error_log指定位置
error_log("无法连接到数据库服务器服务器");
//可以发送邮件,但是php.ini必须配置过邮件系统
error_log('可以用邮件报告错误,让运维人员半夜起床干活',1 ,'liwenkai@phpxy.com');
//记录在指定的位置
error_log("我是一个错误哟", 3, "d:/test/my-errors.log");
?>

附註:
error_log 中發送郵件可能對初學者不熟,您可以不用掌握些塊知識。




#五、自訂錯誤處理函數

#這一塊知識起點有些高。大多數人沒有軟體工程、自訂錯誤處理的經驗,很難想像使用的場景。若你想跳過此區塊的學習,完全可以,並且我們支援。

此區塊知識點對於實際應用程式中應用場景不多。如果,有計畫開始要自己寫框架時、或您做完了本書的第一個專案。

使用者自訂錯誤常用到的兩個函數:

set_error_handler ( callable $回呼的錯誤處理函數)
設定一個使用者定義的錯誤處理函數

trigger_error ( string $error_msg)
產生一個使用者層級的error/warning/notice 資訊

<?php
//定义一个自定义的错误处理函数
function customError($errno, $errstr, $errfile, $errline) {
    //输出错误消息
    echo "<b>Custom error:</b> [$errno] $errstr<br />";
    //输出错误文件和错误行
    echo "Error on line $errline in $errfile<br />";
    echo "Ending Script";
    //中止程序运行
    exit;
}
//使用set_error_handler 绑定用户自定义函数
set_error_handler("customError");
$test=2;
//触发自定义错误
if ($test > 1) {
    trigger_error("A custom error has been triggered");
}
?>


#
繼續學習
||
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>php.cn</title> </head> <body> <?php echo "Hello World!!!"; ?> </body> </html>