SQL-запросы без учета регистра с utf8mb4 (Laravel)

Я пытаюсь создать систему учетных записей, которая позволяет создавать только уникальные имена пользователей. Раньше SQL-запросы были нечувствительны к регистру, но после изменения кодировки на utf8mb4 он чувствителен к регистру, что означает, что люди могут использовать повторяющиеся имена пользователей. (Я перешел на utf8mb4, чтобы разрешить смайлики и другие символы в пользовательских биосах, поэтому возврат к старой кодировке невозможен)

Я пытался изменить сортировку соединения, однако все, что я пробовал, дает мне ошибку 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,
],

Когда пользователь пытается использовать повторяющееся имя пользователя, сервер должен вернуть:

{'статус': 'ошибка, 'сообщение': 'Имя пользователя занято'}

но пользователь фактически может создать учетную запись.


person d0x    schedule 19.08.2019    source источник
comment
Предоставьте SHOW CREATE TABLE и пример проблемной пары имен пользователей.   -  person Rick James    schedule 20.08.2019


Ответы (2)


Вы можете определить в своей модели мутатор. Этот метод будет вызываться каждый раз, когда вы захотите сохранить данные:

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']);
    }
}

Но тогда вам нужно будет добавить это везде... поэтому просто добавьте его в ваш обработчик исключений и все готово.


Примечание. Я использовал этот другой вопрос, чтобы уточнить свой ответ.

person Kenny Horna    schedule 19.08.2019
comment
Я давно не использую Laravel, поэтому я не уверен, что именно я должен делать. Означает ли это, что мне придется заменить все запросы? Или он будет нечувствительным к регистру для всех запросов? Кроме того, у меня есть больше таблиц, в которых есть эта проблема, нет ли способа изменить кодировку, чтобы сделать ее нечувствительной к регистру, но по-прежнему разрешать использование специальных символов? - person d0x; 20.08.2019

Исправлено путем изменения всех параметров сортировки таблиц на utf8mb4_unicode_ci.

ALTER TABLE <table> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
person d0x    schedule 21.08.2019