解決:LNMP架構下訪問php頁面出現500錯誤

如今LNMP架構很流行,php

然而有時咱們會遇到一個莫名其妙的問題,nginx

就是咱們訪問php頁面時服務器返回"HTTP/1.1 500 Internal Server Error"錯誤web

這個錯誤讓人匪夷所思,還覺得是nginx出問題了呢?chrome

實際上是php代碼語法錯誤致使的api

默認狀況下,若是被訪問的php腳本中包含語法錯誤,服務器會返回一個空的「200 ok」頁面安全

在php.ini中的fastcgi.error_header選項容許在這種狀況下產生一個HTTP錯誤碼服務器

以使web服務器能夠正確攔截並處理這個錯誤碼,相似直接在php代碼中調用header()返回500狀態碼,如cookie

header("HTTP/1.1 500 Internal Server Error");session

經過php源碼也能夠看出來,本次使用的php版本是:php-5.3.26架構

源文件是:php-5.3.26/main/main.c

第1110行,以下:

if(!PG(display_errors) && !SG(headers_sent) && SG(sapi_headers).http_response_code == 200){
sapi_header_line ctr = {0};
ctr.line = "HTTP/1.0 500 Internal Server Error";
ctr.line_len = strlen(ctr.line);
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
}

經過if條件能夠得知,在知足 display_errors=0 和 headers_sent=0即空白頁和

http_response_code=200的條件下返回500錯誤


初看這個500錯誤容易誤認爲nginx出錯,能夠適當調整爲其它響應碼

只要在php.ini中設置 fastcgi.error_header 選項便可,如返回503:

fastcgi.error_header = "HTTP/1.1 503 PHP Parse Error"

這樣就能夠顯示出錯誤的根本緣由,能夠在部署LNMP時加上


沒加這個選項時,能夠經過下面方法調試:

將訪問出錯的頁面拷貝一個,成測試文件,防止影響線上業務和安全問題

如:cp index.php index.test.php

打開 display_errors 選項,在文件開頭加入以下內容:

ini_set('display_errors','1');
error_reporting(E_ALL);

這樣就能夠將錯誤暴露出來,完畢!


前幾天就遇到了這個500錯誤問題,狀況是這樣的:

有開發人員說網站訪問出現500錯誤,他說ie和chrome都訪問不了,只有firefox能夠訪問,我本身也試了試,ie和chrome確實不能訪問,我機器沒裝firefox,因此沒試,我忽然想起之前公司也遇到過這個問題,因此想到了cookie的問題,就上服務器上排查php程序代碼,最後發現這麼一段代碼:

protected function __construct($domain){
    ...
    session_name(self::sess_name);
    $this->sess_id = empty($_COOKIE[session_name()]) ? $this->gen_sid() : $_COOKIE[session_name()];
    ...
}
private function gen_sid(){
    return md5(uniqid(microtime() . getClientIP(), true));
}

當程序執行到第9行的時候就會發生500錯誤,最大的可能就是 getClientIP 函數致使的,直接調用這個函數仍然返回500錯誤,用var_dump(function_exists('getClientIP'))調試,輸出false,問題就在這裏了,定義好這個函數就解決了。但是爲何firefox能夠訪問,而ie和chrome不能訪問呢?這是由於firefox裏面存在cookie了,而ie和chrome都是第一次訪問,沒有cookie,那爲何沒有cookie就會出現這個問題呢?這要歸責於:

$this->sess_id = empty($_COOKIE[session_name()]) ? $this->gen_sid() : $_COOKIE[session_name()];

第一次訪問沒有cookie,因此empty($_COOKIE[session_name()])爲true,

就會調用$this->gen_sid(),就會出現上面找不到getClientIP函數的錯誤,而cookie存在的話就不會調用$this->gen_sid(),而是返回冒號後面的$_COOKIE[session_name()],就沒問題了,呵呵!其實這麼排查有點囉嗦,直接打開錯誤報告,錯誤就會顯現出來,如:

ini_set('display_errors','1');
error_reporting(E_ALL);

顯示以下錯誤信息,很容易就發現問題了,good

Fatal error: Call to undefined function getClientIP()


另外在 php-fpm.conf 中設置的php.ini選項優先於在php.ini中設置的選項,如

在 php.ini 中設置 display_errors = on

在 php-fpm.conf 中設置 php_flag[display_errors] = off

那麼結果是 off

相關文章
相關標籤/搜索