При запросе в БД выводится две строки, хотя должна только одна

public function searchLog() {
    $searchlog = $_POST['searchlog'];
    $login = strstr($searchlog, '_', true);
    $search_login = trim(strstr($searchlog, '_'), '_');
    $searchlog_sql = 'SELECT login FROM users';
    $searchlog_result = mysqli_query($this->conn2, $searchlog_sql); 

    foreach ($searchlog_result as $row) {
    
    
        if ($row['login'] == $search_login) {
            echo $row['login'];
           
        }
    }
    
}

Cтолкнулся проблемой, foreach выдает два результата вместо одного, я перепробовал многие варианты, как быть?


Ответы (3 шт):

Автор решения: Solt

Начнём с того, что разрезать строку по разделителю можно гораздо проще:

[,$search_login] = explode('_',$searchlog);

Далее. Кто ж загребает всю базу данных, а потом перелопачивает её в скрипте? Если задача найти слово в бд, надо в запрос его и подставить:

$sql = "SELECT login FROM users WHERE login=?";
$result = $this->conn2->execute_query($sql, [$search_login]); 

Разумеется, сразу с подстановками переменных.

→ Ссылка
Автор решения: Ипатьев

Одним из важнейших умений программиста является адекватное восприятие реальности.

Если запрос к БД находит две строки, это значит, что в БД и лежит две строки, соответствующих этому запросу

В общем случае, если запрос выводит что-то не то, то надо сначала его и проверять:

  1. Сам запрос. В нём могут быть кривые или невыполнимые условия
  2. Используемые в запросе данные. Они могут быть перековерканы неумелыми ручками, или вообще отсутствовать.
  3. Данные в БД. Может быть, их там нету, или есть, но не те.

Соответственно, если из БД выводятся лишние строки, то надо не циклу foreach претензии предъявлять, а для начала проверить базу данных. То есть выполнить тот же самый запрос напрямую в БД, с помощью консоли, нормального GUI или дурацкой программы phpmyadmin (при этом надо помнить, у начинающих программистов бывает так, что РНР код коннкетится к одной БД, а дурацкая программа phpmyadmin - к другой).

И дальше разбираться со своей БД, удалять дублирующие записи, добавлять уникальный индекс, чтобы такое не повторялось в будущем. И только потом, убедившись, что строка осталась только одна, возвращаться к своему РНР коду.

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

  • если мы используем ООП, то никаких глобальных переменных, все данные извне передаются только явно в аргументах
  • если мы используем ООП, то метод делает только что-то одно. Если это поиск по логину, то и выполнять он должен только поиск по логину, а не работу с протоколом HTTP и отрезание каких-то непонятных палочек
  • если мы используем ООП, то пишем код, позволяющий его повторное использование. Поиск пользователя по логину нужен в куче мест, и поэтому надо написать поиск пользователя по логину, а потом использовать его в разных местах, в том числе и для проверки существования логина
  • слово search подходит скорее для нечёткого поиска, по части логина, а у нас тут целый
  • если мы ожидаем только один результат, то и цикла никакого не нужно, а надо сразу запросить у БД нужный результат, и получить его

В итоге получаем вот такую аккуратную функцию

public function getByLogin(string $login): ?array {
    $sql = "SELECT login FROM users WHERE login=?";
    $result = $this->conn2->execute_query($sql, [$login]);
    return $result->fetch_assoc();
}

А уже при её вызове можно будет отрезать непонятные палочки и прочее. При этом надо помнить, никогда нельзя доверять входящим данным, в том числе что у них обязательно будет нужный формат

$parts = explode('_', $_POST['searchlog']);
$login = $parts[1] ?? null;
// если в $_POST['searchlog'] не было чёрточки
if ($login === null) {
    // сделать что-то страшное
}
$user = $user->getByLogin($login);
if ($user) {
    // нашли
} else {
    // не нашли
}

Ну и вместо палочек рекомендую использовать универсальный формат JSON.

→ Ссылка
Автор решения: Pavel Bobkin
if (isset($_POST['searchlog'])) {
$fusions->searchLog();
}

В конце PHP скрипта случайно копировал этот кусочек дважды, поэтому он срабатывал дважды. Спасибо участникам за новые фишки в коде, буду использовать

→ Ссылка