エラーレポートとログ

Debian9

phpのエラー表示とログについての調査

自宅のDebian9ではモジュールとして、レンタルサーバーではCGIで動いている。phpの設定は、php.ini, .htaccess, .user.ini, ユーザースクリプト(ini_set())で行うが、今回は使用状況を考えて、ユーザースクリプトで調査をする。

自宅のDebian9のパッケージになっているPHPのバージョンは次の通り

adachi@debian64:~$ php -v
PHP 7.0.30-0+deb9u1 (cli) (built: Jun 14 2018 13:50:25) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.30-0+deb9u1, Copyright (c) 1999-2017, by Zend Technologies

ユーザースクリプトで値の取得・設定

取得

string ini_get ( string $varname )
成功した場合に設定オプションの値、 
null 値の場合は空の文字列を返します。 
その設定オプションが存在しない場合は FALSE を返します。 
off という boolean の ini 値は空文字列または "0" として返されます。
一方で on の ini 値は "1" として返されます。 
また、この関数はリテラル文字列で設定された INI 値を返すこともできます

値がbooleanでも返値はStringですね。

設定

string ini_set ( string $varname , string $newvalue )
指定した設定オプションの値を設定します。 
設定オプションは、スクリプトの実行中は新しい値を保持し、 スクリプト終了時に元の値へ戻されます。
成功した場合に元の値、失敗した場合に FALSE を返します。 

失敗のFALSEは空の文字列のようです。

display_errors

display_errors:エラーの内容をスクリプトの出力に含めるかどうか

Debian9の初期設定は ini_set('display_errors',0); (スクリプト内で同様の設定をするとしたらという意味です)

表示するようにしたければ ini_set('display_errors',1);

php.ini 中のお勧めは

; display_errors
;   Default Value: On
;   Development Value: On
;   Production Value: Off

php.ini中の記述は: display_errors = Off

display_errors = string

ユーザースクリプトで操作してみます

echo 'initial value of display_errors is [',ini_get('display_errors'),"]\n";
echo 'type is [',gettype(ini_get('display_errors')),"]\n";
echo '===' , ini_get('display_errors')==='' ,"\n";
echo '!==' , ini_get('display_errors')!=='' ,"\n";

初期値である Off の表現は長さ0の文字列です。調べるまでもなく ini_get()の戻値は常にStringでした。

initial value of display_errors is []
type is [string]
===1
!==

===,!==の比較で得られるはずのboolean値は 1長さ0の文字列 だとわかります。

setをしてみます。echo $eee は未定義の変数を参照してNoticeを発生させています。

ini_set('display_errors',0);
echo 'after set 0      display_errors is [',ini_get('display_errors'),"]\n";
ini_set('display_errors',1);
echo 'after set 1      display_errors is [',ini_get('display_errors'),"]\n";
echo $eee;
ini_set('display_errors',"stderr");
echo 'after set 1      display_errors is [',ini_get('display_errors'),"]\n";
echo $eee;
ini_set('display_errors',"Off");
echo 'after set "Off"  display_errors is [',ini_get('display_errors'),"]\n";
echo $eee;
ini_set('display_errors',"On");
echo 'after set "On"   display_errors is [',ini_get('display_errors'),"]\n";
echo $eee;
ini_set('display_errors',"0");
echo 'after set "Off"  display_errors is [',ini_get('display_errors'),"]\n";
echo $eee;
ini_set('display_errors',"1");
echo 'after set "On"   display_errors is [',ini_get('display_errors'),"]\n";
echo $eee;

実行結果は、

after set 0      display_errors is [0]
after set 1      display_errors is [1]


Notice:  Undefined variable: eee in /ファイルへのパス/phb001.php on line 173

after set "stderr" display_errors is [stderr]


Notice:  Undefined variable: eee in /ファイルへのパス/phb001.php on line 176

after set "Off"  display_errors is [Off]
after set "On"   display_errors is [On]


Notice:  Undefined variable: eee in /ファイルへのパス/phb001.php on line 182

after set "0"    display_errors is [0]
after set "1"    display_errors is [1]


Notice:  Undefined variable: eee in /ファイルへのパス/phb001.php on line 188



Notice:が出るので直接示すわけに行きません。ここに出したのは出力のコピーです。

ini_set()では設定された文字列がそのまま文字列として入ります。0, "0", はどちらも "0"

そして、"0", "Off", "" はerrorを表示しない

"1", "On", "stderr" は表示するということになります。

以下は実際のPHPの表示ですが、echo $eee は省いています。

initial value of display_errors is []
type is [string]
===1
!==
after set 0      display_errors is [0]
after set 1      display_errors is [1]
after set "stderr" display_errors is [stderr]
after set "Off"  display_errors is [Off]
after set "On"   display_errors is [On]
after set "0"    display_errors is [0]
after set "1"    display_errors is [1]

true,false の表現は 1 と 長さ0の文字列

true,falseについて確認します

echo "----begin----\n";
$t  = true;
echo $t ? "true\n" : "false\n" ;
echo $t,"\n";
echo is_bool($t), "\n";
echo 'true', "\n";
echo true, True, TRUE, "\n";
echo "----true/false----\n";
$f  = false;
echo $f ? "true\n" : "false\n" ;
echo $f,"\n";
echo is_bool($f), "\n";
echo 'false', "\n";
echo false, False, FALSE, "\n";
echo "----end------\n";

実行結果は

----begin----
true
1
1
true
111
----true/false----
false

1
false

----end------
 

error_reporting

出力する エラーレベル

Debian9の初期設定は error_reporting(E_ALL & ~E_STRICT & ~E_DEPRECATED); (スクリプト内で同様の設定をするとしたらという意味です)

E_ALLにしたければ、error_reporting(E_ALL); または、ini_set('error_reporting', E_ALL);

php.ini 中のお勧めは

; error_reporting
;   Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
;   Development Value: E_ALL
;   Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT

php.ini中の記述は: error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

error_reporting = integer

取得と設定

int error_reporting ([ int $level ] )
出力する PHP エラーの種類を設定する
オプションの level を指定しなかった場合は、現在のエラーレベルを返す
ビットマスクまたは名前つき定数で指定する
error_reporting(E_ALL); は
ini_set('error_reporting', E_ALL); と書いても良い

E_ERROR=1, E_WARNING=2, E_PARSE=3, E_NOTICE=8,... などとビットごとに定数が決まっている

error_reporting(E_ERROR=1 | E_WARNING=2 ) は 0b11 十進で3と指定したのと同じ。|はビット演算でOR

error_reporting(E_ALL) はすべてのビットが1である整数で、現在のバージョンで、32767。

error_reporting(E_ALL & ~E_NOTICE) は not 8 と ANDをとるので、32767-8。

echo 'type is [',gettype(ini_get('error_reporting')),"]\n";
echo 'type is [',gettype(error_reporting()),"]\n";
echo decbin(error_reporting()),':[',error_reporting(),"]: initial value\n";
echo "UDRSUUUCCCCNPWE\n";
echo decbin(E_ALL),':[',E_ALL, "]: E_ALL\n";
echo decbin(E_ALL & ~E_NOTICE),":[",(E_ALL & ~E_NOTICE),"]:(E_ALL & ~E_NOTICE)\n";
echo decbin(~E_NOTICE),": ~E_NOTICE\n";
type is [string]
type is [integer]
101011111111111:[22527]: initial value
UDRSUUUCCCCNPWE
111111111111111:[32767]: E_ALL
111111111110111:[32759]:(E_ALL & ~E_NOTICE)
1111111111111111111111111111111111111111111111111111111111110111: ~E_NOTICE

php.iniからくる初期値は22527。E_ALL & ~E_STRICT & ~E_DEPRECATED である。

UDRSUUUCCccNPWE

USER_DEPRECATED
 DEPRECATED
  RECOVERABLE_ERROR
   STRICT
    USER_NOTICE
     USER_WARNING
      USER_ERROR
       COMPILE_WARNING
        COMPILE_ERROR
         CORE_WARNING
          CORE_ERROR
           NOTICE
            PARSE
             WARNING
              ERROR

詳細は、

PHP マニュアル ->関数リファレンス ->PHP の振る舞いの変更 ->エラー処理 ->定義済み定数

定義済み定数

log_errors

ログに記録するかどうか。

Debian9の初期設定は ini_set('log_errors','On'); (スクリプト内で同様の設定をするとしたらという意味です)

offにしたければ、ini_set('log_errors','Off');

php.ini 中のお勧めは

; log_errors
;   Default Value: Off
;   Development Value: On
;   Production Value: On

php.ini中の記述は: log_errors = On

log_errors = boolean

設定変更してみます。

echo 'initial value of log_errors is [',ini_get('log_errors'),"]\n";
ini_set('log_errors','Off');
echo 'initial value of log_errors is [',ini_get('log_errors'),"]\n";
ini_set('log_errors','On');
echo 'initial value of log_errors is [',ini_get('log_errors'),"]\n";

結果は

initial value of log_errors is [1]
initial value of log_errors is [Off]
initial value of log_errors is [On]

error_log

スクリプトエラーが記録されるファイル名。syslog が指定されると、システムのログに送られます。

Debian9の初期設定は なし

php.ini 中の記述は

; Log errors to specified file. PHP's default behavior is to leave this value
; empty.
; http://php.net/error-log
; Example:
;error_log = php_errors.log
; Log errors to syslog (Event Log on Windows).
;error_log = syslog

Debian9の初期設定は「なし」ですが、この状態でapache2のエラーログ(つまりはsyslog)に残ります。

[Sat Nov 03 13:10:46.644464 2018] [:error] [pid 5473] [client 127.0.0.1:46196] 
PHP Notice:  Undefined variable: eee in /phpファイルへのパス/phb001.php on line 317

スクリプトによる設定では、ページの再読込でリセット(php.iniなどの設定に戻る)されるので、ページの中でerror_logファイルの設定以前のエラーは、apache2のエラーログに送られます。

設定変更してみます。

echo 'initial value of error_log is [',ini_get('error_log'),"]\n";
ini_set('error_log','../../somewhere/errlog');
echo 'initial value of error_log is [',ini_get('error_log'),"]\n";

結果は、(ここに出したのは出力のコピーです)

initial value of error_log is []
initial value of error_log is [../../somewhere/errlog]

この設定の後に起こったエラーはここに記録され、syslogには出ません。

[03-Nov-2018 13:22:12 Asia/Tokyo] PHP Notice:  Undefined variable: eee in /phpファイルへのパス/phb001.php on line 346

改行小ネタ

PHP_EOL を "\n"の代わりに使うことができます。Windowsでは\nの代わりに\r\nとしてくれるとありますが、htmlでは\nのままでも問題はないので、どちらでもかまわないでしょう。

PHP_EOLは改行を表していて、環境によって自動で改行コードを切り替えてくれる。
OS 	改行コード 	改行コード文字
Windows 	CRLF 	\r\n
Linux,Unix,MACOS10 	LF 	\n