Lesson 5 - NOO-CMS - User registration in PHP
In the previous lesson, Programming of NOOCMS, we started up our NOOCMS project, Non-Object-Oriented Content Management System in PHP. What we've got up until now is the presentation layer of the user registration script.
Now, let's right back into it and insert the following PHP block above the HTML part of the script:
<?php session_start(); require('Db.php'); Db::connect('127.0.0.1', 'noocms_db', 'root', ''); if ($_POST) { if ($_POST['captcha'] != date('Y')) $notice = 'Invalid antispam - enter the current year.'; else if ($_POST['password'] != $_POST['password_confirmation']) $notice = "Passwords don't match"; else { $exists = Db::querySingle(' SELECT COUNT(*) FROM user WHERE name=? LIMIT 1 ', $_POST['name']); if ($exists) $message = 'Username already taken.'; else { Db::query(' INSERT INTO user (name, password) VALUES (?, SHA1(?)) ', $_POST['name'], $_POST['password'] . "t&#ssdf54gh"); $_SESSION['user_id'] = Db::getLastId(); $_SESSION['user_name'] = $_POST['name']; $_SESSION['user_admin'] = 0; header('Location: administration.php'); exit(); } } } ?>
First and foremost, we call the session_start() function, which allows us to use what is known as a session. A session remembers the user we're communicating with's data. This line has to be at the very beginning of a PHP file, not at the beginning of a block of PHP, it must be at the very beginning of the file. There must be no HTML code before the session_start() function is called, not even empty lines, spaces, otherwise it won't work. The same goes for the header() function.
Then, we load the Db wrapper and establish the database connection. The credentials show above are for localhost, you already know that your production credentials will be different and are provided by your web hosting service.
Then, we have a bit of code that processes the data provided by the HTML form. We store an error in the notice variable if the entered year does not match the current one . Otherwise, we continue and check if the passwords match in the same way.
Once all of that is done, we have the database count how many users with the given name are in it. To do that, we use the SQL clause SELECT COUNT(*). The asterisk tells it that all of the columns are to be included. So as to not exhaust our database too much, we'll add LIMIT 1 to the item count (all we need to know is whether there is a user with the given username). Then, we execute the request using the Db::querySingle() function (we use it when all we want is a single value from a database). In this case, we only read a single number - the number of users with the given name. If it returns a number greater than zero, that means that the name is already taken and the script will store an error in the notice variable.
The SQL code for adding a user into the database is very similar to the one from the previous tutorial. The only bit that is a slightly more difficult is setting the password. Before we move on, we'll have to improve our code by adding what we refer to as salt. In programming terms salt is a string of completely random characters that we concatenate to the password for security reasons. Users love to set passwords like "password", "passwordpassword", "123456", and so on. Those passwords are very dangerous and can be guessed easily. After salting them up, they'll change to something more along the lines of "passwordt&#ssdf54gh", "passwordpasswordt&#ssdf54gh", or "123456t&#ssdf54gh", which practically resolves the password guessing vulnerability. We won't insert salted password directly because someone could steal our database information and would have access to user passwords.
To save the password we'll use the SHA1() SQL function, which is what is known as a hashing function. In other words, it computes a hash (an imprint) based on a given password. The safest way to store a password into a database is to not store it at all, and only store its hash. A hash is a long string of letters and numbers, and there is no way to recover the original password back once it has been hashed. Meaning that hashing is a one-way process. In order to check whether the entered password is correct, we'll hash it and the hash to the stored hashes in our database. We'll get back to this once we start up on the log-in script.
Once the user has been added to the database, we start up a user session. Along with $_GET and $_POST, there is also a $_SESSION superglobal array in PHP. We use this array when storing data related to the user we're currently communicating with. By default, the session is invalidated after 24 minutes of inactivity or after closing the web browser. Once it is created in a script, its data will remain accessible for other PHP scripts in the application. We will sign the user in immediately after signing him/her up. To do that we will have to save his/her ID, name and whether he/she is an administrator. The ID (primary key) of the last row inserted into a database can be retrieved using the Db:getLastId() function. Last of all, we'll redirect the user to the administration.php page using the header() function. At this moment, we will also terminate the script. If anything goes wrong, the script will continue and display an error notice.
Let's check and see if our error checking is fully functional:
Then, make sure signing up correctly works as well. The script will redirect you to administration.php page, which does not exist yet. Open up the user table on phpMyAdmin (open up the table and click on Browse in the upper-hand part of the menu). There, you will find the newly added user and his/her password hash:
I've used "aaaaa" as a password, given that bit of text, the hash shown above was returned by the SHA1() function.
Administration
Now to finish this part off, let's make an administration.php script. We'll use it as a crossroad where the application moves a user after registering or logging-in. The HTML part will be as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="style.css" type="text/css" /> <title>Administration</title> </head> <body> <article> <div id="centerer"> <header> <h1>Administration</h1> </header> <section> <p>Welcome to the administrative panel, you're signed in as <?= htmlspecialchars($_SESSION['user_name']) ?>.</p> <?php if (!$_SESSION['user_admin']) echo("You don't have an administrator role, ask the administrator for permission."); ?> <h2><a href="editor.php">Article editor</a></h2> <h2><a href="articles.php">Article list</a></h2> <h2><a href="administration.php?sign-out">Sign-out</a></h2> </section> <div class="clear"></div> </div> </article> </body> </html>
- This code is based on three main things
- Printing out the user name retrieved from the session.
- If a user hasn't got an administration role, a message is displayed.
- We link to the administration.php script using the GET "sign-out" parameter used to sign-out.
- Insert the following block of PHP above the HTML code
<?php session_start(); if (!isset($_SESSION['user_id'])) { header('Location: sign-in.php'); exit(); } if (isset($_GET['sign-out'])) { session_destroy(); header('Location: sign-in.php'); exit(); } ?>
Here's what it should look like now:
If a session does not exist, we redirect the user to the log-in page and terminate the script. If the sign-out parameter is entered, we destroy session using the session_destroy() PHP function and redirect the user back to the log-in page.
We'll get deeper into our CMS in the next lesson, NOO-CMS - Article editor in PHP.
Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.
Download
By downloading the following file, you agree to the license terms
Downloaded 79x (389.15 kB)
Application includes source codes in language PHP