Create a Login System with FatFreeFramework and Medoo

Login systems are an integral part of any user-centric website. Whether you are building a blog or a to-do app, you need to have a login system to authenticate users and serve login-protected pages. Here in this tutorial, I am going to walk you through a tutorial on creating a very simple login system. Whether you are using PHP or not, you can use the logic in your own application. I have put up the code on GitHub as well. Feel free to use them on any project.

1. Getting Started

Tools

For this tutorial, we would use FatFreeFramework, a very lightweight yet robust PHP micro-framework. On the database layer, we would use Medoo, a PHP class that provides easy API to access data from a host of databases (MySQL in our case). As for the view layer (i.e. the HTML), we would use Tabler, a Bootstrap 4 based admin panel.

Pre-requisites

I will assume that you have PHP, MySQL, Apache installed and you have a basic understanding of Object Oriented Programming in PHP (however this is not mandatory).

Application Logic

Our app is very simple: Users can login via localhost/login, sign-up from localhost/signup, logout from localhost/logout. Upon logging-in, users will be redirected to localhost/admin. This last page is login protected. So, if a non-loggedin user tries to access /admin, he would be redirected to /login

It creates a new table called users with six fields: id, email, password, firstname, lastname and created_at. id field is our primary key and is set to auto-increament. created_at field will be pre-filled with CURRENT_TIMESTAMP.

The default file-structure is good, but I prefer a more isolated approach. Let us create a new directory called app/ and another called vendors/. Inside app/ we would keep all our application specific logic. And inside vendors/ will be third-party libaries (like Medoo). Also, copy config.ini to app/. So finally, our directory structure is like:

We tell the framework to load app/config.ini for configuration purpose.

We also load the routes from app/routes.ini

Next, we set up Medoo. Note here that we are fetching the configs from config.ini by $f3->get(some_config_name). This is provided by F3’s get method.

We load the controllers from app/controllers (which we will create next). Important thing to note here is that by setting AUTOLOAD we tell F3 to load all files inside app/controllers. Do read the documentation page for details.

Finally, we run our app with $f3->run();

At this point if we run the app, we would see an error. That’s because we have no files inside app/controllers that can be AUTOLOADed.

6. Views

Let’s first set the HTML files which will be served according to the routes. Download the Tabler package from Github. After you unzip the package, you’d have several HTML files. We won’t need them all. Let’s copy: empty.html, login.html, register.html, profile.html and the entire assets/directory. Paste all of these into ui/ directory of our app.

Our view system will work this way:

There will be a layout.html which is the base.

Inside layout.html, we will include other smaller chunks of HTML, according to the application logic.

For example, we will have a small login.html file that contains only the login form. And when the user visits /login, layout.html will output the form along with other content.

Now, if you open empty.html, or login.html (the ones we copied from the Tabler package), you’d notice that all the code until <div class='page'> is same for all three files. So, let us create our base layout.html by deleting all the content after <div class="page"> (but keeping the closing </div> , body and html tags. So our layout.html will look like:

I have replaced the default title with {{ @title }} We will set this variable to the correct title in our Controller classes.

I also added <include href="{{ @inc }}" /> This inc which we will set in our controllers, is the name of the smaller chunks of HTML (for example, login.html, register.html etc).

Next, from the login.html file, delete everything upto <div class="page"> and the closing body and HTML tags. Same for register.html and profile.html. Check this directory, for details.

7. Controllers

Base Controller

From the routes.ini file, you can see are going to have two main controllers: AdminController and AuthController. But let’s first create a Controller.php (inside app/controllers/) which we will use to extend later.

Here, we create $f3 as an instance of F3’s Base class. Also, note that we have set global $md_db;. We did so, because we are going to need the database object for all our controllers. And when we will extend this Controller class, all our controllers will have access to it.

Also note that we have created an afterroute() method. This method will run every time a route is accessed from a controller extending this one. Inside afterroute(), we have used F3’s Template class to render layout.html.

AdminController

Next, create a new file called AdminController.php inside app/controller/ and put these inside:

This controller is as simple as the last one: it extends the base Controller class. The beforeroute() method checks if the user is logged in by checking the existence of SESSION.user_id. If not, it redirects to /login after setting a flash variable. Note the SESSION variable here. It is the PHP equivalent of SESSION global. Read the documentation for more details.

Also note, we have set title and inc. The title variable will be used inside the <title> tag. The inc variable is the name of the specific file which will be loaded for the route (in this case, it is profile.html)

AuthController

This is our main controller. Let us start by extending the base Controller class:

Here, we clear the session (if the user is visiting the login page, there is no point in keeping him logged in). We set COOKIE.sent to true. This variable will be checked later. Finally, we set the title of the login page and serve login.html.

Here we first check if a form is being submitted (with POST). If so, we sanitize all the data using PHP’s builtin filter_var method. Then we run a few checks to validate the data. If validation fails, at any level, we set flash variable with the correct message. Finally, if the validation succeeds, we insert a new record in our database after using PHP’s password_hash method and redirect the user to login page.

Couple of things to note in the above code:

We have used Medoo’s has method to check if user with same email address already exists in our database.

We have also used the insert method. Do read the corresponding documentation pages for a better understanding of how they work.

Finally, we need to actually login the users via auth method. (Recall from our routes.ini that AuthController->auth is called everytime POST request to /auth is made. So let’s create the auth method (inside AuthController class):