PHP Tutorial

Step 10

PHP Tutorial

In this tutorial we will create a simple twitter copycat. In step 10 we will create the login and logout functionalities.

Step 10

1. We will start by adding a login form to our common/header.tpl template. We will try to keep it as simple as possible using placeholders instead of labels and a small submit button:

<section id="login">
  <form action="{$BASE_URL}actions/users/login.php" method="post">
    <input type="text" placeholder="username" name="username">
    <input type="password" placeholder="password" name="password">
    <input type="submit" value="Login">
  </form>
</section>

2. Let’s also style this new form a little by changing adding the following to our css:

body > header h1 {
  margin: 0 1em 0 0;
  align-self: center;
}

body > header a {
  align-self: center;
  display: block;
  margin-right: 1em;
  flex-grow: 1;
  text-align: right;
}

body > header input{
  margin: 1em 0;
  border: 1px solid #666;
  padding: 0.5em;
}

body > header input[type="text"]{
  width: 10em;
}

body > header input[type="password"]{
  width: 10em;
}

body > header input[type="submit"]{
  background-color: #1DA1F2;
  color: white;
  border-color: #1DA1F2;
  box-sizing: content-box;
}

3. The login action (actions/users/login.php) will be very simple. We will start by including our required files:

<?php
  include_once('../../config/init.php');
  include_once($BASE_DIR .'database/users.php');  

Then testing if all required fields are present. If they are not we redirect the user to the previous page using the $_SERVER[‘HTTP_REFERER’] special variable.

  if (!$_POST['username'] || !$_POST['password']) {
    $_SESSION['error_messages'][] = 'Invalid login';
    $_SESSION['form_values'] = $_POST;
    header('Location: ' . $_SERVER['HTTP_REFERER']);
    exit;
  }

To simplify the rest of the action code let’s put the received fields into variables:

  $username = $_POST['username'];
  $password = $_POST['password'];

And now for the action logic, we will use a, not yet created function, to verify if the user credentials are correct. If they are we will store the username in the session. We don’t have success messages yet, so we will use a error message to indicate the login worked for now:

  if (isLoginCorrect($username, $password)) {
    $_SESSION['username'] = $username;
    $_SESSION['error_messages'][] = 'Login successful';  
  } else {
    $_SESSION['error_messages'][] = 'Login failed';  
  }
  header('Location: ' . $_SERVER['HTTP_REFERER']);
?>

4. Our isLoginCorrect function, in the database/users.php file will look like this:

function isLoginCorrect($username, $password) {
  global $conn;
  $stmt = $conn->prepare("SELECT *
                          FROM users
                          WHERE username = ? AND password = ?");
  $stmt->execute(array($username, sha1($password)));
  return $stmt->fetch() == true;
}

5. When a user is logged in, the register link and login forms are no longer needed. We should replace them with an indication of the user that is currently logged in and a logout link. To do that we will start by moving those two elements from the header.tpl file into a menu_logged_out.tpl (also in the common templates folder):

<a href="{$BASE_URL}pages/users/register.php">Register</a>
<form action="{$BASE_URL}actions/users/login.php" method="post">
  <input type="text" placeholder="username" name="username">
  <input type="password" placeholder="password" name="password">
  <input type="submit" value=">">
</form>

We will include this new file in the header template for now:

<header>
  <h1><a href="{$BASE_URL}">Fritter</a></h1>
  {include file='common/menu_logged_out.tpl'}
</header>

6. To choose which menu to include, the templates have to know if a user is logged in and which one. For this to happen, we will assign a new variable to smarty in our config/init.php file:

if (isset($_SESSION['username'])) {
  $smarty->assign('USERNAME', $_SESSION['username']);
}

7. Now we can select which menu to show in header.tpl:

<header>
  <h1><a href="{$BASE_URL}">Fritter</a></h1>
  {if isset($USERNAME)}
    {include file='common/menu_logged_in.tpl'}
  {else}
    {include file='common/menu_logged_out.tpl'}
  {/if}
</header>

The menu_logged_in.tpl would look like this:

<a href="{$BASE_URL}actions/users/logout.php">Logout</a>
<span class="username">{$USERNAME}</span>

And some styling:

body > header .username {
  margin: 1em;
}

8. The actions/users/logout.php file is fairly simple:

<?php
  include_once('../../config/init.php');

  session_destroy();

  header('Location: ' . $BASE_URL);
?>

9. Finally, let’s add some green success messages. For that we need to start using another session array. We will start by sending that array to smarty, and then deleting it, just like we did with our errors array. Add the following lines to our init.php file:

if (isset($_SESSION['success_messages'])) {
  $smarty->assign('SUCCESS_MESSAGES', $_SESSION['success_messages']);
  unset($_SESSION['success_messages']);
}

Then, let’s add these success messages to our header.tpl:

{if isset($SUCCESS_MESSAGES)}
  {foreach $SUCCESS_MESSAGES as $success}
    <div class="success">{$success}</div>
  {/foreach}
{/if}

Now, let’s use this new array. In the login action:

if (isLoginCorrect($username, $password)) {
  $_SESSION['username'] = $username;
  $_SESSION['success_messages'][] = 'Login successful';  
}

And the register action:

$_SESSION['success_messages'][] = 'User registered successfully';  
header("Location: $BASE_URL");

And finally the styling:

#messages .success {
  background-color: #9F9;
  color: #333;
}

In step 11 we will enable our users to tweet (or should we call it freet?).