Implementing Validation in PHP

In this section, we'll look at getting the following outcome.

Implementing Validation in PHP

Note

This section shows how to implement validation in PHP, although it will not work correctly yet as we are yet to create and supply the data source that forms the knowledge of the system.

To resolve this as part of the section, we will be manually creating a user.

Follow these steps to implement validation in PHP:

Creating Helpers:

  1. Before we can start building the authentication, we need two new helpers. In 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();
        }
    }

    Note

    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.

  2. Create a file called Session.php inside app/Helpers.
  3. First, set the namespace and class definition:

    Note

    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;
        }
    }
  4. Next, create a method called 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;
        }
    }
  5. Next, create a method called 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;
    }
  6. Next, create a get method. This will return a session from the provided key:
    public static function get($key)
    {
        if (isset($_SESSION[$key])) {
            return $_SESSION[$key];
        }
    
        return false;
    }

    Note

    Sometimes, you want to see the contents of the session. Create a method called display that returns the $_SESSION object:

    public static function display()
    {
        return $_SESSION;
    }
  7. The last method is used to destroy the session key when the $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]);
            }
        }
    }

    The full class looks like this:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?php namespace AppHelpers;
    
    class Session
    {
        private static $sessionStarted = false;
    ……..
        }
    
    }
  8. Now, we need to set sessions automatically when the application runs. We do this by adding Session::init() inside app/Config.php:

    Note

    This makes use of a Use Statement and includes a call to the session's helper class. Highlighting these OOP features may be beneficial at this stage.

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?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.

  1. Create a new table in your database called users:
    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;

    Note

    The ID is the primary key and will be set to auto increment, meaning each record will have a unique ID.

    The reset_token will only be used when a reset password procedure is needed.

  2. Let's start with the Model. Create a file called User.php inside appModels.
  3. Set the namespace and import the base Model and set the class definition.

    Note

    We will be coming back to this model as we go along to add necessary methods as required.

  4. Add methods for inserting, updating, and deleting records:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?php namespace AppModels;
    …….
        {
            $this->db->delete('users', $where);
        }
    }

Creation of Admin Controller:

  1. Now, create a new file in app/Controllers called Admin.php.

    This will be the entry point for logging in and out of the admin dashboard.

  2. Set the namespace and import the baseController and the Session and URL helpers as well as the User Model.
  3. Set the class definition and create a property called $user. Then, in the __construct method, initialize the User Model by calling new User().

    Note

    This means to access any methods of the User Model, $this->user can be used.

    The next method is index(). This will load the dashboard view as long as the user is logged in.

  4. To ensure that the user is logged in, an 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:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?php namespace AppControllers;
    
    use SystemBaseController;
    ……..
            $this->view->render('admin/index', compact('title'));
        }
    
    }
  5. If the user is logged in, then the 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.

  6. First, include the 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.
  7. Next, include the errors layout to catch any errors or messages.
  8. Now, we'll create a form that will have a method of post to POST its contents to an ACTION URL, in this case, /admin/login.
  9. Then, create two inputs for the username and password. Make sure the input type for password is set to password.

    Note

    Setting the input type to password stops the password from being displayed on the screen.

    When the form is submitted, the named attributes of the inputs is how PHP will know what the data is.

    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.

  10. Finally, close the form and include the footer layout:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?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;
    }
  11. Now, go back to the admin Controller and create a login method:

    Note

    Put in a check that redirects the user if they are logged in. They should not be able to see the login page when they are already logged in.

  12. Inside the 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.

    Note

    compact() makes it possible to use variables by simply entering their names without the $:

    public function login()
    {
        if (Session::get('logged_in')) {
            Url::redirect('/admin');
        }
    
        $errors = [];
    
        $title = 'Login';
    
        $this->view->render('admin/auth/login', compact('title', 'errors'));
    }

    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.

  13. Do the same thing again for 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);
    }
  14. Now, inside our login method, we can check whether the form has been submitted by checking if the $_POST array contains an object called submit.
  15. Then, collect the form data and store them on local variables. Using htmlspecialchars() is a security measure, since it stops script tags from being able to be executed and renders them as plaintext.

    Note

    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.

  16. Set an $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.
  17. Finally, redirect the user to the admin 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'));
    }
  18. Run the framework if it's not already running:
    php –S localhost:8000 –t webroot
  19. Go to http://localhost:8000/admin/login.

    Note

    You will see a login page. Pressing login will show an error message of 'Wrong username or password' no matter what you enter, as there are currently no users in the database.

  20. Let's create our login. We need a hashed password to store in the database. To create one in the 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.

  21. When you refresh the page, you will see a hash like the following:
    $2y$10$OAZK6znqAvV2fXS1BbYoVet3pC9dStWVFQGlrgEV4oz2GwJi0nKtC
  22. Copy this and insert a new record into the database client and leave the ID column blank. That will populate itself.
  23. Create a username and email and paste them into the hash. For the password, enter a valid datetime for the created at section, such as 2017-12-04 23:04:00.
  24. Save the record. Now, you will be able to set up the login.
  25. Upon logging in, you'll be redirected to /admin.

    Note

    Remember to comment out or remove echo password_hash('demo', PASSWORD_BCRYPT), otherwise the hash will always be displayed.

  26. While we're at it, let's go ahead and add in the ability to log out. Logging out is a case of destroying the logged-in and user_id sessions. In the Admin Controller, create a new method called logout.
  27. Inside the method, destroy the session object and then redirect to the login page:
    public function logout()
    {
        Session::destroy();
        Url::redirect('/admin/login');
    }
  28. Now, go back to the application and click logout in the upper-right corner. You will be logged out and taken back to the login page.
  29. Now, log back in. If you click on the 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,
  30. Now, if you click on Admin (after reloading the page), you'll see the admin dashboard.

    Note

    There was once a time where certain standards for password hashing were considered to be the highest level of internet security. But, like most technology, it is inevitably made available, and this weakens the effectiveness of its predecessors.

    Note

    Avoid the following hashing systems at all costs as they are not secure:

    • MD5
    • Shar 1
    • Shar 2 56

    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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset