【Laravel】"storage/app/public"に配置した画像へアクセスしてみる

どーも!

今回はLaravelにて画像を表示してみます...!

今回は"storage/app/public"からのアクセスについてです!

Laravelのパブリックディスクについて

さて、まずはLaravelのアプリで設定されているデフォルトのディスクについて理解しましょう。

ディスクとは、データを保存するもの...といった認識でいいかと思います。

Laravelのデフォルト設定で、外部に公開するためにデータを保存すると...

"storage/app/public"

という風に、storageディレクトリの中が参照され、そこへデータが保存されるようになっています。

それに関しては以下の"パブリックディスク"に書かれています。

ただし...!

次のファイル構成の項目にて、"public"で検索すると...

storageと同じ階層で別のフォルダとしてpublicが用意されています。

publicディレクトリに関しては以下の説明が...

publicディレクトリには、アプリケーションへの全リクエストの入り口となり、オートローディングを設定するindex.phpファイルがあります。また、このディレクトリにはアセット(画像、JavaScript、CSSなど)を配置します。

そして、storageディレクトリに関しては以下の説明が...

storageディレクトリにはコンパイルされたBladeテンプレート、ファイルベースのセッション、ファイルキャッシュなど、フレームワークにより生成されるファイルが保存されます。このフォルダはappframeworklogsディレクトリに分かれています。appディレクトリはアプリケーションにより生成されるファイルを保存するために利用します。frameworkディレクトリはフレームワークが生成するファイルやキャッシュに利用されます。最後のlogsディレクトリはアプリケーションのログファイルが保存されます。

storage/app/publicディレクトリにはプロファイルのアバターなどのようなユーザーにより生成され、外部からアクセスされるファイルが保存されます。public/storageがこのディレクトリを指すように、シンボリックリンクを張る必要があります。リンクは、php artisan storage:linkコマンドを使い生成できます。

publicの説明、storageの後半の説明を見比べてみると、publicディレクトリはサービス提供側が見せたい画像(ロゴの画像やデザイン用の画像等...)を配置し、"storage/app/public"には、ユーザーが追加(ユーザー毎のプロフィール用画像等)するファイルで、なおかつ外部からアクセスが必要になるファイルを配置する用途のようです。

まずは、この違いを理解しておきましょう!

Point!
  • Laravelでは"public"と呼ばれるディレクトリが二つある("public", "storage/app/public")
  • "public"にはロゴ画像やデザイン用のファイルなど、サービス側のリソースを配置する
  • "storage/app/public"にはユーザーが投稿した画像等のリソースを配置する
  • デフォルト設定で、Laravelのアプリのデータ保存先は"storage/app/public"になっている

"storage/app/public"に画像を配置する

では早速試します。

今回は"storage/app/public"に適当な画像を配置し、読み取れることを確認します。

"public"に置いたものの読み取りについては別途以下の記事にて解説しているので、ご参照ください。

先程説明した通り、本来は"storage/app/public"に配置すべき画像はユーザーが投稿した画像等です。

つまり、Laravelのフレームワークの処理として追加した画像が配置されるべきです。

今回は配置されている画像の参照部分にのみ焦点を当てているため、適当な画像をそのまま手動で配置して動作確認をします。

その点はご留意ください。

(今後、フレームワークでの画像の保存処理とかは記事にするかもです...!)

では、画像を保存します!

"storage/app/public"ディレクトリに、"images"ディレクトリを作成し、その下に"icons.png"という形で画像データを配置します。

これで、準備はOKです。

シンボリックリンクを設定する

さて、先程"storage/app/public"に必要なファイルを配置しました。

しかしながら、まだアクセスはできません...!

"storage"のディレクトリ説明の後半部分は以下でした。

storage/app/publicディレクトリにはプロファイルのアバターなどのようなユーザーにより生成され、外部からアクセスされるファイルが保存されます。public/storageがこのディレクトリを指すように、シンボリックリンクを張る必要があります。リンクは、php artisan storage:linkコマンドを使い生成できます。

ユーザーのアイコン画像などは外部からアクセス(Webページに表示等)できるようになっていないといけないのですが、Laravelでは"public"ディレクトリ意外はアクセスできないようになっています。

そのため、この"storage"ディレクトリに配置したicon画像にはアクセスできません。

そこで...!

"storage/app/public"には公開してもいい画像のみ配置されるはずなので...

"storage/app/public"ディレクトリだけは"public"にあるのと同じ状態に設定し、アクセスできるようにする...

というのがシンボリックリンクの役割です。

詳細は再掲しますが、以下の"パブリックディスク”に記載されています。

Webからのアクセスを許すには、public/storageからstorage/app/publicへシンボリックリンクを張る必要があります。

つまり、"public"ディレクトリにある"storage"ディレクトリにアクセスしたら、"storage/app/public"ディレクトリへアクセスできるようなショートカットを貼る作業と言い換えてもいいかもしれません。

では、やっていきましょう!

と言っても...以下のコマンドを叩くだけです...!

php artisan storage:link

叩いて以下のように"... has been linked"となればOKです。

root@5362a8c4161e:/var/www/html# php artisan storage:link
The [public/storage] directory has been linked.

念の為、以下で確認をしておきます。

// publicディレクトリへ移動
cd public

// lsでシンボリックリンクを確認
ls -la
root@5362a8c4161e:/var/www/html# cd public
root@5362a8c4161e:/var/www/html/public# ls -la
total 528
drwxr-xr-x 12 root root    384 Mar 20 11:35 .
drwxr-xr-x 34 root root   1088 Mar 13 15:22 ..
-rw-r--r--  1 root root    593 Nov 28 11:23 .htaccess
...
...
lrwxr-xr-x  1 root root     32 Mar 20 11:35 storage -> /var/www/html/storage/app/public
...
...

上記のように"storage -> /var/www/html/storage/app/public"といった形になっていればOKです!

画像を表示してみる

さて、それでは画像を表示してみます。

まず、リンクが正しく通っているか、以下URLで画像にアクセスしてみます。

http://localhost/storage/images/icon.png

すると...

画像が表示されました!

では、コード上での書き方もみていきます。

例えば以下のようにすると...?

<img src="storage/images/icon.png" width="100" height="100">
<img src="{{ asset('storage/images/icon.png') }}" width="100" height="100">
assetの結果: {{ asset('storage/images/icon.png') }}

以下画像の"テスト画面"の下部分が上記コードにあたります。

画像が二つ、そして"assetの結果"が出ています。

画像の表示はどちらもurlの文字列を指定しているだけです。

laravelでは"asset"というメソッドがあり、このメソッドは"public"ディレクトリへアクセスするurlを自動で生成してくれます。

assetの引数としてpublic以降のアクセスしたいパスを指定できます。

今回の例でいくと...

"storage/images/icon.png"を設定しているため、"public"ディレクトリの"storage/images/icon.png"へアクセスを行います。

ただ、先程言ったように、実際にpublicディレクトリ以下にそういったデータはありません。

だけど、シンボリックリンクを貼ったおかげで、"public"ディレクトリの"storage"へアクセスしたタイミングで、"storage/app/public"へ代わりにアクセスされるわけです。

そして、その後"storage/app/public"の下に"images/icon.png"というファイルがあるため、画像がちゃんと表示さています。

パスのurlに"public"が含まれていないので少し違和感を感じる人もいるかもしれないです。

ここからは筆者の推測ではありますが、laravelではそもそも"public"ディレクトリのファイルにのみアクセスが可能と名言されているため、"http://localhost/storage"の時点で、シンボリックリンクがあれば"public"へのアクセスである...と判断されているようです。

おまけ

少し気になったので検証してみました。

"public"へのアクセスURLとルーティングを重複させてみようと思います。

先程、以下で画像へのアクセスができたので...

http://localhost/storage/images/icon.png

web.phpにて以下のように記載してアクセスしてみます。(絶対あり得ないと思いますが...w)

Route::get('storage/images/icon.png', function () {
    return view('test');
});

この際、画像を表示するURLも、上記のtestブレードを表示するgetのためのURLも同じ状態になっているはずです。

この状態で以下へアクセスしてみると、画像が普通に表示されました。

http://localhost/storage/images/icon.png

つまり、ルーティングが無視された形ですね。

次に、シンボリックリンクを消した状態で再度アクセスをしてみると...

ルーティングが走り、testのブレードが表示されました。

前後は把握できていませんが、シンボリックリンクを貼っている場合、"storage"始まりのルーティングは使わない方が無難ですね...

いや、貼ってる貼ってないに関わらず避けた方がいいでしょう(将来的にシンボリックリンクを使う場合に大変そうなので...)

まとめ

さて、今回は"storage/app/public"にある画像を表示してみました!

ユーザーが投稿する画像系の表示に関してざっくり理解できました!

最後の振り分け部分とかはより深く追って理解した方がいいんだろうなぁ...と思いつつも気力が持たないので...

また余裕があれば調べてみまーす!

それでわ!

おすすめの記事