Contact Form



×






* - Required



A PDO Registration and Login Tutorial

By Strider on May 9, 2014


I have decided to write a registration & login php tutorial to include both mysqli & PDO methods. This is the tutorial featuring the PDO method and in my opinion PDO is easier to understand than mysqli. This website http://code.tutsplus.com/tutorials/pdo-vs-mysqli-which-should-you-use--net-24059 should help you in your decision between mysqli and PDO. The reason I find PDO easier is that you can use name prepared statements, for example array( ':username1' => $username ). Let's get started with the first file, which is your connection file and setting up other variables and functions.

common.inc.php in includes

<?php
//Start session
$seconds = 60;
$minutes = 60;
$hours = 24;
$days = 14;
session_set_cookie_params($seconds * $minutes * $hours * $days, "");
session_start();
 
// Set error message to Null
$errMsg = NULL;
 
// Create the database connection as a PDO object:
try {
 
$db_options = array(
PDO::ATTR_EMULATE_PREPARES => false // important! use actual prepared statements (default: emulate prepared statements)
, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION // throw exceptions on errors (default: stay silent)
, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // fetch associative arrays (default: mixed arrays)
);
 
$pdo = new PDO('mysql:host=localhost;dbname=demo_login_system;charset=utf8', 'root', 'your_password', $db_options);
 
} catch (PDOException $e) { // Report the Error!
 
$errMsg = "<p>Something is not right, check your php.ini settings or code</p>";
 
}
 
// Check for a user in the session:
$user = (isset($_SESSION['user'])) ? $_SESSION['user'] : NULL;
 
// A nice little function that sanitizes the data output:
function html_escape($raw_input) {
return htmlspecialchars($raw_input, ENT_QUOTES | ENT_HTML401, 'UTF-8'); // important! don't forget to specify ENT_QUOTES and the correct encoding
}



This is pretty straight forward and I really don't think any further explanation will be need. I will next proceed to the registration script that I have called "register.php" and the file is located in the root directory.

<?php #PDO VERSION 1.0 Beta

/* COMMENT OUT OR DELETE THE FOLLOWING THAT IS BETWEEN THESE COMMENTS */
/*************************START OF COMMENT SECTION************************/
$table = "users";
try {
$db = new PDO("mysql:dbname=demo_login_system;host=localhost", "root", "your_password" );
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );//Error Handling
$sql =" CREATE TABLE IF NOT EXISTS $table (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(30) NOT NULL,
`password` char(60) NOT NULL,
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;"
;
$db->exec($sql);
print("Created $table Table.\n");
 
} catch(PDOException $e) {
echo $e->getMessage();//Remove in production code
}
/***************************END OF COMMENT SECTION************************/
 
 
// common.inc.php file contains required
// database connection & initialization info:
require 'includes/common.inc.php';
 
// A nice password hashing library for PHP 5
// Find it here: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
// Read the Documentation for further help:
require 'includes/password.inc.php';
 
$errMsg = array();
$displayStatus = 'undetermined';
 
// Check to see if user has submitted form:
if (isset($_POST['action']) && $_POST['action'] == 'register') {
 
// Grab the user's input from form:
$username = $_POST['username'];
$password = $_POST['password'];
 
// Using Regex to check username:
if (preg_match("/^[0-9a-zA-Z_]{5,}$/", $username) === 0) {
$errMsg['username'] = 'Username must be bigger than 5 chars and contain only digits, letters and underscore';
}
 
if (isset($errMsg['username'])) {
$displayStatus = 'FAIL';
$displayUsername = $errMsg['username'];
unset($errMsg['username']);
}
 
// Using Regex to check password:
if (preg_match("/^.*(?=.{8,})(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).*$/", $password) === 0) {
$errMsg['password'] = 'Password must be at least 8 characters, & must contain at least 1 lowercase letter, 1 uppercase letter & 1 digit.';
}
 
if (isset($errMsg['password'])) {
$displayStatus = 'FAIL';
$displayPasswordMsg = $errMsg['password'];
unset($errMsg['password']);
}
 
// Function to check if username is available:
function isUsernameAvailable($username, $pdo) {
 
// The PDO Query:
$query = "
SELECT
1
FROM users
WHERE
username = :username1
"
;
 
// The prepared property/attribute:
$query_params = array(
':username1' => $username
);
 
// These two statements run the query against your database table.
$stmt = $pdo->prepare($query);
$result = $stmt->execute($query_params);
 
// The fetch() method returns an array representing the "next" row from
// the selected results, or false if there are no more rows to fetch.
return $row = $stmt->fetch();
// If a row was returned, then we know a matching username was found in
// the database already and we should return a boolean value back.
 
}
 
if ($displayStatus != 'FAIL') {
// Check to see if username is available:
$row = isUsernameAvailable($username, $pdo);
 
if ($row) {
$displayStatus = 'FAIL';
$displayUsername = $username . ' is already taken.';
unset($row);
}
}
 
// Hash the password - See above for details:
$password = password_hash($password, PASSWORD_BCRYPT, array("cost" => 15));
 
// Store user's credentials, if form data is validated:
if ($displayStatus == 'undetermined') {
// Using prepared statements:
$query = 'INSERT INTO users ( username, password ) VALUES ( :username, :password )';
$stmt = $pdo->prepare($query);
$result = $stmt->execute(array(':username' => $username, ':password' => $password));
$displayStatus = 'SUCCESS';
$displayUsername = $username;
}
 
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Registration Demo</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/grids.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
 
<section class="container shadow">
<table class="mainTable">
<tr>
<th>Status</th>
<th>Username</th>
<th>Password Status</th>
<th>Date Added</th>
</tr>
<tr>
<td class="status"><?php echo ($displayStatus == 'SUCCESS' || $displayStatus == 'FAIL') ? $displayStatus : 'N/A'; ?></td>
<td class="username"><?php echo (isset($displayUsername)) ? $displayUsername : 'Username'; ?></td>
<td class="passMatch"><?php echo (isset($displayPasswordMsg)) ? $displayPasswordMsg : 'N/A'?></td>
<td class="dateAdded"><?php echo gmdate( 'm-Y-d', time( )) ?></td>
</tr>
</table>
</section>
 
 
<article class="container mainContent shadow">
<h1>Registration Demo Page</h1>
<form action="register.php" method="post"/>
 
<input type="hidden" name="action" value="register" />
<label class="labelStyle" for="username">Username: </label>
<input id="username" type="text" name="username" tabindex="1" autofocus>
<label class="labelStyle" for="password">Password:</label>
<input id="password" type="password" name="password" tabindex="2">
<label class="labelStyle" for="re_enter">Re-Enter Password: </label>
<input id="re_enter" type="password" name="re_enter" tabindex="3">
<input class="loginBtn" type="submit" value="Register"/>
</form>
</article>
 
<script src="js/jquery-1.10.2.min.js"></script>
<script>
$(function() {
var $status = $('.status'),
$passMatch = $('.passMatch'),
$username = $('.username'),
$dateAdded = $('.dateAdded'),
$registerBtn = $('.loginBtn');
 
$status.addClass('greenStatus');
$passMatch.addClass('greenStatus');
$username.addClass('greenStatus');
$dateAdded.addClass('greenStatus');
 
$registerBtn.hide();
 
function checkPasswordMatch() {
var password = $("#password").val();
var confirmPassword = $("#re_enter").val();
 
if (password != confirmPassword)
$(".passMatch").html("Passwords do not match!");
else {
$(".passMatch").html("Passwords match.");
$registerBtn.show();
}
 
}
$("#re_enter").keyup(checkPasswordMatch);
 
});
</script>
</body>
</html>
 


This script will automatically create a TABLE called users for you, once you created the TABLE by running the script for first time, either delete what is between the two comments or comment those lines out. I will be including the CSS files in a separate post, for this tutorial is long as it is or you can style or even modify the code. I leave that up to you, for I guess it depends on how comfortable you are with HTML/CSS and PHP. If you want you can change the TABLE from users to something to your liking; however, I thought using users made perfect sense. Next I'll move on to the login script that I have named "login.php" (I know how original) and is located once again in the root directory.

<?php #PDO VERSION 1.0 Beta
// common.inc.php file contains required
// database connection initialization info:
require 'includes/common.inc.php';
 
// A nice password hashing library for PHP 5
// Find it here: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
// Read the Documentation for further help:
require 'includes/password.inc.php';
 
if (isset($_POST['action']) && $_POST['action'] == 'login') {
 
// This query retreives the user's information from the database using
// their username.
$query = '
SELECT
id,
username,
password,
DATE_FORMAT(date_added, "%e %M %Y") as date_added
FROM users
WHERE
username = :username
'
;
 
// The parameter values
$query_params = array(
':username' => $_POST['username']
);
 
 
try
{
// Execute the query against the database
$stmt = $pdo->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
 
// This variable tells us whether the user has successfully logged in or not.
// We initialize it to false, assuming they have not.
// If we determine that they have entered the right details, then we switch it to true.
$login_ok = false;
 
// Retrieve the user data from the database. If $row is false, then the username
// they entered is not registered.
$row = $stmt->fetch();
 
if($row)
{
// Verify Stored Hashed Password:
$result = password_verify($_POST['password'], $row['password']);
 
if ($result) {
$login_ok = true;
} else {
$errMsg = 'Invalid Credientials!';
}
 
}
 
// If login is OK:
if ($login_ok) {
 
// It's not wise to store the password in $_SESSION:
unset($row['password']);
 
// This stores the user's data into the session at the index 'user'.
// We will check this index on the private members-only page to determine whether
// or not the user is logged in. We can also use it to retrieve
// the user's details.
$_SESSION['user'] = $row;
 
 
// Redirect the user to the private members-only page.
header("Location: login.php");
exit();
 
}
 
}
 
?>
 
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/grids.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<article class="container mainContent shadow">
<?php if ($user) { ?>
<h1>Welcome, <?php echo $user['username']; ?>.</h1>
<a class="logout" href="logout.php">Logout</a>
<?php } else { ?>
<!--/Display Errors if there are any - using a ternary operator-->
<?php echo (isset($errMsg)) ? '<h1>' . $errMsg . '</h1>' : '<h1>Demo Login Page</h1>'; ?>
<form action="login.php" method="post"/>
 
<input type="hidden" name="action" value="login" />
<label class="labelStyle" for="username">Username: </label>
<input id="username" placeholder="Username" type="text" name="username" tabindex="1" autofocus>
<label class="labelStyle" for="password">Password: </label>
<input id="password" type="password" name="password" tabindex="2">
<input class="loginBtn" type="submit" value="Login"/ tabindex="3">
</form>
<?php } ?>
</article>
</body>
</html>
 


The login script is actually easier than the registration script in my opinion. You will need the JQuery library if you want to take advantage of the JavaScript and you will need the password hashing library, I have provide a link where you can get it. Well, that basically sums up the PDO PHP tutorial, it's basically the same as the mysqli tutorial with the exception on how the MySQL connection is being made. Like I said I will be including the CSS in a separate post and I put the CSS files in the CSS Forum. Here's a direct link to the CSS files : http://www.jrpepp.com/displayPage.php?page=192 and you can see a demo at

http://www.pepster.com/PD0_demo/register.php