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

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

  • 公開日
  • 更新日
  • カテゴリ:Laravel
  • タグ:PHP,Laravel,Flysystem
LaravelのFileStorageFlysystemパッケージでファイル操作を行う(local/publicディスク編)

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

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

Contents

  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 との連携 を行ってみたいと思います。

Author

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級