サーバーの管理画面でPHPを8.2に切り替えたら、サイトが真っ白になった。あるいは、固定ページだけが「重大なエラー」になり、ログインした状態では同じページが空白で出る。管理画面の一部だけが操作を受け付けない。PHPのバージョンアップで起きることは、実のところ数えられるほどの型に収まります。ここでは実際に修正した案件で壊れていた場所を型ごとに並べ、切り替える前にどこを見ておけば防げたのかまで書きます。上げるかどうかを迷っている段階でも、どこにリスクが集中しているかは分かるはずです。
PHP8系で最初に噴き出すのは、未定義の配列キー
PHP 8.0で変わった仕様のうち、既存サイトへ一番広く効くのが未定義配列キーの扱いです。それまで Notice 止まりだった $_GET['keyword'] のような未定義キーの参照が、Warning へ格上げされました。エラー表示の設定次第では、この警告がページの先頭に大量に出力され、レイアウトごと崩れます。
古いテンプレートには $_GET や $_POST の値を素のまま読む行が並んでいることが珍しくありません。検索用のテンプレートを直した案件では、直した行は3行だけでした。存在を isset() で確かめてから使う、?? 演算子で既定値を与える、array_key_exists() で判定する。どれを選んでも解消します。
<code>// PHP 7 まで通っていた書き方 $kw = $_GET['keyword']; // PHP 8 以降で警告を出さない書き方 $kw = $_GET['keyword'] ?? '';</code>
気をつけたいのは、この警告が出ること自体は動作の停止を意味しないという点です。値が空のまま処理は続きます。つまり「エラーが画面に出ているのに、サイトは動いている」という状態になり、どこから手をつけるかの判断が鈍ります。
そしてもう一つ。バージョンを上げてから出た症状が、すべて同じ原因とは限りません。この案件でも、依頼元が「PHPを更新してから起きた」と説明した二つの症状のうち、画面上のエラー表示はPHP8のエラーレベル変更が原因でしたが、もう一方の「検索窓に何を入れても全件が返る」は無関係でした。原因はHTMLのformタグの指定漏れで、入力したキーワードがそもそもサーバーへ送られていなかったのです。まとめて片付けようとせず、症状ごとに切り分けます。
症状の出方だけで、壊れている場所はかなり絞れる
PHPのバージョンを上げた直後に出る症状は、見え方と原因の対応がはっきりしています。切り分けの入口として使えるものを並べます。
| 見えている症状 | まず疑う場所 | 確認の方法 |
|---|---|---|
| サイト全体が真っ白 | テーマの functions.php、有効化中のプラグイン | デバッグログを有効にして最初のエラー行を読む |
| 特定の種類のページだけエラー | そのページ種別のテンプレート(page.php、single.php など) | テンプレート階層をたどり、該当ファイルを構文チェック |
| ログイン中は空白、ログアウトすると重大なエラー | そのページのテンプレートで致命的エラー | 症状の組み合わせ自体がサイン。同一ファイルを疑う |
| 管理画面の一部の操作だけ効かない | テーマ同梱のライブラリ、廃止済みAPIを呼ぶウィジェット | ブラウザの開発者ツールとデバッグログを併読 |
| ページ上部に警告文が並ぶ | 未定義配列キーなど、エラーレベルの変更 | 表示設定を切り、ログへ出して行番号を特定 |
| 画像の加工処理だけ落ちる | PHP拡張ライブラリのバージョン | phpinfo() で拡張の有無とバージョンを確認 |
| テーマのディレクトリ名を変えると復旧する | ファイルの物理的な状態(BOM、不可視文字) | 制御文字を可視化できるエディタで開く |
切り分けで最初にやることは決まっています。wp-config.php を開いて、エラーを画面ではなくログへ落とす設定に切り替えます。
<code>define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);</code>これで wp-content/debug.log にファイル名と行番号が残ります。訪問者にエラーを見せずに済み、しかも修正の見積りがログの1行目で立ちます。真っ白の画面だけを見て「原因不明」と報告するのと、ファイル名と行番号を添えて報告するのとでは、そこから先の時間がまったく違います。
実際に壊れていた箇所を、型ごとに
テンプレート1本で、フロントと管理画面が同時に落ちる
さくらインターネットのサーバーへ復元したWordPressサイトで、PHPは8.0.30でした。症状は三つです。固定ページを開くと「重大なエラー」が出る。ログインした状態だと、同じ固定ページが真っ白の空ページになる。そして管理画面の「外観」から「メニュー」を開いて固定ページを追加しようとしても反応しない。
並べると別々の不具合に見えますが、共通して読まれているファイルを探すと交差点が見つかります。原因は page.php の1本でした。固定ページの表示にも、メニュー編集画面での固定ページ一覧の生成にも、このテンプレートが関与しており、そこでPHP8非互換の記述が致命的エラーになっていたのです。症状を別々に追いかけると三倍の時間がかかります。交差点を探すと一度で終わります。
「ログイン中は空白、ログアウト時は重大なエラー」という組み合わせは、それ自体がテンプレートでのFatal errorを示す手がかりです。表示の出方はログイン状態やデバッグ設定で変わるので、見え方の違いに引きずられず、同じファイルを見ていると考えたほうが早く着きます。
あわせて、移行や復元を伴う場合はデータベース内のURL置換だけでは終わりません。テーマや固定ページの本文に / 始まりの絶対パスや旧ドメインのURLが直接書かれていると、置換の対象から漏れます。home_url() を使う形へ置き換えるか、設置先のURLへ書き直す必要があります。
テーマの中に隠れている、古いライブラリ
PHP移行の手間は、テーマ本体の行数では決まりません。決めるのは、テーマに同梱されたサードパーティ製ライブラリの有無と、その古さです。
親テーマと子テーマの構成で作られたサイトをPHP8.2へ対応させた案件では、テーマフォルダの中に option-tree というオプション管理用のライブラリが同梱されていました。これはプラグインとして配置されていないため、管理画面のプラグイン一覧には出てきません。テーマ本体より、同梱ライブラリの改修のほうが分量が多くなることもあります。見積りの前にテーマフォルダの直下を開き、option-tree/ inc/ framework/ admin/ といったディレクトリがあれば中身を確かめてください。
この構成では改修対象が親テーマ、子テーマ、同梱ライブラリの3層に分かれます。どの層をどこまで直したかを記録しておかないと、あとで親テーマの公式アップデートが当たった瞬間に、直した内容がまとめて消えます。親テーマを直接書き換えた場合は「以後そのテーマの更新は当てない」という運用が必要になり、その判断は依頼元に伝わっていなければ意味がありません。
WordPress側で動かなくなったAPI
踏むのはPHPの仕様変更だけではありません。WordPressそのものが廃止したAPIも同時に効いてきます。初期のウィジェットAPIである register_sidebar_widget() や wp_register_widget_control() の系統は、現行のWordPressでは動きません。WP_Widget クラスを継承し、register_widget() で登録する書き方へ置き換えます。長く更新されていないテーマほど、この種の古い呼び出しが残っています。PHPのバージョンだけを見ていると見落とします。
コードではなく、ファイルの状態が原因だった
一番手こずったのはこれです。WordPress 6.1.4、PHP 8.2.12という環境で、既製テーマを改造したオリジナルテーマをPHP8.2対応にする依頼でした。修正版を納品したところ致命的エラー。改造前のファイルに戻しても、やはり致命的エラー。ところがテーマのディレクトリ名を変更すると復旧する。
この症状はコードのロジックを追っても答えが出ません。疑うべきはファイルの物理的な状態です。PHPファイルの冒頭や末尾、閉じタグの外に混入したBOM、不可視文字、余分な空白。これらは headers already sent や白画面、致命的エラーの典型的な原因で、制御文字を可視化できるエディタで開けば数分で見つかります。
混入する経路はいくつもあります。FTPクライアントのアスキー転送モードによる改行コードの変換、zipの解凍環境による文字コードの変質。ファイルを受け渡す工程そのものが原因になるため、コードをいくら読み直しても再現しません。壊れている疑いがあるときは、管理画面の「外観」から「テーマファイルエディター」を開いてコードを直接貼り付ける方法が確実です。転送経路を通さないので、変質のしようがありません。
この案件で原因にたどり着くまで二週間かかりました。短縮できた余地ははっきりしていて、画面のスクリーンショットをやり取りしていた期間です。実環境の接続情報を預かって直接見た翌日には原因が出ています。環境に起因する不具合は、環境を見ないと分かりません。
PHPと一緒に動いてしまうもの
PHPのバージョンを上げると、PHP以外も一緒に動きます。WordPressは本体のバージョンに応じて同梱するjQueryも更新しており、PHP8.2に対応した世代のWordPressはjQuery 1.9以上を前提にしています。1.8以前の記法に依存した古いテーマは、PHPの互換性だけ直しても足りず、いずれJavaScript側で止まります。PHP対応とJavaScript対応は別の作業です。見積りの段階で切り分けておかないと、後から範囲の話でもめます。
サーバー側の拡張ライブラリも同じです。CakePHPで作られた物件検索サイトが、去年まで動いていたのに画像の処理だけ急に落ちるようになった案件がありました。コードは一行も変わっていません。変わったのはサーバーです。共用レンタルサーバーでPHPが8.0へ引き上げられ、その環境のImagickが古く、画像処理が通らなくなっていました。
共用サーバーでは、PHPの拡張ライブラリを更新できるのはサーバー管理者だけです。利用者側からは手が出せません。この案件で取れる選択肢は三つでした。事業者へ更新を打診する、VPSなど自分で管理できる環境へ移す、PHPを7.4へ戻す。7.4へ戻せばその場は動きますが、非推奨のバージョンは告知を挟んで選択肢から消えるため、あくまで暫定の措置です。設定自体はコントロールパネルの「スクリプト情報」にある言語バージョンの項目から変えられます。
同じサーバーでは、PHPの実行モードも見ておく必要があります。CakePHPを共用サーバーで動かすなら、CGIではなくモジュールモードを選びます。CGIでは必要なライブラリを利用できないことがあるためです。実行モードの違いは .htaccess による設定の効き方にも影響します。CGIやFastCGIで動いている環境では .htaccess に書いた php_value memory_limit が読まれず、設定したつもりの値が効いていない状態になります。WordPressであれば wp-config.php に define('WP_MEMORY_LIMIT', '512M'); を書き、phpinfo() か管理画面のサイトヘルスで実際に効いている値を確かめてください。
上げる前に見ておく場所
作業の順番として、まずテーマとプラグインのPHPファイル全体へ構文チェックをかけます。SSHが使えるなら、対象のディレクトリで一括して php -l を回すだけで、構文レベルの非互換は洗い出せます。
<code>find wp-content/themes/your-theme -name "*.php" -exec php -l {} ;</code>ただし php -l で見つかるのは構文エラーだけです。未定義配列キーのような実行時の警告や、廃止済み関数の呼び出しは素通りします。実行時の非互換は、検証用の環境を1本立てて、そこでPHPのバージョンだけを切り替えて確認するのが確実です。本番と同じテーマ・同じプラグイン構成でなければ意味がないので、コピーを作る手間はここで惜しまないほうが結果的に安く済みます。
- 使用中のテーマの最終更新日と、テーマフォルダ直下の同梱ライブラリの有無
- 有効化しているプラグインのうち、公式ディレクトリで更新が止まっているもの
- サイトが依存している拡張ライブラリ(画像処理、文字コード変換など)が、新しいPHPで有効かどうか
- PHPの実行モードと、それによって効かなくなる設定ファイル
- 切り戻しの手順と、戻すのにかかる時間
最後の項目が抜けがちです。管理画面から数クリックで前のバージョンへ戻せる事業者もあれば、申請を挟む事業者もあります。戻せない前提で切り替え当日を迎えると、動かないまま朝になります。切り替えは、戻せることを確認してから実行してください。
制作した会社と連絡が取れないサイトを引き継いでからPHPを上げる場合は、そもそも何が入っているかの棚卸しから始まります。手順は制作会社と連絡が取れないWordPressを引き継ぐときのチェックリストに整理しました。使われていない機能やページが残っているなら、上げる前に止めてしまうほうが確認する範囲が減ります。止め方と消す前の確認は使わなくなった機能やページを止めるときの手順と、消す前の確認で扱っています。すでに真っ白になってしまっている状態から戻す作業は、障害復旧の範囲です。
よくある質問
PHP7.4のまま使い続けるのは、どのくらい危険ですか
PHP 7.4は公式のセキュリティサポートが終了しています。共用レンタルサーバーでは事業者側で独自に提供を続けている場合がありますが、選択できるバージョンの一覧からは、告知を挟んでいずれ消えます。消えた時点で新しいバージョンへ強制的に切り替わり、そこで初めてサイトが止まります。この順番が最悪で、こちらが日時を選べません。動いているうちに上げるほうが、検証と切り戻しの時間を自分で確保できるぶん安全です。
上げたら真っ白になりました。すぐ元に戻すべきですか
戻して構いません。ただし戻す前に記録を取ってください。デバッグログを有効にして wp-content/debug.log にエラーを残すか、サーバーのエラーログを保存する。何も残さずに戻すと、次に上げるときも同じ場所で止まります。ファイル名と行番号さえログに残っていれば、修正にかかる手間はその場で判断できます。
テーマをPHP8対応にすれば、それで完了しますか
完了しません。テーマ本体、テーマに同梱されたライブラリ、プラグイン、JavaScript、サーバー側の拡張ライブラリ。この5つがそれぞれ独立して非互換を持ちます。テーマだけ直した状態で数か月動いていたのに、WordPress本体の更新をきっかけにJavaScript側が止まる、という順番で問題が出ることもあります。どこまでを一度に見るかは、そのサイトで実際に使われている機能の範囲で決めます。外部へ任せる場合の線引きの決め方は保守契約でどこまで頼めるのか、範囲の線引きをどう決めるかで扱っています。
