この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: storageフォルダへのアクセス
SEOタイトル: Laravel storage フォルダの権限設定とブラウザからのアクセス方法(symlink)

この記事の要点
  • Laravel の storage/app/public/初期状態ではブラウザからアクセス不可
  • php artisan storage:linkpublic/storagestorage/app/public のシンボリックリンク作成
  • 権限不足エラー: chmod -R 775 storage bootstrap/cache + chown www-data:www-data
  • アップロードは $request->file('photo')->store('photos', 'public')
  • URL は asset('storage/photos/xxx.jpg') または Storage::url($path)

Laravel の storage ディレクトリ構成

storage/
├── app/
│   ├── public/         ← public ディスク。ブラウザ公開ファイル(要 symlink)
│   └── private/        ← 非公開ファイル(ログイン後ダウンロード等)
├── framework/
│   ├── cache/          ← フレームワークキャッシュ
│   ├── sessions/       ← セッションファイル(file driver)
│   ├── testing/
│   └── views/          ← Blade コンパイル済キャッシュ
└── logs/
    └── laravel.log     ← アプリケーションログ

ブラウザから直接アクセスできるのは public/ 配下のみ。storage/app/public/ を公開するにはシンボリックリンクを張ります。

storage:link コマンド

# プロジェクトルートで
php artisan storage:link

# 出力
# The [public/storage] link has been connected to [storage/app/public].

# 実体確認
ls -la public/storage
# lrwxrwxrwx 1 user user 33 May 17 12:00 public/storage -> /path/to/storage/app/public

これで storage/app/public/photos/cat.jpghttp://example.com/storage/photos/cat.jpg でアクセス可能になります。

権限設定

Web サーバー(Apache / Nginx)から書き込みできないと「Permission denied」エラー:

# 所有者を Web サーバーユーザーに
sudo chown -R www-data:www-data storage bootstrap/cache

# 書き込み権限
sudo chmod -R 775 storage bootstrap/cache

# 一般ユーザーも所属させたい(開発時)
sudo usermod -aG www-data $USER
# ログアウト → 再ログイン

# SELinux 環境(CentOS / RHEL)
sudo chcon -R -t httpd_sys_rw_content_t storage bootstrap/cache
sudo setsebool -P httpd_unified 1

ファイルアップロード処理

// app/Http/Controllers/PhotoController.php
public function store(Request $request)
{
    $request->validate([
        'photo' => 'required|image|max:5120',  // 5MB
    ]);

    // 方法1: 自動生成ファイル名で storage/app/public/photos/ に保存
    $path = $request->file('photo')->store('photos', 'public');
    // → "photos/abc123.jpg"

    // 方法2: ファイル名指定
    $path = $request->file('photo')->storeAs(
        'photos',
        'user_' . auth()->id() . '.jpg',
        'public'
    );

    // 方法3: Storage Facade
    use Illuminate\Support\Facades\Storage;
    Storage::disk('public')->putFileAs(
        'photos',
        $request->file('photo'),
        'cat.jpg'
    );

    return view('photo.show', ['url' => Storage::url($path)]);
}

表示・URL 生成

use Illuminate\Support\Facades\Storage;

// DB に保存した相対パス: "photos/abc123.jpg"
$photo = Photo::find(1);  // path = "photos/abc123.jpg"

// 公開 URL
$url = Storage::url($photo->path);
// → "/storage/photos/abc123.jpg"

// asset() でも同じ
$url = asset('storage/' . $photo->path);

// 絶対パスが必要なとき
$url = Storage::disk('public')->url($photo->path);
// → "http://example.com/storage/photos/abc123.jpg"

// ファイルが存在するか
if (Storage::disk('public')->exists($photo->path)) { ... }

// 削除
Storage::disk('public')->delete($photo->path);
{{-- Blade --}}

非公開ファイル(ログイン認証付ダウンロード)

// 非公開ファイルは storage/app/ 直下に保存(symlink 不要)
$path = $request->file('contract')
    ->storeAs('contracts/' . auth()->id(), 'contract.pdf');
// → storage/app/contracts/123/contract.pdf (public からアクセス不可)

// コントローラーで認証 + ダウンロード
public function download($id)
{
    $doc = Document::findOrFail($id);
    if ($doc->user_id !== auth()->id()) abort(403);

    return Storage::download($doc->path);
    // または
    return Storage::response($doc->path);
}

カスタムディスク追加

// config/filesystems.php
'disks' => [
    // 既存
    'public' => [
        'driver' => 'local',
        'root' => storage_path('app/public'),
        'url' => env('APP_URL').'/storage',
        'visibility' => 'public',
    ],

    // 追加: 画像専用ディスク
    'images' => [
        'driver' => 'local',
        'root' => storage_path('app/public/images'),
        'url' => env('APP_URL').'/storage/images',
        'visibility' => 'public',
    ],

    // S3
    's3' => [
        'driver' => 's3',
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
        'url' => env('AWS_URL'),
    ],
],

本番デプロイ時の注意

  • php artisan storage:linkデプロイのたびに必要。デプロイスクリプトに含める
  • Symlink が動かないホスティング(一部のシェアードホスティング)では .htaccess で代用
  • S3 / Cloudflare R2 等のクラウドストレージに切り替えるとサーバー間共有 / バックアップが楽
  • storage 配下を Git 管理しない(.gitignorestorage/app/public/*

FAQ

Q: php artisan storage:link がエラーになる
A: 既に public/storage が存在すると失敗します。rm public/storage してから再実行。

Q: アップロード後にファイルが見えない
A: ① symlink 未作成 → storage:link、② 権限不足 → chmod 775、③ public/storage がディレクトリとして実在(symlink でない)→ 削除して再作成。

Q: 大きなファイル(数百 MB)が保存できない
A: php.iniupload_max_filesize / post_max_size / memory_limit を増やす。Web サーバー側のサイズ制限(Nginx client_max_body_size)も。