皆さん、今日は他人のPHPコードを調べたことがある人なら誰でも気が狂いそうになることについて話します。ウェブサイトを開くと、そこには何もありません。白い画面。エラーもなければ、何が悪かったのかの手がかりもありません。

心当たりがありますか?

これはPHPの致命的エラーの古典的なケースで、スクリプトを殺して、さよならも言わずに消え去ります。今日は、PHPに話させる方法、ログを有効にする方法、そして「死の白い画面」の背後に隠れている致命的なエラーを見つける方法を学びます。

PHPが黙っている理由:少し理論

まず、PHPが一般的にエラーをどのように処理するかを理解しましょう。それは単に「エラー→ログ」ではありません。そこには完全な階層があります。

PHP 7+では、うまくいかない可能性のあるすべてのものは Throwable インターフェースを実装しています。それには2つの主要な継承元があります: - Error — PHP内部エラー(致命的、パース、型エラー) - Exception — try-catchでキャッチできる例外

致命的エラー(E_ERROR、E_PARSE、E_CORE_ERROR)は、すべての開発者にとって最悪の悪夢です。これらはスクリプトを即座に殺し、set_error_handler() を介した標準ハンドラはそれらをキャッチしません 。致命的エラーをインターセプトする唯一の方法は、register_shutdown_function() を使用することです。

しかし、順を追って進めましょう。まず、エラーが実際にどこかに書き込まれるように、ロギングを有効にする必要があります。

ステップ1:php.iniを介したロギングの有効化

ログを設定する最も適切な方法は、PHP構成ファイルを編集することです。その場所はシステムによって異なります :

| システム | php.iniへのパス | |---------|-----------------| | Ubuntu/Debian (Apache) | /etc/php/7.x/apache2/php.ini | | Ubuntu/Debian (CLI) | /etc/php/7.x/cli/php.ini | | Ubuntu/Debian (PHP-FPM) | /etc/php/7.x/fpm/php.ini | | CentOS/RHEL | /etc/php.ini または /etc/php.d/ | | Windows (XAMPP) | C:\xampp\php\php.ini | | Windows (WAMP) | C:\wamp\bin\php\phpX.X.X\php.ini |

このファイルでは、次のディレクティブに注目します :

```ini ; ログファイルへのエラー書き込みを有効にする(必須!) log_errors = On

; ログファイルへのパスを指定 error_log = /var/log/php_errors.log

; 画面上へのエラー表示を無効にする(プロダクション用!) display_errors = Off

; 開発用にはこれを有効にできますが、後で無効にしてください display_startup_errors = Off

; エラーレポートレベル — すべてのエラー error_reporting = E_ALL ```

重要: コマンドラインインターフェース(CLI)は独自のphp.iniを使用し、ログは別の場所に書き込まれる可能性があります 。コンソールでスクリプトをテストしている場合は、別途確認してください。

変更後、ウェブサーバーを再起動する必要があります : bash sudo systemctl restart apache2 # Apache用 sudo systemctl restart php7.4-fpm # PHP-FPM用

これらの設定の意味

  • log_errors = On — エラーのファイルへの書き込みを有効にします。これがないと、PHPは墓のように黙ったままになります 。
  • error_log — すべてが書き込まれるファイルへのパス。ウェブサーバーユーザー(通常は www-data または apache)がこのファイルとそのディレクトリに対して書き込み権限を持っていることが重要です 。
  • display_errors = Off — ユーザーに詳細を公開しないように、プロダクションでは必ず無効にしてください 。
  • error_reporting = E_ALL — すべてのタイプのエラーを記録します。プロダクションではこれを制限できますが、デバッグのためにはすべてを見る方が良いです。

ステップ2:代替案:コード内で直接ロギングを有効にする

php.iniにアクセスできない場合(例えば、共有ホスティングなど)、ini_set() 関数を使用してスクリプト内で直接ロギングを有効にしてみることができます。

問題のあるファイルの先頭にこれを挿入します:

```php

/dev/null ``` または、`phpinfo();` を含むPHPファイルを作成し、**error_log** セクションを探します。 ## ステップ4:ログの読み取り:ツールとテクニック ログが書き込まれたら、それらをすばやく表示してフィルタリングする方法を知る必要があります。 ### tail — 最新のイベントを表示 ```bash # 最後の50行 tail -n 50 /var/log/php_errors.log # リアルタイムで追跡(docker logs -f のように) tail -f /var/log/php_errors.log ``` ### grep — 特定のエラーを検索 ```bash # 致命的エラーのみ grep "Fatal error" /var/log/php_errors.log # パースエラー(構文エラー) grep "Parse error" /var/log/php_errors.log # 大文字と小文字を区別しない grep -i "warning" /var/log/php_errors.log ``` ### less — ナビゲーション付きの便利な表示 ```bash less /var/log/php_errors.log ``` lessの中では、`/` を押して検索する単語を入力し、`n` で次の一致、`N` で前の一致に移動できます。 ### 組み合わせ — 強力なパイプライン ```bash # 最後の100行を表示し、エラーを検索 tail -n 100 /var/log/php_errors.log | grep -i fatal # リアルタイムで追跡し、フィルタリング tail -f /var/log/php_errors.log | grep --line-buffered "error" # タイプ別にエラーをカウント grep -o "PHP [A-Za-z]* error" /var/log/php_errors.log | sort | uniq -c ``` ## ステップ5:エラーの解読:何が何か 典型的なログエントリは次のようになります : ``` [2026-03-04 14:35:22 UTC] PHP Fatal error: Uncaught Error: Call to undefined function foo() in /var/www/html/index.php on line 10 ``` 分解してみましょう: - **日付と時刻** — いつ発生したか - **PHP Fatal error** — エラーレベル - **Uncaught Error: Call to undefined function foo()** — メッセージ - **/var/www/html/index.php:10** — ファイルと行番号 主なエラーレベル : | レベル | 意味 | 例 | |--------|------|-----| | **E_ERROR** / **Fatal error** | 致命的エラー、スクリプトは停止 | 存在しない関数の呼び出し、メモリ不足 | | **E_WARNING** / **Warning** | 警告、しかしスクリプトは継続 | 存在しないファイルの `include` | | **E_PARSE** / **Parse error** | 構文エラー、スクリプトは実行されない | セミコロン欠落 | | **E_NOTICE** / **Notice** | 通知、通常は重要でない | 未定義変数へのアクセス | | **E_DEPRECATED** | 非推奨の構文 | `mysql_connect()` の使用 | ## ステップ6:致命的エラーのキャッチ(興味深い部分) 致命的エラーは、標準の `set_error_handler()` ではキャッチできないものです。これらはスクリプトを即座に殺し、デフォルトハンドラは実行する時間が単にありません 。 しかし、方法があります! `register_shutdown_function()` を使用してください — この関数は、致命的エラーが発生した場合でも、必ず呼び出されます。 ### シンプルな致命的エラーハンドラ ```php getMessage()." | ".$e->getFile().":".$e->getLine()." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); }); // 致命的エラー用ハンドラ register_shutdown_function(function() use ($logFile) { $error = error_get_last(); if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { $url = ($_SERVER['HTTP_HOST'] ?? 'CLI') . ($_SERVER['REQUEST_URI'] ?? ''); $msg = "[".date('Y-m-d H:i:s')."] [FATAL] ".$error['message']." | ".$error['file'].":".$error['line']." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); } }); ``` このコードをメインファイル(例:`index.php` や `header.php`)の先頭に挿入すると、絶対にすべてをキャッチします 。 ## ステップ7:人気フレームワークでのログ 最新のフレームワークを使用している場合、ロギングはすでに設定されていますが、ログのパスは異なります。 ### Laravel ログは `storage/logs/laravel.log` に保存されます。デフォルトでは Monolog を使用します。形式はテキストまたはJSONです。エラーを表示するには: ```bash tail -f storage/logs/laravel.log ``` ### Symfony デフォルトのログ:`var/log/dev.log` と `var/log/prod.log`。同じく Monolog を使用し、高度に設定可能です。 ### WordPress デフォルトでは、WordPressはログを書きませんが、`wp-config.php` にこれを追加することで有効にできます: ```php define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false); ``` ログは `/wp-content/debug.log` にあります。 ## ステップ8:一般的な問題とその解決策 ### 問題:ログがまったく書き込まれない 確認すること: 1. `log_errors = On` が確実に設定されていますか? 2. ファイルとそのディレクトリに書き込み権限がありますか? 3. 正しい php.ini を編集しましたか(`phpinfo()` で確認)? 4. 変更後にウェブサーバーを再起動しましたか? ### 問題:致命的エラーがキャッチされない ロギングが有効でも、致命的エラーが非常に早く発生した場合(例えば、ロギングを有効にしているのと同じファイルでのパースエラー)、書き込まれないことがあります。唯一の解決策は正しい配置です — 他の何よりも先に、先頭に置くことです 。 ### 問題:ログが多すぎる プロダクションで `E_ALL` が有効になっていると、ログは急速に増大します。`error_reporting` を賢明に設定してください : ```ini error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE ``` ### 問題:ログがディスクを埋め尽くす `logrotate` でログローテーションを設定します。PHPログ用の設定: ``` /var/log/php_errors.log { daily rotate 30 compress delaycompress missingok notifempty create 644 www-data www-data } ``` ## ステップ9:実践例:白い画面の調査 状況を想像してください:ウェブサイトを開くと、真っ白です。ステップバイステップで何をしますか? 1. **ウェブサーバーのログを確認する**(Apache/Nginx)— 多くの場合、手がかりが含まれています 2. **PHPログを確認する** — 過去数分のエントリを探します ```bash tail -n 50 /var/log/php_errors.log | grep -A5 -B5 "$(date +%Y-%m-%d)" ``` 3. **エラーを見つける** : ``` [2026-03-04 15:30:22] PHP Fatal error: Uncaught Error: Class 'DB' not found in /var/www/site/index.php on line 12 ``` 4. **ファイルを開く**、12行目を確認する — 確かに、クラスをインクルードするのを忘れていました。 5. **修正する**、テストする — サイトは動きます! 魔法! ## クイックリファレンス:チートシート | アクション | コマンド / コード | |-----------|-------------------| | php.iniでロギングを有効にする | `log_errors = On` + `error_log = /ファイル/への/パス` | | コードで有効にする | `ini_set('log_errors', 'On');` | | 最後の行を表示 | `tail -f /var/log/php_errors.log` | | 致命的エラーを検索 | `grep "Fatal error" /var/log/php_errors.log` | | 致命的エラーをキャッチ | `register_shutdown_function()` + `error_get_last()` | | Laravelのログはどこ? | `storage/logs/laravel.log` | | Symfonyのログはどこ? | `var/log/dev.log` と `var/log/prod.log` | ## 結論に代えて PHPは、よく描かれるほど怖くありません。はい、「死の白い画面」は恐ろしいですが、その背後には常に、ただ話したがらない特定のエラーがあります。ログを有効にすることを学べば、PHPは話し始めます。 主なルール: - プロダクションでは、**常に** `log_errors` を有効にし、`display_errors` を無効にする - ログは syslog ではなく、専用のファイルに書き込む — 検索が簡単です - 致命的エラーをキャッチするには `register_shutdown_function` を使用する - 定期的にログを確認する — 少なくとも1日1回 そして覚えておいてください:完璧なコードはエラーを書きません。しかし、もしエラーが発生したら、せめてメモを残してください。 ?>