表单处理 #

一、表单基础 #

1.1 创建表单 #

blade
<form method="POST" action="{{ route('users.store') }}">
    @csrf
    
    <div class="form-group">
        <label for="name">姓名</label>
        <input type="text" class="form-control" id="name" name="name" value="{{ old('name') }}">
    </div>
    
    <div class="form-group">
        <label for="email">邮箱</label>
        <input type="email" class="form-control" id="email" name="email" value="{{ old('email') }}">
    </div>
    
    <button type="submit" class="btn btn-primary">提交</button>
</form>

1.2 CSRF保护 #

Laravel自动为所有表单提供CSRF保护:

blade
<form method="POST" action="/users">
    @csrf
    <!-- 表单字段 -->
</form>

1.3 表单方法伪造 #

blade
<form method="POST" action="/users/1">
    @method('PUT')
    @csrf
    <!-- 表单字段 -->
</form>

<form method="POST" action="/users/1">
    @method('DELETE')
    @csrf
    <!-- 表单字段 -->
</form>

二、获取输入 #

2.1 在控制器中获取输入 #

php
use Illuminate\Http\Request;

public function store(Request $request)
{
    // 获取所有输入
    $all = $request->all();
    
    // 获取单个值
    $name = $request->input('name');
    
    // 获取带默认值
    $name = $request->input('name', 'Guest');
    
    // 检查是否存在
    if ($request->has('name')) {
        // 存在
    }
    
    // 检查是否有值
    if ($request->filled('name')) {
        // 有值(非空)
    }
    
    // 只获取指定字段
    $data = $request->only(['name', 'email']);
    
    // 排除指定字段
    $data = $request->except(['_token']);
}

2.2 动态属性 #

php
// 通过动态属性获取
$name = $request->name;
$email = $request->email;

2.3 数组输入 #

blade
<input type="text" name="users[][name]">
<input type="text" name="users[][email]">
php
$users = $request->input('users');
// [['name' => 'John', 'email' => 'john@example.com']]

2.4 JSON输入 #

php
// 获取JSON输入
$data = $request->json()->all();

// 获取JSON字段
$name = $request->json('name');

三、文件上传 #

3.1 基本上传 #

blade
<form method="POST" action="/upload" enctype="multipart/form-data">
    @csrf
    <input type="file" name="avatar">
    <button type="submit">上传</button>
</form>
php
public function upload(Request $request)
{
    // 检查文件是否存在
    if ($request->hasFile('avatar')) {
        $file = $request->file('avatar');
        
        // 检查是否有效
        if ($file->isValid()) {
            // 获取文件信息
            $path = $file->path();
            $extension = $file->extension();
            $size = $file->getSize();
            $mime = $file->getMimeType();
            
            // 存储文件
            $path = $file->store('avatars');
            // 存储到指定磁盘
            $path = $file->store('avatars', 's3');
            // 自定义文件名
            $path = $file->storeAs('avatars', 'custom_name.jpg');
        }
    }
}

3.2 文件验证 #

php
$validated = $request->validate([
    'avatar' => 'required|image|max:1024', // 最大1MB
    'document' => 'required|mimes:pdf,doc,docx|max:10240',
]);

3.3 文件信息 #

php
$file = $request->file('avatar');

// 原始文件名
$name = $file->getClientOriginalName();

// 原始扩展名
$extension = $file->getClientOriginalExtension();

// 文件大小(字节)
$size = $file->getSize();

// MIME类型
$mime = $file->getMimeType();

3.4 存储配置 #

php
// config/filesystems.php
'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_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
    ],
],

3.5 访问上传文件 #

php
// 创建符号链接
php artisan storage:link

// 在视图中访问
<img src="{{ asset('storage/' . $user->avatar) }}">

// 或使用Storage门面
$url = Storage::url($user->avatar);

四、旧输入 #

4.1 获取旧输入 #

php
// 在控制器中
$name = $request->old('name');

// 在视图中
<input type="text" name="name" value="{{ old('name') }}">

4.2 闪存输入 #

php
// 闪存当前输入
$request->flash();

// 闪存部分输入
$request->flashOnly(['name', 'email']);
$request->flashExcept(['password']);

// 重定向时闪存
return redirect()->back()->withInput();
return redirect()->route('users.create')->withInput();

五、表单组件 #

5.1 创建表单组件 #

blade
<!-- resources/views/components/form/input.blade.php -->
@props(['label', 'name', 'type' => 'text', 'error'])

<div class="form-group">
    <label for="{{ $name }}">{{ $label }}</label>
    <input 
        type="{{ $type }}" 
        class="form-control {{ $error ? 'is-invalid' : '' }}" 
        id="{{ $name }}" 
        name="{{ $name }}"
        value="{{ old($name, $value ?? '') }}"
        {{ $attributes }}
    >
    @if($error)
        <div class="invalid-feedback">{{ $error }}</div>
    @endif
</div>

5.2 使用表单组件 #

blade
<x-form.input 
    name="email" 
    label="邮箱地址" 
    type="email" 
    :error="$errors->first('email')"
/>

六、多步表单 #

6.1 控制器处理 #

php
public function step1(Request $request)
{
    $validated = $request->validate([
        'name' => 'required',
        'email' => 'required|email',
    ]);
    
    session()->put('form.step1', $validated);
    
    return redirect()->route('form.step2');
}

public function step2(Request $request)
{
    $validated = $request->validate([
        'address' => 'required',
        'phone' => 'required',
    ]);
    
    $data = array_merge(
        session('form.step1', []),
        $validated
    );
    
    // 保存数据
    User::create($data);
    
    session()->forget('form');
    
    return redirect()->route('success');
}

七、表单安全 #

7.1 CSRF排除 #

php
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'api/*',
        'webhook/*',
    ]);
})

7.2 XSS防护 #

blade
{{-- 自动转义 --}}
{{ $userInput }}

{{-- 原始输出(谨慎使用) --}}
{!! $trustedHtml !!}

7.3 SQL注入防护 #

php
// 使用参数绑定
$users = DB::select('SELECT * FROM users WHERE email = ?', [$email]);

// 使用Eloquent
$user = User::where('email', $email)->first();

八、最佳实践 #

8.1 使用表单请求验证 #

php
// 创建表单请求
php artisan make:request StoreUserRequest

// 使用
public function store(StoreUserRequest $request)
{
    $user = User::create($request->validated());
    return redirect()->route('users.show', $user);
}

8.2 表单组件化 #

blade
<!-- 使用组件 -->
<x-form.input name="name" label="姓名" required />
<x-form.select name="country" label="国家" :options="$countries" />
<x-form.textarea name="bio" label="简介" />

8.3 错误显示 #

blade
@if($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

九、总结 #

9.1 核心要点 #

要点 说明
@csrf CSRF保护
@method 表单方法伪造
$request->input() 获取输入
$request->file() 获取文件
old() 获取旧输入

9.2 下一步 #

掌握了表单处理后,让我们继续学习 数据验证,了解Laravel强大的验证系统!

最后更新:2026-03-28