RitoLabo

LaravelのFileStorageFlysystemパッケージでファイル操作を行う(local/publicディスク編)

  • 公開:
  • 更新:
  • カテゴリ: PHP Laravel
  • タグ: PHP,Laravel,Flysystem,FileStorage,5.5,5.4,5.3,ftp,Package,5.6

フレームワークを通してWEBアプリケーションを構築していると、ファイル操作の際のパスの管理が煩雑になりがちですが、Laravelにはそんなファイル操作の際にパスの管理を一切心配しなくて良い抽象ファイルシステム「Flysystem PHPパッケージ」が組み込まれています。

今回はFlysystemを使う準備から実際の操作までを行っていきます。

アジェンダ
  1. 開発環境
  2. ファイルストレージ設定ファイルの確認と設定
    1. ローカルストレージ「local」と「public」の違い
  3. ストレージへの保存・読み取り

開発環境

今回の開発環境については以下の通りです。

  • Linux CentOS 7
  • Apache 2.4
  • PHP 7.1
  • Laravel

Laravelのバージョンについては5.6/5.5/5.4/5.3にて動作確認済みです。

Laravelのルートディレクトリを「laravel/」としています。

ファイルストレージ設定ファイルの確認と設定

FileSystemの設定ファイルを確認してみます。

laravel/config/filesystems.php
<?php

return [
'default' => 'local',
'cloud' => 's3',
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_KEY'),
'secret' => env('AWS_SECRET'),
'region' => env('AWS_REGION'),
'bucket' => env('AWS_BUCKET'),
],
],
];
default
デフォルトのファイルシステムディスク
フレームワークが使用するデフォルトのファイルシステムディスクを指定することができます。
cloud
デフォルトクラウドファイルシステムディスク
デフォルトの「クラウド」ドライバをここで指定することができます
disks
ファイルシステムディスク
ここでは、同じドライバの複数のディスクを記述する事が出来ます。フォルトで記載されているのは、各ドライバのデフォルト値での設定です。

尚、サポートされているドライバは以下「local」「ftp」「s3」「rackspace」の4つです。

local
laravel内に保存・読み取り
ローカルストレージ
ftp
FTPを使って任意の場所へ保存・読み取り
sftp
クラウドストレージ
SFTPを使って任意の場所へ保存・読み取り。ver5.6.7からサポートされました。
クラウドストレージ
s3
Amazon S3へ保存・読み取り
クラウドストレージ
rackspace
rackspace社が提供するオンデマンド型ストレージ 「Cloud Block Storage(クラウドブロックストレージ)」への保存・読み取り
クラウドストレージ

デフォルトで記述の無い「ftp」ドライバの記述ですが、書式としては以下のように記述します。

'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],

'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],

's3' => [
'driver' => 's3',
'key' => env('AWS_KEY'),
'secret' => env('AWS_SECRET'),
'region' => env('AWS_REGION'),
'bucket' => env('AWS_BUCKET'),
],
// ↓FTPの場合の記述↓
'ftp' => [
'driver' => 'ftp',
'host' => 'YOUR-HOST-NAME',
'username' => 'YOUR-USER-NAME',
'password' => 'YOUR-PASSWORD',
],
],

SFTPについては、Laravel - SFTP転送にまとめてあります。

ローカルストレージ「local」と「public」の違い

ここで1つ気が付くでしょうか?ドライバとしては4つなのですが、 disk設定の記述には「public」という項目が存在しています。 これはlocalドライバで扱われるローカルディスク設定の1種なのですが、 「local」と「public」は、使い方が少し違います。

local
非公開用のファイルストレージとして扱います。 ここでの設定で扱われるファイルは、laravel/storage/app 配下へ保存、読み出しが行われ、 外部からはアクセス出来ない領域内でのファイル操作になります。
public
一般公開用のファイルストレージとして扱います。 ここでの設定で扱われるファイルは storage/app/public 配下へ保存・読み出しが行われ、「public/storage」から「storage/app/public」へシンボリックリンクを張る事で外部からもアクセスが可能になります。

例を上げると、
「プログラム上の処理などを行う際に一時的にファイルを置きたいけど、外部には公開する必要がない」
といったような時は「local」を。
「ふつうにファイルを保存して公開(表示)したい」
などといった場合には「public」を。
という具合に使い分ける事が出来ます。通常なら後者になるでしょうか。

ちなみに、上記の通り「public」を使う為には、シンボリックリンクを張る必要があるので、その場合はlaravelルートディレクトリへ移動し、以下のコマンドを叩いてください。

php artisan storage:link

これで public/storage から storage/app/public へシンボリックリンクが貼られます。

ただし上記のコマンドあくまでも「public/storage」から「storage/app/public」へシンボリックリンクを張るので、 もしpublicディレクトリを移動させていたら使えません。その場合は、artisanコマンドではなく、 Linuxコマンドでシンボリックリンクを張ってください。
例えば、

├─ public
└─ laravel

こんな感じで、デフォルトとは違うディレクトリ構成の場合は、publicディレクトリへ移動した後に、 lnコマンドでシンボリックリンクを張ってあげます。

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

# シンボリックリンクを貼る
ln -s /path/to/PROJECT_DIR/laravel/storage/app/public storage

こうすると、publicディレクトリの中に「storage」というシンボリックリンクを張る事が出来ます。 そして、この「storage」の先は、「storage/app/public」になります。
試しに、publicディレクトリの中でllコマンドを叩いて一覧を確認してみます。

[demo@localhost public]# ll
total 28
drwxr-xr-x. 2 root root 20 Oct 17 15:41 css
-rw-r--r--. 1 root root 0 Oct 17 15:41 favicon.ico
-rw-r--r--. 1 root root 1799 Oct 17 15:44 index.php
drwxr-xr-x. 2 root root 61 Oct 17 01:48 js
-rw-r--r--. 1 root root 24 Oct 17 15:41 robots.txt
lrwxrwxrwx. 1 root root 60 Oct 17 17:37
storage -> /path/to/PROJECT_DIR/laravel/storage/app/public

きちんとシンボリックリンクが張れている事が確認できました。

ストレージへの保存・読み取り

それでは実際にFileSystemを使ってファイルを保存し、読み出してみたいと思います。 今回はシンプルに、画像ファイルを、FileSystemを使って保存するという流れです。 専用コントローラを作る形にて、一通りの主要メソッドを詰めました。

<?php
namespace App\Http\Controllers;

use Storage; // ← (1)

class FileSystemPublicController extends Controller
{
/**
* ファイルを保存する
*/
public function index()
{
$disk = Storage::disk('public'); // ← (2)

| $public_path = '/path/to/public/';
(3)| $img_path = sprintf('%s%s', $public_path, 'test.jpg');
| $contents = file_get_contents($img_path);

// 保存ディレクトリ
| $store_dir = 'images/put';
| // 保存新ファイル名
(4) | $store_filename = 'store.jpg';
| // 保存先ファイルパス
| $storefile = sprintf('%s/%s',$store_dir ,$store_filename );

// ファイルをアップロード(パスはlaravel/storage/app/publicを起点として相対パスで記述)
$disk->put($storefile, $contents); // ← (5)

$url = $disk->url($storefile); // ← (6)

echo $url; // → https://XXX.com/storage/images/put/test.jpg ← (7)


// ファイルが存在するか確認
if($disk->exists($storefile)) { // ← (8)
echo'<pre>'; echo 'exists'; echo'</pre>';
} else {
echo'<pre>'; echo 'NONE'; echo'</pre>';
}

// ファイル取得はget()
$contents = $disk->get($storefile); // ← (9)
| $put_path = sprintf('%s%s', $public_path, 'test_put999.jpg');
(10)| // 別の場所に保存
| file_put_contents($put_path, $contents);

}
}

上から説明していきます。

use Storage;

まずは、Storageをuseします。これがないと始まりません。
エイリアスが登録されているので上記で問題ないですが、

use Illuminate\Support\Facades\Storage;

という書き方でもOKです。

$disk = Storage::disk('public');

どのディスクを使うかの指定をしています。ここでは「public」を指定しています。

    | $public_path = '/path/to/public/';
(3)| $img_path = sprintf('%s%s', $public_path, 'test.jpg');
| $contents = file_get_contents($img_path);

「/path/to/public/test.jpg」という画像ファイルが今回の保存対象という事にして、 フルパス指定でfile_get_contentsにてファイルの内容を全て文字列に読み込んでいます。
保存の際に、ただ画像ファイルのパスを指定しただけでは保存されないので、 読み込みを行うというのがここのポイントです。

      // 保存ディレクトリ
| $store_dir = 'images/put';
| // 保存新ファイル名
(4) | $store_filename = 'store.jpg';
| // 保存先ファイルパス
| $storefile = sprintf('%s/%s',$store_dir ,$store_filename );

保存先のパスと、保存する時のファイル名をここで指定しています。
保存ディレクトリに images/put を指定しているので、保存先は storage/app/public/images/put になります。 storage/app/public/ からの相対パスを指定している形です。

// ファイルをアップロード(パスはlaravel/storage/app/publicを起点として相対パスで記述)
$disk->put($storefile, $contents); // ← (5)

putメソッドを使ってファイルを保存しています。
(3)で読み込んだ画像データを、(4)で指定いたパスとファイル名にて保存している。という形です。

$url = $disk->url($storefile); // ← (6)

echo $url; // → https://XXX.com/storage/images/public_put/test.jpg ← (7)

ここでは、保存の件はもう終わりとして、保存した画像ファイルの完全URLをurlメソッドにて取得しています。
(7)で出力している通り、
「https://XXX.net/storage/images/put/test.jpg」
のような完全URLにて値が返ってきます。

$disk->exists($storefile); // ← (8)

existsメソッドを使って、ファイルが存在するかを確認出来ます。

$contents = $disk->get($storefile); // ← (9)

getメソッドを使って、ファイルのデータを取得しています。

    | $put_path = sprintf('%s%s', $public_path, 'test_put999.jpg');
(10)| // 別の場所に保存
| file_put_contents($put_path, $contents);

取得したファイルのデータを、別の名前で同じ場所へ保存しています。

まとめ

FileSystemを使ってのでローカルでのファイル操作は以上になります。
Flysystem PHPパッケージを用いる利点としては、記述自体がシンプルになる事と、 パスやURLまわりが簡潔になる事だと思います。Laravelを使うなら、ここも是非使っておきたいところですね。

次回は、FileSystemを使ってAmazon S3との連携を行ってみたいと思います。