Learn the basic concepts, tools and functions that you will need for user authentication using a PHP MVC framework.
Add registration and login to the PHP MVC framework we built on the "Build a PHP MVC Framework From Scratch" course.
Build Registration and Login using Models, Views and Controllers
Most websites and web applications need user authentication. Once users sign up to your site, you can tailor content specifically to them, and restrict content to logged-in users only.
By developing user authentication using an MVC framework, your code will be easier to write and maintain.
All the concepts you need to know to understand why the system is developed the way it is are explained in detail.
Content and Overview
I designed this course to follow on from the Write PHP Like a Pro: Build a PHP MVC Framework From Scratch course. At the end of that course you had built your own PHP MVC framework. If you want to add user registration and login to that framework, then this course will cover all you need to know, starting from where that course left off.
Starting with the basic concepts of authentication, this course will take you through all the steps needed to build a complete registration and login system, one piece at a time.
Beginning with the PHP MVC framework from the previous course, each lecture explains what you're going to add to the code and why, building up the project step by step. At the end of this course, you'll have built a complete registration and login system using the PHP MVC framework, ready to use in your own projects.
Complete with working source code at every stage, you'll be able to work alongside the instructor and will receive a verifiable certificate of completion upon finishing the course. Also, at all times throughout the course you have access to the instructor to ask for help with any topic related to the course.
Welcome to the course!
In this lecture we'll look at:
To get the most out of the course, you should be running the code yourself as we go along. The best place to do this is on your own web server, installed locally on your computer. In this lecture you'll learn how to do that.
At the end of this lecture, you should have a web server and database server running on your computer.
Throughout this course we’re going to be developing the login system using the PHP MVC framework that we developed on the Write a PHP MVC framework from Scratch course.
So you'll need a copy of that framework code as a starting point. This lecture shows you how to get a fresh copy of that code from Github if you need it.
Now that you've got the framework installed, we need to configure the web server.
In this lecture you'll configure the root of the web server to point to the public folder of the framework.
The application that you’re going to be creating needs a database. In this lecture you'll learn how to use phpMyAdmin to create one, that we'll be using throughout the rest of the course.
The first thing we need to do is let visitors to our site register or sign up. They can’t login until they’ve created an account. We need a table of users in the db to store these user accounts.
In this lecture you'll learn how to uniquely identify each user account. We'll look at the advantages and disadvantages of using a username or an email address.
When a user logs in, they’re going to enter their username and their password. To authenticate them, we need to take the username they supplied, look it up in the database, and check their password is correct.
So along with the username, we need to store the password in the database.
In this lecture you'll learn the most secure way to do that, so that even if the database is stolen, an attacker can't use the data in the database to login.
In this lecture you'll learn the various options for generating a hash in PHP, for example md5, sha1 and bcrypt. We'll look at which ones to use, and which ones not to use. You'll also learn the most secure method for generating a secure password hash in PHP.
To store user accounts in the database, we need a users table. In this lecture we'll use phpMyAdmin to create the users table in the database. You'll also learn why we use a unique, numeric ID as the primary key and not the email address.
The SQL to create the users table is attached to this lecture in the resources section.
We'll start coding our application in this lecture by adding the signup controller and the signup page view.
In this lecture we'll add the signup form with its input fields to the signup page. In addition, you'll learn:
In this lecture we'll add the controller action method that will handle the submission of the signup form, and link this to the signup form with the form's action attribute.
In this lecture you'll learn exactly how SQL injection attacks work, and how dangerous they can be to your application.
In this lecture you'll learn how SQL injection attacks work when inserting variables into SQL statements. You'll also learn how to use PDO's quote function and prepared statements to avoid them.
In this lecture you'll learn how to create the user record in the database by adding a method to the user model.
We'll also add code to get the data from the signup form to the model via the controller, and we'll learn how to use the class constructor to assign property values.
At the end of this lecture a new user will be able to sign up for a new account, creating a new record in the database.
Test your knowledge of the concepts covered in this section.
Before we insert a new record into the database, we want to validate the data in the form.
In this lecture we'll add a validate function to our user model that’s going to validate the current property values.
If we try to sign up another user with an email address that already exists in the database, we get an error.
In this lecture we'll add validation that an email address doesn’t already exist in the database before we save the data.
When there are validation errors, it would be much better to redisplay the signup form and have the error messages on the same page.
In this lecture we'll use the user model to pass validation error messages back to the signup form when there are validation errors.
If you reload or refresh a page after submitting a form that uses the POST method, you might see a warning message.
It’s a warning that if you refresh the page, the form data will be submitted again, and any action taken on the server might be repeated. This could include placing an order or charging a credit card for example.
In this lecture you'll learn how to avoid this using the post / redirect / get pattern.
Normally, a user requests a page by typing in a URL, clicking on a link or submitting a form. The server receives the request, and sends back a response, for example, a page of HTML. Sometimes though, instead of replying with some content, the server replies with a message to tell the browser to request a different URL.
This is known as a redirect. It’s common to redirect to another page after inserting some data into a database, or logging in for example.
In this lecture you'll learn how and why to redirect to another page using PHP, including best practices.
Now that we know why we should redirect after making changes in the database, in this lecture you'll change the result of a successful signup to redirect to another page instead of just showing a template as part of the same request.
Test your knowledge of the material covered in this section.
In this lecture you'll learn how client-side validation can enhance the user experience and can save server resources, but shouldn't be relied on as the only validation. You should always validate data on the server as well.
In this lecture you'll add HTML5 validation to the signup form.
Instead of writing all your validation code from scratch, there are some excellent libraries available that make the job much easier.
In this lecture you'll add client-side validation to the signup form using the jQuery Validation Plugin.
Built-in jQuery Validation Plugin methods don’t include a method for a custom format, which is what we need to validate the password.
In this lecture you'll add a custom validation method to the jQuery Validation Plugin to validate the password, using a regular expression to check its validity.
Even though we're validating the form data in the browser, to validate the uniqueness of the email address, we need to communicate with the server to check if the email address already exists in the database or not. The jquery validation plugin provides us with the remote method so we can do this.
In this lecture we'll add a remote validation call to validate the email address, using Ajax. You'll also learn how "regular" and Ajax requests differ, and how to do Ajax requests using the MVC framework.
When you sign up for a new account on a website, one of the pieces of data you have to provide is a password. You usually have to type these into password-type input fields, which are masked, meaning that you can't see what you've typed. This is to prevent someone seeing the password you've entered. Because you can't see it, it's common for websites to make you repeat what you've typed in another password field. This is to make sure you know what you've typed.
In this lecture you'll learn why this can be a problem, and how to solve it.
In this lecture you'll change the password confirmation field on the signup form so that there's a single password field, but with a button to reveal the password if the user wants to.
Test your knowledge of the material learnt in this section.
To log in, the user needs to supply their email address and their password.
In this lecture, you'll add the login screen and its associated controller. You'll also add a custom route for a "pretty" login URL.
In this lecture you'll add the controller action that's going to authenticate the user when they submit the login form.
The first thing we need to do when authenticating is to find the user based on their email address. In this lecture you'll add a method to the user model to do this.
You'll also learn how to return an object of the User class when fetching a record from the database using PDO.
We're not storing the passwords in plain text, rather we're storing a hash of the password. So to check the password when the user logs in, we can't just compare what they typed in to what we have in the database using a simple string comparison.
So how do we check the password? We're using the password_hash function to generate the hash from the plain text password, and PHP also provides the password_verify function that we can use to check a password matches a hash.
In this lecture you'll add a method to the User model to authenticate a user by checking their password.
When we login incorrectly, the form is redisplayed. As the password is masked, it's more likely that we've typed the password incorrectly than the email address. So if we login incorrectly, it would be good if the email address was remembered when the form was redisplayed.
In this lecture you'll redisplay the email address in the login form when the login is incorrect.
We just added code in our login controller to redirect to another page. We're also doing this exact same thing in our signup controller. Redirecting is something you probably want to do quite often in a controller.
To make this easier and to remove this repetition, in this lecture you'll add a redirect method to the core controller.
As far as the web server is concerned, each request is unrelated and independent to any previous one. This is because HTTP, the protocol used between web browsers and servers, is stateless.
Not having state isn't very useful however if we want to remember that someone has already been to our site, so we can do things like logging in, shopping carts, and so on.
We can add state by using sessions.
In this lecture you'll learn how sessions can be used to remember that someone has already visited your site, and exactly how sessions work in PHP.
In this lecture you'll use sessions to store the user's ID in order to remember that they've logged in. You'll also add code to show on the homepage if the user is logged in or not.
PHP sessions are destroyed automatically when the browser is closed. However, our users will need to be able to log out without closing the browser. In this lecture you'll learn how to completely destroy a session in PHP without having to close the browser.
When we logged the user in, we stored the user ID in the session. To log the user out, we could just remove this value from the session array, but we might have stored other values in the session in other places in the application. Much better to simply destroy the session when the user wants to log out.
In this lecture you'll completely destroy the session when the user logs out.
Test your knowledge of the material covered in this section.
In this section we're going to learn how to restrict content based on whether the user is logged in or not. Before we do that though, in this lecture let's create a class to group together all the authentication code, so it's not distributed around different controllers and models, and therefore easier to manage.
One of the reasons you want login is to be able to restrict content to those users that have identified themselves, or logged in.
In this lecture you'll restrict access to a page if the user is not logged in, redirecting them to the login page.
At the moment, if a user tries to access a page that requires login, we redirect them to the login page. But once they've logged in, it goes back to the homepage, so the user has to type the URL of the original page again.
In this lecture we'll remember the page they originally requested, and once they've logged-in successfully, redirect them back to it.
To require the user to login before viewing a page, we're using all this code:
It's likely that we're going to have more than one page that requires login, so we don't want to be repeating all this code for every action that requires login.
In this lecture you'll extract this out into a reusable method in the core controller.
To restrict access to an action to logged-in users only, we call the requireLogin method we just added.
If we're doing this for every action method in the controller, there's an easier way to do it. In this lecture you'll add a before filter method to restrict access to every action method in a controller.
In this lecture you'll add a base controller that automatically requires login for all action methods in the controller.
Having access to the current logged-in user in our controllers and views will be useful for things like showing the username, getting records from the database that are linked to the user record and so on.
In this lecture you'll add a method to the Auth class that returns the current logged-in user.
The isLoggedIn method and the getUser method contain repeated code.
In this lecture you'll simplify the code to clean up this repetition.
So far in our site we can do things like login, logout, request a page that requires login and get redirected to the login screen and so on. What it lacks though are status messages telling the user what's going on. For example, if they try to access a page that requires login, it simply redirects to the login screen without saying anything else. Not very user friendly. So what we need to add are notification messages at different points in our application.
In this section we'll add flash messages that allow us to pass status messages between requests. In this lecture you'll learn how these are going to work.
In this lecture we'll start by adding a class to handle the flash messages.
Then we'll start using this by showing a message when the user tries to access a restricted page, but they're not logged in.
In order to display the messages, we want to get them from the session first.
In this lecture you'll add a method to do that, then we'll display the messages in the base view. We'll also add a global variable to Twig to make the messages available in our Twig templates.
Now we have our flash messages established, we can add them to more controllers. Let's add messages to the login controller.
In this lecture you'll add a flash message for when the user authenticates successfully and also unsuccessfully.
In this lecture we'll add a flash message when the user logs out. We'll also learn why we have to do this via an intermediate request.
At the moment the flash messages are just text, and they all look the same. We can make these stand out a bit more by styling them using CSS.
In this lecture we'll add a CSS stylesheet and style the flash messages.
At the moment the flash message shown when login fails is styled in the same way as when login is successful. We could style these differently though, to show the user that some messages require more attention than others.
In this lecture we'll add different types of flash messages, and associated styles that make the messages look different depending on their type.
If we close the browser when we're logged in, when we restart the browser we're no longer logged in.
It would be nice for your users if the site could remember the login for their next visit, so they don't have to login again.
In this section you'll learn why the user is logged out when the browser is closed, and how we can give the user the option of remembering the login even after the browser is closed.
In this lecture you'll learn how to create unique, random tokens, and also how to create secure hashes of these tokens. We'll use these methods in this and subsequent sections.
Now that we know how to generate a unique token and also hash it, in this lecture we'll create a utility class to do that for us. That way we can reuse that class throughout the site.
To enable remember me functionality, we're going to store the hash of the token in the database.
In this lecture we'll learn where the best place to store this in the database is, and we'll use phpMyAdmin to create the new fields in the database table.
When the user logs in, we're going to give them the option of remembering the login.
Checkboxes are excellent for options, so in this lecture we'll do this by adding a checkbox to the login form. We'll also learn how checkboxes are handled when coming from the HTML to PHP.
Now that we have the value coming in from the login form, we can start to actually remember the login. The first thing we need to do is generate a unique token, and save a hash of this in the database. That's what we'll do in this lecture.
In this lecture, you'll learn:
Now that we've generated a unique token, and saved a hash of it in the database, next we need to set this value in a cookie. That's what we'll do in this lecture.
We can login and remember the login by checking the remember me checkbox, which sets the cookie. But if we close the browser and restart it, it doesn't remember the login yet. The cookie is still there, so in this lecture we'll use the cookie to automatically log the user back in.
At the moment, when we log in using the token in the remember cookie, all we're doing is checking that a record exists in the database that corresponds to the token. As we're also storing the expiry in the database, we can add an additional layer of security by checking the remembered login hasn't expired. That's what we'll do in this lecture.
If the user has logged in and remembered the login, the logout link no longer works to log the user out. In this lecture you'll learn why this is broken, and we'll also fix it so it works again.
Test your knowledge of the material learnt in this section.
What happens when a user forgets their password?
In this lecture we'll look at options for resetting a user's password when they forget it, and the pros and cons of each.
You'll learn how we're going to allow the user to securely reset their password, which we'll develop the code for in this and the next section.
Starting in this section we're going to be sending emails from our code. If you've taken my PHP email course, you'll already know all about this, but don't worry if you haven't, I'll go over all you need to know in this section.
In this lecture we'll look at the different options for sending email, from SMTP servers to API services, and get access to an email service, ready to start sending emails.
In this lecture we'll create a mail class in our project so we can send an email easily.
We'll also learn why we send the same content both as text and html.
We'll start the password reset process by giving the user the form where they can supply their email address.
In this lecture we'll add a new controller, a method to show the form and a view that contains the form.
Next we need to process this form once it's submitted.
In this lecture we'll add an action method for that, link it to the form, and add a method to the User model.
As we saw at the start of this section, we're going to send the user a token in an email, and save a hash of this token in the database.
In this lecture we'll look at the best place to save this data, and use phpMyAdmin to add fields to the database.
Now we have the fields in the database, we can save the password reset token and expiry in them.
In this lecture we'll add a method to the User model that starts the password reset process, generating a new token, hash and expiry, then saving these in the new fields in the database.
Now that we've generated the unique token, we can send the user the email containing the URL that includes this token.
In this lecture we'll send an email to the user containing the password reset URL.
At the moment we've got the content of the emails inside a method in the User model. This isn't ideal, as if you want a lot of content you'd have lots of text in here; plus it's not very in keeping with the MVC paradigm. Content like this should be in a view.
In this lecture we'll modify the Core View class to allow us to render a view template to a string, so we can use this as the content of an email.
At this point, the user has forgotten their password, and started the password reset process using the form we developed in the last section. They've received an email containing a URL, so now we need to add code to handle this link when they click on it.
In this lecture we'll add an action method in the password controller that matches the URL, and also a custom route that contains a regular expression so we can get the value of the token from the URL in the controller action.
Now that we're getting the token from the URL, we can use this to get the associated user record.
In this lecture we'll add a method to the User model to do that, first getting the token hash from the token in the URL, then using that to look up the user record in the database.
Once we've got a valid reset token that hasn't expired, we can display the password reset form.
In this lecture we'll add the password reset form, basing it on the signup form which has a lot in common with it.
To create the password reset form, we based it on the signup form. The code adds a jQuery Validation Plugin method to validate the password is repeated in both views. To avoid repeating ourselves, in this lecture we'll extract this out to a separate file.
Now we have the password reset form, in this lecture we'll add an action method to process it when it's submitted. We'll add a hidden field to pass the token value through to the action method.
In the last two methods added to the password controller, we're getting the user based on the token, and if we find a user we do one thing, and if not we display a message.
In this lecture we'll clean this up by removing the repetition. We'll also add a view that will be displayed when the token is expired instead of just outputting a string.
In this lecture we'll add code to the controller and model to validate the password on the server.
Now we have the server-side validation in place, we can finally reset the password.
In this lecture we'll add code to the User model to reset the password in the database, and also clear the password reset token and expiry.
Test your knowledge of the material covered in this and the previous section.
Hi, I'm Dave Hollingworth. I'm an IT trainer and web application developer. I've been programming for over twenty-five years, and teaching IT since 1999.
I've developed enterprise-level applications on platforms ranging from mainframes to mobiles: from my first web application, a quotes system created for a major insurance company back in 1999 - the first of its type in the sector - to interactive learning management systems for online language learning.
I've taught courses ranging from basic use of email to advanced web application development, both online and in-person. I've been teaching on Udemy since 2012.
I'm passionate about technology, and love teaching it! I believe it's possible to explain even the most complex subjects in a simple, straightforward way that doesn't confuse the student.
I look forward to welcoming you onto one of my courses!