Параметризованные SQL-запросы и оптимизация PHP-кода для регистрации пользователей. - PullRequest
0 голосов
/ 05 июля 2018

Довольно новый для PHP здесь, и я изучал, как использовать параметризованные запросы для моих соединений SQL. Но все, на что я смотрю, заставляет меня думать, что мне нужно каждый раз менять одни и те же значения, чтобы использовать параметризованные запросы. Есть ли способ уменьшить то, что я сейчас делаю со своими запросами, используя параметризованные запросы? Я читаю на эти вещи неправильно?

Возможно, я новичок в PHP, но в целом знаю достаточно, чтобы понять, что этот код довольно дерьмовый. Мне не нравится иметь несколько запросов select *, а затем ссылаться на нужные мне поля по ассоциации. Но у меня также были проблемы, не делая это таким образом. Может ли кто-нибудь взглянуть на это и подтолкнуть меня в правильном направлении? Я готов быть названным глупым, так что принеси это. :) Спасибо.

<?php
    session_start();

    // initializing variables
    $username = "";
    $email    = "";
    $errors = array(); 

    // connect to the database
    $db = mysqli_connect('db_server', 'db_user', 'db_pw', 'db_name');

    // REGISTER USER
    if (isset($_POST['register-submit'])) {
      // receive all input values from the form
      $username = mysqli_real_escape_string($db, $_POST['reg_username']);
      $email = mysqli_real_escape_string($db, $_POST['reg_email']);
      $password_1 = mysqli_real_escape_string($db, $_POST['reg_password_1']);
      $password_2 = mysqli_real_escape_string($db, $_POST['reg_password_2']);
      $actcode  = mysqli_real_escape_string($db, $_POST['reg_actcode']);

      // form validation: ensure that the form is correctly filled ...
      // by adding (array_push()) corresponding error unto $errors array
      if (empty($username)) { array_push($errors, "Username is required"); }
      if (empty($email)) { array_push($errors, "Email is required"); }
      if (empty($password_1)) { array_push($errors, "Password is required"); }
      if ($password_1 != $password_2) { array_push($errors, "The two passwords do not match"); }
      if ($actcode != "tobecaps") { array_push($errors, "Wrong activation code"); }

      // first check the database to make sure 
      // a user does not already exist with the same username and/or email
      $user_check_query = "SELECT * FROM `users` WHERE user_name='$username' OR user_email='$email' LIMIT 1";
      $result = mysqli_query($db, $user_check_query);
      $user = mysqli_fetch_assoc($result);

      if ($user) { // if user exists
        if ($user['user_name'] === $username) {
          array_push($errors, "Username already exists");
        }

        if ($user['user_email'] === $email) {
          array_push($errors, "email already exists");
        }
      }

      // Finally, register user if there are no errors in the form
      if (count($errors) == 0) {
        $password = md5($password_1);//encrypt the password before saving in the database

        $query1 = "INSERT INTO `users` (user_name, user_email, user_password, user_register_time) VALUES('$username', '$email', '$password', 'time()')";
        mysqli_query($db, $query1);

        $query2 = "SELECT * FROM `users` WHERE user_name='$username' LIMIT 1";
        $result2 = mysqli_query($db, $query2);
        $new_user = mysqli_fetch_assoc($result2);
        $user_id = $new_user['user_id'];

        $planet_found = false;

        while (!$planet_found) {
            $galaxy = mt_rand(1, 1);
            $system = mt_rand(1, 15);
            $planet = mt_rand(1, 15);

            $query3 = "SELECT * FROM `planets` WHERE planet_galaxy='$galaxy' AND planet_system='$system' AND planet_planet='$planet' LIMIT 1";
            $result3 = mysqli_query($db, $query3);
            $planet_result = mysqli_fetch_assoc($result3);

            if (!$planet_result) {
                $planet_found = true;
            }
        }

        $query4  = "INSERT INTO `planets` (planet_user_id, planet_galaxy, planet_system, planet_planet) VALUES('$user_id', '$galaxy', '$system', '$planet')";
        $result4 = mysqli_query($db, $query4);

        $query5  = "SELECT * FROM `planets` WHERE planet_user_id='$user_id' LIMIT 1";
        $result5 = mysqli_query($db, $query5);
        $planets_info = mysqli_fetch_assoc($result5);
        $planets_id = $planets_info['planet_id'];

        $query6  = "UPDATE `users` SET user_home_planet_id='$planets_id', user_galaxy='$galaxy', user_system='$system', user_planet='$planet' WHERE user_id='$user_id'";
        $result6 = mysqli_query($db, $query6);

        //update tables with new ids here


        $_SESSION['username']   = $username;
        $_SESSION['success']    = "You are now logged in";
        header("Location: ../");
      } else {
          header("Location: ../");
      }
    }       
?>

Да, в настоящее время это работает; но я уверен, что смогу сломать это. Любые предложения приветствуются.

Как правило, код проверяет, существует ли пользователь или нет. Если нет, он добавляет их в пользовательскую базу данных, а затем создает случайное место для их использования.

1 Ответ

0 голосов
/ 05 июля 2018

Несколько указателей:

функции

Вы поместили все в глобальную область действия PHP. Для небольших приложений это допустимо, но быстро выходит из-под контроля. Случаются странные ошибки, которые трудно отследить, потому что вы потеряли контроль над своими переменными. Одним из признаков того, что вы знаете об этой проблеме, является нумерация ваших переменных: $result1, $result2, $result3 и т. Д. Каждый запрос лучше выполнять в пределах функции и только, если необходимо, вернуть результат.

Не повторяйся (принцип СУХОГО)

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

$query  = "SELECT * FROM `table` WHERE column = value LIMIT 1";
$result = mysqli_query($db,$query);
$data   = mysqli_fetch_assoc($result);

Вы можете поместить это в функцию:

function retrieveDataRow($db,$table,$column,$value)
{
  $query  = "SELECT * FROM `$table` WHERE `$column` = $value LIMIT 1";
  $result = mysqli_query($db,$query);
  return mysqli_fetch_assoc($result);
}

Это простой пример, прочитайте параграф sql-injection ниже. Я хочу сказать, что вы можете написать эту функцию один раз, а затем использовать ее несколько раз. Кроме того, предположим, что вы хотите что-то сделать с проблемой sql-инъекций, теперь вам нужно решать эту проблему только в одном месте, а не во многих местах.

классы

Говоря о структуре, почему бы не использовать объектно-ориентированный интерфейс mysqli вместо процедурного интерфейса? Я не верю, что это был осознанный выбор. При использовании PHP вы обнаружите, что почти все написано с использованием классов, поэтому логично использовать также объектно-ориентированный интерфейс mysqli. В конце концов это ваш выбор, но вы должны подумать об этом. Смотрите:

http://php.net/manual/en/mysqli.quickstart.dual-interface.php

проверка ошибок

Если все идет хорошо, ваш код будет работать хорошо, но что, если возникнет проблема, как ваш код справится с этим? Не очень, по моему мнению. Вы не проверяете результат выполнения запроса. Например: mysqli_query() вернет FALSE при сбое, а не массив ассоциативных данных. По крайней мере, проверьте, что:

$result = mysqli_query($db,$query);
if ($result !== FALSE) {
  .... your code ....
} else error('Query error: '.mysqli_error($db));

SQL-инъекция

Вы вставляете свои переменные прямо в строки запроса. Их нельзя назвать «параметризованными запросами». Об этом были написаны книги, но в основном mysqli использует привязку параметров для предотвращения sql-инъекций, см .:

https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection

но есть много других источников. Это очень распространенная ошибка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...