PHPのエラー表示とログの設定

要約

ini_set('display_errors',1); で画面への表示を指定する。完成したらini_set('display_errors',0);にするか、削除する。

ini_set('error_log',dirname($_SERVER['DOCUMENT_ROOT'])."/phpdata/errlog"); でログの出力先を変更する。

はじめに

ローカルネットでノートPCをウェブサーバーに」の条件のサーバーで作業します。サーバーのOSはDebianまたはUbuntuで、Debian8 と Ubuntu18.04で検証しています。サーバーのIPアドレスは192.168.1.10と仮定します。

ウェブサーバーはapache2(2.4.29)、php7.2です。

エラー表示とログ

プログラムの作成中に、書き間違いがあったときにはエラーが出て知らせてくれます。ところが、PHPのデフォルトでは画面には何も出ません。場合によってはブラウザのページが真っ白で、どこが違っていたのか見当を付けることさえできなくなります。

エラーは、apache2のログにも記録されますが、管理者権限がなければ見ることができません。

ブラウザの画面は、プログラム作成者だけでなく閲覧者も見ますから、開発時には表示するようにして、完成したら出さないようにしなければなりません。また、ログについても開発者の所属グループを工夫してログは見えるようにすれば良いのです。

エラーとログの出力の設定場所は、php.ini, .htaccess, .user.ini, の他、各ページに置くコマンド(ini_set()など)が使えます。今回は使用状況を考えて、メリットもデメリットもありますが、コマンドで行います。

ini_set('display_errors',1);            画面への表示
error_reporting(E_ALL & ~E_NOTICE);     表示するエラーの選択
ini_set('log_errors','On');             ログを残す
ini_set('error_log',__DIR__.'/errlog'); ログの出力先

display_errors

ページ上にエラーを表示するかの選択。1,0 や 'On','Off'で指定します。

デフォルトは当然「表示しない」になっています。作成中は表示するように設定しましょう。

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

実運用でエラーが出るなら使い物にならないし、サイトの構造を知られることになるので危険とも言われます。実運用では表示しないように戻しておきます。

ページを構成中にエラーが出ると、ページそのものが出せなくなります。このようなときには役に立ちません。ログを頼りにします。

error_reporting

表示するエラーの種類の選択です。1:E_ERROR, 2:E_WARNING, 4:E_PARSE, 8:E_NOTICE という具合に決められているのでこれを加えたもの(論理和)が指定値になります。

デフォルトは22527です。デフォルトのままでいいでしょう。

不要な情報です。ちらっと見るだけにして、次のlog_errorsに進んでください。

<?php
echo "UDRSUUUCCCCNPWE\n";
echo decbin(error_reporting()),': initial value of error_reporting is [',error_reporting(),"]\n";
error_reporting(E_ALL & ~E_NOTICE);
echo decbin(error_reporting()),': changed value of error_repopting to [',error_reporting(),"]\n";
?>

こうなります。

UDRSUUUCCccNPWE
101011111111111: initial value of error_reporting is [22527]
111111111110111: changed value of error_repopting to [32759]

各ビットの意味です。

1	E_ERROR (integer) 
2	E_WARNING (integer) 
4	E_PARSE (integer) 
8	E_NOTICE (integer) 
16	E_CORE_ERROR (integer) 
32	E_CORE_WARNING (integer) 
64	E_COMPILE_ERROR (integer) 
128	E_COMPILE_WARNING (integer) 
256	E_USER_ERROR (integer) 
512	E_USER_WARNING (integer) 
1024	E_USER_NOTICE (integer) 
2048	E_STRICT (integer) 
4096	E_RECOVERABLE_ERROR (integer) 
8192	E_DEPRECATED (integer) 
16384	E_USER_DEPRECATED (integer) 
32767	E_ALL (integer) 

log_errors

ログを残すかどうかの選択です。

デフォルトは「残す」です。このままでいいでしょう。

もし、残っていなければ、

<?php
ini_set('log_errors','On');
?>

エラーが多くてログファイルが肥大することがあるので、あえて残していないという可能性もあります。

error_log

ログの出力先です。

デフォルトは、/var/log/apache2/error.log です。sudoできるか、admのグループメンバーならこのままでも閲覧できますが、PHP以外のウェブサーバー関係のエラーも時系列で入っています。出力先を指定すればPHPのみのエラーログを取得できます。

お勧め1

第一のお勧めは、

<?php
ini_set('error_log', dirname($_SERVER['DOCUMENT_ROOT']).'/phpdata/errlog');
?>

設定方法は、

ini_set('error_log', ファイル名); 

です。

$_SERVER['DOCUMENT_ROOT']
ドキュメントルートを取得します。多分/var/www/htmlです。
dirname()
親ディレクトリを求めます。/var/wwwになります。
.'/phpdata/errlog'
'/phpdata/errlog'を連結します。
結局、ログは'/var/www/phpdata/errlog'に書き込まれます。

/var/wwwにphpdataというディレクトリを作り、errlogというファイルを作ってwww-dataというユーザーが書き込めるようにパーミッションを変更します。やり方は次項で説明します。

お勧め2

第一のお勧めに従うだけの権限がない(sudoできない)場合は、これかな。

<?php
ini_set('error_log', ,__DIR__.'/errlogAKWIX3CERQ'); 
?>
__DIR__
phpファイルのあるディレクトリです。多分/var/www/htmlです。
.'/errlogAKWIX3CERQ'
'/errlogAKWIX3CERQ'を連結します。
結局、ログは'/var/www/html/errlogAKWIX3CERQ'に書き込まれます。

編集する.phpファイルのある場所に、errlogAKWIX3CERQというファイルを作ってwww-dataというユーザーが書き込めるようにパーミッションを変更します。これもやり方は次項で説明します。

どちらに指定してもページ構成ができない時には/var/log/にエラーログが出ることがあります。

エラーログファイルを用意する

PHPはapache2を動かしているユーザであるwww-data(apache2の設定で変更可)で動いています。www-dataが読み書きできないものは、使えません。

お勧め1では

OSのパーミッション設定にも依りますが、ここはrootでないとファイルが作れませんから、rootになるか、sudoを使ってファイルを作り、PHPから書き込みができるようにしておく必要があります。

パーミッションの詳しい話は避けますが、たとえば、こんな感じ。

adachi@adachi-CF-Y7:/var/www/html$ sudo mkdir ../phpdata
adachi@adachi-CF-Y7:/var/www/html$ sudo touch ../phpdata/errlog 
adachi@adachi-CF-Y7:/var/www/html$ sudo chgrp www-data ../phpdata/errlog 
adachi@adachi-CF-Y7:/var/www/html$ sudo chmod g+w ../phpdata/errlog 
adachi@adachi-CF-Y7:/var/www/html$ ls -l ../phpdata/
-rw-rw-r-- 1 root www-data 0  1月 16 13:28 errlog

お勧め2では

ローカルネットでノートPCをウェブサーバーにのドキュメントルートの説明では、/var/www/htmlをドキュメントルートにして、ここを普段作業する一般ユーザーadachiの所有にしていました。

adachi@adachi-CF-Y7:~$ sudo chown adachi: /var/www/html -R

これを前提にすると、

adachi@adachi-CF-Y7:/var/www/html$ touch errlogAKWIX3CERQ
adachi@adachi-CF-Y7:/var/www/html$ chgrp www-data errlogAKWIX3CERQ
adachi@adachi-CF-Y7:/var/www/html$ chmod g+w errlogAKWIX3CERQ
adachi@adachi-CF-Y7:/var/www/html$ ls -l errlogAKWIX3CERQ
-rw-rw-r-- 1 adachi www-data 0  1月 16 13:38 errlogAKWIX3CERQ

ログファイルはウェブページの閲覧者からは見えないようにしておきたいデータです。

お勧め1の /var/wwwはドキュメントルートの外になりますから、ウェブサーバーは絶対にサービスしない場所です。見せる予定のないものはドキュメントルート以下に置かないというのが鉄則です。これはapache2が決めていることです。PHPはこれ以外の場所のファイルも読み書きできます。

お勧め2ではこの原則から外れますが、ファイル名がわからないようにしておけば、大丈夫だろうという気持ちです。

試しに書いてみる

エラーログのファイルが機能するかの確認は、エラーを起こさなくても可能です。

<?php
error_log( "Hello, errors!" );
?>

ページに書いたままにすると、ページが閲覧されるたびに1行ずつログが増えていきます。

[16-Jan-2020 14:01:59 Asia/Tokyo] Hello, errors!
[16-Jan-2020 14:02:01 Asia/Tokyo] Hello, errors!
[16-Jan-2020 14:02:06 Asia/Tokyo] Hello, errors!

ログが溜まってきたら

デフォルトの、/var/log/apache2/error.log はログローテートの対象なので、古いものは自動的に圧縮されたり、最終的に消去されたりしてゆきます。

自分で設定したものは、いつまでもそのままですから、肥大する可能性があります。不要になったら消去するのが吉です。

ただし、ファイルを消去すると作り直してパーミッションの設定が必要になりますから、次のやり方がおすすめです。

adachi@adachi-CF-Y7:/var/www/html$ sudo echo  '' > /vae/www/phpdata/errlog

改行がひとつだけのファイルになります。