PHP Sessions

A session is used to store variables that can be used across multiple pages. Session variables are not stored on a computer. By default, session variables last until the user closes the browser.

Once a session has been set up, then all other webpages that are from the same origin website will have access to the session. To start a new session use the code below:

<?php
session_start();
?>

IMPORTANT: All webpages in a session need to have the above code at the top of the file.

 

Once a session has started, you can set up session variables. The content of session variables will be availabe across all of the webpages from the origin website. To set up a session variable use the code below:

<?php
$_SESSION["user_id"] = $id; // set the session variable user_id to be the same as $id
?>

 

To see if there is a value in a given session variable, use the code below:

<?php
if(isset($_SESSION["error_message"]))
{
   // The session variable error_message is set
   // ...
}
?>

 

Restricting Access to Webpages That require a Password

Assuming that a session variable called "user_id" is set when a user logs into the system, then this variable can be used to restrict access to webpages that require a password. The check to see it the "user_id" session variable has been set should be done at the top of the webpage, immediately after the session_start(). This is shown in the code below.

<?php
session_start();

if(!isset($_SESSION["user_id"]))
{
   header("location: login.php");
   exit();
}
?>

Configuration File

We shall need to store user passwords in a database. The database configuration files is:

configuration.php
<?php
/* * ************************ You need to set the values below to match your project ************************ */

// localhost website and localhost database
$localHostSiteFolderName = "D00123456";

$localhostDatabaseName = "D00123456";
$localHostDatabaseHostAddress = "localhost";
$localHostDatabaseUserName = "root";
$localHostDatabasePassword = "";



// remotely hosted website and remotely hosted database       /* you will need to get the server details below from your host provider */
$serverWebsiteName = "http://mysql02.comp.dkit.ie/D00123456"; /* use this address if hosting website on the college students' website server */

$serverDatabaseName = "D00123456";
$serverDatabaseHostAddress = "mysql02.comp.dkit.ie";         /* use this address if hosting database on the college computing department database server */
$serverDatabaseUserName = "D00123456";
$serverDatabasePassword = "ABCD";




$useLocalHost = true;      /* set to false if your database is NOT hosted on localhost */



/* * ******************************* WARNING                                 ******************************** */
/* * ******************************* Do not modify any code BELOW this point ******************************** */

if ($useLocalHost == true)
{
    $siteName = "http://localhost/" . $localHostSiteFolderName;
    $dbName = $localhostDatabaseName;
    $dbHost = $localHostDatabaseHostAddress;
    $dbUsername = $localHostDatabaseUserName;
    $dbPassword = $localHostDatabasePassword;
}
else  // using remote host
{
    $siteName = $serverWebsiteName;
    $dbName = $serverDatabaseName;
    $dbHost = $serverDatabaseHostAddress;
    $dbUsername = $serverDatabaseUserName;
    $dbPassword = $serverDatabasePassword;
}



chmod("configuration.php", 0600); // do not allow anyone to view this file
?>

Login

Login control is achieved by setting a $_SESSION["user_id"] variable when the user logs into the system. Every webpage that requires the user to be logged in will check to see if the $_SESSION["user_id"] variable has been set. If it is not set, then the user is not logged in. This is shown in the example below:

create_password_database_table.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
</head>
<body>
    
<?php
/* Include "configuration.php" file */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // set the PDO error mode to exception
/* If the table already exists, then delete it */ $query = "DROP TABLE IF EXISTS users"; $statement = $dbConnection->prepare($query); $statement->execute(); /* create table */ $query = "CREATE TABLE users (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, email VARCHAR(100) NOT NULL, password VARCHAR(100) NOT NULL )"; $statement = $dbConnection->prepare($query); $statement->execute(); /* Add a test username and password for this exercise */ $query = "INSERT INTO users (email, password) VALUES ('a@a.com', '1234')"; $statement = $dbConnection->prepare($query);; $statement->execute(); /* Provide feedback to the user */ echo "Table 'users' created."; ?> </body> </html>

 

home.php
(This is a password protected webpage)
<?php
session_start();
if (!isset($_SESSION["user_id"]))
{
    header("location: login.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
</head>
<body>
<p>If you see this text, then you have successfully logged in!</p>
</body>
</html>

login.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>  
</head>

<body>

<form action="login_transaction.php" method="post">

<label for="email">Email: </label>
<input type="email" id = "email" name = "email" placeholder = "Enter your email" required><br>

<label for="password">Password: </label>
<input type="password" id = "password" name = "password" placeholder = "Enter your password" required><br>

<input type="submit" value="Login"><br>

</form>

</body>
</html>

 

login_transaction.php
<?php
session_start();

// if it exists, then destroy any previous session 
session_unset();
session_destroy();
session_start();


/* Validate and assign input data */
$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
if (empty($email) || (!filter_var($email, FILTER_VALIDATE_EMAIL)))
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL))
    {
        header("location: error.php"); // deal with invalid input
    }
}

$password = ltrim(rtrim(filter_input(INPUT_POST, "password", FILTER_SANITIZE_STRING)));
if (empty($password))
{
    header("location: login.php"); // deal with invalid input
}



/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Check that user is not already user_added  */
$query = "SELECT id, password FROM users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();



if ($statement->rowCount() > 0)
{
$row = $statement->fetch(PDO::FETCH_OBJ);
if ($password === $row->password)
{
// set session user_id
$_SESSION["user_id"] = $row->id;
}
} // Go to password protected webpage. // Note, if the $_SESSION["user_id"] has not been set in the "if" statement above, then the "home.php" file will redirect the user back to the login webpage header("location: home.php"); ?>

Modify the code above so that the home.php webpage displays the user's name.

Modify the toyota example so that only logged in users can add, modify or delete records

Modify the code above so that only users with an access level of greater than 1 are able to delete records. All other loggin in users can only add or modify records.

Logout

In order to log out from a session, we need to unset the session variables and destroy the session. This is shown in the code below:

logout_transaction.php
<?php
session_start();

// remove all session variables and destroy the session
session_unset();
session_destroy();

header("location: login.php");
?>

Add a logout feature to the Toyota example.

Advanced Login

In a real-world application, we should never store unencrypted passwords. The code below will encrypt a user's password if it's encryption is not up-to-date.

<?php
if (password_needs_rehash($row->password, PASSWORD_DEFAULT))
{
$newHashedPassword = password_hash($row->password, PASSWORD_DEFAULT); // ...
} ?>

 

The code below will check that a user entered password matches an encrypted password

<?php
if (password_verify($password, $row->password))
{
   // passwords match
   // ...
}
?>

Complete Session Example

In a real-world application, users will be able to register, change password, recover forgotten passwords and change their profile details. In addition, in a real-world application, all passwords need to be stored in an encrypted format. The set of files below implements all of these features.

Click here to download a .zip file containing a complete NetBeans project. Once you have created a php application in NetBeans, the zip file can be extracted into your student sub-folder within the c:/xampp/htdocs folder (e.g. c:/xampp/htdocs/D00123456).

To set up the password related database, you will need to follow the steps below:

1) run the file "create_database.php"

2) run the file "create_users_table.php"

3) run the file "create_pending_users_table.php"

4) run the file "create_access_level_table.php"

Apply this code to the Toyota example.

Where does this code use AJAX/JSON?

What is the pending_users table used for?

How do the transaction files POST error messages back to the form files?

The "confirm_registration.php" and the "forgot_password_confirm_new_password.php" files get a token from the url. In the event of a data-input error being identified in the related transaction file, how does the transaction file send the token back to the form file?

Change the code to place the main menu at the top of the webpage.

Change the code to make the content fill the entire width of the screen.

Change the code to give a different look-and-feel.

The postscript "dkit_" has been inserted in front of all the css classes and IDs. What is the purpose of this?

 

configuration.php
<?php
/* * ************************ You need to set the values below to match your project ************************ */

// localhost website and localhost database
$localHostSiteFolderName = "D00123456";

$localhostDatabaseName = "D00123456";
$localHostDatabaseHostAddress = "localhost";
$localHostDatabaseUserName = "root";
$localHostDatabasePassword = "";



// remotely hosted website and remotely hosted database       /* you will need to get the server details below from your host provider */
$serverWebsiteName = "http://mysql02.comp.dkit.ie/D00123456"; /* use this address if hosting website on the college students' website server */

$serverDatabaseName = "D00123456";
$serverDatabaseHostAddress = "mysql02.comp.dkit.ie";         /* use this address if hosting database on the college computing department database server */
$serverDatabaseUserName = "D00123456";
$serverDatabasePassword = "ABCD";




$useLocalHost = true;      /* set to false if your database is NOT hosted on localhost */



/* * ******************************* WARNING                                 ******************************** */
/* * ******************************* Do not modify any code BELOW this point ******************************** */

if ($useLocalHost == true)
{
    $siteName = "http://localhost/" . $localHostSiteFolderName;
    $dbName = $localhostDatabaseName;
    $dbHost = $localHostDatabaseHostAddress;
    $dbUsername = $localHostDatabaseUserName;
    $dbPassword = $localHostDatabasePassword;
}
else  // using remote host
{
    $siteName = $serverWebsiteName;
    $dbName = $serverDatabaseName;
    $dbHost = $serverDatabaseHostAddress;
    $dbUsername = $serverDatabaseUserName;
    $dbPassword = $serverDatabasePassword;
}



chmod("configuration.php", 0600); // do not allow anyone to view this file
?>

 

create_database.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP Create Database Table Example</title>
</head>
<body>

<?php
/* Include "configuration.php" file */
require_once "configuration.php";


/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Create the database */
$query = "CREATE DATABASE IF NOT EXISTS $dbName";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Provide feedback to the user */
echo "Database '$dbName' created.";
?>
create_users_table.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP Create Database Table Example</title>
</head>
<body>

<?php
/* Include "configuration.php" file */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* If the table already exists, then delete it */
$query = "DROP TABLE IF EXISTS users";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Create table */
$query = "CREATE TABLE users (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
                               name VARCHAR(50) NOT NULL,
                               email VARCHAR(100) NOT NULL,
                               password VARCHAR(100) NOT NULL,
                               access_level INT(6) NOT NULL
                              )";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Provide feedback to the user */
echo "Table 'users' created.";
?>

</body>
</html>
create_pending_users_table.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP Create Database Table Example</title>
</head>
<body>

<?php
/* Include "configuration.php" file */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* If the table already exists, then delete it */
$query = "DROP TABLE IF EXISTS pending_users";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Create table */
$query = "CREATE TABLE pending_users (token VARCHAR(100) NOT NULL,
                               email VARCHAR(100) NOT NULL,
                               expiry_time_stamp int(10) NOT NULL
                              )";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Provide feedback to the user */
echo "Table 'pending_users' created.";
?>

</body>
</html>
create_access_level_table.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP Create Database Table Example</title>
</head>
<body>

<?php
/* Include "configuration.php" file */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* If the table already exists, then delete it */
$query = "DROP TABLE IF EXISTS access_level";
$statement = $dbConnection->prepare($query);
$statement->execute();



/* Create table */
$query = "CREATE TABLE access_level (id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
                               name VARCHAR(50) NOT NULL
                              )";
$statement = $dbConnection->prepare($query);
$statement->execute();

$query = "INSERT INTO access_level (name) VALUES ('Admin')";
$statement = $dbConnection->prepare($query);
$statement->execute();

$query = "INSERT INTO access_level (name) VALUES ('Normal')";
$statement = $dbConnection->prepare($query);
$statement->execute();

/* Provide feedback to the user */
echo "Table 'access_level' created.";
?>

</body>
</html>
index.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<meta http-equiv = "refresh" content="0; url=home.php">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<!-- If required, place landing page animation here -->
<input type="button" value="Go to Website Homepage" onclick="window.open('home.php', '_self')">
</body>
</html>
home.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Home Page");
    ?>

<main>
<p>The "home.php" file can be used as a template for any webpage that is not password protected within this website.</p>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

about_us.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "About Us");
    ?>

<main>
<p>Example of a webpage that is not password protected. This file usese the "home.php" as its template.</p>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

members_area.php
<?php
session_start();
if (!isset($_SESSION["user_id"]))
{
    header("location: login.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Home Page");
    ?>

<main>
<p>The "members_area.php" file contains a template that can be used for any webpages that is password protected within this website.</p>
<p>The user must be logged in to see this webpage.</p>
<?php
echo "<h1>Welcome " . $_SESSION["user_name"] . "</h1>";
?>

<p>If you see this text, then you have successfully logged in!</p>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

header.php
<?php
function set_header($mainHeading, $subHeading = "", $showLogin = true)
{
    echo '<header><link rel="icon" type="image/png" href="dkit.png"><div id="dkit_main_heading">' . $mainHeading . '</div>' .
    '<div id="dkit_sub_heading">' . $subHeading . '</div>' .
    '<div id="dkit_header_image_container">' . '<a href="members_area.php"><img src="dkit.png" alt="Go to Homepage" title="Go to Homepage"></a>' .
    '</div> <!-- dkit_header_image_container -->' . '<div id="dkit_header_user_name_container">';
    if (isset($_SESSION["user_name"]))
    {
        echo "<a href='user_profile.php' alt='Change User Profile' title='Change User Profile'>" . $_SESSION["user_name"] . "</a>";
    }
    else if ($showLogin)
    {
        echo "<a href='login.php'>Login/Registration</a>";
    }
    echo '</div> <!-- dkit_header_user_name_container -->' . '<div id="dkit_header_logout_container">';
    if (isset($_SESSION["user_id"]))
    {
        echo "<a href='logout_transaction.php'>Logout</a>";
    }
    echo '</div> <!-- dkit_header_logout_container --></header>';
    /* Main menu */
    echo "<div id='dkit_main_menu'><nav class='dkit_horizontal dkit_menu'><ul><li><a href='home.php'>Home</a></li><li><a href='about_us.php'>About Us</a></li><li><a href='members_area.php'>Members Area</a></li></ul></nav></div>";
}
?>

footer.php
<footer>
<p>Copyright© and/or Website Designed by Notice goes here.</p>
</footer>

error.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>  
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
<?php
/* Show error message for any user input errors if this form was previously submitted */
if (isset($_SESSION["error_message"]))
{
    echo "<div class='error_message'>" . $_SESSION["error_message"] . "</div>";
    unset($_SESSION["error_message"]);
}
else
{
    echo "<div class='error_message'><p>Invalid input.</p></div>";
}
?>

<br><a href="login.php">Go to login webpage</a>

</div> <!-- dkit_container -->
</body>
</html>

 

login.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>  
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "User Login", false);
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form action="login_transaction.php" method="post">
<label for="email">Email: </label>
<input type="email" id = "email" name = "email" placeholder = "Enter your email" required autofocus><br>

<label for="password">Password: </label>
<input type="password" id = "password" name = "password" placeholder = "Enter your password" required><br>

<input type="submit" value="Login"><br>
</form>

<br><a href="forgot_password.php">Forgot password</a>
<br><a href="register_new_user.php">Register as a new user</a>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

login_transaction.php
<?php
session_start();

// if it exists, then destroy any previous session 
session_unset();
session_destroy();
session_start();


/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]


$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
if (empty($email) || (!filter_var($email, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: login.php"); // deal with invalid input
    exit();
}

$password = ltrim(rtrim(filter_input(INPUT_POST, "password", FILTER_SANITIZE_STRING)));
if (empty($password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: login.php"); // deal with invalid input
    exit();
}


/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Check that user exists  */
$query = "SELECT id, name, password FROM users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


if ($statement->rowCount() > 0)
{
    $row = $statement->fetch(PDO::FETCH_OBJ);

    if (!password_verify($password, $row->password))
    {
        $_SESSION["error_message"] = $ERROR_MESSAGE_EMAIL_OR_PASSWORD_IS_INCORRECT;
        header("location: login.php"); // deal with invalid input
        exit();
    }
    else
    {
        // set session variables
        $_SESSION["user_id"] = $row->id;
        $_SESSION["user_name"] = $row->name;
    }
}


// keep password up-to-date
if (password_needs_rehash($password, PASSWORD_DEFAULT))
{
    // the password needs to be rehashed as it is not up-to-date
    $new_password = password_hash($password, PASSWORD_DEFAULT);

    // update the hash in the database
    $query = "UPDATE users SET password = :password WHERE id = :id";
    $statement = $dbConnection->prepare($query);
    $statement->bindParam(":password", $new_password, PDO::PARAM_STR);
    $statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT);
    $statement->execute();
}


// set session variables
$_SESSION["user_id"] = $row->id;
$_SESSION["user_name"] = $row->name;

// keep password up-to-date
if (password_needs_rehash($row->password, PASSWORD_DEFAULT))
{
    // the password needs to be rehashed as it is not up-to-date
    $new_password = password_hash($password, PASSWORD_DEFAULT);

    // update the hash in the database
    $query = "UPDATE users SET password = :password WHERE id = :id";
    $statement = $dbConnection->prepare($query);
    $statement->bindParam(":password", $new_password, PDO::PARAM_STR);
    $statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT);
    $statement->execute();
}


// Note that if the password fails, then the members_area.php webpage will automatically redirect the user back to the login webpage
header("location: members_area.php");
?>
logout_transaction.php
<?php
session_start();

// remove all session variables and destroy the session
session_unset();
session_destroy();

header("location: login.php");
?>

 

register_new_user.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title> 
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Register New User");
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form id="dkit_register_new_user_form" action="register_new_user_transaction.php" method="post">

<label for="email">Email: </label>
<input type="email" id = "email" name = "email" required autofocus><br>

<label for="confirmEmail">Confirm Email: </label>
<input type="email" id = "confirmEmail" name = "confirmEmail" required><br>

<input type="submit" value="Register New User">
</form>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

register_new_user_transaction.php
<?php
session_start();

/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]

$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
if ((empty($email)) || (!filter_var($email, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: register_new_user.php"); // deal with invalid input
    exit();
}

$confirmEmail = ltrim(rtrim(filter_input(INPUT_POST, "confirmEmail", FILTER_SANITIZE_EMAIL)));
if ((empty($confirmEmail)) || (!filter_var($confirmEmail, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: register_new_user.php"); // deal with invalid input
    exit();
}


/* Validate input data */
if ($email != $confirmEmail)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_EMAILS_DO_NOT_MATCH;
    header("location: register_new_user.php");
}


/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Check that user is not already user_added  */
$query = "SELECT email FROM users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();

if ($statement->rowCount() > 0)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_EMAIL_ALREADY_REGISTERED;
    header("location: login.php");
    exit();
}


/* Check that the user is not already pending */
$query = "DELETE FROM pending_users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


/* Create new pending user */
$expiry_time_stamp = 1200 + $_SERVER["REQUEST_TIME"]; // 1200 = 20 minutes from now
$token = sha1(uniqid($email, true));

$query = "INSERT INTO pending_users (token, email, expiry_time_stamp) VALUES (:token, :email, :expiry_time_stamp)";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":token", $token, PDO::PARAM_STR);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->bindParam(":expiry_time_stamp", $expiry_time_stamp, PDO::PARAM_INT);
$statement->execute();


/* remove all old pending users from database */
$query = "DELETE FROM pending_users WHERE expiry_time_stamp < :expiry_time_stamp";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":expiry_time_stamp", $_SERVER["REQUEST_TIME"], PDO::PARAM_INT);
$statement->execute();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="dkit_container">

<?php
include_once 'header.php';
set_header("DkIT", "Register New User", false);
?>
<main>

<?php
/* Provide feedback and provide a way for the user to proceed or automatically redirect to a new webpage */

echo "<p>In the real world, the user will either be registering remotely or they will be registered by an administrator.<br>";
echo "If the user is registering remotely, then forward the url below to them in a email.<br>";
echo "If the user is being registered by an administrator, then automatically redirect to the url below.</p>";
echo "<br>";
echo "<a href ='" . $siteName . '/confirm_registration.php?token=' . $token . "'>" . $siteName . '/confirm_registration.php?token=' . $token . "</a>";
echo "<br><br><br>";

echo "<h3 style='color:red'>Below is an axample content that can be used if sending a registration confirmation email to the user</h3>";
echo "An email has been sent to you to activate your new account.<br><br>" .
 "If you do not receive an email, please check your junk folder for an email from us. Our email is:<br>" .
 "<strong>D00123456.student.dkit.ie</strong><br><br>" .
 "If you still cannot find our email, please add our email address to your email whitelist and attempt to recover your email again.<br><br>";



$subject = "DkIT Login Example Register New User";
$comment = "You are receiving this email because you requested to register with DkIT Login Example." .
        " If you did not request to register with us, then simply ignore this email.<br><br>" .
        "Click on the link below to register:<br>" .
        "<a href = '" . $siteName . "/confirm_registration.php?token=" . $token . "'>" . $siteName . '/confirm_registration.php?token=' . $token . "</a><br><br>" .
        "If the link above does not work, then cut-and-paste it into your browser address bar and run it from there.<br><br>" .
        "<br><br>Yours Sincerly<br>DkIT Login Example Registration Team";

$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
mail($email, $subject, $comment, $headers);
?>


<br><br><input type="button" value = "Go back to login webpage" onclick="window.open('login.php', '_self')">

</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

confirm_registration.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<title>Login Example</title> 
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
<script>
    async function ajaxFillAccessLevelList()
    {
        let url = "ajaxGetAccessLevels.php";   /* use POST method to send data to ajax_json_search.php */
        let urlParameters = "";   /* Construct a url parameter string to POST to fileName */

        try
        {
            const response = await fetch(url,
            {
                method: "POST",
                headers: {'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                body: urlParameters
            });

            updateWebpage(await response.text());
        }
        catch (error)
        {
            console.log("Fetch failed: ", error);
        }


        /* use the fetched data to change the content of the webpage */
        function updateWebpage(responseText)
        {
            let accessLevelDetails = JSON.parse(responseText);
            let htmlString = "<select id = 'accessLevel' name = 'accessLevel' required>";
            htmlString += "<option value=''>Select Access Level</option>";
            for (let i = 0; i < accessLevelDetails.length; i++)
            {
                htmlString += "<option value='" + accessLevelDetails[i].id + "'>" + accessLevelDetails[i].name + "</option>";
            }
            htmlString += "</select>";
            document.getElementById('accessLevelDiv').innerHTML = htmlString;
        }
    }
</script>

</head>

<body onload="ajaxFillAccessLevelList()">
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Confirm Registration");
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form id="dkit_confirm_registration_form" action="confirm_registration_transaction.php" method="post">
<input type="hidden" id ="token" name = "token">
<label for="name">Name: </label>
<input type="text" id = "name" name = "name" required autofocus><br>

<label for="email">Email: </label>
<input type="email" id = "email" name = "email" required><br>

<label for="password">Password: </label>
<input type="password" id = "password" name = "password" required><br>

<label for="confirmPassword">Confirm Password: </label>
<input type="password" id = "confirmPassword" name = "confirmPassword" required><br>

<label for="accessLevel">Access Level: </label>
<span id="accessLevelDiv"></span>
<br>

<input type="submit" value="Activate Account">
</form>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->

<script>
    /* get the 'token' from the url */
    function getURLValue(name)
    {
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        let regexS = "[\\?&]" + name + "=([^&#]*)";
        let regex = new RegExp(regexS);
        let results = regex.exec(window.location.href);
        if (results === null)
            return null;
        else
            return results[1];
    }

    document.getElementById('token').value = getURLValue('token');
</script>

</body>
</html>

 

confirm_registration_transaction.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<title>Login Example</title>
</head>
<body>

<?php
/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]

$token = ltrim(rtrim(filter_input(INPUT_POST, "token", FILTER_SANITIZE_STRING)));
if (empty($token))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}

$name = ltrim(rtrim(filter_input(INPUT_POST, "name", FILTER_SANITIZE_STRING)));
if (empty($name))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}

$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
if ((empty($email)) || (!filter_var($email, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}

$password = ltrim(rtrim(filter_input(INPUT_POST, "password", FILTER_SANITIZE_STRING)));
if (empty($password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}

$confirmPassword = ltrim(rtrim(filter_input(INPUT_POST, "confirmPassword", FILTER_SANITIZE_STRING)));
if (empty($confirmPassword))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}

$accessLevel = ltrim(rtrim(filter_input(INPUT_POST, "accessLevel", FILTER_SANITIZE_STRING)));
if (empty($accessLevel))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}


/* Validate input data */
if ($password != $confirmPassword)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_PASSWORDS_DO_NOT_MATCH;
    header("location: confirm_registration.php?token=" . $token);
    exit();
}


/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Check that user is not already added */
$query = "SELECT email FROM users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


if ($statement->rowCount() > 0)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_EMAIL_ALREADY_REGISTERED;
    header("location: confirm_registration.php?token=" . $token);
    exit();
}


/* Check that the user is in the pending users database */
$query = "SELECT token, email, expiry_time_stamp FROM pending_users WHERE token = :token AND email = :email AND expiry_time_stamp > :expiry_time_stamp";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":token", $token, PDO::PARAM_STR);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->bindParam(":expiry_time_stamp", $_SERVER["REQUEST_TIME"], PDO::PARAM_INT);
$statement->execute();


if ($statement->rowCount() == 0)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: confirm_registration.php?token=" . $token); // deal with invalid input
    exit();
}



/* remove this record from database */
$query = "DELETE FROM pending_users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


/* remove all old pending users from database */
$query = "DELETE FROM pending_users WHERE expiry_time_stamp < :expiry_time_stamp";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":expiry_time_stamp", $_SERVER["REQUEST_TIME"], PDO::PARAM_INT);
$statement->execute();


/* create hash */
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

$query = "INSERT INTO users (email, name, password, access_level) VALUES (:email, :name, :password, :access_level)";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->bindParam(":name", $name, PDO::PARAM_STR);
$statement->bindParam(":password", $hashedPassword, PDO::PARAM_STR);
$statement->bindParam(":access_level", $accessLevel, PDO::PARAM_INT);
$statement->execute();


/* get user id */
$query = "SELECT email FROM users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


if ($statement->rowCount() > 0)
{
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row)
    {
        $_SESSION["user_id"] = $row->id;
        header("location: members_area.php");
    }
}
?>        
</body>
</html>

 

ajaxGetAccessLevels.php
<?php

/* Connect to the database */
require_once "configuration.php";

/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


$query = "SELECT id, name FROM access_level";
$statement = $dbConnection->prepare($query);
$statement->execute();

$json = "[";

if ($statement->rowCount() > 0)
{
    /* Get field information for all fields */
    $isFirstRecord = true;
    $result = $statement->fetchAll(PDO::FETCH_OBJ);
    foreach ($result as $row)   
    {
        if (!$isFirstRecord)
        {
            $json .= ",";
        }

        /* NOTE: json strings MUST have double quotes around the attribute names, as shown below */
        $json .= '{"name":"' . $row->name . '","id":"' . $row->id . '"}';

        $isFirstRecord = false;
    }
}
$json .= "]";

/* Send the $json string back to the webpage that sent the AJAX request */
echo $json;

?>

 

forgot_password.php
<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title> 
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Forgot Password");
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form id="dkit_forgot_password_form" action="forgot_password_transaction.php" method="post">

<label for="email">Email: </label>
<input type="email" id = "email" name = "email" required autofocus><br>

<label for="confirmEmail">Confirm Email: </label>
<input type="email" id = "confirmEmail" name = "confirmEmail" required><br>

<input type="submit" value="Request new password">
</form>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

forgot_password_transaction.php
<?php
session_start();
?>


<?php
/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]

$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
if ((empty($email)) || (!filter_var($email, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password.php"); // deal with invalid input
    exit();
}


$confirmEmail = ltrim(rtrim(filter_input(INPUT_POST, "confirmEmail", FILTER_SANITIZE_EMAIL)));
if ((empty($confirmEmail)) || (!filter_var($confirmEmail, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password.php"); // deal with invalid input
    exit();
}


if ($email != $confirmEmail)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_EMAILS_DO_NOT_MATCH;
    header("location: forgot_password.php"); // deal with invalid input
    exit();
}

/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Check that user is already added  */
$query = "SELECT email FROM users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


if ($statement->rowCount() == 0)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password.php"); // deal with invalid input
    exit();
}


/* If the user is already in the pending_user table, then remove the old entry */
$query = "DELETE FROM pending_users WHERE email = :email";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->execute();


/* Create new entry in the pending_user table for this email */
$expiry_time_stamp = 1200 + $_SERVER["REQUEST_TIME"]; // 1200 = 20 minutes from now
$token = sha1(uniqid($email, true));

$query = "INSERT INTO pending_users (token, email, expiry_time_stamp) VALUES (:token, :email, :expiry_time_stamp)";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":token", $token, PDO::PARAM_STR);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->bindParam(":expiry_time_stamp", $expiry_time_stamp, PDO::PARAM_INT);
$statement->execute();


/* remove all old pending users from database */
$query = "DELETE FROM pending_users WHERE expiry_time_stamp < :expiry_time_stamp";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":expiry_time_stamp", $_SERVER["REQUEST_TIME"], PDO::PARAM_INT);
$statement->execute();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="dkit_container">

<?php
include_once 'header.php';
set_header("DkIT", "Password Reset", false);
?>
<main>

<?php
/* Provide feedback and provide a way for the user to proceed or automatically redirect to a new webpage */
echo "In a real website, an email would now be sent to the user with the link below.<br>";
echo "In this example, you can click on the link below to emulate the effect of following the link in the email.<br><br>";

echo "<a href = '" . $siteName . "/forgot_password_confirm_new_password.php?token=" . $token . "'>" . $siteName . "/forgot_password_confirm_new_password.php?token=" . $token . "</a>";
echo "<br><br><br>";

echo "<h3 style='color:red'>Below is an axample content that can be used if sending a forgot password email to the user</h3>";



echo "An email has been sent to you to allow you to change your password.<br><br>" .
 "If you do not receive an email, please check your junk folder for an email from us. Our email is:<br>" .
 "<strong>D00123456@student.dkit.ie</strong><br><br>" .
 "If you still cannot find our email, please add our email address to your email whitelist and attempt to recover your email again.<br><br>";

$subject = "DkIT Login Example Password Reset";
$comment = "You are receiving this email because you requested a new password from DkIT Login Example." .
        " If you did not request a new password from us, then simply ignore this email.<br><br>" .
        "Click on the link below to reset your password:<br>" .
        "<a href = '" . $siteName . "/forgot_password_confirm_new_password.php?token=" . $token . "'>" . $siteName . "/forgot_password_confirm_new_password.php?token=" . $token . "</a><br><br>" .
        "If the link above does not work, then cut-and-paste it into your browser address bar and run it from there.<br><br>" .
        "<br><br>Yours in Sport<br>DkIT Login Example Registration Team";

$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
mail($email, $subject, $comment, $headers);
?>        

<br><br><input type="button" value = "Go back to login webpage" onclick="window.open('login.php', '_self')">


</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

 

forgot_password_confirm_new_password.php
<?php
session_start();
?>

<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>  
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Confirm New Password");
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form id="dkit_forgot_password_confirm_new_password_form" action="forgot_password_confirm_new_password_transaction.php" method="post">
<input type="hidden" id ="token" name = token>

<label for="email">Email: </label>
<input type="email" id = "email" name = "email" required autofocus><br>

<p>Password must be at least eight-digits long and contains at least one lowercase letter, one uppercase letter, one digit and one of the following characters (£!()#€$%^&*)</p>
<label for="password">New Password: </label>
<input type="password" id = "password" name = "password" required pattern="(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[£!()#€$%^&*]).{8,}" title="Password must be at least eight-digits long and contains at least one lowercase letter, one uppercase letter, one digit and one of the following characters (£!()#€$%^&*)"><br>

<label for="confirmPassword">Confirm Password: </label>
<input type="password" id = "confirmPassword" name = "confirmPassword" required pattern="(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[£!()#€$%^&*]).{8,}" title="Password must be at least eight-digits long and contains at least one lowercase letter, one uppercase letter, one digit and one of the following characters (£!()#€$%^&*)"><br>

<input type="submit" value="Change Password">
</form>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->

<script>
    /* get the 'token' from the url */
    function getURLValue(name)
    {
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        let regexS = "[\\?&]" + name + "=([^&#]*)";
        let regex = new RegExp(regexS);
        let results = regex.exec(window.location.href);
        if (results === null)
            return null;
        else
            return results[1];
    }

    document.getElementById('token').value = getURLValue('token');
</script>

</body>
</html>

 

forgot_password_confirm_new_password_transaction.php
<?php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
</head>
<body>

<?php
/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]

$token = ltrim(rtrim(filter_input(INPUT_POST, "token", FILTER_SANITIZE_STRING)));
if (empty($token))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password_confirm_new_password.php?token=" . $token); // deal with invalid input
    exit();
}

$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
if ((empty($email)) || (!filter_var($email, FILTER_VALIDATE_EMAIL)))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password_confirm_new_password.php?token=" . $token); // deal with invalid input
    exit();
}

$password = ltrim(rtrim(filter_input(INPUT_POST, "password", FILTER_SANITIZE_STRING)));
if (empty($password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password_confirm_new_password.php?token=" . $token); // deal with invalid input
    exit();
}

$confirmPassword = ltrim(rtrim(filter_input(INPUT_POST, "confirmPassword", FILTER_SANITIZE_STRING)));
if (empty($confirmPassword))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: forgot_password_confirm_new_password.php?token=" . $token); // deal with invalid input
    exit();
}


/* Validate input data */
if ($password != $confirmPassword)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_PASSWORDS_DO_NOT_MATCH;
    header("location: forgot_password_confirm_new_password.php?token=" . $token);
    exit();
}


/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception



/* Check that the user is in the pending users database */
$query = "SELECT token, email, expiry_time_stamp FROM pending_users WHERE token = :token AND email = :email AND expiry_time_stamp > :expiry_time_stamp";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":token", $token, PDO::PARAM_STR);
$statement->bindParam(":email", $email, PDO::PARAM_STR);
$statement->bindParam(":expiry_time_stamp", $_SERVER["REQUEST_TIME"], PDO::PARAM_INT); $statement->execute(); if ($statement->rowCount() == 0) { $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD; header("location: forgot_password_confirm_new_password.php?token=" . $token); // deal with invalid input exit(); } /* remove this record and all old pending users from database */ $query = "DELETE FROM pending_users WHERE email = :email"; $statement = $dbConnection->prepare($query); $statement->bindParam(":email", $email, PDO::PARAM_STR); $statement->execute(); /* remove all old pending users from database */ $query = "DELETE FROM pending_users WHERE expiry_time_stamp < :expiry_time_stamp"; $statement = $dbConnection->prepare($query); $statement->bindParam(":expiry_time_stamp", $_SERVER["REQUEST_TIME"], PDO::PARAM_INT); $statement->execute(); /* change the user's password */ $hashedPassword = password_hash($password, PASSWORD_DEFAULT); $query = "UPDATE users SET password = :password WHERE email = :email"; $statement = $dbConnection->prepare($query); $statement->bindParam(":password", $hashedPassword, PDO::PARAM_STR); $statement->bindParam(":email", $email, PDO::PARAM_STR); $statement->execute(); header("location: members_area.php"); ?> </body> </html>

 

change_password.php
<?php
session_start();
if (!isset($_SESSION["user_id"]))
{
    header("location: login.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>  
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "Change Password");
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form id="dkit_change_password_form" action="change_password_transaction.php" method="post">
<label for="old_password">Old Password: </label>
<input type="password" id = "old_password" name = "old_password" required autofocus><br>
<br>

<p>Password must be at least eight-digits long and contains at least one lowercase letter, one uppercase letter, one digit and one of the following characters (£!()#€$%^&*)</p>
<label for="new_password">New Password: </label>
<input type="password" id = "new_password" name = "new_password" required pattern="(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[£!()#€$%^&*]).{8,}" title="Password must be at least eight-digits long and contains at least one lowercase letter, one uppercase letter, one digit and one of the following characters (£!()#€$%^&*)"><br>

<label for="confirm_new_password">Confirm New Password: </label>
<input type="password" id = "confirm_new_password" name = "confirm_new_password" required pattern="(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[£!()#€$%^&*]).{8,}" title="Password must be at least eight-digits long and contains at least one lowercase letter, one uppercase letter, one digit and one of the following characters (£!()#€$%^&*)"><br>

<input type="submit" value="Change Password">
</form>

</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->

</body>
</html>

 

change_password_transaction.php
<?php
session_start();
if (!isset($_SESSION["user_id"]))
{
    header("location: login.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
</head>
<body>

<?php
/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]

$old_password = ltrim(rtrim(filter_input(INPUT_POST, "old_password", FILTER_SANITIZE_STRING)));
if (empty($old_password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: change_password.php"); // deal with invalid input
    exit();
}

$new_password = ltrim(rtrim(filter_input(INPUT_POST, "new_password", FILTER_SANITIZE_STRING)));
if (empty($new_password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: change_password.php"); // deal with invalid input
    exit();
}

$confirm_new_password = ltrim(rtrim(filter_input(INPUT_POST, "confirm_new_password", FILTER_SANITIZE_STRING)));
if (empty($confirm_new_password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: change_password.php"); // deal with invalid input
    exit();
}


/* Validate input data */
if ($new_password != $confirm_new_password)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_PASSWORDS_DO_NOT_MATCH;
    header("location: change_password.php");
    exit();
}


/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


/* Check that user is not already added  */
$query = "SELECT password FROM users WHERE id = :id";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT);
$statement->execute();

if ($statement->rowCount() == 0)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD;
    header("location: change_password.php"); // deal with invalid input
    exit();
}

$row = $statement->fetch(PDO::FETCH_OBJ);
if (!password_verify($old_password, $row->password))
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_OLD_PASSWORD_INCORRECT;
    header("location: change_password.php");
    exit();
}

// change the user's password
$hashedPassword = password_hash($new_password, PASSWORD_DEFAULT);
$query = "UPDATE users SET password = :password WHERE id = :id";
$statement = $dbConnection->prepare($query);
$statement->bindParam(":password", $hashedPassword, PDO::PARAM_STR);
$statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT); $statement->execute(); header("location: members_area.php"); ?> </body> </html>
 
user_profile.php
<?php
session_start();
if (!isset($_SESSION["user_id"]))
{
    header("location: login.php");
    exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
<link href="login_and_registration.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div id="dkit_container">
    <?php
    include_once 'header.php';
    set_header("DkIT", "User Profile");
    ?>

<main>
    <?php
    /* Show error message for any user input errors if this form was previously submitted */
    if (isset($_SESSION["error_message"]))
    {
        echo "<div class='error_message'><p>" . $_SESSION["error_message"] . "<br>Please input data again.</p></div>";
        unset($_SESSION["error_message"]);
    }
    ?>

<form id="dkit_user_profile_form" action="user_profile_transaction.php" method="post">
<label for="name">New Name: </label>
<input type="text" id = "name" name = "name"  autofocus><br>

<label for="email">New Email: </label>
<input type="email" id = "email" name = "email" ><br>

<label for="confirmEmail">Confirm New Email: </label>
<input type="email" id = "confirmEmail" name = "confirmEmail" ><br>

<a href="change_password.php">Change Password</a><br><br>

<input type="submit" value="Update Profile">
</form>
</main>

<?php
include_once 'footer.php';
?>
</div> <!-- dkit_container -->
</body>
</html>

user_profile_transaction.php
<?php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Example</title>
</head>
<body>

<?php
/* Read posted data */
require_once "error_messages.php";  // contains a list of error messages that can be assigned to $_SESSION["error_message"]

$name = ltrim(rtrim(filter_input(INPUT_POST, "name", FILTER_SANITIZE_STRING)));

$email = ltrim(rtrim(filter_input(INPUT_POST, "email", FILTER_SANITIZE_EMAIL)));
filter_var($email, FILTER_VALIDATE_EMAIL);

$confirmEmail = ltrim(rtrim(filter_input(INPUT_POST, "confirmEmail", FILTER_SANITIZE_EMAIL)));
filter_var($confirmEmail, FILTER_VALIDATE_EMAIL);


/* Validate input data */
if ($email != $confirmEmail)
{
    $_SESSION["error_message"] = $ERROR_MESSAGE_EMAILS_DO_NOT_MATCH;
    header("location: user_profile.php");
    exit();
}


/* Connect to the database */
require_once "configuration.php";



/* Connect to the database */
$dbConnection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUsername, $dbPassword);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);   // set the PDO error mode to exception


if (($name == "") && (($email != "")))
{
    $query = "UPDATE users SET email = :email WHERE id = :id";
    $statement = $dbConnection->prepare($query);
    $statement->bindParam(":email", $email, PDO::PARAM_STR);
    $statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT);
    $statement->execute();
}
else if (($name != "") && (($email == "")))
{
    $query = "UPDATE users SET name = :name WHERE id = :id";
    $statement = $dbConnection->prepare($query);
    $statement->bindParam(":name", $name, PDO::PARAM_STR);
    $statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT);
    $statement->execute();

    $_SESSION["user_name"] = $name;
}
else if (($name != "") && (($email != "")))
{
    $query = "UPDATE users SET name = :name, email = :email WHERE id = :id";
    $statement = $dbConnection->prepare($query);
    $statement->bindParam(":name", $name, PDO::PARAM_STR);
    $statement->bindParam(":email", $email, PDO::PARAM_STR);
    $statement->bindParam(":id", $_SESSION["user_id"], PDO::PARAM_INT);
    $statement->execute();

    $_SESSION["user_name"] = $name;
}
mysqli_close($dbConnection);

header("location: members_area.php");
?>        
</body>
</html>

error_messages.php
<?php
$ERROR_MESSAGE_FAILED_TO_CONNECT_TO_DATABASE = "Failed to connect to database. Please contact customer support if this error persists.";
$ERROR_MESSAGE_INVALID_OR_EMPTY_FIELD = "Input contained invalid or empty fields.";
$ERROR_MESSAGE_PASSWORDS_DO_NOT_MATCH = "'New Password' and 'Confirm New Password' did not match.";
$ERROR_MESSAGE_OLD_PASSWORD_INCORRECT = "'Old password' was incorrect.";
$ERROR_MESSAGE_EMAIL_ALREADY_REGISTERED = "The email that was entered is already registered.";
$ERROR_MESSAGE_EMAILS_DO_NOT_MATCH = "'Email' and 'Confirm Email' did not match.";
$ERROR_MESSAGE_EMAIL_OR_PASSWORD_IS_INCORRECT = "The email or password that was entered was incorrect.";
?>

login_and_registration.css
/* Container */
#dkit_container
{
    position:relative;
    overflow:hidden;
    width:1000px;
    margin-left: auto;
    margin-right: auto;
    border:thin solid #666;
    border-radius: 10px;
    padding:10px;
}

#dkit_container input,
#dkit_container select
{
    margin-bottom:10px;
}

#dkit_container label
{
    display: inline-block;
    min-width:70px;
}

#dkit_register_new_user_form label,
#dkit_forgot_password_form label
{
    min-width:100px;
}

/* Some forms need to be pushed out further because the labels are longer */
#dkit_confirm_registration_form label,
#dkit_forgot_password_confirm_new_password_form label
{
    min-width:125px;
}

#dkit_change_password_form label
{
    min-width:160px;
}

#dkit_user_profile_form label
{
    min-width:140px;
}

#dkit_forgot_password label,
#dkit_register_new_user label
{
    min-width:100px;
}
/* End Container */


/* Header, main and footer common styles */
header,
main
{
    position:relative;
    border-radius:10px;
    background-color: #def;
    border: thin solid #ddd;
}
/* End Header, main and footer common styles */


/* Header */
header
{
    height:100px;
    margin-bottom: 10px;
}

#dkit_header_image_container
{
    position:absolute;
    top:0px;
    left:0px;
    padding:10px;
    width:80px;
    height:80px;
}

#dkit_header_image_container:hover
{
    padding:5px;
    width:90px;
    height:90px;
}

#dkit_header_image_container img
{
    width:100%;
    height:100%;
}

#dkit_header_user_name_container,
#dkit_header_logout_container
{
    position:absolute;
    right:5px;
}

#dkit_header_user_name_container
{
    top:10px;
}

#dkit_header_logout_container
{
    bottom:10px;
}

header p,
header a
{
    font-weight: bolder;
    color:#666;
    margin:0px;
    padding:0px;
}

header a
{
    text-decoration: none;
}

header a:hover,
header a:active
{
    font-size:larger;
}

#dkit_main_heading,
#dkit_sub_heading
{
    position:absolute;
    left:110px;
    color:#444;
}

#dkit_main_heading
{
    top:10px;
    font-size: 40px;
}

#dkit_sub_heading
{
    bottom:10px;
    font-size: 25px;
}
/* End of Header */


/* Main content */
main
{
    padding:10px;
}
/* End Main content */


/* Footer */
footer
{
    border-radius:10px;
    background-color: #fff;
    width:100%;
    margin-top:10px;
}

footer p
{
    text-align: center;
    margin: 0px;
    padding: 0px;
    padding-top:5px;
    color:#666;
}
/* End of Footer */


/* Error Message */
.error_message:before,
.error_message
{
    -webkit-box-shadow : #666 5px 5px 5px;
    -moz-box-shadow    : #666 5px 5px 5px;
    -ms-box-shadow    : #666 5px 5px 5px;
    -o-box-shadow    : #666 5px 5px 5px;
    box-shadow         : #666 5px 5px 5px;
    behavior           : url(/css_styles/PIE.htc);      
    border:thin #ddd solid;
    background-color:#fdd;
    padding:3px;
}

.error_message:before
{
    content:' Error \A';
    font-size: larger;
    white-space: pre;
    font-weight:bold;
    left:5px;
    padding-bottom:0px;
    border-radius:15px;
}

.error_message:before,
.error_message p
{
    position:relative;
    top:-14px;
}

.error_message p
{
    margin-bottom:0px;
}

.error_message
{
    margin-top:25px;
    margin-bottom:50px;
    padding-top:0px;
    padding-bottom:0px;
}
/* End of Error Message */


/* Menu */
#dkit_main_menu
{
    position:relative;
    background-color: #def;
    width:100%;
    height:20px;
    margin-bottom:10px;
    border-radius: 10px;
}

.dkit_menu ul
{
    list-style : none;  /* Remove the bullet from list items */
    padding    : 0px;   /* Remove default padding from list items */
    margin     : 0px;   /* Remove default margin from list items */
}

.dkit_menu li
{
    width      : 180px;    /* width for each list item. Not absolutely necessary for horizontal menus. */
    text-align : center;  /* Not needed for either menu. */

    margin-right:5px;
}

.dkit_menu a,
.dkit_menu span
{
    text-decoration  : none;    /* remove the underline from a menu */ 
    color            : #ccc; 
    background-color : #61c6f0;
    display          : block;   /* Expand hyperlink to fill container*/
    border-radius: 10px;
}

.dkit_menu a:hover,
.dkit_menu a:active,
.dkit_menu span:hover
{
    color            : #0ac;
    background-color : #ddd;
}

.dkit_menu span:hover /* make the mouse hoveing over a span be the same as hoving over a hyperlink */
{
    cursor: pointer;
}

/* needed for drop-down menus */ 
.dkit_menu ul li ul
{
    visibility : hidden;
    position   : absolute;  
}

.dkit_menu ul li:hover ul
{
    visibility : visible;
}

.dkit_menu ul li
{
    position : relative; 
}

.dkit_horizontal.dkit_menu li
{
    display : inline-block;  /* Force list items onto same line. */
    float   : left;          /* Force list items tight together. */
}

.dkit_vertical.dkit_menu ul li ul
{
    left : 80px;  /* Position vertical drop-down menus */
    top  : 0px;
}
/* End Menu */

 

 
<div align="center"><a href="../../versionC/index.html" title="DKIT Lecture notes homepage for Derek O&#39; Reilly, Dundalk Institute of Technology (DKIT), Dundalk, County Louth, Ireland. Copyright Derek O&#39; Reilly, DKIT." target="_parent" style='font-size:0;color:white;background-color:white'>&nbsp;</a></div>