PHP 8.3.36への更新後、ApacheからアクセスするとPHPが実行されず、ソースがそのまま表示されるトラブルに遭遇しました。これは認証付きサイトでも機密情報の漏洩につながるため、見つけたらアクセスを遮断して対処する必要があります。

1、モジュールはロードされていた
apache2ctl -M | grep -E "php|mpm"
# mpm_event_module (shared)
# php_module (shared)

php_moduleは有効でApacheも起動しています。ところが、PHPファイルをPHPハンドラへ割り当てる設定だけがなくなっていました。

2、make installでphp.loadが書き換わった

実際には、/etc/apache2/mods-available/php.loadが書き換えられ、以前の内容はphp.load.bak~として残っていました。diffすると次の部分がなくなっていました。

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

この設定がなければ、mod_phpをロードできても.phpに対するハンドラの関連付けが行われない構成があります。PHPが実行されないことと、ソースが配信されてしまうことは別の問題なので、公開領域の応答まで確認します。

3、ハンドラ設定を別ファイルにする

再発防止として、make installで書き換わり得るphp.loadにはLoadModuleだけを残し、ハンドラは独立したApache設定に置きます。すでにハンドラ設定がある場合は重複させません。

cat > /etc/apache2/conf-available/php-handler.conf <<'EOF'
<IfModule php_module>
    <FilesMatch "\.php$">
        SetHandler application/x-httpd-php
    </FilesMatch>
</IfModule>
EOF

a2enconf php-handler
apache2ctl configtest && systemctl restart apache2
4、CLIとWeb側の両方で検証する
<?php
echo PHP_VERSION, " ", PHP_SAPI, "\n";

Basic認証などで保護した一時的な確認ページで「8.3.36 apache2handler」と表示されることを確認しました。確認用ファイルは作業後に削除します。

5、ロードバランサー配下の各ホストを確認

複数台に振り分けている場合は、各バックエンドが同じ版かを個別に確認します。バックエンド自身がHTTPSを受け付け、直接到達できる場合、curl --resolveを使うとホスト名・SNIを保ったまま接続先IPを選べます。

curl --resolve www.example.com:443:192.0.2.10 \
  -u testuser \
  https://www.example.com/check.php

TLSをロードバランサーで終端している場合は、バックエンド側の実際のHTTP/HTTPS構成に合わせて検証します。

6、まとめ

PHPのソース更新は、make installとApache再起動だけでは完了しません。ハンドラ関連付け、Web応答、各ホストのバージョン確認まで実施する必要があります。