静的サイトの画像管理をどこに置くか

記事に画像を貼れるようにしたときの設計メモです。

落とし穴: 生成物に直置きする

公開ディレクトリ(生成された静的HTMLの置き場)に画像をアップロードする方式は、一見素直ですが破綻します。公開のたびに生成物を掃除して作り直すため、置いた画像が消えるからです。

正本と生成物を分ける

そこで、画像も記事と同じく「正本」側に置くことにしました。

content/
  posts/     ← 記事の正本(.md)
  uploads/   ← 画像の正本
dist/        ← 生成物(毎回作り直される)
  uploads/   ← 公開時に content/uploads/ からコピー

公開処理が content/uploads/dist/uploads/ へコピーします。これで「画像も記事と一緒にバックアップされる」「生成物はいつ消しても復元できる」という静的サイトの利点が画像にも及びます。

アップロード時の検査

管理画面からのアップロードは、拡張子の許可リストに加えてファイルの中身(マジックバイト)も確認しています。拡張子だけの検査は、PHPコードを .png と偽って置かれる古典的な攻撃に無力だからです。

  • 許可: jpg / jpeg / png / gif / webp / svg
  • ファイル名は記号を落として正規化し、衝突したら連番を付ける

小さな道具でも、ファイルを受け取る口だけは丁寧に作る価値があります。