【问题标题】:Case insensitive SQL queries with utf8mb4 (Laravel)使用 utf8mb4 (Laravel) 的不区分大小写的 SQL 查询
【发布时间】:2019-12-25 03:36:50
【问题描述】:

我正在尝试创建一个只允许创建唯一用户名的帐户系统。 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,
],

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

{'status': 'error, 'message': '用户名被占用'}

但用户实际上可以创建帐户。

【问题讨论】:

  • 请提供SHOW CREATE TABLE 和有问题的用户名对示例。

标签: php sql laravel character-encoding utf8mb4


【解决方案1】:

已通过将所有表排序规则更改为 utf8mb4_unicode_ci 来修复。

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

【讨论】:

    【解决方案2】:

    您可以在模型中定义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();
    });
    

    然后它会抛出异常错误,因为它会检测到系统正在尝试创建重复记录。因此,只需处理此异常即可向用户返回正确的响应。

    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 即可。


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

    【讨论】:

    • 我很久没有使用 Laravel,所以我不确定我应该做什么。这是否意味着我必须替换所有查询?还是对所有查询都不区分大小写?另外,我有更多有这个问题的表,有没有办法改变字符集使其不区分大小写但仍然允许特殊字符?
    猜你喜欢
    • 2018-11-05
    • 2015-07-23
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多