Making username case insensitive and making this code invulnerable to injections

I’m new to PHP and I have the following code:

<?php
session_start();

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

// connect to the database
$db = mysqli_connect('', '', '', ''); //This has the real informations

// REGISTER USER
if (isset($_POST['reg_user'])) {
  // receive all input values from the form
  $username = mysqli_real_escape_string($db, $_POST['username']);
  $email = mysqli_real_escape_string($db, $_POST['email']);
  $password_1 = mysqli_real_escape_string($db, $_POST['password_1']);
  $password_2 = mysqli_real_escape_string($db, $_POST['password_2']);

  // 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");
  }

  // 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 username='$username' OR email='$email' LIMIT 1";
  $result = mysqli_query($db, $user_check_query);
  $user = mysqli_fetch_assoc($result);
  
  if ($user) { // if user exists
    if ($user['username'] === $username) {
      array_push($errors, "Username already exists");
    }

    if ($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

  	$query = "INSERT INTO users (username, email, password) 
  			  VALUES('$username', '$email', '$password')";
  	mysqli_query($db, $query);
  	$_SESSION['username'] = $username;
  	$_SESSION['success'] = "You are now logged in";
  	header('location: home.php');
  }
}
// LOGIN USER
if (isset($_POST['login_user'])) {
  $username = mysqli_real_escape_string($db, $_POST['username']);
  $password = mysqli_real_escape_string($db, $_POST['password']);

  if (empty($username)) {
  	array_push($errors, "Username is required");
  }
  if (empty($password)) {
  	array_push($errors, "Password is required");
  }

  if (count($errors) == 0) {
  	$password = md5($password);
  	$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
  	$results = mysqli_query($db, $query);
  	if (mysqli_num_rows($results) == 1) {
  	  $_SESSION['username'] = $username;
  	  $_SESSION['success'] = "You are now logged in";
  	  header('location: home.php');
  	}else {
  		array_push($errors, "Wrong username/password combination");
  	}
  }
}
?>

The problem when registering a new user is that the username is case sensitive. So “randomuser” and “Randomuser” will be treated different and I don’t want that. How can I change this?

Also, I learned that the code above is vulnerable to injections, could someone help me change it so it won’t be? I want to try mysqli for that not pdo.

I usually store the username as it is typed in. But, for comparisons, I set both to lower-case.
Instead of checking the row of data for username like this :

if ($username==$user["username"]) {

Do it this way :

if (strtolower($username)==strtolower($user["username"]) {

This drops the user’s input from the login form and the database’s username field to lower case
before it is compared. This insures a valid compare!

Yep, this is what I was looking for! Could you help me change the code so I make it invulnerable to injections? I know where to start, I just don’t know how to do it properly.

Well, there are two parts to that question. First, form input cleaning. (removing infections.) And, safe database access and storage. I will try to explain these…

Injections are done by placing code into input form fields. To prevent that, you need to filter the inputs.
You can use the newer filter_input() function to do this. You need to study that function just a little.
It is each to use. Basically, just $name=filter_input(INPUT_POST, “fieldname”); Easy. But, you do
need to add the type of field so that the function can clean it appropriately. There are several types
of filters you can use to customize the filtering process. Such as for email addresses, you can use:

$email = filter_input(INPUT_POST, "email", FILTER_VALIDATE_EMAIL);

This will make sure it is a valid email address. There are filters for validation and sanitation.
You can view this function at: Filter-Input Read the filter-types page for more details…
( You do not need to use the real_escapes anymore, use filter_input() instead. )

Next, most infections can damage the database by inserting bad code into the inputs on forms.
To prevent that, you need to learn about “prepared statements” ! Very important section. These types
of database accesses will bypass running the data inputted from a form and store the data directly into
the database. This prevents the data from “running”, it just stores the data. Here is an explanation:

When you “build” your query as in a string like this: $query = "SELECT * FROM ? WHERE x=“xxx”;
you are placing data directly into the query itself. Then, when the query runs on the database, it can
run bad code in the query such as “DROP TABLE ?” which would erase the table completely!
Instead you replace all the data with a PREPARED version and use ?'s instead of the data.
Next, the data is executed and entered in a different way that does not allow the code to run in the
database system. This prevents data from running code. Sounds complicated, but, it is actually easy!

Here is a sample… (Using your query from above…)

$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$results = mysqli_query($db, $query);

Would become something like this:

$query = $mysqli->prepare("SELECT * FROM users WHERE username=? AND password=?");
$results = mysqli_prepare($db, $query);  //  Prepare  the statement
mysqli_stmt_bind_param($results, "SS", $username, $password);  //  Bind two strings to statement
mysqli_stmt_execute();  //  Execute the query
$user_data = mysqli_stmt_fetch($results);  //  Get the data (One record only)

This looks more complicated, but basically just adds the binding process into the code.
It creates a query, binds it to two strings marked by “SS” and the two inputs, executes it and gets data.
You do not need to check the number of rows. If data is retrieved, you can just check if there is anything
in the $user_data variable. If it is there, you have results, if not, it is an invalid user.

Hope that helps to get you started. I just wrote this off the top of my head and it is not tested at all.

One further comment. Since you are learning programming, you might want to consider moving from
MySQLi to the newer and better PDO. PDO is very similar to MySQLi, but, it is more secure and it is
what all professional programmers use now. It is simple to upgrade to. Here is a link for you to read
up on it and study. I suggest moving to PDO. PDO

Hope this helps and gets you started…

2 Likes

Thank you so much! I’ll try to learn everything and prepare my database in the best way possible! <3

Sponsor our Newsletter | Privacy Policy | Terms of Service