Laravel 5 如何验证路由参数?
Laravel 5 how to validate route parameters?
我想验证 "form request" 中的路由参数,但不知道该怎么做。
下面是代码示例,我正在尝试:
路线
// controller Server
Route::group(['prefix' => 'server'], function(){
Route::get('checkToken/{token}',['as'=>'checkKey','uses'=> 'ServerController@checkToken']);
});
控制器
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests;
class ServerController extends Controller {
public function checkToken( \App\Http\Requests\CheckTokenServerRequest $request) // OT: - why I have to set full path to work??
{
$token = Token::where('token', '=', $request->token)->first();
$dt = new DateTime;
$token->executed_at = $dt->format('m-d-y H:i:s');
$token->save();
return response()->json(json_decode($token->json),200);
}
}
CheckTokenServerRequest
namespace App\Http\Requests;
use App\Http\Requests\Request;
class CheckTokenServerRequest extends Request {
//autorization
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'token' => ['required','exists:Tokens,token,executed_at,null']
];
}
}
但是当我尝试验证一个简单的 url http://myurl/server/checkToken/222 时,我得到了响应:no " token " parameter set
.
是否可以在单独的 "Form request" 中验证参数,或者我必须在控制器中完成所有操作?
ps。抱歉我的英语不好。
对于 Laravel < 5.5:
这样做的方法是覆盖 CheckTokenServerRequest
的 all()
方法,如下所示:
public function all()
{
$data = parent::all();
$data['token'] = $this->route('token');
return $data;
}
编辑
对于 Laravel >= 5.5:
以上解决方案适用于 Laravel < 5.5。如果你想在Laravel 5.5或以上使用它,你应该使用:
public function all($keys = null)
{
$data = parent::all($keys);
$data['token'] = $this->route('token');
return $data;
}
相反。
表单请求验证器用于验证通过POST[=35=发送到服务器的HTML表单数据 ] 方法。最好不要使用它们来验证路由参数。路由参数主要用于从数据库中检索数据,因此为了确保您的令牌路由参数正确,请更改代码的这一行,从
$token = Token::where('token', '=', $request->token)->first();
到
$token = Token::where('token', '=', $request->input(token))->firstOrFail();
firstOrFail() 是一个非常好的函数,如果用户插入任何无效令牌,它会向您的用户发送 404。
你得到 no " token " parameter set
因为 Laravel 假设你的 "token" 参数是一个 POST 数据,而在你的情况下它不是。
如果你坚持验证你的 "token" 参数,通过表单请求验证器你会减慢你的应用程序,因为你对你的数据库执行 两次 查询,
这里有一个
$token = Token::where('token', '=', $request->token)->first();
这里还有一个
return [
'token' => ['required','exists:Tokens,token,executed_at,null']
];
我建议使用 firsOrFail 同时执行 validating 和 retrieving。
对于\App\Http\Requests\CheckTokenServerRequest
,您可以在顶部添加use App\Http\Requests\CheckTokenServerRequest;
。
如果您将 token
传递给 url
,您可以像 controller
中的变量一样使用它。
public function checkToken($token) //same with the name in url
{
$_token = Token::where('token', '=', $token)->first();
$dt = new DateTime;
$_token->executed_at = $dt->format('m-d-y H:i:s');
$_token->save();
return response()->json(json_decode($token->json),200);
}
您只是缺少标记前的下划线。替换为
_token
无论你在哪里检查由 laravel 生成的表格。
public function rules()
{
return [
'_token' => ['required','exists:Tokens,token,executed_at,null']
];
覆盖请求对象上的 all()
函数以自动将验证规则应用于 URL 参数
class SetEmailRequest
{
public function rules()
{
return [
'email' => 'required|email|max:40',
'id' => 'required|integer', // << url parameter
];
}
public function all()
{
$data = parent::all();
$data['id'] = $this->route('id');
return $data;
}
public function authorize()
{
return true;
}
}
像这样从控制器正常访问数据,注入请求后:
$setEmailRequest->email // request data
$setEmailRequest->id, // url data
如果您不想指定每个路由参数而只是放置所有路由参数,您可以像这样覆盖:
Laravel < 5.5:
public function all()
{
return array_merge(parent::all(), $this->route()->parameters());
}
Laravel 5.5或以上:
public function all($keys = null)
{
// Add route parameters to validation data
return array_merge(parent::all(), $this->route()->parameters());
}
特征可以使这种验证相对自动。
特质
<?php
namespace App\Http\Requests;
/**
* Class RouteParameterValidation
* @package App\Http\Requests
*/
trait RouteParameterValidation{
/**
* @var bool
*/
private $captured_route_vars = false;
/**
* @return mixed
*/
public function all(){
return $this->capture_route_vars(parent::all());
}
/**
* @param $inputs
*
* @return mixed
*/
private function capture_route_vars($inputs){
if($this->captured_route_vars){
return $inputs;
}
$inputs += $this->route()->parameters();
$inputs = self::numbers($inputs);
$this->replace($inputs);
$this->captured_route_vars = true;
return $inputs;
}
/**
* @param $inputs
*
* @return mixed
*/
private static function numbers($inputs){
foreach($inputs as $k => $input){
if(is_numeric($input) and !is_infinite($inputs[$k] * 1)){
$inputs[$k] *= 1;
}
}
return $inputs;
}
}
用法
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyCustomRequest extends FormRequest{
use RouteParameterValidation;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(){
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(){
return [
//
'any_route_param' => 'required'//any rule(s) or custom rule(s)
];
}
}
$request->merge(['id' => $id]);
...
$this->validate($request, $rules);
或
$request->merge(['param' => $this->route('param')]);
...
$this->validate($request, $rules);
FormRequest 有一个方法 validationData()
定义用于验证的数据。因此,只需在您的表单请求 class:
中使用路由参数覆盖那个
/**
* Use route parameters for validation
* @return array
*/
protected function validationData()
{
return $this->route()->parameters();
}
或保留大部分 all
逻辑并覆盖 trait \Illuminate\Http\Concerns\InteractsWithInput
中的 input
方法
/**
* Retrieve an input item from the request.
*
* @param string|null $key
* @param string|array|null $default
* @return string|array|null
*/
public function input($key = null, $default = null)
{
return data_get(
$this->getInputSource()->all() + $this->query->all() + $this->route()->parameters(), $key, $default
);
}
我想验证 "form request" 中的路由参数,但不知道该怎么做。
下面是代码示例,我正在尝试:
路线
// controller Server
Route::group(['prefix' => 'server'], function(){
Route::get('checkToken/{token}',['as'=>'checkKey','uses'=> 'ServerController@checkToken']);
});
控制器
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests;
class ServerController extends Controller {
public function checkToken( \App\Http\Requests\CheckTokenServerRequest $request) // OT: - why I have to set full path to work??
{
$token = Token::where('token', '=', $request->token)->first();
$dt = new DateTime;
$token->executed_at = $dt->format('m-d-y H:i:s');
$token->save();
return response()->json(json_decode($token->json),200);
}
}
CheckTokenServerRequest
namespace App\Http\Requests;
use App\Http\Requests\Request;
class CheckTokenServerRequest extends Request {
//autorization
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'token' => ['required','exists:Tokens,token,executed_at,null']
];
}
}
但是当我尝试验证一个简单的 url http://myurl/server/checkToken/222 时,我得到了响应:no " token " parameter set
.
是否可以在单独的 "Form request" 中验证参数,或者我必须在控制器中完成所有操作?
ps。抱歉我的英语不好。
对于 Laravel < 5.5:
这样做的方法是覆盖 CheckTokenServerRequest
的 all()
方法,如下所示:
public function all()
{
$data = parent::all();
$data['token'] = $this->route('token');
return $data;
}
编辑
对于 Laravel >= 5.5:
以上解决方案适用于 Laravel < 5.5。如果你想在Laravel 5.5或以上使用它,你应该使用:
public function all($keys = null)
{
$data = parent::all($keys);
$data['token'] = $this->route('token');
return $data;
}
相反。
表单请求验证器用于验证通过POST[=35=发送到服务器的HTML表单数据 ] 方法。最好不要使用它们来验证路由参数。路由参数主要用于从数据库中检索数据,因此为了确保您的令牌路由参数正确,请更改代码的这一行,从
$token = Token::where('token', '=', $request->token)->first();
到
$token = Token::where('token', '=', $request->input(token))->firstOrFail();
firstOrFail() 是一个非常好的函数,如果用户插入任何无效令牌,它会向您的用户发送 404。
你得到 no " token " parameter set
因为 Laravel 假设你的 "token" 参数是一个 POST 数据,而在你的情况下它不是。
如果你坚持验证你的 "token" 参数,通过表单请求验证器你会减慢你的应用程序,因为你对你的数据库执行 两次 查询, 这里有一个
$token = Token::where('token', '=', $request->token)->first();
这里还有一个
return [
'token' => ['required','exists:Tokens,token,executed_at,null']
];
我建议使用 firsOrFail 同时执行 validating 和 retrieving。
对于\App\Http\Requests\CheckTokenServerRequest
,您可以在顶部添加use App\Http\Requests\CheckTokenServerRequest;
。
如果您将 token
传递给 url
,您可以像 controller
中的变量一样使用它。
public function checkToken($token) //same with the name in url
{
$_token = Token::where('token', '=', $token)->first();
$dt = new DateTime;
$_token->executed_at = $dt->format('m-d-y H:i:s');
$_token->save();
return response()->json(json_decode($token->json),200);
}
您只是缺少标记前的下划线。替换为
_token
无论你在哪里检查由 laravel 生成的表格。
public function rules()
{
return [
'_token' => ['required','exists:Tokens,token,executed_at,null']
];
覆盖请求对象上的 all()
函数以自动将验证规则应用于 URL 参数
class SetEmailRequest
{
public function rules()
{
return [
'email' => 'required|email|max:40',
'id' => 'required|integer', // << url parameter
];
}
public function all()
{
$data = parent::all();
$data['id'] = $this->route('id');
return $data;
}
public function authorize()
{
return true;
}
}
像这样从控制器正常访问数据,注入请求后:
$setEmailRequest->email // request data
$setEmailRequest->id, // url data
如果您不想指定每个路由参数而只是放置所有路由参数,您可以像这样覆盖:
Laravel < 5.5:
public function all()
{
return array_merge(parent::all(), $this->route()->parameters());
}
Laravel 5.5或以上:
public function all($keys = null)
{
// Add route parameters to validation data
return array_merge(parent::all(), $this->route()->parameters());
}
特征可以使这种验证相对自动。
特质
<?php
namespace App\Http\Requests;
/**
* Class RouteParameterValidation
* @package App\Http\Requests
*/
trait RouteParameterValidation{
/**
* @var bool
*/
private $captured_route_vars = false;
/**
* @return mixed
*/
public function all(){
return $this->capture_route_vars(parent::all());
}
/**
* @param $inputs
*
* @return mixed
*/
private function capture_route_vars($inputs){
if($this->captured_route_vars){
return $inputs;
}
$inputs += $this->route()->parameters();
$inputs = self::numbers($inputs);
$this->replace($inputs);
$this->captured_route_vars = true;
return $inputs;
}
/**
* @param $inputs
*
* @return mixed
*/
private static function numbers($inputs){
foreach($inputs as $k => $input){
if(is_numeric($input) and !is_infinite($inputs[$k] * 1)){
$inputs[$k] *= 1;
}
}
return $inputs;
}
}
用法
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyCustomRequest extends FormRequest{
use RouteParameterValidation;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(){
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(){
return [
//
'any_route_param' => 'required'//any rule(s) or custom rule(s)
];
}
}
$request->merge(['id' => $id]);
...
$this->validate($request, $rules);
或
$request->merge(['param' => $this->route('param')]);
...
$this->validate($request, $rules);
FormRequest 有一个方法 validationData()
定义用于验证的数据。因此,只需在您的表单请求 class:
/**
* Use route parameters for validation
* @return array
*/
protected function validationData()
{
return $this->route()->parameters();
}
或保留大部分 all
逻辑并覆盖 trait \Illuminate\Http\Concerns\InteractsWithInput
input
方法
/**
* Retrieve an input item from the request.
*
* @param string|null $key
* @param string|array|null $default
* @return string|array|null
*/
public function input($key = null, $default = null)
{
return data_get(
$this->getInputSource()->all() + $this->query->all() + $this->route()->parameters(), $key, $default
);
}