In this section, we'll look at getting the following outcome.
Follow these steps to implement validation in PHP:
Creating Helpers:
app/Helpers,
create a new file called Url.php
and enter:<?php namespace AppHelpers; class Url { public static function redirect($path = '/') { header('Location: '.$path); exit(); } }
This provides a single method called redirect that defaults to / when no parameters are passed. This is an easy way to redirect to another page of our application.
To use the class after it's been included into a page, use: Url::redirect('url/to/redirect/to')
To redirect to the home page, use:
Url::redirect()
Next, we need a way of using a session. Sessions are a way PHP can track data from page to page, which is perfect for our needs, such as being able to detect is a user is logged in or not by reading the session data.
We could use normal $_SESSION calls, but since we're using OOP, let's take advantage of that and build a session helper.
Session.php
inside app/Helpers
.The first method needed is to determine if a session has started. If it does update the sessionStarted
parameter, it will set it to false. This
will tell the init
method to turn on sessions:
<?php namespace AppHelpers; class Session { private static $sessionStarted = false; /** * if session has not started, start sessions */ public static function init() { if (self::$sessionStarted == false) { session_start(); self::$sessionStarted = true; } }
set
which accepts two parameters, $key
and $value.
This is used to add a $key
to a session and set the $value
to the $key:
public static function set($key, $value = false) { /** * Check whether session is set in array or not * If array then set all session key-values in foreach loop */ if (is_array($key) && $value === false) { foreach ($key as $name => $value) { $_SESSION[$name] = $value; } } else { $_SESSION[$key] = $value; } }
pull
with one parameter. This will extract the key
from the session and return it after removing it from the session, which is useful for one-time messages:public static function pull($key) { $value = $_SESSION[$key]; unset($_SESSION[$key]); return $value; }
public static function get($key) { if (isset($_SESSION[$key])) { return $_SESSION[$key]; } return false; }
$key
is provided, otherwise the entire session will be destroyed:public static function destroy($key = '') { if (self::$sessionStarted == true) { if (empty($key)) { session_unset(); session_destroy(); } else { unset($_SESSION[$key]); } } }
Session::init()
inside app/Config.php
:<?php namespace App; use AppHelpersSession; class Config { ……. ]; } }
Building Authentication:
We are now ready to start building the admin Controller and users Model, which will be the entry point for users to log in.
CREATE TABLE `users` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `created_at` datetime DEFAULT NULL, `reset_token` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
User.php
inside appModels
.<?php namespace AppModels; ……. { $this->db->delete('users', $where); } }
Creation of Admin Controller:
app/Controllers
called Admin.php
.This will be the entry point for logging in and out of the admin dashboard.
baseController
and the Session
and URL
helpers
as well as the User
Model.$user.
Then, in the __construct
method, initialize the User
Model by calling new User().
if
statement is run to check for the existence of a session key called logged_jn,
which is set only after logging in. If the user is not logged in, then redirect them to the login
method:<?php namespace AppControllers; use SystemBaseController; …….. $this->view->render('admin/index', compact('title')); } }
admin/index
view will be loaded. Create the view app/views/admin/index.php
and the entry:<?php include(APPDIR.'views/layouts/header.php'); include(APPDIR.'views/layouts/nav.php'); include(APPDIR.'views/layouts/errors.php'); ?> <h1>Dashboard</h1> <p>This is the application dashboard.</p> <?php include(APPDIR.'views/layouts/footer.php');?>
Now, we need to create a login
view. Create a folder called auth
inside app/views/admin
and create login.php.
header
layout and then create a div
with a caller of wrapper
and well
. The well
class is a bootstrap class which gives a grey square styling. The wrapper
class will be used to position the div
.errors
layout to catch any errors or messages.post
to POST its contents to an ACTION URL,
in this case, /admin/login
.username
and password.
Make sure the input type for password is set to password
.A submit button is also required to submit the form. A good practice is to offer a reset option if the user cannot remember their login details. We will create a link that points the user to /admin/reset
.
<?php include(APPDIR.'views/layouts/header.php');?> <div class="wrapper well"> <?php include(APPDIR.'views/layouts/errors.php');?> ……. .wrapper h1 { margin-top: 0px; font-size: 25px; }
login
method:login
method, create an empty $errors
array and set the page $title
and load
a view calling admin/auth/login,
passing the $title
and $errors
variables by using a compact
function.This loads the login
view and, upon pressing submit, won't actually do anything. We'll need to check for the form being submitted, but before doing that, we will need to add two methods to the user
Model:
public function get_hash($username) { $data = $this->db->select('password FROM users WHERE username = :username', [':username' => $username]); return (isset($data[0]->password) ? $data[0]->password : null); }
get_hash($username)
will select the password
from the users
table, where the username
matches the one provided.
Setting username = :username
creates a placeholder. Then, [':username' => $username
] will use that placeholder so it knows what the value is going to be.
Then, check whether $data[0]->password
is set and return it. Otherwise, return null
.
get_data(),
only this time, return an array of data rather than a single column:public function get_data($username) { $data = $this->db->select('* FROM users WHERE username = :username', [':username' => $username]); return (isset($data[0]) ? $data[0] : null); }
login
method, we can check whether the form has been submitted by checking if the $_POST
array contains an object called submit.
htmlspecialchars()
is a security measure, since it stops script tags from being able to be executed and renders them as plaintext.Next, an if
statement is run that calls password_verify(),
which is a built-in function which returns true
or false
. The first parameter is the user-provided $password,
and the second is the hashed password returned from the database by calling $this->user->get_hash($username)
. As long as password_verify
equals to false,
the login check has failed.
$errors
variable to contain an errors
message. Next, count the $errors
and if it equals to 0,
this means there are no errors so get the user data from $this->user->get_data($username).
Then, use the session helper to create a session key called logged_in
with a value of true,
and another session key with the user ID as its value.index
page:if (isset($_POST['submit'])) { $username = htmlspecialchars($_POST['username']); $password = htmlspecialchars($_POST['password']); if (password_verify($password, $this->user->get_hash($username)) == false) { $errors[] = 'Wrong username or password'; } if (count($errors) == 0) { //logged in $data = $this->user->get_data($username); Session::set('logged_in', true); Session::set('user_id', $data->id); Url::redirect('/admin'); } }
The full method looks like this:
public function login() { if (Session::get('logged_in')) { Url::redirect('/admin'); } …… $this->view->render('admin/auth/login', compact('title', 'errors')); }
php –S localhost:8000 –t webroot
http://localhost:8000/admin/login.
login
method, enter:echo password_hash('demo', PASSWORD_BCRYPT);
The first parameter is the password
you want, in this case, demo.
The second parameter is the type of PASSWORD
function to use. Using the default PASSWORD_ BCRYPT
means PHP will use the strongest version possible.
$2y$10$OAZK6znqAvV2fXS1BbYoVet3pC9dStWVFQGlrgEV4oz2GwJi0nKtC
username and email
and paste them into the hash. F
or the password, enter a valid datetime
for the created at
section, such as 2017-12-04 23:04:00./admin.
user_id
sessions. In the Admin
Controller, create a new method called logout
.object
and then redirect to the login
page:public function logout() { Session::destroy(); Url::redirect('/admin/login'); }
logout
in the upper-right corner. You will be logged out and taken back to the login
page.Admin
link, you will be taken to the default page. In this case, it would be better to load the admin as soon as you load the application. We can do this by setting the Admin
Controller to be the default app/Config.php.
Find the following:
'default_controller' => 'Home'
Replace it with:
'default_controller' => Admin,
Admin
(after reloading the page), you'll see the admin dashboard.Avoid the following hashing systems at all costs as they are not secure:
These password hashing functions are weak, and computers are now so powerful that it would take just seconds to break them.
It is advisable to comb through code when a developer is scoping out a new project to check for security flaws like the use of these.
In this section, we learned about the authentication process. We have seen how to make a login process. We have learned the process of password hashing. Now, we have experience in building, configuring, and routing functionality to a framework.
In the next section, we will cover the concept of password recovery wherein we will set up a functionality to reset the password in our application.