Register and login application with php and json

Updated: 04-May-2022 / Tags: PHP-OOP / Views: 7903 - Author: George

Introduction

In this full stack tutorial we are going to put together a register and login application. But instead of registering the user in a database, we are going to put the username and password in a JSON file.

When we register the user, we will have a username validation to check if the username is available, and we are going to encrypt the password so if someone gets his hands on our JSON file the passwords are useless.

Every user will have a unique username, so based on the username we will be able to validate the user's password when he logs in.

This will be fun to code so lets start.

Project files

Lets start with our project's files.

\-- register-login-app	
  |-- data.json		
  |-- index.php		
  |-- login.class.php		
  |-- login.php		
  |-- register.class.php		
  |-- styles.css		
  • Create a folder in your localhost server, and name it anything you like, but choose a name that makes sense.

  • Next inside the folder create the files that you see above. It's important to type the file names exactly as they are.

If you finished with the files, lets move to each of them and start coding our application.

The JSON file

In the data.json file we are going to create an empty array which is going to hold the users.

[

]

The index file

Open the blank index.php file and type the code below. In the index file we are gonna have the register form. The form will be submitted to the same file, (as you will see in the next section), so we have to catch the data with php before we write any HTML.

<?php require("register.class.php") ?>
<?php
	if(isset($_POST['submit'])){
		$user = new RegisterUser($_POST['username'], $_POST['password']);
	}
?>
<!DOCTYPE html>
  • In line 1 we require the register.class.php file so we have access to the RegisterUser() class that we are gonna write.

  • In line 3 we have an if statement and we are checking if someone clicked on the form's submit button.

  • If the form is submitted, then we creating a new RegisterUser() object, and we pass-in as arguments the user's username and password that the form sends. The RegisterUser() object does not yet exist. We are going to write the class later on when we get to the register.class.php file.

Next we are going to write a basic HTML structure of the index page.

<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="styles.css">
	<title>Register form</title>
</head>
<body>

</body>
</html>

Now we go between the body tags and write the register form in line 16.

<body>
	<form action="" method="post" enctype="multipart/form-data" autocomplete="off">
		<h2>Register form</h2>
		<h4>Both fields are <span>required</span></h4>

		<label>Username</label>
		<input type="text" name="username">

		<label>Password</label>
		<input type="text" name="password">

		<button type="submit" name="submit">Register</button>

		<p class="error"><?php echo @$user->error ?></p>
		<p class="success"><?php echo @$user->success ?></p>
	</form>
</body>
  • The important things in the form are:

  • The action="" attribute has no value, that means that the form will be submitted to the same page. That's why we wrote the php code at the top of the page, so we can catch the form's data.

  • In line 21 we have the username's input field and the name attribute is set to username name="username".

  • In line 24 we have the password's input field and the name attribute is set to password name="password".

  • In line 26 the submit button's name attribute has a value of "submit" name="submit". If you go back to line 3 you will see that this is the value that we are checking in the php code to see if the form is submitted.

    	if(isset($_POST['submit'])){
  • In line 28 we have a p tag with a class="error", and inside we have a php class property that will print out any registration error that occurs. The value of the @$user->error property will be set in the RegisterUser() class.

    The @ sign tells the server to ignore any warning, because when the page first loads the properties are undefined. But this is not causing any problem to the code.

  • The same thing applies to the "success" paragraph element in line 29.

This is all the HTML we need in the index file, lets go to the register.class.php and write the RegisterUser() class.

The Register user class

Here we are in the register.class.php file. Here we are going to write the RegisterUser() class, which will take the user's input, validate the username, hash the password, and put the values in the JSON file.

<?php
class RegisterUser{
	// class properties.
	private $username;
	private $raw_password;
	private $encrypted_password;
	public $error;
	public $success;
	private $storage = "data.json";
	private $stored_users; // array
	private $new_user; // array

  • In line 2, we defining the class.

  • Next we creating the properties we need so we can use their values throughout the class. In line 4 we have the incoming username.

  • In line 5 we have the incoming password. I named the property to $raw_password because in the next line i have a property called $encrypted_password which will hold the hashed password.

  • in line 7 and 8 we have an $error and a $success property. Notice that those two properties are public, that means we can call them outside the class. And that is what we are doing in the register form in line 28 and 29.

    	<p class="error"><?php echo @$user->error ?></p>
    	<p class="success"><?php echo @$user->success ?></p>
    		
  • in line 9 we are storing the file path of the json file to the $storage property.

  • In line 10, the $stored_users property will hold all the recorded users from the JSON file.

  • And in line 11, we have the $new_user array property that will hold the username and the hashed password.

All those properties are going to initialized with their values immediately when the class is called. Lets do this right now by writing the classes constructor method.

	public function __construct($username, $password){
		$this->username = filter_var(trim($username), FILTER_SANITIZE_STRING);
		$this->raw_password = filter_var(trim($password), FILTER_SANITIZE_STRING);
		$this->encrypted_password = password_hash($password, PASSWORD_DEFAULT);
		$this->stored_users = json_decode(file_get_contents($this->storage), true);
		$this->new_user = [
			"username" => $this->username,
			"password" => $this->encrypted_password,
		];
	}
  • The class constructor takes two arguments, the username and the password, those are the values that the register form sends. We pass in those values when we create a new ReigsterUser object in the index file in line 4.

    $user = new RegisterUser($_POST['username'], $_POST['password']); // index file
  • In line 14 we sanitize and trim the incoming username and store it in the username property.

    $this->username = filter_var(trim($username), FILTER_SANITIZE_STRING);
  • In line 15 we do the same thing with the incoming password.

     $this->raw_password = filter_var(trim($password), FILTER_SANITIZE_STRING);
  • In line 16 we use the password_hash function to encrypt the password, which we store in the encrypted_password property.

    $this->encrypted_password = password_hash($password, PASSWORD_DEFAULT);
  • In line 17 we fetch the recorded users from the json file with the file_get_contents function and we use the json_decode function to convert them to a php array.

    $this->stored_users = json_decode(file_get_contents($this->storage), true);

    The keyword true, which is the second argument of the json_decode function, tells the function to return the data as an array. If we omit it the function returns an object.

  • And in line 18 we create an associative array with the username and the encrypted password and store it in the $new_user property. The $new_user property holds the data that we are going to store in the JSON file.

    $this->new_user = [
    	"username" => $this->username,
    	"password" => $this->encrypted_password,
    ];
    
  • And we are done we the constructor.

Now lets take a look at the functions that we are going to write.

	private function checkFieldValues(){} // Checking for empty fields.
	private function usernameExists(){} // Checking if the username is taken.
	private function insertUser(){} // Insert the user in the JSON file.
  • The checkFieldValues function is going to validate that the username and password input fields are not empty.

  • The usernameExists function will loop through all stored users and will check if the incoming username is not already in use.

  • And the insertUser function will record the user in the JSON file.

Lets start with the checkFieldValues function.

	private function checkFieldValues(){
		if(empty($this->username) || empty($this->raw_password)){
			$this->error = "Both fields are required.";
			return false;
		}else{
			return true;
		}
	}
  • We have an if statement inside the function and we are checking if both input fields have values. If the condition is true we set an error message in the $error property, which is displayed in the register form. If both fields have values the function returns true.

Next we have the usernameExists function.

	private function usernameExists(){
		foreach ($this->stored_users as $user) {
			if($this->username == $user['username']){
				$this->error = "Username already taken, please choose a different one.";
				return true;
			}
		}
	}
  • We use a foreach function to loop through the stored users that we have in the JSON file. Remember that the $stored_users property is holding all the records from the JSON file.

  • In line 35 we use an if statement to check if the incoming username is already used by another user. If the condition is true then we set an error message to the $error property. And return true.

The last function is the insertUser function.

	private function insertUser(){
		if($this->usernameExists() == FALSE){
			array_push($this->stored_users, $this->new_user);
			if(file_put_contents($this->storage, json_encode($this->stored_users))){
				return $this->success = "Your registration was successful";
			}else{
				return $this->error = "Something went wrong, please try again";
			}
		}
	}
  • In line 43 we run an if statement and we check if the usernameExists function returns false. If the condition is true, that means that the incoming username doesn't exist in the JSON file. Therefore we can add the user to the file.

  • In line 44 we use the array_push method to add the new user to the stored users array.

  • And in line 45 we use the file_put_contents function to write the data in the JSON file. The file_put_contents function takes two arguments. The first argument is the file's path, and the second argument are the data that we want to write to the file.

    But to put the data in the file we have to encode them in a json format. So we use the json_encode function to encode the data. And we wrap the fille_put_contents function in an if statement, so we can check if the action was successful.

To complete our class and to execute the methods that we wrote we have to add the following if statement in our class constructor. Basically we are saying that if both fields have values then insert the user in the JSON file.

if($this->checkFieldValues()){
	$this->insertUser();
}

If you load the index.php file in the browser and do a user registration, and check the data.json file you will see the input data stored in the file.

And we are done with the registration process, now lets see how to log-in the user, using the data from the JSON file.

The login form

Lets structure the login.php file. We are gonna have again the php code at the beginning of the file, so we can catch the login data that the form submits. And then we will have the html code.

<?php require("login.class.php") ?>
<?php
	if(isset($_POST['submit'])){
		$user = new LoginUser($_POST['username'], $_POST['password']);
	}
?>
<!DOCTYPE html>
  • In line 1 we require the login.class.php file. This is the file where we write the LoginUser class.
  • In line 3 we have an if statement and we check if the form is submitted. If so we create a new LoginUser object and we pass in the constructor the form data, which is the users username and password.
    We are gonna write the LoginUser class in the login.class.php file when we finish with the login form.

Next we have the html page structure and the login form. This is the exact same form as the register form that we saw earlier. So i don't have anything new here to explain.

<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	 <link rel="stylesheet" href="styles.css">
	<title>Log in form</title>
</head>
<body>
	<form action="" method="post" enctype="multipart/form-data" autocomplete="off">
		<h2>Log in form</h2>
		<h4>Both fields are <span>required</span></h4>
		<label>Username</label>
		<input type="text" name="username">

		<label>Password</label>
		<input type="text" name="password">

		<button type="submit" name="submit">Log in</button>

		<p class="error"><?php echo @$user->error ?></p>
		<p class="success"><?php echo @$user->success ?></p>
	</form>
</body>
</html>

This is all the html we need for our login form, now lets write the LoginUser class.

The LoginUser class

This is the login.class.php file in which we have the LoginUser class.

<?php
class LoginUser{
	// class properties --------------------------------------
	private $username;
	private $password;
	public $error;
	public $success;
	private $storage = "data.json";
	private $stored_users;

	// class methods -----------------------------------------
	public function __construct($username, $password){
		$this->username = $username;
		$this->password = $password;
		$this->stored_users = json_decode(file_get_contents($this->storage), true);
		$this->login();
	}

	private function login(){
		foreach ($this->stored_users as $user) {
			if($user['username'] == $this->username){
				if(password_verify($this->password, $user['password'])){
					// You can set a session and redirect the user to his account.
					return  $this->success = "You are loged in";
				}
			}
		}
		return $this->error = "Wrong username or password";
	}
} // end of class

Code breakdown

Lets breakdown the LoginUser class.

class LoginUser{
	// class properties --------------------------------------
	private $username;
	private $password;
	public $error;
	public $success;
	private $storage = "data.json";
	private $stored_users; // array

  • In line 2 we defining the class.

  • Next we have the classes properties. In line 4 we have the $username property.

  • In line 5 we have the $password property.

  • In line 6 and 7 we have the $error and the $success properties.

  • In line 8 we have the path of the JSON file assigned to the $storage property.

  • And in line 9 we have an array of all stored users.

In line 11 we have the class constructor, as we have done in the register class we are going to initialize our properties .

	public function __construct($username, $password){
		$this->username = $username;
		$this->password = $password;
		$this->stored_users = json_decode(file_get_contents($this->storage), true);
		$this->login();
	}
  • In line 12 we assign the incoming username to the $username property.

  • In line 13 we assign the incoming password to the $password property.

  • In line 14 we fetch all the users from the JSON file and store them in the $stored_users property.

  • In line 15 we execute the login() method which we are going to write next.

The login method will loop through all stored users and search for the given username. If there is a match the function will then check if the given password matches the stored password. The method returns a success message if the user's username and password are correct. Else it returns an error message.

	private function login(){
		foreach ($this->stored_users as $user) {
			if($user['username'] == $this->username){
				if(password_verify($this->password, $user['password'])){
					return  $this->success = "You are logged in";
				}
			}
		}
	return $this->error = "Wrong username or password";
}
  • In line 22 we use the password_verify function to verify if the incoming password matches the stored hashed password. When we register a user in the RegisterUser class we hash the user's password with the password_hash function.

    password_hash($password, PASSWORD_DEFAULT); // RegisterUser class

    When we use the password_hash function to hash a password, we have to use the password_verify function to verify it.

The CSS code

And last we have the css file in which we apply some styling to the register, and login form.

*{
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
body{
	font-family: sans-serif;
	min-height: 100vh;
	color: #555;
	background-color: coral;
}
form{
	max-width: 400px;
	margin: 100px auto;
	border:  thin solid #e4e4e4;
	padding: 40px 30px;
	box-shadow: 0 5px 5px rgba(0, 0, 0, 0.2);
	background-color: white;
}
form h2{
	margin-bottom: 10px;
}
form h4{
	margin-bottom: 40px;
	font-weight: normal;
}
form h4 span{
	color:  coral;
	font-weight: bold;
	text-decoration: underline;
}
form label{
	display: block;
	margin-bottom: 10px;
	padding-left: 5px;
}
form input, form textarea{
	display: block;
	width:  100%;
	padding: 10px;	
	margin-bottom: 10px;
	font-size: 16px;
	border:  thin solid #e4e4e4;
	margin-bottom: 30px;
}
form select{
	display: block;
	width:  100%;
	margin-bottom: 10px;
	padding: 10px;
	font-size: 16px;
	border:  thin solid #e4e4e4;
	background-color: white;
	color: #555;
}
form input:focus
{
	outline: none;
	border: thin solid coral;
}
form textarea{
	min-height: 150px;
}
form input::placeholder{
	font-size: 16px;
}
form button{
	background: #32749a;
	color: white;
	border: none;
	padding: 15px;
	width:  100%;
	font-size: 16px;
	margin-top: 20px;
	cursor: pointer;
}
form button:active{
	background-color: green;
}
.error{
	margin-top: 30px;
	color: #af0c0c;
}
.success{
	margin-top: 30px;
	color: green;
}
	

Summary

We saw how to register users in a JSON file, and also we used the data from the file to log the users in.

We used PHP OOP (Object Oriented Programming) to achieve our tasks. So we coded a register class, and a login class. Also we saw the html and css code that we needed.

Last Words

Thanks for reading, i hope you find the article helpful.
Please leave a comment if you find any error's, so i can update the page with the correct code.

Source code

You can download the source code and use it in any way you like.

Times downloaded: 1450

Buy me a coffee

If you like to say thanks, you can buy me a coffee.

Buy me a coffee with paypal