Basic E-commerce site development part-2

The registration and login processes of the user have shown in this tutorial. Do the following steps to complete the tutorial.

Steps:
Modify the index.php file inside the html folder to omit the default session information. So, commented the following lines.


/*
$_SESSION['user_id'] = 1;
$_SESSION['user_admin'] = true;
$_SESSION['user_not_expired'] = true;
*/

2. Add the following script in form_functions.php.


<?php
function create_form_input($name, $type, $label = '', $errors = array(), $options = array()) {
// Assume no value already exists:
$value = false;
// Check for a value in POST:
if (isset($_POST[$name])) $value = $_POST[$name];
// Strip slashes if Magic Quotes is enabled:
if ($value && get_magic_quotes_gpc()) $value = stripslashes($value);
// Start the DIV:
echo '<div class="form-group';
// Add a class if an error exists:
if (array_key_exists($name, $errors)) echo ' has-error';

// Complete the DIV:
echo '">';
// Create the LABEL, if one was provided:
if (!empty($label)) echo '<label for="' . $name . '" class="control-label">' . $label . '</label>';
// Conditional to determine what kind of element to create:
if ( ($type === 'text') || ($type === 'password') || ($type === 'email')) {
// Start creating the input:
echo '<input type="' . $type . '" name="' . $name . '" id="' . $name . '" class="form-control"';
// Add the value to the input:
if ($value) echo ' value="' . htmlspecialchars($value) . '"';
// Check for additional options:
if (!empty($options) && is_array($options)) {
foreach ($options as $k => $v) {
echo " $k=\"$v\"";
}
}

// Complete the element:
echo '>';
// Show the error message, if one exists:
if (array_key_exists($name, $errors)) echo '<span class="help-block">' . $errors[$name] . '</span>';
} elseif ($type === 'textarea') { // Create a TEXTAREA.
// Show the error message above the textarea (if one exists):
if (array_key_exists($name, $errors)) echo '<span class="help-block">' . $errors[$name] . '</span>';
// Start creating the textarea:
echo '<textarea name="' . $name . '" id="' . $name . '" class="form-control"';
// Check for additional options:
if (!empty($options) && is_array($options)) {
foreach ($options as $k => $v) {
echo " $k=\"$v\"";
}
}
// Complete the opening tag:
echo '>';
// Add the value to the textarea:
if ($value) echo $value;
// Complete the textarea:
echo '</textarea>';
} 
echo '</div>';
} 

3. Download the following file. Unzip the folder and store inside html/includes folder to generate strong password.

password_compat.zip

4. Create register.php inside the html folder and add the following script.

<?php

require('./includes/config.php');
// Require the database connection:
require(MYSQL);
// Include the header file:
$page_title = 'Register';
include('./includes/header.php');
// For storing registration errors:
$reg_errors = array();
// Check for a form submission:
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Check for a first name:
if (preg_match('/^[A-Z \'.-]{2,45}$/i', $_POST['first_name'])) {
$fn = escape_data($_POST['first_name'], $dbc);
} else {
$reg_errors['first_name'] = 'Please enter your first name!';
}

// Check for a last name:
if (preg_match('/^[A-Z \'.-]{2,45}$/i', $_POST['last_name'])) {
$ln = escape_data($_POST['last_name'], $dbc);
} else {
$reg_errors['last_name'] = 'Please enter your last name!';
}
// Check for a username:
if (preg_match('/^[A-Z0-9]{2,45}$/i', $_POST['username'])) {
$u = escape_data($_POST['username'], $dbc);
} else {
$reg_errors['username'] = 'Please enter a desired name using only letters and numbers!';
}

// Check for an email address:
if (filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) === $_POST['email']) {
$e = escape_data($_POST['email'], $dbc);
} else {
$reg_errors['email'] = 'Please enter a valid email address!';
}

// Check for a password and match against the confirmed password:
if (preg_match('/^(\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*){6,}$/', $_POST['pass1']) ) {
if ($_POST['pass1'] === $_POST['pass2']) {
$p = $_POST['pass1'];
} else {
$reg_errors['pass2'] = 'Your password did not match the confirmed password!';
}
} else {
$reg_errors['pass1'] = 'Please enter a valid password!';
}

if (empty($reg_errors)) { // If everything's OK...
// Make sure the email address and username are available:
$q = "SELECT email, username FROM users WHERE email='$e' OR username='$u'";
$r = mysqli_query($dbc, $q);
// Get the number of rows returned:
$rows = mysqli_num_rows($r);
if ($rows === 0) { // No problems!
// Add the user to the database...
$q = "INSERT INTO users (username, email, pass, first_name, last_name, date_expires) VALUES ('$u', '$e', '" . password_hash($p, PASSWORD_BCRYPT) . "', '$fn', '$ln', SUBDATE(NOW(), INTERVAL 1 DAY) )";
$r = mysqli_query($dbc, $q);
if (mysqli_affected_rows($dbc) === 1) { // If it ran OK.

$uid = mysqli_insert_id($dbc);
// $_SESSION['reg_user_id'] = $uid;

// Display a thanks message...
echo '<div class="alert alert-success"><h3>Thanks!</h3><p>Thank you for registering! To complete the process, please now click the button below so that you may pay for your site access via PayPal. The cost is $10 (US) per year. <strong>Note: When you complete your payment at PayPal, please click the button to return to this site.</strong></p></div>';

echo '<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="email" value="' . $e . '">
<input type="hidden" name="hosted_button_id" value="8YW8FZDELF296">
<input type="image" src="https://www.sandbox.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
';

// Send a separate email?
$body = "Thank you for registering to our site\n\n";
mail($_POST['email'], 'Registration Confirmation', $body, 'From: admin@example.com');
// Finish the page:
include('./includes/footer.html');
exit();
} else { 
trigger_error('You could not be registered due to a system error. We apologize for any inconvenience. We will correct the error ASAP.');
}
} else { 
if ($rows === 2) { // Both are taken.
$reg_errors['email'] = 'This email address has already been registered. If you have forgotten your password, use the link at left to have your password sent to you.';
$reg_errors['username'] = 'This username has already been registered. Please try another.';
} else { 

// Get row:
$row = mysqli_fetch_array($r, MYSQLI_NUM);
if( ($row[0] === $_POST['email']) && ($row[1] === $_POST['username'])) { // Both match.
$reg_errors['email'] = 'This email address has already been registered. If you have forgotten your password, use the link at left to have your password sent to you.';
$reg_errors['username'] = 'This username has already been registered with this email address. If you have forgotten your password, use the link at left to have your password sent to you.';
} elseif ($row[0] === $_POST['email']) { // Email match.
$reg_errors['email'] = 'This email address has already been registered. If you have forgotten your password, use the link at left to have your password sent to you.';
} elseif ($row[1] === $_POST['username']) { // Username match.
$reg_errors['username'] = 'This username has already been registered. Please try another.';
}
} 
} 
} 
} 

// Need the form functions script, which defines create_form_input():
require_once('./includes/form_functions.php');
?><h1>Register</h1>

<p>Access to the site's content is available to registered users at a cost of $10.00 (US) per year. Use the form below to begin the registration process. <strong>Note: All fields are required.</strong> After completing this form, you'll be presented with the opportunity to securely pay for your yearly subscription via <a href="http://www.paypal.com">PayPal</a>.</p>

<form action="register.php" method="post" accept-charset="utf-8">
<?php
create_form_input('first_name', 'text', 'First Name', $reg_errors);
create_form_input('last_name', 'text', 'Last Name', $reg_errors);
create_form_input('username', 'text', 'Desired Username', $reg_errors);
echo '<span class="help-block">Only letters and numbers are allowed.</span>';
create_form_input('email', 'email', 'Email Address', $reg_errors);
create_form_input('pass1', 'password', 'Password', $reg_errors);
echo '<span class="help-block">Must be at least 6 characters long, with at least one lowercase letter, one uppercase letter, and one number.</span>';
create_form_input('pass2', 'password', 'Confirm Password', $reg_errors);
?>
<br/>
<input type="submit" name="submit_button" value="Next" id="submit_button" class="btn btn-primary" />
</form>
<br>
<?php // Include the HTML footer:
include('./includes/footer.html');
?>

5. Add the following script in login.php.


<?php
// Array for recording errors:
$login_errors = array();
// Validate the email address:
if (filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$e = escape_data($_POST['email'], $dbc);
} else {
$login_errors['email'] = 'Please enter a valid email address!';
}
// Validate the password:
if (!empty($_POST['pass'])) {
$p = $_POST['pass'];
} else {
$login_errors['pass'] = 'Please enter your password!';
}
if (empty($login_errors)) { // OK to proceed!
// Query the database:
$q = "SELECT id, username, type, pass, IF(date_expires >= NOW(), true, false) AS expired FROM users WHERE email='$e'";
$r = mysqli_query($dbc, $q);
if (mysqli_num_rows($r) === 1) { // A match was made.
// Get the data:
$row = mysqli_fetch_array($r, MYSQLI_ASSOC);
// Validate the password:
// Include the password_compat library, if necessary:
if (password_verify($p, $row['pass'])) {
if ($row['type'] === 'admin') {
session_regenerate_id(true);
$_SESSION['user_admin'] = true;
}

// Store the data in a session:
$_SESSION['user_id'] = $row['id'];
$_SESSION['username'] = $row['username'];
// Only indicate if the user's account is not expired:
if ($row['expired'] === 1) $_SESSION['user_not_expired'] = true;
} else { // Right email address, invalid password.
$login_errors['login'] = 'The email address and password do not match those on file.';
}
} else { // No match was made. (technically, only the email address failed)
$login_errors['login'] = 'The email address and password do not match those on file.';
}
} 

6. Add the following code in login_form.php.


<?php
// This script displays the login form.
if (!isset($login_errors)) $login_errors = array();
// Need the form functions script, which defines create_form_input():
require('./includes/form_functions.php');
?>
<form action="index.php" method="post" accept-charset="utf-8">
<fieldset>
<legend>Login</legend>
<?php
if (array_key_exists('login', $login_errors)) {
echo '<div class="alert alert-danger">' . $login_errors['login'] . '</div>';
}
create_form_input('email', 'email', '', $login_errors, array('placeholder'=>'Email address'));
echo '<br/>';
create_form_input('pass', 'password', '', $login_errors, array('placeholder'=>'Password'));
echo '<span class="help-block"><a href="forgot_password.php">Forgot password?</a></span>';
?>
<br/><br/>
<button type="submit" class="btn btn-primary">Login</button>
</fieldset>
</form>

7. Create logout.php inside html folder and add the following script.


<?php
require('./includes/config.php');
redirect_invalid_user();

// Destroy the session:
$_SESSION = array(); // Destroy the variables.
session_destroy(); // Destroy the session itself.
setcookie (session_name(), '', time()-300); // Destroy the cookie.

// Header file needs the database connection:
require(MYSQL);
$page_title = 'Logout';
// Include the header file
include('./includes/header.php');
// Print a customized message:
echo '<h1>Logged Out</h1><p>Thank you for visiting. You are now logged out. Please come back soon!</p>';
// Include the HTML footer:
include('./includes/footer.html');
?>

8. Create change_password.php file inside html folder and add the following script.


<?php

require('./includes/config.php');
redirect_invalid_user();
require(MYSQL);

$page_title = 'Change Your Password';
include('./includes/header.php');

// For storing errors:
$pass_errors = array();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!empty($_POST['current'])) {
$current = $_POST['current'];
} else {
$pass_errors['current'] = 'Please enter your current password!';
}

// Check for a password and match against the confirmed password:
if (preg_match('/^(\w*(?=\w*\d)(?=\w*[a-z])(?=\w*[A-Z])\w*){6,}$/', $_POST['pass1']) ) {
if ($_POST['pass1'] == $_POST['pass2']) {
$p = $_POST['pass1'];
} else {
$pass_errors['pass2'] = 'Your password did not match the confirmed password!';
}
} else {
$pass_errors['pass1'] = 'Please enter a valid password!';
}

if (empty($pass_errors)) { // If everything's OK.
$q = "SELECT pass FROM users WHERE id={$_SESSION['user_id']}";
$r = mysqli_query($dbc, $q);
list($hash) = mysqli_fetch_array($r, MYSQLI_NUM);

if (password_verify($current, $hash)) { 
// Define the query:
$q = "UPDATE users SET pass='" . password_hash($p, PASSWORD_BCRYPT) . "' WHERE id={$_SESSION['user_id']} LIMIT 1";
if ($r = mysqli_query($dbc, $q)) { // If it ran OK.

echo '<h1>Your password has been changed.</h1>';
include('./includes/footer.html'); // Include the HTML footer.
exit();
} else { 
trigger_error('Your password could not be changed due to a system error. We apologize for any inconvenience.');
}
} else { 
$pass_errors['current'] = 'Your current password is incorrect!';
}
} 
} 

require_once('./includes/form_functions.php');
?><h1>Change Your Password</h1>
<p>Use the form below to change your password.</p>
<form action="change_password.php" method="post" accept-charset="utf-8">
<?php

create_form_input('current', 'password', 'Current Password', $pass_errors);
create_form_input('pass1', 'password', 'Password', $pass_errors);
echo '<span class="help-block">Must be at least 6 characters long, with at least one lowercase letter, one uppercase letter, and one number.</span>';
create_form_input('pass2', 'password', 'Confirm Password', $pass_errors);
?>
<br/>
<input type="submit" name="submit_button" value="Change Password" id="submit_button" class="btn btn-primary" />
</form>
<?php 

include('./includes/footer.html');
?>

9. Create forgot_password.php inside html folder and add the following script.


<?php

require('./includes/config.php');
require(MYSQL);
$page_title = 'Forgot Your Password?';
include('./includes/header.php');

$pass_errors = array();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$email = $_POST['email'];

$q = 'SELECT id FROM users WHERE email="'. escape_data($email, $dbc) . '"';
$r = mysqli_query($dbc, $q);
if (mysqli_num_rows($r) === 1) { 
list($uid) = mysqli_fetch_array($r, MYSQLI_NUM);
} else { 
$pass_errors['email'] = 'The submitted email address does not match those on file!';
}
} else { 
$pass_errors['email'] = 'Please enter a valid email address!';
} 

if (empty($pass_errors)) {
$p = substr(md5(uniqid(rand(), true)), 10, 15);

// Update the database:
$q = "UPDATE users SET pass='" . password_hash($p, PASSWORD_BCRYPT) . "' WHERE id=$uid LIMIT 1";
$r = mysqli_query($dbc, $q);
if (mysqli_affected_rows($dbc) === 1) { // If it ran OK.

// Send an email:
$body = "Your password to log into <whatever site> has been temporarily changed to '$p'. Please log in using that password and this email address. Then you may change your password to something more familiar.";
mail($_POST['email'], 'Your temporary password.', $body, 'From: admin@example.com');

// Print a message and wrap up:
echo '<h1>Your password has been changed.</h1><p>You will receive the new, temporary password via email. Once you have logged in with this new password, you may change it by clicking on the "Change Password" link.</p>';

include('./includes/footer.html');
exit();

} else {
trigger_error('Your password could not be changed due to a system error. We apologize for any inconvenience.');
}

$token = openssl_random_pseudo_bytes(32);
$token = bin2hex($token);
// Store the token in the database:
$q = 'REPLACE INTO access_tokens (user_id, token, date_expires) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 15 MINUTE))';

$stmt = mysqli_prepare($dbc, $q);
mysqli_stmt_bind_param($stmt, 'is', $uid, $token);
mysqli_stmt_execute($stmt);
if (mysqli_stmt_affected_rows($stmt) > 0) {
$url = 'https://' . BASE_URL . 'reset.php?t=' . $token;
$body = "This email is in response to a forgotten password reset request at 'Knowledge is Power'. If you did make this request, click the following link to be able to access your account:
$url For security purposes, you have 15 minutes to do this. If you do not click this link within 15 minutes, you'll need to request a password reset again. If you have _not_ forgotten your password, you can safely ignore this message and you will still be able to login with your existing password. ";

mail($email, 'Password Reset at Knowledge is Power', $body, 'FROM: ' . CONTACT_EMAIL);

echo '<h1>Reset Your Password</h1><p>You will receive an access code via email. Click the link in that email to gain access to the site. Once you have done that, you may then change your password.</p>';

include('./includes/footer.html');
exit(); 
} else { 
trigger_error('Your password could not be changed due to a system error. We apologize for any inconvenience.');
}
} 
}

require_once('./includes/form_functions.php');
?><h1>Reset Your Password</h1>
<p>Enter your email address below to reset your password.</p>
<form action="forgot_password.php" method="post" accept-charset="utf-8">
<?php create_form_input('email', 'text', 'Email Address', $pass_errors); ?>
<br/>
<input type="submit" name="submit_button" value="Reset Password" id="submit_button" class="btn btn-primary" />
</form>
<?php 
include('./includes/footer.html');
?>

10. Check the output in the browser.

***Reference: Main code has taken from effortless e-commerce with PHP and MySQL book.

Attachments