従来はプログラムから特定のパスにディレクトリやファイルを追加する際、それらのパーミッションの変更にはPHPのchmod()を使用していました。しかし、最近ドキュメントを読み返してみてLaravelらしいやり方を学んだのでまとめます。

デフォルトの権限

まずはStorageファサードを使用してstorage配下にディレクトリやファイルを追加した場合に、それらのパーミッションがどうなっているのか確認してみましょう。config/filesystems.phpの設定をデフォルトの状態から変更していない前提で話を進めます。tinkerで以下を実行してみてください。

// ディレクトリを作成
> Storage::makeDirectory('memos');
= true
// ファイルを作成
> Storage::put('memos/todo.txt', '今日のTODOリスト...');
= true

ディスクを指定していないのでデフォルトのlocalディスクドライバが選択され、storage/app配下にmemos/todo.txtが追加されたはずです。追加されたディレクトリとファイルのパーミッションを確認してみましょう。

$ ls -la storage/app/ | grep memos
drwx------  3 hikaru  staff   96 12 12 22:53 memos

$ ls -la storage/app/memos/todo.txt
-rw-r--r--  1 hikaru  staff  20 12 12 23:12 storage/app/memos/todo.txt

※ユーザ名及びグループ名は実行環境毎に異なるので仮です。ご自身の環境の値に置き換えて読み進めてください。
上記の実行結果から分かる通りパーミッションは以下の通りになっていました。

  • memosディレクトリ(rwx——): ユーザのみフルアクセス可能
  • todo.txt(rw-r–r–): 誰でも閲覧可能、書き込みはユーザのみ可能

todo.txt自体は誰でも閲覧可能となっていますが、memosディレクトリ自体の権限がユーザにのみ付与されているので、他のユーザはその配下にアクセスする事ができません。アクセスしようとするとPermission deniedと表示されます。memosディレクトリも誰でも閲覧可能とするにはどうすれば良いでしょうか?

visibilityの設定

Laravelにおいてはパーミンションの事をvisibilityと呼ぶ様です。visibilityの設定値はpublicprivateの2択に簡略化されており、ローカルであれクラウドであれ同じ操作でアクセス権の設定を行えます。詳しくは公式ドキュメントをご確認ください。visibilityを設定するにはsetVisibility()を使用します。第一引数にvisibilityを設定するターゲットを、第二引数にpublic or privateを指定します。例えば、前項のmemosディレクトリをpublicにするなら、

> Storage::setVisibility('memos', 'public');
= true

権限をチェックしてみましょう。

$ ls -la storage/app/ | grep memos
drwxr-xr-x  3 hikaru  staff   96 12 12 23:39 memos

誰でも閲覧可能となりましたね。今度は逆にtodo.txtをprivateにしてみましょう。

> Storage::setVisibility('memos/todo.txt', 'private');
= true

権限を確認するとユーザhikaruのみ閲覧可能となっていました。

$ ls -la storage/app/memos/todo.txt
-rw-------  1 hikaru  staff   25 12 12 23:43 todo.txt

デフォルトの設定ではpublicとprivateを指定した場合のアクセス権についてまとめると以下の通りになっていました。

filesystems.phpで詳細設定

publicやprivateによって設定されるアクセス権をより細かくカスタマイズしたいケースがあるかもしれません。その場合はfilesystems.phpにて指定する事ができます。以下はデフォルトのlocalディスクドライバの設定です。

...
    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
            'throw' => false,
        ],
...

これを次のように変更してみます。

...
    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
            'throw' => false,
            'directory_visibility' => 'public',
            'visibility' => 'public',
            'permissions' => [
                'file' => [
                    'public' => 0664,
                    'private' => 0600,
                ],
                'dir' => [
                    'public' => 0775,
                    'private' => 0700,
                ],
            ]
        ],
...

directory_visibilityvisibilityはディレクトリやファイルを追加した際のデフォルトのvisibilityを指定しています。前項ではディレクトリ追加時のvisibilityがprivateになっていましたが、publicに変更しました。そして、permissions内ではファイルとディレクトリにおけるpublicとprivateを指定した際に割り当てるパーミッションを8進数で指定します。上記ではpublic時にグループユーザにも書き込み権限を付与しました。設定通りにアクセス権が付与されるか、再度tinkerでチェックしてみましょう。

> Storage::makeDirectory('memos2');
= true

権限を確認すると

$ ls -la storage/app/ | grep memos2
drwxr-xr-x  2 hikaru  staff   64 12 21 20:27 memos2

あれれ、グループユーザに書き込み権限が付与されていません。何故でしょう?しばらくソースコードと睨めっこしてやっと気づきました。犯人はumaskです。Storage::makeDirectory()は内部的にPHPのmkdir()を使用しているのですが、そちらのドキュメントにはこう書かれています。

また permissions は、 現在設定されている umask の影響も受けます。 umask を変更するには umask() を使用します。

umaskとはUnix系OSにおいてディレクトリやファイルを追加した際のアクセス権を指定するコマンドです。例えば、私の環境、macOSではデフォルトでは標準的な022が指定されており、基本パーミッションである0777から022を引いた0755がデフォルトのパーミッションとなります。ドキュメントに書かれている通り、umask()で制限を解除してからディレクトリ作成コマンドを実行してみましょう。

> umask(000);
= 18
> Storage::makeDirectory('memos3');
= true
> Storage::put('memos3/todo.txt', '今日のTODOリスト...');
= true

パーミッションを確認すると

$ ls -la storage/app/ | grep memos3
drwxrwxr-x  3 hikaru  staff   96 12 21 20:48 memos3
$ ls -la storage/app/memos3/todo.txt
-rw-rw-r--  1 hikaru  staff   13 12 21 20:48 todo.txt

config/filesystems.phpで指定した通り、ディレクトリもファイルもグループユーザにも書き込み権限が付与されました。

By hikaru