レガシーPHP → PHP 8.3/8.4 モダナイザー
いつ使うか
このスキルは、レガシーなPHPプロジェクト(通常はPHP 5.x用に書かれた独自CMS)が以下の条件を満たす必要がある場合に使用します:
- PHP 8.3 / 8.4 でフルリライトせずに動作する必要がある、かつ/または
- FTP経由で共有ホスティング(cPanel/Plesk) にデプロイする必要がある(Dockerなし)。
典型的な症状:mysql_*、ereg/eregi、<? ショートタグ、PHP4スタイルのコンストラクタ、
裸の配列キー($row[Id])、$$var['key']、sizeof(null)、MyISAMダンプ、
TemplatePowerテンプレート、config/defines*.php 内の平文認証情報。
このスキルが提供するもの
| アセット | 目的 |
|---|---|
scripts/compat.php | 互換シム:mysql_*→mysqli、ereg*/split→preg、userErrorHandler |
scripts/fix_barewords.php | トークナイザーを使用した裸の配列キーの安全な引用符付け |
scripts/fix_variable_variables.php | PHP 8の $$var['key'] 統一変数構文の破損を修正 |
scripts/check_signatures.php | 静的LSPメソッドシグネチャチェッカー |
scripts/lint-all.sh | php -l スイープ |
scripts/smoke-test.sh | URLリストに対するHTTPスモークテスト |
templates/defines.php | .env ローダー + DB定数(Dockerあり/なし両対応) |
templates/env.example | .env テンプレート(DB_* + FTP_*) |
templates/htaccess | モダンなApache/PHP-FPM用 .htaccess |
templates/user.ini | 共有ホスティング用PHP-FPMオーバーライド |
templates/timthumb.php | 安全なGDサムネイル生成(脆弱なTimThumbの置き換え) |
deploy/deploy.sh | FTPまたはrsyncデプロイ、開発ファイルを除外、リモート .env を書き込み |
黄金律
- 安全第一:何かに触れる前に
git init+ ベースラインコミット。DBのバックアップを取る。 - リファクタリングより先に動作を確保:シムによりコードベース全体がすぐに動作するようになる。
- 一元化されたDBレイヤー:まず
dbClassを置き換え/制限する。シムは生のmysql_*呼び出しをカバーする。 - セキュリティは早期に:サイトがレンダリングされたらすぐに危険なツールやTimThumbを削除する。
- 継続的に検証:バッチごとに
php -lを実行し、その後すべてのURLをスモークテストする。
手順
0. ベースライン
git init -q && git add -A && git commit -qm "baseline: legacy PHP"
find . -name '*.php' -not -path './node_modules/*' | wc -l
scripts/smoke-test.sh 用に、実際の公開URLのリストを(DB/サイトマップから)保存します。
1. 互換シムのインストール
scripts/compat.phpを例えばincludes/compat.phpにコピーします。- ブートストラップの一番上で、レガシーコードの前に読み込みます:
include_once(__DIR__.'/../includes/compat.php'); - これにより、
mysql_*、ereg/eregi/ereg_replace/eregi_replace/split、mysqli_report(MYSQLI_REPORT_OFF)(SQLエラーはスローされずfalseを返す)、 およびuserErrorHandler()(PHP 5の古いE_NOTICE「undefined index/variable」を抑制)が提供されます。 - ハンドラを一度登録します:
if (function_exists('userErrorHandler')) set_error_handler('userErrorHandler');
2. 機械的な修正(スクリプト)
php scripts/fix_barewords.php # ドライラン
php scripts/fix_barewords.php --apply
php scripts/fix_variable_variables.php # ドライラン
php scripts/fix_variable_variables.php --apply
scripts/lint-all.sh
その後、lintでまだ報告されるものを修正します:
- ショートタグ:
<?→<?php(grep<\(?!php|=|xml\)) - PHP4コンストラクタ:
function ClassName()→function __construct() - 中括弧による文字列オフセット:
$s{0}→$s[0] - ループ/switch外の
break(PHP 8では致命的エラー) ${...}内の可変変数:裸のワードを引用符付け/${$var['k']}を使用
3. シグネチャ、静的、ヌルセーフティ
php scripts/check_signatures.php
各 MISMATCH について、子メソッドにデフォルトパラメータを追加します(例:$tabla = null)。
その後、実行時に現れる致命的エラーを修正します:
| エラー | 修正 |
|---|---|
ArgumentCountError: too few arguments | 末尾のパラメータにデフォルト値を設定 |
静的メソッド内の $this | self::/static:: を使用するか、アプリコンテキストを渡す |
method_exists(null, ...) | is_object($x) && method_exists($x, ...) |
Cannot access offset of type string on string | $x['k'] の前に is_array($x) を配置 |
Undefined constant "X" | 裸のワードキー/定数を引用符付け |
sizeof/count/array_keys(null) | is_array($x) ? ... : ...、(array)$x |
foreach(null) | foreach ((array)$x as ...) |
Accessing static property X as non static | $this->prop → self::$prop |
4. 実際のDBに対して実行し繰り返す
設定をDBに向け、すべてのURLをリクエストします。scripts/smoke-test.sh がゼロ失敗を報告し、ログに警告がなくなるまで、テストごとに1つの致命的エラーを修正します。
5. セキュリティ(早めに行う)
- TimThumbを
templates/timthumb.phpで置き換えます。 scanner.php、chmod777.php、info.php、不要なデバッグスクリプトを削除します。.htaccessで.env、.git、config/defines.php、ドットファイルへのアクセスを拒否します。- コミットされたDBパスワードを変更し、秘密を
.envに移動します。 - CSRFトークン、CSP/HSTS、レート制限、プリペアドステートメントを推奨します。
6. 設定 + デプロイ
templates/defines.php(.envローダー)とtemplates/env.exampleを使用します。templates/htaccessとtemplates/user.iniを使用します。deploy/deploy.shでデプロイします。
.env システム
config/defines.php はプロジェクトルートから .env を読み込み、getenv() にフォールバックし、最後に安全なデフォルト値にフォールバックします。これにより、Dockerでも同じ DB_* キーで動作し続け、FTPデプロイは1ファイルの編集で済みます。
.env(コミットしない):
DB_HOST=localhost
DB_NAME=cpaneluser_termospa
DB_USER=cpaneluser_termospa
DB_PASS=super-secret
DB_SUBDIRECTORIO=
デプロイ(Dockerなし)
共有ホスティング(cPanel/Plesk)チェックリスト
- PHP:8.3(または8.1以上)を選択し、
mysqli、gd、mbstring、pdo_mysqlを有効化。 - DB:DB + ユーザを作成し、ダンプをインポート。MySQL 8の場合:
SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION';utf8_spanish_ci→utf8mb3_spanish_ciの警告が想定される(またはutf8mb4移行を実行)。 - ファイル:
public_html/にアップロード(docker/、tools/、router.php、_DOCS/、.git/は除外)。 - パーミッション:ディレクトリ
755、ファイル644;recursos/cache/、.cache/、upload/は書き込み可能(775/777)。 - 設定:リモート
.envを作成(deploy.shが実行)し、DB_*を確認。 .htaccessで.envへのアクセスを拒否。
deploy.sh
./deploy.sh ftp # lftp リバースミラー
./deploy.sh ftp --dry-run
./deploy.sh rsync # SSH経由のrsync
.env(FTP_HOST/USER/PASS/PATH/TLS または SSH_*)を読み込み、ランタイムファイルのみをステージングし、リモート専用の DB_* のみを含む.env(FTP認証情報がサーバーに保存されないように)を書き込み、アップロードし、パーミッションとDBの手順を表示します。
検証チェックリスト
-
scripts/lint-all.sh→ すべてクリーン -
scripts/smoke-test.sh urls.txt→ 失敗0 - ホーム / 商品 / プロジェクト / ニュース / お問い合わせページが表示される
-
/sitemap.xmlと/rssが有効なXMLを返す -
/imagenes/thumbnail/...が画像を返す(GD + リライト) -
/administracion/login/が読み込まれ、ログイン + コンテンツマネージャが動作する - お問い合わせフォームが送信される
- 管理者の画像アップロードが
upload/に書き込まれる - エラーログに
PHP Warning/Fatalがない
よくある落とし穴
mysqli_queryはPHP 8.1以上ではデフォルトでスローする。mysqli_report(MYSQLI_REPORT_OFF)を呼び出して、従来のor die()/if($q=...)が動作し続けるようにする。.htaccess内のphp_flag/php_valueは PHP-FPM環境下でHTTP 500を引き起こす –.user.iniを使用する。- PHP 8の統一変数構文は
$$var['key']を静かに壊す(間違った変数に書き込む) –fix_variable_variables.phpを実行する。 include()の相対パスはスクリプトディレクトリ/CWDに対して解決される。__DIR__を優先して使用する。- PHP 8で削除されたもの:
mysql_*、ereg*、split、create_function、each、マジッククォート。 - OPcacheは古いファイルをキャッシュする。編集後はFPM/Apacheを再起動する。
- UTF-8:
SET NAMES utf8mb4;新しい作業ではInnoDB +utf8mb4_unicode_ciを推奨。
関連プロジェクト
これらのCMSプロジェクトは同じアーキテクチャを共有しています。ブートストラップパスとサムネイルリライトターゲットのみを調整して、同じ手順を実行します。scripts/ を対象の tools/ にコピーし、プロジェクトルートから実行します。