Laravel - 文件上传
Laravel - 文件上传
Section titled “Laravel - 文件上传”Laravel 可以轻松处理用户上传的文件。这通常包括创建一个用于文件选择的 HTML 表单和一个用于处理和存储上传文件的控制器动作(action)。
HTML 表单
Section titled “HTML 表单”要允许文件上传,你的 HTML 表单的 enctype 属性必须设置为 multipart/form-data。
视图示例(resources/views/upload.blade.php):
@extends('layouts.app') {{-- 假设有一个布局文件 --}}
@section('content')<div class="container"> <h2>Upload a File</h2>
@if (session('success')) <div class="alert alert-success"> {{ session('success') }} @if (session('filePath')) <br>Uploaded file path: <a href="{{ session('filePath') }}" target="_blank">{{ session('filePath') }}</a> @endif </div> @endif
@if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif
<form action="{{ route('file.upload.post') }}" method="POST" enctype="multipart/form-data"> @csrf {{-- CSRF 保护令牌 --}}
<div class="mb-3"> <label for="fileInput" class="form-label">Select file:</label> <input type="file" class="form-control" id="fileInput" name="user_file" required> </div>
<button type="submit" class="btn btn-primary">Upload File</button> </form></div>@endsection表单中的关键元素:
method="POST":文件上传应使用 POST 方法。enctype="multipart/form-data":文件上传必不可少。@csrf:Laravel 的 CSRF 保护指令。<input type="file" name="user_file">:文件输入字段。name属性(此处为user_file)用于在控制器中访问文件。
创建一个控制器来处理文件上传请求。我们将其命名为 FileUploadController。
php artisan make:controller FileUploadController在 app/Http/Controllers/FileUploadController.php 中:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;use Illuminate\Http\RedirectResponse;use Illuminate\View\View;use Illuminate\Support\Facades\Storage; // 对于文件存储很重要
class FileUploadController extends Controller{ /** * Display the file upload form. */ public function showUploadForm(): View { return view('upload'); }
/** * Handle the uploaded file. */ public function storeUpload(Request $request): RedirectResponse { // 1. 验证上传的文件 $request->validate([ 'user_file' => 'required|file|mimes:jpg,jpeg,png,pdf,doc,docx|max:2048', // 验证规则示例 ]);
// 2. 检查是否有文件上传 if ($request->hasFile('user_file')) { $file = $request->file('user_file');
// 3. 获取文件信息 (可选,用于显示或记录日志) $originalName = $file->getClientOriginalName(); $extension = $file->getClientOriginalExtension(); $size = $file->getSize(); // 大小,单位字节 $mimeType = $file->getMimeType();
// 4. 存储文件 // 选项 A: 存储到 'public' 存储盘(通常是 storage/app/public) // `store` 方法会生成一个唯一的文件名以避免冲突。 // 确保运行 `php artisan storage:link` 使这些文件可以通过 Web 访问。 $path = $file->store('uploads', 'public'); // 存储到 'storage/app/public/uploads' $publicUrl = Storage::disk('public')->url($path);
// 选项 B: 使用原始名称存储 (注意名称冲突) // $filename = time() . '_' . $originalName; // $path = $file->storeAs('uploads', $filename, 'public'); // $publicUrl = Storage::disk('public')->url($path);
// 选项 C: 直接移动到 public 目录 (使用 Storage Facade 较少见) // $destinationPath = public_path('/user_uploads'); // $safeName = time() . '_' . $file->getClientOriginalName(); // $file->move($destinationPath, $safeName); // $publicUrl = asset('user_uploads/' . $safeName);
// 演示目的,我们将返回一些信息 return back() ->with('success', 'File uploaded successfully!') ->with('fileName', $originalName) ->with('filePath', $publicUrl) // 传递可访问的 URL ->with('fileSize', round($size / 1024, 2) . ' KB') ->with('fileMimeType', $mimeType); } else { return back()->withErrors(['user_file' => 'No file was uploaded.']); } }}控制器逻辑说明:
- 验证: 对于安全性和应用程序稳定性至关重要。使用 Laravel 的验证规则(
file、mimes、max大小以千字节为单位)。 $request->hasFile('user_file'): 检查请求中是否存在指定名称的文件。$request->file('user_file'): 获取Illuminate\Http\UploadedFile的实例。- 文件信息:
getClientOriginalName()、getClientOriginalExtension()、getSize()、getMimeType()等方法提供有关上传文件的详细信息。 - 存储文件:
-
UploadedFile对象上的store('directory', 'disk')方法是推荐的方式。它处理唯一命名,并使用 Laravel 的文件系统配置(config/filesystems.php)。 -'public'存储盘通常映射到storage/app/public。你必须运行php artisan storage:link来创建从public/storage到storage/app/public的符号链接,从而使这些文件可以通过 Web 访问,通过asset('storage/path_to_file')或Storage::url('path_to_file')进行访问。 - 反馈: 重定向回带有成功消息,可选地包含文件详细信息。
在 routes/web.php 中定义用于显示表单和处理 POST 请求的路由:
use App\Http\Controllers\FileUploadController;
// 用于显示上传表单的路由Route::get('/upload-file', [FileUploadController::class, 'showUploadForm'])->name('file.upload.form');
// 用于处理文件上传 POST 请求的路由Route::post('/upload-file', [FileUploadController::class, 'storeUpload'])->name('file.upload.post');-
如果尚未运行,请运行
php artisan storage:link(每个项目只需运行一次)。 -
在浏览器中导航到
http://your-app.test/upload-file。 -
使用表单选择一个文件并点击“上传文件”。
-
你应该会看到一个成功消息,并且文件应该存储在
storage/app/public/uploads(或你指定的目录)中。成功消息也应该显示访问该文件的公共 URL。
实际应用:用户头像或文档管理
文件上传对于以下功能至关重要:
- 用户个人资料图片(头像)。
- 将文档附加到记录(例如,发票、报告)。
- 内容管理系统,用户上传图片或其他媒体。
常见的学习障碍:文件权限和 storage:link
一个常见的困惑点是文件的可见性。存储在 storage/app 中的文件不能直接通过 Web 访问。对于需要公开的文件(如网站上显示的图片),请将它们存储在 'public' 存储盘上,并确保你已运行 php artisan storage:link。此外,确保你的 Web 服务器对 storage/app 目录及其子目录具有写入权限。
- Laravel 关于文件上传的文档:https://laravel.com/docs/requests#files
- Laravel 关于文件存储的文档:https://laravel.com/docs/filesystem