Lesson 5: Adding Security. Implementing Application User Logon

This tutorial needs a review. You can edit it in GitHub following these contribution guidelines.

In this lesson you implement the logon functionality for a wisher. This affects the following files:

  • index.php

  • createNewWisher.php

  • editWishlist.php

  • db.php

Implementing the logon functionality consists of the following steps:

The current document is a part of the Creating a CRUD Application in the NetBeans IDE for PHP tutorial.

Application Source Code from the Previous Lesson

MySQL users: Click here to download the source code that reflects the project state after the previous lesson is completed.

Oracle Database users: Click here to download the source code that reflects the project state after the previous lesson is completed.

Saving the Wisher’s ID in the Session Upon Creation

A Session is persistent storage for transferring information from one page to another without using an HTML input form. This functionality is supported through the predefined PHP array $_SESSION .

For the sake of security, after a new wisher is created he should be logged on automatically without filling in a form. Therefore you need to modify the createNewWisher.php file to implement the following functionality:

  • Add a new wisher to the database.

  • Open a session.

  • Store the wisher’s name in the session.

  • Transfer the wisher’s name in the session when the wisher is redirected to the editWishList.php page.

In the createNewWisher.php file, locate the line:

WishDB::getInstance()->create_wisher($_POST['user'], $_POST['password']);

and enter the following code block right below:

session_start();
$_SESSION['user'] = $_POST['user'];

The code block starts a session, which means opening the $_SESSION array for entering or retrieving data. Then the code adds an element to the $_SESSION array. The added element contains a value and an identifier (key). The value is the name of the newly created wishers and the identifier is "user". Then the program redirects the wisher to the editWishList.php page.

Validating User Logon

When a user reaches the editWishList.php page the application should confirm that the page is accessed by the same person who was just registered on the createNewWisher.php page.

Implementing this functionality consists of two steps:

Retrieving the Wisher’s Name from the Session

Replace the default code in the PHP block of editWishList.php with the following:

session_start();
if (array_key_exists("user", $_SESSION)) {
    echo "Hello " . $_SESSION['user'];
}

The code block opens the $_SESSION array for retrieving data and verifies that $_SESSION contains an element with the identifier "user". If the check is successful, the code prints a welcome message.

To check that the session is implemented correctly:

  1. Run the createNewWisher.php file and create a new wisher, for example Jack. The editWishList.php opens with Hello Jack.

    1. Clear session cookies in your browser or end the session and run editWishList.php from the IDE. The editWishList.php file opens with Hello because no user has been transferred through a session. This is not correct because it enables someone who is not logged in and not registered to create or edit a wish list. In order to avoid this, the user needs to be redirected to the index.php page.

Redirecting a User Who Is Not Logged In

Add the following code block to editWishList.php , below the if clause:

else {
   header('Location: index.php');
   exit;
}

The code redirects the user to the index.php page and cancels PHP code execution.

To check that the functionality is implemented correctly, run the editWishList.php file. The expected result is that the index.php page opens.

Logging In from the index.php Page

The logon from the index.php page consists of two steps:

HTML Form for Logon on index.php

In the index.php file, enter the following code before the closing </body> tag:

<form name="logon" action="index.php" method="POST" >
  Username: <input type="text" name="user">
  Password  <input type="password" name="userpassword">
  <input type="submit" value="Edit My Wish List">
</form>

Note: You can ignore warnings from the HTML validator.

The code presents an HTML form that enables entering the name and password of the user in the text fields. When the user clicks Edit My Wish List, the data is transferred to the same page, index.php.

Logon Validation

Logon validation involves:

A user may access the index.php page on starting the application, or from the editWishList.php page, or when redirected from the index.php page after entering name and password.

Because only in the last case is the HTML request method POST used, you can always learn where the user was located when they accessed index.php .

In the index.php file, create a <?php ?> block above the HTML block, with the following code:

<?php
require_once("Includes/db.php");
$logonSuccess = false;

// verify user's credentials
if ($_SERVER['REQUEST_METHOD'] == "POST") {
    $logonSuccess = (WishDB::getInstance()->verify_wisher_credentials($_POST['user'], $_POST['userpassword']));
    if ($logonSuccess == true) {
      session_start();
      $_SESSION['user'] = $_POST['user'];
      header('Location: editWishList.php');
      exit;
    }
}
?>

The top of the code block enables the use of the db.php file and initializes the $logonSuccess variable with the value false . If validation succeeds, this value will change to true .

The code that verifies the user’s credentials first checks if the request method is POST. If the request method is POST, the user was redirected after submitting the logon form. In this case, the code block calls the verify_wisher_credentials function with the name and password entered in the logon form.

The verify_wisher_credentials function, which you write in the next section, checks whether there is a record in the wishers table where the user and password match the values submitted in the logon form. If the verify_wisher_credentials function returns true , a wisher with the specified combination of name and password is registered in the database. This means that validation succeeds, and $logonSuccess changes value to true . In this case, a session starts, and the $_SESSION array opens. The code adds a new element to the $_SESSION array. The element contains a value and an identifier (key). The value is the name of the wisher and the identifier is "user". Then the code redirects the user to the editWishList.php page in order to edit the wish list.

If the verify_wisher_credentials function returns false , the value of the $logonSuccess variable remains false. The value of the variable is used in displaying an error message.

Function verify_wisher_credentials

In order to implement verification of the wisher’s credentials, you need to add a new function to the WishDB class in the db.php file. The function requires a name and a password as the input parameters and returns 0 or 1.

For the MySQL database, enter the following code block:

public function verify_wisher_credentials($name, $password) {
  $name = $this->real_escape_string($name);
  $password = $this->real_escape_string($password);
  $result = $this->query("SELECT 1 FROM wishers WHERE name = '"
                  . $name . "' AND password = '" . $password . "'");
  return $result->data_seek(0);
}

For the Oracle Database, enter the following code block (Because OCI8 has no equivalent to mysql_num_rows , this code is a modified form of get_wisher_id_by_name ):

public function verify_wisher_credentials($name, $password) {
  $query = "SELECT 1 FROM wishers WHERE name = :name_bv AND password = :pwd_bv";
  $stid = oci_parse($this->con, $query);
  oci_bind_by_name($stid, ':name_bv', $name);
  oci_bind_by_name($stid, ':pwd_bv', $password);
  oci_execute($stid);

//Because name is a unique value I only expect one row
  $row = oci_fetch_array($stid, OCI_ASSOC);
  if ($row)
    return true;
  else
    return false;
}

The code block executes the query ` "SELECT 1 FROM wishers WHERE Name = '" . $name . "' AND Password = '" . $password . "'"` and returns the number of records that meet the specified query. If such record is found, the function returns true . If there is no such record in the database, the function returns false .

Displaying Error Messages

In order to enable the application to display error messages, enter the following <? php ?> code block into the logon form in index.php , below the input fields but above the button:

<?php
if ($_SERVER['REQUEST_METHOD'] == "POST") {
  if (!$logonSuccess)
    echo "Invalid name and/or password";
}
?>

The code block checks the value of the $logonSuccess variable and if it is false, displays an error message.

Testing the Logon from the index.php Page

To check that the logon functionality works correctly on the index.php front page:

  1. Run the application.

  2. On the index.php page, enter Tom in the Username edit box and Tim in the Password edit box.

  3. Press Edit My Wish List. An error message is displayed (Note that browser window below is reduced to 600px width, which adds some line breaks):

incorrectNamePasswordIndex
  1. Enter Tom in the Username edit box and tomcat in the Password edit box.

  2. Press Edit My Wish list. The editWishList.php page is displayed:

SuccessfulLogonOnIndexRedirectToEditWishList

Application Source Code after the Current Lesson Is Completed

MySQL users: Click here to download the source code that reflects the project state after the lesson is completed.

Oracle Database users: Click here to download the source code that reflects the project state after the lesson is completed.