Special Feature — PHP Upgrade after PHP2Shell
PHP2Shell(CVE-2026-109618 / 109619)の対応で 8.x の修正版を入れたあと、
5.3〜8.1 で書かれたソースコードを移すための、起点バージョン別ガイドです。
2026年10月21日、PHP の開発チームは認証なしの遠隔コード実行につながる脆弱性 2 件を直した 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 を公開しました。まずやるべきはサーバー側の更新で、これはこのページの前半に書きます。後半と各論ページは、その次の段階、つまり「8.1 以前で動いているコードを、サポートの続く版で動くように直す」作業のためのものです。
起点のバージョン(いま動いている PHP)ごとにページを分け、移行先までに入った削除・非推奨・挙動変更を 1 項目ずつ並べました。お使いのバージョンが分かれば、該当ページだけ読めば足ります。
あなたのPHPコードが動いているバージョンをクリックすれば作業内容がわかります。。作業の途中で「どの項目まで見たか」を確かめに戻れるよう、このトップページを保存しておいてください。
チームで分担するときは、このURLを共有してください。
PHP2Shell は、CVE-2026-109618 と CVE-2026-109619 の 2 件をまとめた呼び名です。どちらも CVSS v4.0 で 9.2 と評価され、PHP 公式の勧告は「認証なしの遠隔コード実行を許し得る」と書いています。アプリケーションのコードではなく、PHP 本体がリクエストを処理する部分の不具合なので、自分のコードに問題がなくても影響を受けます。
| 日時 | 出来事 |
|---|---|
| 10/20(火) | PHP セキュリティチームが「10月21日 14:00 UTC(日本時間 23:00)に、CVSS v4.0 9.2 の致命的な脆弱性 2 件を直すセキュリティリリースを出す」と予告。詳細が公になったり悪用が確認されたりした場合は前倒しする、とも書いた |
| 10/21(水) | 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 を公開し、セキュリティ勧告を掲載。CERT-EU の記録では公開は 13:30 UTC(日本時間 22:30)で、予告より 30 分早い |
| 10/21(水) | 同じ勧告で、EOL の 7.4 / 8.0 / 8.1 向けに最小限のソースバックポートを GitHub のブランチで提供。ディストリビューションと LTS ベンダーは事前にパッチを受け取っていた |
出典: PHP News Archive 2026(10/20 予告・10/21 勧告とリリース告知)、CERT-EU Security Advisory 2026-018
CVE-2026-109618(メモリ不足時の破損による RCE、GHSA-w8hw-w9fx-j79w)。PHP は memory_limit を超えたリクエストを longjmp() で途中から打ち切ります。フォームからのファイルアップロードを解析している最中のように、リクエストの内部データがまだ途中までしか初期化されていない時点で打ち切られると、後片付けの処理がその不完全なデータを正しいものとして扱い、初期化されていないメモリを解放してしまう。そのメモリには、攻撃者が送り込んだデータが前の確保から残っている可能性があります。
CVE-2026-109619(古いグローバル状態による RCE、GHSA-6wmf-4rv5-p3rp)。Fatal error などのあと、リクエストに属する内部状態が、裏のメモリを解放された後も残ることがあります。同じワーカーが次に処理するリクエストが、通常の初期化で上書きされる前にその古い状態を使ってしまう、という不具合です。
図1: 上は「途中で打ち切られたデータを、後片付けが正しいものとして扱う」流れ。下は「前のリクエストの状態を、次のリクエストが使ってしまう」流れ(PHP 公式勧告と CERT-EU の説明から作図)。
公式勧告が対象に挙げているのは、Web リクエストを処理するすべての PHP です。CLI で動かすバッチだけの環境は列挙に入っていませんが、同じマシンで Web も動いているなら対象になります。
| 実行形態(SAPI) | 対象 | 補足 |
|---|---|---|
| Apache + mod_php | 対象・最も危険 | 公式は危険度が最も高いと評価。アプリケーションのコードが動く前に、認証なしの 1 リクエストで攻撃を起こせる実証がある |
| PHP-FPM(nginx / Apache など) | 対象 | 公式の列挙に含まれる。nginx と組み合わせた構成もここに入る |
| php-cgi | 対象 | 公式の列挙に含まれる |
| FrankenPHP / LiteSpeed | 対象 | 公式の列挙に含まれる |
影響を受ける版は、8.5 系の 8.5.12 未満、8.4 系の 8.4.27 未満、8.3 系の 8.3.36 未満、8.2 系の 8.2.35 未満です(CERT-EU の整理)。8.1 以前は PHP プロジェクトの更新対象外の EOL 版で、CERT-EU も影響を受ける製品として EOL 系列を挙げています。
見落としやすいのが、PHP を中に組み込んだ製品です。CERT-EU は「多くの商用・オープンソース製品が PHP をバックエンドに使っている」と注意を促し、オランダの NCSC-NL が公開している一覧リポジトリ NCSC-NL/php2shell で、自社で使っている機器やソフトが該当するか確かめるよう勧めています。サーバーに PHP を入れた覚えがなくても、管理画面が PHP で動くアプライアンスは珍しくありません。
ここは情報源によって書き方が違うため、断定はしません。CERT-EU は「最初の概念実証コード(PoC)が出回り始めており、攻撃者がすでに悪用している可能性がある」と書いています[1]。カナダのサイバーセキュリティセンターは 10月21日の時点で「PoC は入手可能だが、実際の悪用は確認されていない。状況はすぐ変わり得る」としています[2]。どちらにしても、インターネットから届く場所にある古い PHP は、更新を後回しにできる状態ではありません。
コードの改修より先に、まずサーバーです。公式の告知は「完全な緩和策は無く、更新だけが安全な選択」と明記しています。いま動いている系列ごとに、やることは次のとおりです。
| いまの系列 | 更新先・対処 | 状況 |
|---|---|---|
| 8.5 | 8.5.12 へパッチ更新(コード改修なし) | 修正版あり |
| 8.4 | 8.4.27 へパッチ更新(コード改修なし) | 修正版あり |
| 8.3 | 8.3.36 へパッチ更新(コード改修なし) | 修正版あり |
| 8.2 | 8.2.35 へパッチ更新。ただし 2026-12-31 でセキュリティサポートが終わるので、続けて 8.4 以降への移行を計画する | 修正版あり |
| 8.1 / 8.0 / 7.4 | ディストリビューションや LTS ベンダーのバックポート版を使う。ソースからビルドしている場合は、公式が出した最小限のソースバックポート(8.1 / 8.0 / 7.4)を使う | 応急処置のみ |
| 7.3 以前(5.x を含む) | 公式のバックポートは 7.4 / 8.0 / 8.1 向けだけ。ベンダーの延長サポートが無ければ、サポートされる系列へ移すことが唯一の根本対策。移行が終わるまでは下の緩和策と、公開範囲の縮小で守る | 修正なし |
FROM php:8.4-fpm のような書き方でも、手元にキャッシュされた古いイメージから作り直すと更新されません。docker pull してから再ビルドし、コンテナの中で版を確かめます。パッケージを入れ替えただけでは、動いているプロセスは古いままです。CVE-2026-109619 は「同じワーカーが次に処理するリクエスト」で起きるので、全ワーカーの再起動まで済ませて初めて更新が効きます。コマンド名やサービス名はディストリビューションで違うので、下は例として読んでください。
# CLI の版(Web 側と別のバイナリのこともある)
php -v
# FPM の版(Debian / Ubuntu では php8.4-fpm のような名前)
php-fpm -v
# Apache に mod_php が読み込まれているか(php_module が出たら mod_php)
apachectl -M | grep -i php
# FPM を再起動して全ワーカーを入れ替える(サービス名は環境に合わせる)
sudo systemctl restart php-fpm
# Web 経由でも版を確かめる。確認後はこのファイルを必ず消す
echo '<?php echo PHP_VERSION;' | sudo tee /var/www/html/v.php
curl -s http://localhost/v.php ; sudo rm /var/www/html/v.php
以下は公式勧告が挙げているものをそのまま並べたものです。公式は「特定の攻撃経路への露出を減らすだけで、安全にはならない」と明記しています。更新までのつなぎとして使ってください。
| 対象 | 緩和策(公式の列挙) |
|---|---|
| CVE-2026-109618 |
|
| CVE-2026-109619 |
|
CERT-EU はさらに、すぐ更新できないインターネット向けの資源は、修正を適用して確認できるまで隔離するよう勧めています。7.3 以前のように修正版が存在しない環境では、mod_php から PHP-FPM への切り替え、WAF、管理画面を社内からしか開けないようにする、といった公開範囲の縮小を組み合わせて、移行完了までの時間を稼ぐことになります。
8.2〜8.5 のどれかを使っていた人は、パッチ版を上げるだけで今回の対応は終わります。問題は 8.1 以前で動いていたシステムです。バックポートで今回の穴をふさいでも、本家のサポートが終わった系列には次の脆弱性の修正が出ません。同じことがまた起きたとき、その都度ベンダー頼みになります。
では 8.2〜8.5 のどれへ移すか。ここで、よく聞かれる「8.2 / 8.3 / 8.4 / 8.5 の間で互換性は保たれているか」に答えておきます。
そのうえで、移行先は 8.4.27 を第一候補、新しい版を長く使いたいなら 8.5.12 とします。8.2.35 は 2026-12-31 でセキュリティサポートが終わるので、いまから移す先には選びません。8.3.36(2027-12-31 まで)は、8.4 で増える非推奨(暗黙の nullable 型など、Deprecated が大量に出るもの)を今回は踏みたくない場合の妥協点です。各論ページでは、移行先を切り替えると必要な項目だけが表示されるようにしてあります。
| 移行先 | 公開日 | セキュリティサポート | 位置づけ |
|---|---|---|---|
| 8.4.27 | 2026-10-21 | 2028-12-31 まで | 第一候補 |
| 8.5.12 | 2026-10-21 | 2029-12-31 まで | 最も長く使える。8.5 の非推奨 12 項目も一度に片付ける |
| 8.3.36 | 2026-10-21 | 2027-12-31 まで | 8.4 の非推奨を後回しにしたい場合の妥協点 |
| 8.2.35 | 2026-10-21 | 2026-12-31 まで | 選ばない(あと約 2 か月) |
サポート期限の出典: PHP Supported Versions、8.2 の EOL は 8.2.35 のリリース告知にも明記
php -v に出る番号をそのまま入れてください。同じ系列(2 つ目の数字まで同じ)なら、どのパッチ版から移しても必要な対応は同じなので、案内するページは系列ごとに 1 つです。
試す:
セルの数字は、起点から移行先までに入った変更の数です(括弧内は 削除/非推奨/挙動変更)。数字を押すと、その移行先を選んだ状態で各論ページが開きます。
| 起点(系列の最終版) | → 8.2.35 | → 8.3.36 | → 8.4.27(推奨) | → 8.5.12 |
|---|---|---|---|---|
| 5.3.29 | 16151/36/74 | 17552/40/83 | 19154/47/90 | 21355/59/99 |
| 5.4.45 | 14842/35/71 | 16243/39/80 | 17845/46/87 | 20046/58/96 |
| 5.5.38 | 14241/32/69 | 15642/36/78 | 17244/43/85 | 19445/55/94 |
| 5.6.40 | 13241/29/62 | 14642/33/71 | 16244/40/78 | 18445/52/87 |
| 7.0.33 | 10026/26/48 | 11427/30/57 | 13029/37/64 | 15230/49/73 |
| 7.1.33 | 8620/25/41 | 10021/29/50 | 11623/36/57 | 13824/48/66 |
| 7.2.34 | 7718/22/37 | 9119/26/46 | 10721/33/53 | 12922/45/62 |
| 7.3.33 | 6717/21/29 | 8118/25/38 | 9720/32/45 | 11921/44/54 |
| 7.4.33 | 5415/15/24 | 6816/19/33 | 8418/26/40 | 10619/38/49 |
| 8.0.30 | 283/13/12 | 424/17/21 | 586/24/28 | 807/36/37 |
| 8.1.34 | 131/6/6 | 272/10/15 | 434/17/22 | 655/29/31 |
起点の次のマイナー版から移行先までの各版で入った変更を、順に確認していくことになります。「山」は互換性を大きく壊した 7.0 と 8.0 のことです。
| 起点 | 8.4.27 まで | 8.5.12 まで | 越える山 |
|---|---|---|---|
| 5.3.29 | 5.4〜8.4(13 版) | 5.4〜8.5(14 版) | PHP 7.0・PHP 8.0 |
| 5.4.45 | 5.5〜8.4(12 版) | 5.5〜8.5(13 版) | PHP 7.0・PHP 8.0 |
| 5.5.38 | 5.6〜8.4(11 版) | 5.6〜8.5(12 版) | PHP 7.0・PHP 8.0 |
| 5.6.40 | 7.0〜8.4(10 版) | 7.0〜8.5(11 版) | PHP 7.0・PHP 8.0 |
| 7.0.33 | 7.1〜8.4(9 版) | 7.1〜8.5(10 版) | PHP 8.0 |
| 7.1.33 | 7.2〜8.4(8 版) | 7.2〜8.5(9 版) | PHP 8.0 |
| 7.2.34 | 7.3〜8.4(7 版) | 7.3〜8.5(8 版) | PHP 8.0 |
| 7.3.33 | 7.4〜8.4(6 版) | 7.4〜8.5(7 版) | PHP 8.0 |
| 7.4.33 | 8.0〜8.4(5 版) | 8.0〜8.5(6 版) | PHP 8.0 |
| 8.0.30 | 8.1〜8.4(4 版) | 8.1〜8.5(5 版) | なし(Deprecated 中心) |
| 8.1.34 | 8.2〜8.4(3 版) | 8.2〜8.5(4 版) | なし(Deprecated 中心) |
パッチ番号は各系列で x.y.0 から最終版まで連番で、欠番はありません。たとえば 7.3 系の最終は 7.3.33 なので、「7.3.44」というリリースは存在しません。サーバーの表示がそれ以外の番号なら、ディストリビューションが独自に付けた番号の可能性があります。
どの起点からでも、順番はほぼ同じです。各論ページでは、これを起点ごとの事情に合わせて具体的に書いています。
--runtime-set testVersion 8.4)、PHPStan、Rector(withPhpSets() で 8.4 までの規則)で、削除された関数や構文を一覧にします。each()、create_function()、文字列中の ${}、暗黙の nullable 型、(integer) キャストなどは Rector でほぼ自動変換できます。error_reporting=E_ALL、display_errors=Off、log_errors=On にして、Deprecated を全件ログに出して潰します。5.x 起点は 7.4 を経由する 2 段階移行にして、7.0 の山と 8.0 の山を分けて越えるほうがデバッグしやすくなります。== による比較 [8.0]、ENT_QUOTES の既定化 [8.1]、PDO のネイティブ型 [8.1]、strtolower() のロケール非依存化 [8.2]、range() [8.3]、round() [8.4]、foreach と変数構文 [7.0]、htmlspecialchars() の UTF-8 既定 [5.4] は、各論ページの「特に危ない変更」で個別に取り上げています。項目数が 100 を超える起点では、1 項目ずつ人が grep して直すより、Claude Code や Codex のようなコーディングエージェントに機械的な部分を任せたほうが早く終わります。ただし任せ方を間違えると、テストの無いところで静かに挙動が変わります。各論ページの「コーディングエージェントに一括で任せる」節に、その起点と移行先を埋め込んだ完成形のプロンプト、CLAUDE.md / AGENTS.md に書く移行ルールの例、使える静的解析ツールの設定例を載せました。ここでは考え方だけ書きます。
#v80-05 のような id が付いているので、「この URL の項目を 1 つずつ確認し、該当箇所と対応を表で報告して」と頼めます。いま動いている系列のページを開いてください。どのページも、移行先を 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 から選ぶと、必要な項目数と一覧が切り替わります。
5.3.0〜5.3.29(30 版)。7.0 と 8.0 の 2 つの山を越える。
8.4.27 まで 191 項目 → 読む 起点 5.4 系5.4.0〜5.4.45(46 版)。7.0 と 8.0 の 2 つの山を越える。
8.4.27 まで 178 項目 → 読む 起点 5.5 系5.5.0〜5.5.38(39 版)。7.0 と 8.0 の 2 つの山を越える。
8.4.27 まで 172 項目 → 読む 起点 5.6 系5.6.0〜5.6.40(41 版)。7.0 と 8.0 の 2 つの山を越える。
8.4.27 まで 162 項目 → 読む 起点 7.0 系7.0.0〜7.0.33(34 版)。山は 8.0 の 1 つ。
8.4.27 まで 130 項目 → 読む 起点 7.1 系7.1.0〜7.1.33(34 版)。山は 8.0 の 1 つ。
8.4.27 まで 116 項目 → 読む 起点 7.2 系7.2.0〜7.2.34(35 版)。山は 8.0 の 1 つ。
8.4.27 まで 107 項目 → 読む 起点 7.3 系7.3.0〜7.3.33(34 版)。山は 8.0 の 1 つ。
8.4.27 まで 97 項目 → 読む 起点 7.4 系7.4.0〜7.4.33(34 版)。山は 8.0 の 1 つ。
8.4.27 まで 84 項目 → 読む 起点 8.0 系8.0.0〜8.0.30(31 版)。Deprecated の対応が中心。
8.4.27 まで 58 項目 → 読む 起点 8.1 系8.1.0〜8.1.34(35 版)。Deprecated の対応が中心。
8.4.27 まで 43 項目 → 読む各論ページの変更一覧は、次の移行ガイドと php-src の UPGRADING を元にしています。変更の一覧には、項目ごとに版別の公式リンクを付けました。
📌 ※2026年10月23日時点の公開情報に基づきます。脆弱性の影響範囲、悪用の状況、各ベンダーのバックポートの提供状況は日々更新されます。対応を決める前に、上の一次情報とお使いのディストリビューション・ホスティング事業者の告知を必ず確認してください。
🔖 各論ページで改修を進めながら、迷ったらこのページに戻ってきてください。ページ上部のブックマーク案内から URL をコピーできます。
本特集に掲載したコード・コマンド・設定例・エージェント向けプロンプトは、あくまで説明のための例です。お使いのソースコードや環境でそのまま動くこと、改修が漏れなく完了することを保証するものではありません。各変更点の最終確認は、php.net の公式 ChangeLog・移行ガイド、php-src の UPGRADING など一次情報で必ず行ってください。
本特集の内容は現状有姿で提供するものであり、正確性・完全性・有用性について、瑕疵担保責任・契約不適合責任を含め、当方(野口真一)はいかなる保証も行いません。本特集の内容やコードを利用したこと、または利用できなかったことにより生じた損害について、当方は一切の責任を負いません。
「どの版へ、どの順で移すか」「エージェントにどこまで任せてよいか」から、
古い PHP アプリの棚卸しと改修計画づくりまで、30分の無料相談で承ります。