用 min:1 想擋掉數字 0,結果驗證竟然通過了。
為什麼 min 規則沒有擋住
我們可能會這樣寫驗證規則:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class MinNumberController extends Controller
{
public function check(Request $request): JsonResponse
{
$request->validate(['value' => 'required|min:1']);
return response()->json($request->all());
}
}
|
寫個測試來驗證,送 value = 0 預期應該收到 422:
1
2
3
4
5
6
7
8
9
10
11
12
13
| namespace Tests\Feature\Http\Controllers;
use Tests\TestCase;
class MinNumberControllerTest extends TestCase
{
public function test_validate_minimum_value(): void
{
$response = $this->postJson('/min-number/check', ['value' => 0]);
$response->assertStatus(422);
}
}
|
結果測試失敗,驗證居然通過了。
前端送過來的都是 string
從前端 POST 過來的資料,Laravel 會把所有 input 都當成 string 處理。所以 0 變成字串 "0",而 min:1 對 string 是檢查字串長度,"0" 長度是 1,自然就通過了。
加上 numeric 讓 Laravel 知道這個欄位是數字,min 規則才會改用數值比較:
1
2
3
4
5
6
7
8
9
| class MinNumberController extends Controller
{
public function check(Request $request): JsonResponse
{
$request->validate(['value' => 'required|numeric|min:1']);
return response()->json($request->all());
}
}
|
所以數字相關的驗證規則 (min, max, between) 前面都要加上 numeric,否則 Laravel 會用字串長度來判斷。