使用 utf8mb4 (Laravel) 的不区分大小写的 SQL 查询

Case insensitive SQL queries with utf8mb4 (Laravel)

我正在尝试创建一个只允许创建唯一用户名的帐户系统。 SQL 查询过去不区分大小写,但在将字符集更改为 utf8mb4 后,它区分大小写,这意味着人们可以使用重复的用户名。 (我更改为 utf8mb4 以允许用户 BIOS 中的表情符号和其他符号,因此无法恢复到旧字符集)

我试过更改连接排序规则,但是我尝试的所有操作都给我错误 500。我需要一些不需要我在每个查询中添加 "strtolower($username)" 的东西。

示例查询:

if(DB::table('users')->where('username', $username)->count() > 0){
    return response()->json(['status'=>'error','message'=>'Username is taken']);
}

SQL配置:

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', 'localhost'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

当用户尝试使用重复的用户名时,服务器应该 return:

{'status': 'error, 'message': 'Username is taken'}

但用户实际上能够创建一个帐户。

您可以在模型中定义 mutator。每次要存储数据时都会调用此方法:

class User extends Model
{
    /**
     * Set the user's username in lowercase.
     *
     * @param  string  $value
     * @return void
     */
    public function setUsernameAttribute($value)
    {
        $this->attributes['username'] = strtolower($value);
    }
}

现在,如果您在迁移中将该列声明为 unique(如下所示):

Schema::create('users', function (Blueprint $table) {
    // ...
    $table->string('username')->unique();
});

然后它会抛出异常错误,因为它会检测到系统正在尝试创建重复的记录。所以只要处理这个异常就可以return对用户的正确响应。

use Illuminate\Database\QueryException;

// ...

try
{
    $user = User::create($data);
}
catch (QueryException $e)
{
    $errorCode = $e->errorInfo[1];

    if ($errorCode == 1062)
    {
        return response()->json(['status'=>'error', 'message'=>'Username is taken']);
    }
}

但是,你需要在任何地方添加它.. 所以只需将它添加到 your exception handler 然后你就可以开始了。


注意:我使用 来详细说明我的答案。

已通过将所有 table 归类更改为 utf8mb4_unicode_ci 来修复。

ALTER TABLE <table> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;