Проверьте тип переменной перед обновлением базы данных | PHP

#php #mysql #pdo

#php #mysql #pdo

Вопрос:

У меня есть эта функция, которая обновляет a user_token для соответствующего user_id :

 public function setUserToken($userId, $userToken)
    {
        $stmt = $this->conn->prepare("UPDATE $this->dbname.user SET user_token=:user_token WHERE user_id=:user_id;");

        try {
            $stmt->bindParam(':user_token', $userToken, PDO::PARAM_STR, 70);
            $stmt->bindValue(':user_id', "sdf", PDO::PARAM_INT);
            $result['success'] = $stmt->execute();
            $result['message'] = "Successfully updated user_token for user_id " . $userId;

        } catch (PDOException $e) {
            $result['success'] = false;
            $result['message'] = "Failed to update user_token with error: " . $e->getMessage();
        }

        return $result;
    }
 

С помощью этой строки:
$stmt->bindValue(':user_id', "sdf", PDO::PARAM_INT); и try-catch операция, я попытался выдать ошибку, если значение user_id не является целым числом.

Но это терпит неудачу. Я предполагаю, это потому, что PHP автоматически преобразует строку «sdf» в целое число со значением 0.

Каково здесь решение?

Комментарии:

1. Используйте функцию is_numeric, чтобы проверить, является ли идентификатор пользователя числовым, и выполните следующую операцию

2. Вы говорите, что это не удается, потому что PHP преобразует строку «sdf» в INT со значением 0. Вы заявляете, что значение для :user_id должно быть INT, используя PDO::PARAM_INT , если user_id является первичным ключом для таблицы, то, скорее всего, это будет INT, и поэтому вам нужно будет всегда передавать ему INT, а не строку. Как утверждает Shibon, вы можете использовать if( is_numeric( $userId ) ) { //Yes } для проверки переменной перед продолжением.

Ответ №1:

Да, вы правы. PDO не применяет принудительное приведение типов с привязкой. Вероятно, это связано с возможными ошибками с точностью — безопаснее отправлять некоторое значение в виде строки, чтобы позволить базе данных сортировать данные по своему значению.

В PHP7 вы можете объявить аргумент функции с подсказкой PHP, какого типа он должен быть:

 function whatever (int $id)
{
    echo $id;
}
whatever("sdf");
 

выдаст исключение, как вы и хотели.

Если ваш PHP устарел, то вам придется написать код для проверки вручную. Чтобы использовать конкретную функцию, вы должны решить, хотите ли вы проверить тип переменной или ее содержимое. Для первого вы можете использовать is_int() функцию, а ctype_digit() для второго — функцию.

 if (!ctype_digit($user_id))
{
     throw new Exception("Whatever");
}
 

Кроме того,

Обратите внимание, что ваша обработка ошибок неверна. Вы не должны перехватывать ошибку прямо на месте, оставляя код как

 public function setUserToken($userId, $userToken)
{
    $stmt = $this->conn->prepare("UPDATE $this->dbname.user SET user_token=:user_token WHERE user_id=:user_id;");

    $stmt->bindParam(':user_token', $userToken, PDO::PARAM_STR, 70);
    $stmt->bindValue(':user_id', "sdf", PDO::PARAM_INT);
    $result['success'] = true;
    $result['message'] = "Successfully updated user_token for user_id " . $userId;
    return $result;
}
 

в то время как отчеты об ошибках должны быть централизованными и безопасными, как описано здесь

Если вы хотите сообщать клиенту об ошибках проверки, я не вижу в этом особого смысла, но если вы все еще этого хотите, либо верните это сообщение об ошибке непосредственно из кода проверки,

 if (!ctype_digit($user_id))
{
     $result['success'] = false;
     $result['message'] = "wrong data type";
}
 

или создайте отдельное исключение ValidationException, выбросьте его, перехватите это и отправьте отчет обратно клиенту

Комментарии:

1. Отличный ответ. 1 для справки о php7 и для того, чтобы приблизить вас к 111k!

2. Просто чтобы добавить к этому, PHP все равно будет выполнять некоторое принуждение к типу для вас, когда он не потеряет данные. Например, если бы вместо 5 я использовал «5» для $userId, то PHP автоматически преобразовал бы строку 5 в целое число 5. Это нормально в данном конкретном вопросе, но просто знайте, что если вы не хотите автоматического преобразования, вы должны использовать строгую типизацию, как это declare(strict_types=1); в самой первой строке вашего скрипта.

3. Да, именно так