0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravelのstorage書き込み権限の判定用関数を作成

Last updated at Posted at 2025-09-06

権限の確認用関数を用意

Linuxサーバでは権限の問題でアップロード処理が失敗することはよくあるので
アップロードの失敗原因を出来るだけ分かりやすくする関数を用意
app/Services/StoragePermissionService.php

<?php

namespace App\Services;

use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;

class StoragePermissionService
{
    public function check(string $directory = 'spec-md'): array
    {
        $disk = Storage::disk('public');
        $path = $directory.'/_perm_check.txt';

        $writable = false;
        $deletable = false;
        $errorMsg = null;

        try {
            $writable = $disk->put($path, 'ok');
        } catch (\Throwable $e) {
            $writable = false;
            $errorMsg = 'Write error: '.$e->getMessage();
            Log::error('Storage write failed', [
                'path' => $disk->path($path),
                'error' => $e->getMessage(),
            ]);
        }

        if ($writable) {
            try {
                $deletable = $disk->delete($path);
            } catch (\Throwable $e) {
                $deletable = false;
                $errorMsg = 'Delete error: '.$e->getMessage();
                Log::error('Storage delete failed', [
                    'path' => $disk->path($path),
                    'error' => $e->getMessage(),
                ]);
            }
        }

        $result = [
            'disk'      => 'public',
            'dir'       => $directory,
            'writable'  => (bool) $writable,
            'deletable' => (bool) $deletable,
            'path'      => $disk->path($path),
            'error'     => $errorMsg,
        ];

        Log::info('Storage permission check result', $result);

        return $result;
    }
}

コントローラーでの使用例

mdファイルをstorage/app/public/spec-mdフォルダ内に保存するstore関数内に設置しました。
app/Http/Controllers/SpecMdController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use App\Services\StoragePermissionService;

class SpecMdController extends Controller
{
    public function index()
    {
        $dir = storage_path('app/public/spec-md');
        $files = is_dir($dir) ? array_values(array_filter(scandir($dir), fn($f) =>
            !in_array($f, ['.','..']) && is_file("{$dir}/{$f}")
        )) : [];

        $docs = array_map(fn($f) => asset("storage/spec-md/{$f}"), $files);

        return view('spec-md.index', compact('docs'));
    }

    public function store(Request $request, StoragePermissionService $permService)
    {
        // ファイルアップロード前に権限チェック
        $check = $permService->check('spec-md');
        if (!$check['writable']) {
            return back()->with('status', '保存先ディスクに書き込みできません。管理者に連絡してください。');
        }

        Log::info('upload debug', [
            'hasFile'     => $request->hasFile('mdfile'),
            'isValid'     => $request->file('mdfile')?->isValid(),
            'origName'    => $request->file('mdfile')?->getClientOriginalName(),
            'clientMime'  => $request->file('mdfile')?->getClientMimeType(),
        ]);

        $validated = $request->validate([
            'mdfile' => ['required','file','mimetypes:text/markdown,text/plain','max:10240'],
        ]);

        $file = $validated['mdfile'];
        if (!$file) {
            return back()->with('status', 'ファイルが取得できませんでした。');
        }

        Storage::disk('public')->makeDirectory('spec-md');

        $ext  = $file->getClientOriginalExtension();
        $name = now()->format('Ymd_His') . '_' . Str::random(8) . '.' . $ext;

        $savedPath = Storage::disk('public')->putFileAs('spec-md', $file, $name);

        $abs = Storage::disk('public')->path($savedPath);
        $url = asset('storage/spec-md/'.$name);

        Log::info('spec-md saved', compact('savedPath','abs','url'));

        return back()->with('status', "アップロードOK: {$savedPath}");
    }
}

ポイント

まず判定用のサービスクラスを下記で呼び出します。

use App\Services\StoragePermissionService;

次に、store関数内 の以下のコードで判定してログに書き込んでいます。

        // ファイルアップロード前に権限チェック
        $check = $permService->check('spec-md');
        if (!$check['writable']) {
            return back()->with('status', '保存先ディスクに書き込みできません。管理者に連絡してください。');
        }

ログ出力例

書き込みできなかった場合

laravel.log
[2025-09-06 14:22:10] local.ERROR: Storage write failed {"path":"/var/www/.../storage/app/public/spec-md/_perm_check.txt","error":"Permission denied"}  
[2025-09-06 14:22:10] local.INFO: Storage permission check result {"disk":"public","dir":"spec-md","writable":false,"deletable":false,"path":"/var/www/.../storage/app/public/spec-md/_perm_check.txt","error":"Write error: Permission denied"}

書き込みはできたけど削除できなかった場合

laravel.log
[2025-09-06 14:22:20] local.ERROR: Storage delete failed {"path":"/var/www/.../storage/app/public/spec-md/_perm_check.txt","error":"Permission denied"}  
[2025-09-06 14:22:20] local.INFO: Storage permission check result {"disk":"public","dir":"spec-md","writable":true,"deletable":false,"path":"/var/www/.../storage/app/public/spec-md/_perm_check.txt","error":"Delete error: Permission denied"}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?