Это подготовленное заявление?

Вот мой код.

function login($username,$password){
    global $db;
    
    $sql = "SELECT * FROM users133 WHERE username=:username";
    $stmt = $db->prepare($sql);
    $stmt->execute(array(':username' => $username));
    if ($stmt->rowCount() > 0){
        $result = $stmt->fetchAll();
        $hash = $result[0]['password'];
        if (password_verify($password, $hash)) {
            $_SESSION['loggedIn'] = $result[0]['id'];
        header("location: ?page=profile"); /*<----AFTER LOGING IN YOU GET TO THIS PAGE*/
        }else{
            header("location: ?page=loginfailed");
        }
        
    }
    else{
        header("location: ?page=loginfailed");
    }
}

Да, я знаю, что этот пост дублируется, но есть дополнительные вещи, которые мне нужно спросить!! Сегодня я провожу около 6 часов, читая, как делать подготовленные операторы. я читал о команде $stmt->bindParam, которая заставляет базу данных проверять, является ли входное значение целым, строковым и т. д. (на случай, если пользователь играл с параметром элемента проверки или поместил вредоносный код в форму). Это необходимо для подготовленного оператора SELECT? Я планирую скопировать код этой функции входа в систему и использовать его в другом месте на своем сайте. Вот почему мне нужно спросить, на 100% ли это так, как сейчас.

Комментарии не для расширенного обсуждения; этот разговор был перешел в чат.

Samuel Liew 14.03.2019 03:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
14
1
115
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, вы используете подготовленный оператор с параметром. Это правильно. В большинстве случаев параметры — это лучший способ написать безопасные операторы SQL. Есть всего несколько крайних случаев, когда они не помогают (см. мой ответ на насколько безопасны подготовленные операторы PDO)

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

$sql = "SELECT id, password FROM users133 WHERE username=:username";

Избегайте SELECT *, всегда четко указывайте столбцы. Видеть

$stmt = $db->prepare($sql);
$stmt->execute(['username' => $username]);

Если вы включили исключения PDO, это нормально, потому что любая ошибка SQL прервет код и вызовет исключение. Но если вы не включили исключения, вы всегда должны проверять возвращаемое значение как prepare(), так и execute(). См. http://php.net/manual/en/pdo.error-handling.php и http://php.net/manual/en/pdo.errorinfo.php

Синтаксис array() взят из старых версий PHP, а начиная с PHP 5.4 вы можете использовать более короткий синтаксис с квадратными скобками.

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

while (row = $stmt->fetch()) {
    $hash = $row['password'];
    if (password_verify($password, $hash)) {
        $_SESSION['loggedIn'] = $row['id'];
        header("location: ?page=profile");
    }else{
        header("location: ?page=loginfailed");
    }
}
header("location: ?page=loginfailed");

Вышеизложенное позволяет избежать вызова rowCount(). Если рядов нет, то while() естественно завершается, не сделав ни одного цикла, а потом проваливается до последнего вызова header().

Я предпочитаю не звонить rowCount(), потому что сложно вспомнить, когда это работает, а когда нет. rowCount() вернет 0 до того, как клиент получит все строки с сервера MySQL. Иногда выполнение запроса неявно извлекает все строки в память клиента, а затем вызов fetch() просто перебирает их. Это называется буферизованным запросом. Но небуферизованные запросы полезны, если ваш результат будет содержать слишком много строк для буферизации. Так что не всегда ясно, когда rowCount() вернет точный счет.

Большое спасибо за ваше время. Честно говоря, ваш вариант мне кажется немного сложным. Я даже никогда не использовал команду «пока». Я буду продолжать свой путь. Еще раз спасибо за ваше время. Да, исключения PDO включены.

user10523311 13.03.2019 18:31

В этом случае, поскольку вы ищете только один результат, вы можете использовать «если» вместо «пока». Аргумент для оператора while является важной вещью. Он делает две вещи одновременно: извлекает следующую строку, но если строки не существует, условное выражение терпит неудачу. Это очень полезная практика, которой стоит научиться. Не говоря уже о том, что это позволяет избежать душевной боли, которая может быть у rowCount.

Tim Morton 13.03.2019 18:44

Другие вопросы по теме