Laravelでのpublicディレクトリについて
やりたかったのは次のようなことです。
- /storage/app/publicにファイル保存
- /public/storageにシンボリックリンク
- 保存ファイルを外部から表示できるように
なんか public という単語が紛らわしい...
そういう訳もあって少し苦戦しました。
ここでは/storage/app/publicの使い方を解説。
そして外部から表示することを目標にします。
このページの目次
まずは/storage/app/publicにシンボリックリンク
これは公式でも丁寧に解説されています。
▼ Laravel8.x ファイルストレージの一節
これらのファイルにWebからアクセスできるようにするには、public/storageからstorage/app/publicへのシンボリックリンクを作成する必要があります。このフォルダ規約を利用すると、Envoyerのようなダウンタイムゼロのデプロイメントシステムを使用する場合に、パブリックにアクセス可能なファイルを1つのディレクトリに保持し、デプロイメント間で簡単に共有できます。
▼ つまり次のコマンド実行すればOK
1 |
php artisan storage:link |
これで何が起こるかというと、 [laravelルート]/public/storage が作成され、そのフォルダの指し示す場所が [laravelルート]/storage/app/public になるということです。
これは「シンボリックリンク」と仰々しい名前が付いていますが、要はショートカットを作成してるだけです。
似た言葉に「ハードリンク」があるけど、それとも別ですね。シンボリックリンクは平たく言うなら「ショートカット」のことです。(参考記事 : Windowsでシンボリックリンク・ハードリンクの作成方法を解説)
ファイルを/storage/app/publicに保存する
これが分からなくて苦戦しました。
なんか専用のメソッドがあると思ってたんですよね。
でもなかったので、周りくどい方法になりました。
▼ 例えばこういうコードを書いてみた
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/// 保存したいダウンロード先URL $download_url = 'https://hoge.com/hoeg.png'; /// public以下に hoge ディレクトリ作成 $hoge_dir = storage_path('app/public/hoge/'); if( ! file_exists($hoge_dir)){ /// PHPのmkdir関数で作成する mkdir($hoge_dir, 0755, true); } /// ファイルをguzzleを使って保存 $client = new \GuzzleHttp\Client(); $file_name = 'hoge.png'; $client->request( 'GET', $download_url, [ 'sink' => $hoge_dir.'/'.$file_name ] ); |
ここで重要なのが storage_path() は [laravelルート]/storage の絶対パスを返してくることです。そして引数にはサブディレクトリのパスが渡せます。
そしてディレクトリが存在していなければPHPに元々あるmkdirを使って作成。こうしてるのはlaravelでpublicディレクトリを扱うメソッドがないためです。
▼ つまりこういうディレクトリ構成になる
1 2 3 4 5 6 7 8 9 |
- laravelルート - storage/app - public (リンク元) - hoge - hoge.png - public - storage (リンク先) - hoge - hoge.png |
Laravelのストレージ関係のAPIは充実してるけど、調べるのが面倒になったから原始的な方法を使いました。
あとguzzleでのファイル保存について
▼ もう一度このコードを載せておく
1 2 3 4 5 6 7 8 |
/// ファイルをguzzleを使って保存 $client = new \GuzzleHttp\Client(); $file_name = 'hoge.png'; $client->request( 'GET', $download_url, [ 'sink' => $hoge_dir.'/'.$file_name ] ); |
Guzzleにはsinkオプションなるものがあり、それに保存したいファイルパスを渡すことで保存まで行ってくれます。もちろん作成するのはファイルまでなので、ディレクトリが存在するかのチェックは必要ですね。
こういう感じでpublic内にファイル保存できました。
ファイルURLはassetメソッドを使えば取得可能
保存ファイルはassetsメソッドで取得すると楽
▼ このようなコード
1 2 |
/// ファイルURLを取得 $url = assets('/storage/hoge/hoge.png'); |
このコードは [laravelルート]/public 直下のパスを取得できるので、上記URLは http(s)://[ドメイン]/storage/hoge/hoge.png のようになります。
Laravelは便利だけどストレージ関係は少し分かりにくい気がする。もし迷ったなら原始的にPHP関数(mkdir、file_exists、etc...)を使う方がいいかもしれません。
画像に関わらずに他ファイル形式でも同じ
もちろん画像ファイルだけではなく、
- 音声・動画ファイル
- テキスト形式ファイル
- その他バイナリなど
ここで紹介した方法で保存できます。
以上、Laravelでのpublicディレクトリ保存でした。