2026-10-28確認。引継ぎ資料のないPHPサイトを調べるとき、最初に決めたいのは「どのコマンドを打つか」より、何を根拠にどこまで調べてよいかです。
composer.lockが渡されたとしても、それだけで本番と同じ環境を作れるとは限りません。手元のファイルが現在の配置物と一致するか、Web側のPHPや拡張が何か、変更した後に戻せるかは、別の確認だからです。
許可された資料の静的な棚卸しから始め、実行・変更に必要な条件が欠けた場所で止める。 この記事では、その調査範囲の切り方を考えます。依存一覧の確認には進めても、環境再現や修正の可否は保留、という結論を残せるようにします。
コードと結果は、Codexが架空データを用意して実行した個人ローカル検証です。実際のPHPサイト、PHPランタイム、Composerを動かした結果ではなく、顧客サイトの調査事例でもありません。
「フォームの一症状」を調べる範囲から始める
たとえば「送信後に画面が変わらない」という架空の症状があるとします。サイト全体の仕様復元を最初の完了条件にせず、対象URL、再現した操作、分かっている受付結果を一つの調査メモにします。権限のある担当者から受け取る資料も、その問いに必要な範囲に絞ります。
| 段階 | 確認するもの | この段階で残せる結論 | 次へ進めない条件 |
|---|---|---|---|
| 資料の棚卸し | 許可済みコピーのファイル一覧、依存定義、設定項目名 | 受領資料に書かれている構成の候補 | 対象・閲覧権限が不明、秘密値が混在 |
| 本番との照合 | 配置版、Web側のPHP・拡張、関連する保存・通知先の種類 | 資料と稼働環境の一致/不一致/不明 | 稼働環境の情報を取得できない |
| 隔離環境での再現 | 架空入力、外部接続を止めた環境、期待する保存結果 | その条件での再現結果 | 安全なデータ・接続制限・実行権限がない |
| 修正・反映の検討 | 回帰確認、反映担当、戻す対象と手順 | 修正範囲と反映条件の案 | 復旧方法・担当・承認が未確定 |
これは調査計画の案です。閲覧権限があることを、実行・更新の許可へ読み替えません。DBや通知サービスなどへ影響が及ぶと分かったら、その場で対象を広げず、追加で何を確認するかを返します。
次の図は、この調査計画を「資料に書いてあること」と「動かして確認すること」の境界で分けたものです。実システムの構成図ではありません。
図の03で止まっても、01と02の成果は残ります。「依存はここまで確認できたが、稼働環境との一致は不明」と返せれば、次に必要な資料や担当者が具体的になります。
lockの読取とComposerの実行を分ける
Composerの公式資料では、composer.lockに解決済みの依存バージョンを記録し、installはその版を使うと説明されています。一方、updateは依存を再解決します。調査のつもりで更新すると、調べたかった状態を変えてしまいます。Composer Basic usage
さらに、Composerにはscriptsとpluginsによって第三者コードが実行される経路があります。公式は、未信頼の依存をインストールするなら隔離を勧めています。--no-plugins --no-scriptsを付けることと、未知のプロジェクトを安全に動かせることも同一ではありません。Composer安全FAQ
そこで、最初の検証は指定したlockファイルをJSONとして読むだけにしました。vendor/autoload.phpは読み込まず、ComposerもPHPも起動しません。Composer未採用のサイトやlockが残っていないサイトでは、この方法は使えません。「依存なし」とせず、別の資料を探す判断になります。
小さな依存一覧を取り出す
次はPython標準ライブラリだけの読取例です。対象は、閲覧を許可されたコピーです。packages内の名前と版を取り出し、同じ読取バイト列のSHA-256を残します。
import hashlib
import json
from pathlib import Path
def inventory(path):
path = Path(path)
if path.is_symlink():
raise ValueError("snapshot must be a regular file, not a symlink")
raw = path.read_bytes()
data = json.loads(raw)
if not isinstance(data, dict) or not isinstance(data.get("packages"), list):
raise ValueError("packages must be an array")
rows = []
for package in data["packages"]:
if not isinstance(package, dict) or any(
not isinstance(package.get(key), str) or not package[key].strip()
for key in ("name", "version")
):
raise ValueError("package name/version must be nonempty strings")
rows.append((package["name"], package["version"]))
return hashlib.sha256(raw).hexdigest(), sorted(rows)
ファイル未取得・読取拒否・JSON不正は例外で止めます。欠落を空配列へ置き換えて成功にしません。実運用の収集器ではなく、小さな既知のコピーを読む例です。パスの隔離や競合対策を実装したものではなく、シンボリックリンク拒否だけで未知のファイル群を安全に扱えるとも考えていません。
以下を同じディレクトリのdemo.pyに保存し、python3 demo.pyで架空入力を確認できます。
import json
from pathlib import Path
from tempfile import TemporaryDirectory
from inventory import inventory
with TemporaryDirectory() as directory:
path = Path(directory) / "composer.lock"
path.write_text(json.dumps({"packages": [
{"name": "sample/mail-form", "version": "1.0.0"},
{"name": "sample/http-adapter", "version": "2.0.0"},
]}), encoding="utf-8")
digest, rows = inventory(path)
print(rows)
print("sha256_length:", len(digest))
これはComposer全体のlock形式を満たす配布サンプルではなく、読取箇所だけを抜き出した架空のJSONです。sample/のパッケージも実在製品の仕様を表していません。
[('sample/http-adapter', '2.0.0'), ('sample/mail-form', '1.0.0')]
sha256_length: 64
2026-10-28、Python 3.11.8で確認しました。追加した検証も含め、次の9ケースで期待する結果と一致しました。
| 入力・確認条件 | 結果 |
|---|---|
| 正常な2件 | 名前順の2件を返す |
packages: [] |
この配列内の記録は0件と分かる |
| 不正なJSON |
JSONDecodeErrorで停止 |
ルートが配列/packages欠落/版がnull |
各ケースでValueError
|
| ファイル欠落 |
FileNotFoundErrorで停止 |
| 指定ファイルがシンボリックリンク |
ValueErrorで停止 |
| lockを変えず、別ファイルの配置版メモだけ変更 | 読取結果は同じ。配置物の差は検出できない |
書いたfixtureを読む6ケースでは、読取前後のファイル内容も不変でした。最後のケースは機能の限界を確認したものです。lockのハッシュは受領した資料を識別するための値で、本番と同一である証拠ではありません。
このコードはpackages-dev、手動配置ライブラリ、独自コード、PHP拡張、脆弱性、依存関係の整合性までは調べません。得られるのは「この資料の、この配列に記録されている一覧」です。
実行へ進む前に残しておく不明点
依存一覧ができた後も、次の三つは別に確認します。
一つ目は、どの環境の情報かです。 PHPはSAPIなどによって異なる設定ファイルを使えます。手元でphp -vやphp --iniを見ても、Webリクエストを処理するPHPの版・拡張・設定と同じとは限りません。管理担当者と取得方法を決め、必要項目だけ照合します。公開場所へphpinfo()を置く手順にはしません。環境変数なども出力し得るためです。PHP設定ファイル、phpinfo
二つ目は、失敗した後に戻せるかです。 バックアップファイルの存在と、対象を復元して期待状態に戻せることは分けます。ファイル、DB、アップロード済みデータのどれを戻す必要があるか、誰が実行するか、復元後に何を見るかが不明なら、本番変更へは進めません。復旧未確認でも許可済み資料の読取はできますが、それを修正可能の根拠にはしません。
三つ目は、誰が次の判断をするかです。 調査担当は証拠と不明点を返し、管理担当は権限・配置版・復旧方法を確認し、業務担当は受付結果や完了条件を確認する、という分担を先に決めます。これは役割の案であり、実際の体制に合わせて合意が必要です。
調査の完了を「全部分かった」にしない
| 選択肢 | 選べる条件 | 残る制約 |
|---|---|---|
| 現状維持し、操作と既存記録を整理 | 実行権限や資料が足りない | 原因は確定できない。業務影響が大きければ管理担当へ対応を依頼する |
| 手動で資料を読む | 対象が少なく、閲覧範囲が明確 | 見落としを減らす照合が必要 |
| 既存の依存管理情報と小さな読取コードを使う | lockがあり、コピーの取得が許可されている | 配置物・環境・脆弱性は別確認 |
| 既製の検査ツールや隔離環境へ広げる | 接続先、データ、実行権限、復旧条件を確認できる | 導入・設定・結果確認の工数が加わる |
最初の完了条件は、たとえば「対象の一症状について、受領資料から分かる構成候補、不明点、次の確認先、実行を止めている理由を返す」です。原因特定や修復を、この静的調査の結果だけで約束しません。
工数にはファイルを読む時間だけでなく、資料受領、権限確認、不明点の照会、結果メモの作成も含めます。対象が増えたら、元の範囲で分かったことを残し、追加調査の範囲を決め直します。今回、調査費用や削減効果は測っていません。
次に進めるなら、まず受領資料と稼働中の配置版の対応を確認します。その後、外部送信を止めた隔離環境で一症状を再現できるかを別途判断します。再現、修正、反映、復旧のどこまで確認したかを分けて残すと、引継ぎ資料が少ない段階でも調査の結論を説明しやすくなります。
参考資料
公式資料の確認日はいずれも2026-10-28です。資料に基づく仕様の説明と、この記事の調査計画案・架空JSONの検証結果を分けています。
- Composer — Basic usage
- Composer — How do I install untrusted packages safely?
- PHP — The configuration file
- PHP — phpinfo
この記事を書いた人✏️@YushiYamamoto
個人事業ITPRODX.comの山本勇志です。PHPサイトの改修・保守、Web・CMS開発の担当経験を基に、既存システムの切り分けや設計判断を発信しています。
古いホームページやPHPサイトの調査・限定改修は、対応できる範囲を確認のうえご相談を承ります。
