Laravel在插入数据之前不验证输入数据。

huangapple go评论65阅读模式
英文:

Laravel does not validate input data before insertion

问题

I encountered an error when the user registers, everything is ok and works perfectly, but when the user registers again with the same previous data, it shows this error:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '123456789' for key 'users.users_phone_unique'

and i have no ideo what is wrong in these codes
i'm using laravel 10

this is my register controller

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'min:10'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
            'phone' => ['required', 'string', 'max:11'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'phone' => $data['phone'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

this is my user.php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'phone',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'phone',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];
}

this is my create user table migration

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('password');
            $table->string('phone')->unique();
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};
英文:

I encountered an error when the user registers, everything is ok and works perfectly, but when the user registers again with the same previous data, it shows this error:

> SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '123456789' for key 'users.users_phone_unique'

and i have no ideo what is wrong in these codes
i'm using laravel 10

this is my register controller

namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this-&gt;middleware(&#39;guest&#39;);
}
/**
* Get a validator for an incoming registration request.
*
* @param  array  $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
&#39;name&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;min:10&#39;],
&#39;password&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;min:8&#39;, &#39;confirmed&#39;],
&#39;phone&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;max:11&#39;],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param  array  $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
&#39;name&#39; =&gt; $data[&#39;name&#39;],
&#39;phone&#39; =&gt; $data[&#39;phone&#39;],
&#39;password&#39; =&gt; Hash::make($data[&#39;password&#39;]),
]);
}
}

this is my user.php

namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array&lt;int, string&gt;
*/
protected $fillable = [
&#39;name&#39;,
&#39;email&#39;,
&#39;password&#39;,
&#39;phone&#39;,
];
/**
* The attributes that should be hidden for serialization.
*
* @var array&lt;int, string&gt;
*/
protected $hidden = [
&#39;password&#39;,
&#39;phone&#39;,
&#39;remember_token&#39;,
];
/**
* The attributes that should be cast.
*
* @var array&lt;string, string&gt;
*/
protected $casts = [
&#39;email_verified_at&#39; =&gt; &#39;datetime&#39;,
&#39;password&#39; =&gt; &#39;hashed&#39;,
];
}

this is my create user table migration

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create(&#39;users&#39;, function (Blueprint $table) {
$table-&gt;id();
$table-&gt;string(&#39;name&#39;);
$table-&gt;string(&#39;password&#39;);
$table-&gt;string(&#39;phone&#39;)-&gt;unique();
$table-&gt;rememberToken();
$table-&gt;timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists(&#39;users&#39;);
}
};

答案1

得分: 0

在你的控制器中,你没有验证电话号码的唯一性,因此数据会“传递到”数据库级别,然后由于违反了“unique”约束而失败。

你应该在你的RegisterController中添加一个unique验证规则,以便在表单发送后立即失败。

例如:

'phone' => ['required', 'string', 'max:11','unique:users']

英文:

In your controller you're not validating the uniqueness of the phone number, hence the data is "passed down" to the DB level, and then it fails because of the violated unique constraint.

You should add a unique validation rule in your RegisterController in order to fail as soon as the form is sent.

For example:

&#39;phone&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;max:11&#39;,&#39;unique:users&#39;]

答案2

得分: 0

我建议采用另一种被认为是更好的验证实践的方法。

  1. 运行 php artisan make:request CreateUserRequest,将在 /app/Http/Requests 目录下创建 CreateUserRequest 文件。
  2. 根据你的需求编辑该文件,例如:
/**
 * 获取适用于请求的验证规则。
 *
 * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
 */
public function rules(): array
{
    return [
        'name' => ['required', 'string', 'min:10'],
        'phone' => ['required', 'string', 'max:11','unique:users'],
        'password' => ['required', 'string', 'min:8', 'confirmed'],
        /**
         * 或者如果你想接受复杂的密码,可以在`CreateUserRequest`的顶部添加`use Illuminate\Validation\Rules\Password;`,
         * 然后使用以下规则
         */
        'password' => [
            'required', 'confirmed', 
            Password::min(8)->letters()->mixedCase()->numbers()->symbols()
        ],
    ];
}
  1. 如果需要在验证失败时添加自定义消息,你可以在 CreateUserRequest 类中添加以下方法:
/**
 * 为验证失败设置适当的错误消息
 *
 * @return array<string>
 */
public function messages() {
    return [
        'password.required' => '我友好的提示消息给用户',
    ];
}

你需要相应地修改你的控制器,更多信息请参考表单验证文档

英文:

I'm gonna suggest a different approach which is considered to be a better practice for validation.

  1. run php artisan make:request CreateUserRequest, the CreateUserRequest file will be created in /app/Http/Requests directory.
  2. edit the file according to your needs, for example:
/**
* Get the validation rules that apply to the request.
*
* @return array&lt;string, \Illuminate\Contracts\Validation\Rule|array|string&gt;
*/
public function rules(): array
{
return [
&#39;name&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;min:10&#39;],
&#39;phone&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;max:11&#39;,&#39;unique:users&#39;],
&#39;password&#39; =&gt; [&#39;required&#39;, &#39;string&#39;, &#39;min:8&#39;, &#39;confirmed&#39;],
/**
* or if you want to accept complex passwords add `use Illuminate\Validation\Rules\Password;`
* on top of the `CreateUserRequest` and then use the following rule instead
*/
&#39;password&#39; =&gt; [
&#39;required&#39;, &#39;confirmed&#39;, 
Password::min(8)-&gt;letters()-&gt;mixedCase()-&gt;numbers()-&gt;symbols()
],
];
}
  1. for a custom message in case of a failed validation you can add the following method to your CreateUserRequest class:
/**
* Set proper error messages for failed validations
*
* @return array&lt;string&gt;
*/
public function messages() {
return [
&#39;password.required&#39; =&gt; &#39;my friendly message to the user&#39;,
];
}

You need to modify your controller accordingly, for more information take a look at Form Validation Docs.

huangapple
  • 本文由 发表于 2023年7月3日 14:44:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602402.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定