myChef

A web application that matches you with local chefs in the nearby area to receive a personalized home cooked meal.

Background

When I was in college, a friend of mine reached out to me about an idea for a company. He wanted to create a web application that will help match local chefs with people looking for home cooked meals.

This was an awesome opportunity to practice adding authentication to a website for a registration and login system. The name of the application was going to be called myChef.

Requirements

I was told by myChef to lay out the foundation of their site. This included three major things:

  1. Login Page
  2. Registration Page
  3. Home Page

I also wanted to learn how to implement prepared statements, as I had recently learned about SQL injection, and how bad it can be for websites in production.

Implementation

Creating the database schema

The first thing I wanted to do was lay out the database schema.

For the basic user, they would need to fill out the following fields:

  1. First Name
  2. Last Name
  3. Password
  4. Email
  5. Zip Code

I also gave every account a unique ID to be used as the primary key for the table. Once that was created it was time to get started on the Home Page.

Home Page

After searching for different images to use on StockSnap, I settled on these three images:

Using a jQuery plugin I found, I set it up to fade through each image every second or so. I made sure to choose rich imagery for the photos, as it was going to be a service focused around food.

Login & Registration Page

For the login page, I used CSS3 transitions to make a stylish login box: The example can be seen here:

If the credentials are correct, the user is then redirected to the home page, where they can get started with the application. Otherwise, an error is shown based off of which field was wrong.

To prevent SQL injections, I made sure to use prepared statements and bound parameters in my PHP code. In order to do this, I used the PDO Library that is provided by PHP.

I set my bound parameters, and execute each prepared statement in a try/catch block in order to make sure there were no errors with the database:

<?php 
// State our connection to our database and start a session.
require("common.php");

// Use this in order to resubmit username value if user fails login
$submitteduser = "";
$error = "";

if(!empty($_SESSION['user'])){
  header("Location: main");

}

// Check to see if a form was submitted;
if(!empty($_POST))
{
  if(empty($_POST['email']) || empty($_POST['pass']))
  {
    $error = "All fields are required.";
  }
  else
  {
    // Retrieve info from database
    $query = "SELECT id, fname, lname, password, salt, email FROM users WHERE email = :email";

    // Set param values
    $queryparams = array(
      ':email' => $_POST['email']
      );

    try
    {
      // Execute query against database
      $stmt = $db -> prepare($query);
      $result = $stmt -> execute($queryparams);
    }

    // Catch error
    catch (PDOException $ex)
    {
      $error = "Oops! There was an error. Please try again.";
    }

    // Create variable to tell us whether user has logged in or not. 
    // Set to false in beginning, and switch it to true if correct credentials.
    $goodlogin = false;

    // Retrieve user data from database. If false, then username is not registered.
    $row = $stmt -> fetch();

    if($row)
    {
      // Using password submitted by user and salt stored in database, we check to see if passwords match
      $check_password = hash('sha256', $_POST['pass'] .$row['salt']);

      for($round = 0; $round < 65536; $round++)
      {
        $check_password = hash('sha256', $check_password . $row['salt']);
      }

      if($check_password == $row['password'])
      {
        // If true, then we change login variable to true.
        $goodlogin = true;
      }
    }

    // If user logged in successfully, then send them to the private members-only page.
    if($goodlogin)
    {
      unset($row['salt']);
      unset($row['password']);
      $_SESSION['user'] = $row;
      header("Location: http://dev.beesdesign.net/mychef");
    }
    else
    {
      $error = "Login failed. Please try again.";
      // Show them the email they entered.
      $submitteduser = htmlentities($_POST['email'], ENT_QUOTES, 'UTF-8');
    }
  }
}
?>

  // load the html          
            

You will notice that I separated the standard database connection info into a file called "common.php". I do this so I can call the database on both every page, and check if the user is a valid user when they are trying to access content on myChef.

Project Challenges

I spent a lot of time learning about the Post/Redirect/Get pattern. The pattern prevents duplicate form submissions, which I was running into when I first started.

I also ran into trouble changing what was shown on the home page. I learned about PHP sessions, and with the use of an .htaccess file on the server I was able to get it to redirect based on a cookie that is set by the server.

Some cool things that I learned about were:

  • The PDO Library
  • Prepared Statements
  • MySQL & PHPMyAdmin

Technologies Used

  • HTML5/CSS3
  • JavaScript
  • jQuery
  • PHP/MySQL

Available Links