Can You FoolProof This Login-Registration Page?

Hi,

Can php seniors check this login-registration page out ?
Basically, it asks you for your email. If it finds present in db then it assumes you are existing member and login() triggers to log you in your account.
Else, it assumes you are new person and registration() triggers to register you.
Can someone kindly check if it is ok or not. My code. For any serious flaws.

I really need you to check my prepared statements.
On registrartion() I used INSERT and in login() I used SELECT. Otherwise, they pretty much copy & paste. Same with each other.
Do concentrate on these if I got my sql queries with prepared statements correct or not. That is most important.

On the login(), at the end when user is logged into his member account, his personal details get displayed on screen.
I need you to check if this following line (especially) is correct or not:

if($row = mysqli_fetch_array($result_3,MYSQLI_ASSOC))

In short, is there any errors in my code that will result in malfunction or hacker sql injecting or hacking ?

I have left-out the password prompt because I have forgotten how to do it with encryption. Can someone show me a typical example how to query for password with SHA256 or whatever the latest strong algorithm is ? A snippet would be handy.
I will the modify your snippet a little to suit my purpose and add it on the login().
Yes, I need to add the password prompt on the regsitration() aswell but you don’t have to worry about that. You just teach me how to do it in the login() and from there I will take it on to add it on the registration().

Also, show me how to show error messages from array. I have not a clue how to perform this.
The best I did is this:

<?php if(!empty($email_error)){echo $email_error;}?>

You know what should be done here. Error messages should be in array. Script should check if error occured then echo it in the appropriate form input after grabbing the error message from the error array. that sort of thing. So, if user forgot to input password then password error message will be grabbed from error array and echoed on the password prompt input field. That sort of basic thing that you usually do. I just don’t know how how to code it. Not a single clue. I need a sample shown. Something to start with. You be my starting point. Show me a basic snippet how it should be done.

Thanks

<?php

session_start();

if($_SERVER['REQUEST_METHOD'] == 'POST')
{
	if(!isset($_POST['email_account']) || !isset($_POST['email_service']))
	{
		$email_error = "<font color='red'>Input Email Address!</color>";
	}
	else
	{
		//Connect to Database. (DB_SERVER, BD_USERNAME, DB_PASSWORD, DB_NAME).
		$conn = mysqli_connect("localhost","root","","powerpage");
		$conn->set_charset('utf8mb4'); //Always set Charset.
		
		if($conn === false)
		{
			die("ERROR: Connection Error!. " . mysqli_connect_error());
		}
		else
		{
			//Set Parameters.
			$email = trim($_POST["email_account"]) . '@' . trim($_POST["email_service"]);
			$_SESSION['email'] = trim($_POST["email_account"]) . '@' . trim($_POST["email_service"]);//If this fails on test then replace it with above line
			echo "line 25 triggered: $email<br>";
			
			$sql_query = "SELECT COUNT(personal_email) FROM users WHERE personal_email = ?";
			$stmt = mysqli_prepare($conn,$sql_query);
			if($stmt == False)
			{
				//Close Connection.
				mysqli_close($conn);
				echo "Line 33<br>";//DELETE THIS
				die("<pre>Mysqli Prepare Failed!\n".mysqli_stmt_error($stmt)."\n$sql_query</pre>");
			}
			else
			{
				mysqli_stmt_bind_param($stmt,'s',$email);
				
				if(!mysqli_stmt_execute($stmt))
				{
					//Close Connection.
					mysqli_close($conn);					
					die("Could not mysqli_stmt_execute! Please try again later!");
				}
				
				$result = mysqli_stmt_get_result($stmt);
				
				if(mysqli_fetch_array($result, MYSQLI_NUM)[0])//WHY THIS NOT WORK UNLESS NUM ARRAY GIVEN ?
				{
					echo "Line 57 triggered: Function login() will trigger!<br>"; //DELETE THIS
					$_SESSION['session_type'] = 'login';
					login();
				
				}
				else
				{
					echo "Line 61 triggered: Function register() will trigger!<br>"; //DELETE THIS
					$_SESSION['session_type'] = 'register';
					register();
				}
			}
		}
	}
}

function register()
{
	//if(!isset($_SESSION['session_type'] or $_SESSION['session_type'] != 'registration')//Nog Dog's copied & pasted line
	if(!isset($_SESSION['session_type']) || $_SESSION['session_type'] != 'register')
	{
		//Close Statement.
		mysqli_stmt_close($stmt);
		//Close Connection.
		mysqli_close($conn);
		
		die("Line 86: Could not check email! Please try again later!");
	}
	
	//$email = trim($_POST["email_account"]) . '@' . trim($_POST["email_service"]);
	$email = $_SESSION['email'];//If this fails on test then replace it with above line
	
	//Connect to Database. (DB_SERVER, BD_USERNAME, DB_PASSWORD, DB_NAME).
	$conn = mysqli_connect("localhost","root","","powerpage");
	
	//Prepare an INSERT Statement.
	$sql_query_2 = "INSERT INTO users (personal_email) VALUES (?)";
	
	if(!$stmt_2 = mysqli_prepare($conn,$sql_query_2))
	{
		//Close Connection.
		mysqli_close($conn);
		die("Could not register! Please try again later!");
	}
	else
	{
		//Bind Variables to the Prepared Statement as parameters.
		mysqli_stmt_bind_param($stmt_2,'s',$email);
		
		//Attempt to execute the Prepared Statement.
		if(!mysqli_stmt_execute($stmt_2))
		{
			//Close Statement.
			mysqli_stmt_close($stmt_2);
			//Close Connection.
			mysqli_close($conn);
			die("Could not register! Please try again later!");
		}
		mail();
	}
}

function login()
{
	if(!isset($_SESSION['session_type']) || $_SESSION['session_type'] != 'login')
	{
		//Close Statement.
		mysqli_stmt_close($stmt);				
		//Close Connection.
		mysqli_close($conn);
		
		die("Could not check email! Please try again later!");
	}
	
	//$email = trim($_POST["email_account"]) . '@' . trim($_POST["email_service"]);
	$email = $_SESSION['email'];//If this fails on test then replace it with above line
	
	//Connect to Database. (DB_SERVER, BD_USERNAME, DB_PASSWORD, DB_NAME).
	$conn = mysqli_connect("localhost","root","","powerpage");
	
	//Prepare a Select Statement.
	$sql_query_3 = "SELECT id,username,first_name,middle_name,surname,gender,age_range FROM users WHERE personal_email = ?";
	if(!$stmt_3 = mysqli_prepare($conn,$sql_query_3))
	{
		//Close Statement.
		mysqli_stmt_close($stmt_3);
		//Close Connection.
		mysqli_close($conn);
		
		die("Could not check email! Please try again later!");
	}
	else
	{
		//Bind Variables to the Prepared Statement as parameters.
		mysqli_stmt_bind_param($stmt_3,'s',$email);
		
		//Attempt to execute the Prepared Statement.
		if(!mysqli_stmt_execute($stmt_3))
		{
			//Close Statement.
			mysqli_stmt_close($stmt_3);
			//Close Connection.
			mysqli_close($conn);
			
			die("Could not check email! Please try again later!");
		}
		//mysqli_stmt_bind_result($stmt,$email);		
		
		$result_3 = mysqli_stmt_get_result($stmt_3);
		
		//if(mysqli_fetch_array($result_3, MYSQLI_NUM))
		
		//Fetch result row as an associative array. Since the result set contains only one row, we don't need to use the 'While loop'.
		//mysqli_stmt_fetch($stmt);//use this if you use 'mysqli_stmt_bind_result($stmt,$email).
		if($row = mysqli_fetch_array($result_3,MYSQLI_ASSOC)) //Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of 'mysqli_stmt_bind_result($stmt,$email)'.
		{
			//Retrieve Values.
			$id = $row["id"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
			$username = $row["username"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
			$first_name = $row["first_name"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
			$middle_name = $row["middle_name"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
			$surname = $row["surname"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
			$gender = $row["gender"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
			$age_range = $row["age_range"];//Use this if you use '$result = mysqli_stmt_get_result($stmt)' instead of //'mysqli_stmt_bind_result($stmt,$email_count)';
		
			echo "Id: $id<br>";
			echo "Username: $username<br>";
			echo "First Name: $first_name<br>";
			echo "Middle Name: $middle_name<br>";
			echo "Surname: $surname<br>";
			echo "Gender: $gender<br>";
			echo "Age Range: $age_range<br>";
			
			//Close Statement.
			mysqli_stmt_close($stmt_3);
			//Close Connection.
			mysqli_close($conn);
		}
	}
}

//DO NOT NEED TO REDO THE HTML CODE BELOW AS WAS NOT COPY & PASTE FROM ELESEWHERE ....
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
<meta name="viewport" content="width=device=width, initial-scale=1">
</head>

<body>

<form action="" method="post">
<label for="email_account">Email:</label>
<input type="text" name="email_account" id="email_first_part" placeholder="Email Address before '@'">
<label for="email_service"><b>@</b></label>
<input type="text" name="email_service" id="email_last_part" placeholder="Email Address after '@'">
<?php if(!empty($email_error)){echo $email_error;}?>
<br>
<button type="submit" class="login_register" name="login_register">Register/Login</button>
</body>
<html>

<?php
?>

Use password_hash() to store the password when your user registers, and use password_verify() to compare it. From what I read on here (I have little to no real-world experience of security) that’s generally better than trying to write your own stuff with various hashes. Both functions are in the doc, which almost certainly has code examples.

That will just show “array” when you echo it. Have a look at foreach(), that will allow you to iterate through each element of the array and display it.

Why do you make your users split out their email into two sections, before the @ and after the @? Do you do anything with the separate parts? And if you do (I can’t think what), why can’t you just use explode and split it yourself, instead of making the user do it?

I’m not sure what this line

mail();

will do, with no parameters provided. In any case, I read on here that you should use PHPMailer instead of the built-in mail function, for reliability.

This line

if(mysqli_fetch_array($result, MYSQLI_NUM)[0])//WHY THIS NOT WORK UNLESS NUM ARRAY GIVEN ?

seems incorrect too. Your query does a SELECT COUNT(), so it will always return a single row containing a number. You must retrieve the value from the row and look to see if it is zero or a different number to check for matching emails, or SELECT the user-id or anything other than a row count. Or you could give the email column a unique constraint, attempt to insert the new user, and trap the “duplicate” error condition.

The part after the @ to be checked to see if it matches a list of known “throw-away email domains” and if it does could be rejected

1 Like

Thread closed as the OP is no longer a member.

Thanks to those who replied.

1 Like