php artisan storage:link とは?画像が表示されないときに
画像をアップロードする機能を作った。保存はできているはずなのに、画面に表示すると画像が出ない。リンクを開くと「404 Not Found(見つかりません)」になる。
Laravel で画像を扱うとき、多くの人が最初につまずくところです。原因はたいてい1つで、php artisan storage:link を実行していないことです。
この記事では、このコマンドが何をしているのかを仕組みから説明します。
結論(急いでいる人向け)
ターミナル(黒い画面)でプロジェクトのフォルダに移動し、次を実行します。
php artisan storage:link
これで表示されるようになります。以下で「なぜこれが必要なのか」を説明します。
なぜ画像が表示されないのか
理由を知るには、Laravel のフォルダ構成を理解する必要があります。ポイントは2つのフォルダです。
| フォルダ | 役割 |
|---|---|
public/ | ブラウザから直接見える場所。CSS や画像など公開ファイルを置く |
storage/app/private/ など storage/ 配下 | ブラウザから直接は見えない場所。アップロードされたファイルを置く |
Web サーバーは、セキュリティのために public/ フォルダだけを外部に公開しています。public/ の外にあるファイルは、URL を直接叩いても見られません。これはわざとそうしている仕組みです。データベースのパスワードが書かれた .env などが外から見えてしまったら大変ですから。
ところが、アップロードした画像は storage/app/public/ に保存されます。名前に public と付いていますが、場所は public/ フォルダの外です。
プロジェクト/
├── public/ ← ブラウザから見える
│ └── (ここに無いと表示できない)
└── storage/
└── app/
└── public/ ← 画像はここに保存される(ブラウザから見えない)
└── photo.jpg
つまり、保存はできているけれど、ブラウザから届かない場所にある。これが画像が表示されない理由です。
storage:link は「近道」を作るコマンド
ではどうするか。画像を public/ にコピーする、という方法もありそうですが、それだとファイルが二重になってしまいます。
そこで Laravel は「シンボリックリンク」という仕組みを使います。
シンボリックリンクとは、**別の場所へつながっている「近道(ショートカット)」**のことです。Windows のショートカット、macOS のエイリアスと同じ考え方です。実体は1つのまま、別の場所からもたどれるようにします。
php artisan storage:link を実行すると、次のリンクが作られます。
public/storage →(つながっている)→ storage/app/public
これで、ブラウザが public/storage/photo.jpg を見にくると、実際には storage/app/public/photo.jpg が返されます。ファイルをコピーせずに、公開できるようになるわけです。
実行してみる
プロジェクトのフォルダで実行します。
php artisan storage:link
成功すると、次のように表示されます。
INFO The [public/storage] link has been connected to [storage/app/public].
これで完了です。ブラウザを再読み込みすると画像が表示されるはずです。
どこへリンクが作られるかは設定で決まっている
このコマンドが「どこからどこへ」リンクを作るかは、config/filesystems.php に書かれています。
'links' => [
public_path('storage') => storage_path('app/public'),
],
これは「public/storage から storage/app/public へリンクを作る」という意味です。public_path() と storage_path() は、それぞれのフォルダの場所を返す Laravel の関数です。
特別な理由がなければ、この設定はそのままで問題ありません。
ビューでの画像の表示方法
リンクを作ったら、画面に表示するときは asset() 関数を使います。
// コントローラ側: 画像を保存する
// storage/app/public/photos/ に保存され、"photos/xxx.jpg" のようなパスが返る
$path = $request->file('photo')->store('photos', 'public');
保存したパスをビュー(画面を作るファイル)で表示します。
<img src="{{ asset('storage/' . $photo->path) }}" alt="写真">
asset('storage/...') の storage/ の部分が、さきほど作ったシンボリックリンクです。ここを忘れると表示されないので注意してください。
なお、Storage::url() を使う書き方もあり、こちらでも同じ URL が得られます。
<img src="{{ Storage::disk('public')->url($photo->path) }}" alt="写真">
よくあるつまずき
1. サーバーにデプロイしたら、また表示されなくなった
シンボリックリンクは環境ごとに作る必要があります。自分のパソコンで実行しても、公開サーバーには反映されません。
デプロイ(公開サーバーへ設置すること)したあと、サーバー側で改めて実行してください。
php artisan storage:link
多くのプロジェクトでは、デプロイ手順の中にこのコマンドを含めておきます。
2. 「already exists」と言われる
すでにリンクがある場合、次のように表示されます。
ERROR The [public/storage] link already exists.
ERROR と出るので不安になりますが、これは「すでに近道があるので作らなかった」という意味です。リンクが正しく張れているなら、そのままで問題ありません。
壊れたリンクが残っていて作り直したい場合は、--force(フォース=強制)を付けます。
php artisan storage:link --force
これは既存のリンクを作り直すオプションです。
3. レンタルサーバーでシンボリックリンクが使えない
共用のレンタルサーバーなどでは、シンボリックリンクの作成が許可されていない場合があります。その場合は --relative(相対パスでリンクを作る)を試すと通ることがあります。
php artisan storage:link --relative
それでも通らない場合は、コントローラ経由でファイルを返す方法(Storage::download() などを使う)を検討します。
4. public/storage を Git に入れてしまっている
シンボリックリンクは環境ごとに作るものなので、Git(バージョン管理)に含める必要はありません。Laravel の標準の .gitignore では、はじめから除外されています。
まとめ
- 画像が表示されないのは、保存先の
storage/app/publicがpublic/の外にあり、ブラウザから直接見えないため。 php artisan storage:linkは、public/storageからstorage/app/publicへの**シンボリックリンク(近道)**を作るコマンド。- リンクの設定は
config/filesystems.phpのlinksに書かれている。 - 表示は
asset('storage/' . パス)またはStorage::disk('public')->url(パス)を使う。 - デプロイ先でも実行が必要。すでにある場合の作り直しは
--force、環境の制約があるときは--relativeを試す。
ファイルのアップロード自体のやり方は、カリキュラムの フォームを作る で解説しています。