Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] - نسخه متنی

David Lane, Hugh E. Williams

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








20.3 Authentication


The
authentication module consists of the
authentication.inc include file, the login and
logout scripts, and the password change scripts. The code is closely
based on that presented in Chapter 11 and we
describe it only briefly here.


20.3.1 General-Purpose Functions


Example 20-4 shows the helper functions stored in the
authentication.inc include file. The function
newUser( ) creates a new row in the
users table, and digests the password
that's passed as a parameter using the
md5( ) hash function. This is discussed in
detail in Chapter 11.

The function authenticateUser( ) checks whether
a row in the users table matches the supplied
username and password (the supplied password is digested prior to
comparison with those stored in the database). It returns
true when there's a match and
false otherwise.

The registerLogin( ) function saves the
user's username as a session variable, and also
stores the IP address from which they've accessed
the winestore. The presence of the
$_SESSION["loginUsername"] variable indicates the
user has logged in successfully. The function
unregisterLogin( ) deletes the same two session
variables.

The function sessionAuthenticate( ) checks
whether a user is logged in (by testing for the presence of
$_SESSION["loginUsername"]) and that
they're returning from the same IP address. If
either test fails, the script calls unregisterLogin(
)
and redirects to the script supplied as a parameter.
This approach won't work for all
situationsfor example, if a user's ISP
accesses the winestore through different web proxy servers, their IP
address may change. It's up to you to decide whether
this additional security step is needed in your applications. This is
discussed in more detail in Chapter 11.


Example 20-4. The authentication.inc include file



<?php
// Add a new user to the users table
function newUser($loginUsername, $loginPassword, $cust_id, $connection)
{
// Create the encrypted password
$stored_password = md5(trim($loginPassword));
// Insert a new user into the users table
$query = "INSERT INTO users SET
cust_id = {$cust_id},
password = '{$stored_password}',
user_name = '{$loginUsername}'";
$result = $connection->query($query);
if (DB::isError($result))
trigger_error($result->getMessage( ), E_USER_ERROR);
}
// Check if a user has an account that matches the username and password
function authenticateUser($loginUsername, $loginPassword, $connection)
{
// Create a digest of the password collected from the challenge
$password_digest = md5(trim($loginPassword));
// Formulate the SQL to find the user
$query = "SELECT password FROM users
WHERE user_name = '$loginUsername'
AND password = '$password_digest'";
$result = $connection->query($query);
if (DB::isError($result))
trigger_error($result->getMessage( ), E_USER_ERROR);
// exactly one row? then we have found the user
if ($result->numRows( ) != 1)
return false;
else
return true;
}
// Register that user has logged in
function registerLogin($loginUsername)
{
// Register the loginUsername to show the user is logged in
$_SESSION["loginUsername"] = $loginUsername;
// Register the IP address that started this session
$_SESSION["loginIP"] = $_SERVER["REMOTE_ADDR"];
}
// Logout (unregister the login)
function unregisterLogin( )
{
// Ensure login is not registered
if (isset($_SESSION["loginUsername"]))
unset($_SESSION["loginUsername"]);
if (isset($_SESSION["loginIP"]))
unset($_SESSION["loginIP"]);
}
// Connects to a session and checks that the user has
// authenticated and that the remote IP address matches
// the address used to create the session.
function sessionAuthenticate($destinationScript)
{
// Check if the user hasn't logged in
if (!isset($_SESSION["loginUsername"]))
{
// The request does not identify a session
$_SESSION["message"] = "You are not authorized to access the URL
{$_SERVER["REQUEST_URI"]}";
unregisterLogin( );
header("Location: {$destinationScript}");
exit;
}
// Check if the request is from a different IP address to previously
if (isset($_SESSION["loginIP"]) &&
($_SESSION["loginIP"] != $_SERVER["REMOTE_ADDR"]))
{
// The request did not originate from the machine
// that was used to create the session.
// THIS IS POSSIBLY A SESSION HIJACK ATTEMPT
$_SESSION["message"] = "You are not authorized to access the URL
{$_SERVER["REQUEST_URI"]} from the address
{$_SERVER["REMOTE_ADDR"]}";
unregisterLogin( );
header("Location: {$destinationScript}");
exit;
}
}
?>


20.3.2 Logging In and Out


The auth/login.php

and
auth/logincheck.php scripts are shown in Example 20-5 and Example 20-6 respectively.
The auth/login.php script is a straightforward
use of the winestoreFormTemplate class described
in Chapter 16, and it simply collects the
user's login name (their email address) and their
password. The
auth/logincheck.php

script validates the
username and password using functions from
validate.inc discussed in Chapter 16, and then uses the helper functions
discussed in the previous section to check the
user's credentials and complete the login process.

The

auth/logout.php
script that logs the user out is shown in Example 20-7.



Example 20-5. The auth/login.php script that collects the user's credentials


<?php
// Show the login page
require_once "../includes/template.inc";
require_once "../includes/winestore.inc";
require_once "../includes/validate.inc";
set_error_handler("customHandler");
session_start( );
// Takes <form> heading, instructions, action, formVars name, and
// formErrors name as parameters
$template = new winestoreFormTemplate("Login",
"Please enter your username and password.",
S_LOGINCHECK, "loginFormVars", "loginErrors");
$template->mandatoryWidget("loginUsername", "Username/Email:", 50);
$template->passwordWidget("loginPassword", "Password:", 8);
// Add buttons and messages, and show the page
$template->showWinestore(NO_CART, B_HOME);
?>



Example 20-6. The auth/logincheck.php that validates and checks the user's credentials


<?php
// This script manages the login process.
// It should only be called when the user is not logged in.
// If the user is logged in, it will redirect back to the calling page.
// If the user is not logged in, it will show a login <form>
require_once "DB.php";
require_once "../includes/winestore.inc";
require_once "../includes/authenticate.inc";
require_once "../includes/validate.inc";
set_error_handler("customHandler");
function checkLogin($loginUsername, $loginPassword, $connection)
{
if (authenticateUser($loginUsername, $loginPassword, $connection))
{
registerLogin($loginUsername);
// Clear the formVars so a future <form> is blank
unset($_SESSION["loginFormVars"]);
unset($_SESSION["loginErrors"]);
header("Location: " . S_MAIN);
exit;
}
else
{
// Register an error message
$_SESSION["message"] = "Username or password incorrect. " .
"Login failed.";
header("Location: " . S_LOGIN);
exit;
}
}
// ------
session_start( );
$connection = DB::connect($dsn, true);
if (DB::isError($connection))
trigger_error($connection->getMessage( ), E_USER_ERROR);
// Check if the user is already logged in
if (isset($_SESSION["loginUsername"]))
{
$_SESSION["message"] = "You are already logged in!";
header("Location: " . S_HOME);
exit;
}
// Register and clear an error array - just in case!
if (isset($_SESSION["loginErrors"]))
unset($_SESSION["loginErrors"]);
$_SESSION["loginErrors"] = array( );
// Set up a formVars array for the POST variables
$_SESSION["loginFormVars"] = array( );
foreach($_POST as $varname => $value)
$_SESSION["loginFormVars"]["{$varname}"] =
pearclean($_POST, $varname, 50, $connection);
// Validate password -- has it been provided and is the length between
// 6 and 8 characters?
if (checkMandatory("loginPassword", "password",
"loginErrors", "loginFormVars"))
checkMinAndMaxLength("loginPassword", 6, 8, "password",
"loginErrors", "loginFormVars");
// Validate email -- has it been provided and is it valid?
if (checkMandatory("loginUsername", "email/username",
"loginErrors", "loginFormVars"))
emailCheck("loginUsername", "email/username",
"loginErrors", "loginFormVars");
// Check if this is a valid user and, if so, log them in
checkLogin($_SESSION["loginFormVars"]["loginUsername"],
$_SESSION["loginFormVars"]["loginPassword"],
$connection);
?>



Example 20-7. The auth/logout.php script that logs the user out


<?php
// This script logs a user out and redirects
// to the calling page.
require_once '../includes/winestore.inc';
require_once '../includes/authenticate.inc';
set_error_handler("customHandler");
// Restore the session
session_start( );
// Check they're logged in
sessionAuthenticate(S_LOGIN);
// Destroy the login and all associated data
session_destroy( );
// Redirect to the main page
header("Location: " . S_MAIN);
exit;
?>


20.3.3 Changing Passwords



The password change feature is
implemented in the
auth/password.php

script shown in Example 20-8 and the
auth/changepassword.php

script in Example 20-9. The password change form
that's output by
auth/password.php is based on the
winestoreFormTemplate class described in Chapter 16, and requires the user to enter their
current password and two copies of their new password.



Example 20-8. The auth/password.php script that collects the user's old and new passwords


<?php
// This script shows the user a <form> to change their password
// The user must be logged in to view it.
require_once "../includes/template.inc";
require_once "../includes/winestore.inc";
require_once "../includes/authenticate.inc";
set_error_handler("customHandler");
session_start( );
// Check the user is properly logged in
sessionAuthenticate(S_MAIN);
// Takes <form> heading, instructions, action, formVars name,
// and formErrors name as parameters
$template = new winestoreFormTemplate("Change Password",
"Please enter your existing and new passwords.",
S_CHANGEPASSWORD, "pwdFormVars", "pwdErrors");
// Create the password change widgets
$template->passwordWidget("currentPassword", "Current Password:", 8);
$template->passwordWidget("newPassword1", "New Password:", 8);
$template->passwordWidget("newPassword2", "Re-enter New Password:", 8);
// Add buttons and messages, and show the page
$template->showWinestore(NO_CART, B_HOME);
?>

The auth/changepassword.php script checks that
all three passwords are supplied and that each is between 6 and 8
characters in length. It then checks that the two copies of the new
password are identical, that the new password is different to the old
one, and that the old password matches the one stored in the
users table. If all the checks pass, the new
password is digested with the md5( ) hash
function, and the users table updated with the
new value. The script then redirects to the winestore home page,
where a success message is displayed. If any check fails, the script
redirects to
auth/password.php

.



Example 20-9. The auth/changepassword.php script that validates a password change and updates the database




<?php
require_once "DB.php";
require_once "../includes/winestore.inc";
require_once "../includes/authenticate.inc";
require_once "../includes/validate.inc";
set_error_handler("customHandler");
session_start( );
// Connect to a authenticated session
sessionAuthenticate(S_MAIN);
$connection = DB::connect($dsn, true);
if (DB::isError($connection))
trigger_error($connection->getMessage( ), E_USER_ERROR);
// Register and clear an error array - just in case!
if (isset($_SESSION["pwdErrors"]))
unset($_SESSION["pwdErrors"]);
$_SESSION["pwdErrors"] = array( );
// Set up a formVars array for the POST variables
$_SESSION["pwdFormVars"] = array( );
foreach($_POST as $varname => $value)
$_SESSION["pwdFormVars"]["{$varname}"] =
pearclean($_POST, $varname, 50, $connection);
// Validate passwords - between 6 and 8 characters
if (checkMandatory("currentPassword", "current password",
"pwdErrors", "pwdFormVars"))
checkMinAndMaxLength("loginPassword", 6, 8, "current password",
"pwdErrors", "pwdFormVars");
if (checkMandatory("newPassword1", "first new password",
"pwdErrors", "pwdFormVars"))
checkMinAndMaxLength("newPassword1", 6, 8, "first new password",
"pwdErrors", "pwdFormVars");
if (checkMandatory("newPassword2", "second new password",
"pwdErrors", "pwdFormVars"))
checkMinAndMaxLength("newPassword2", 6, 8, "second new password",
"pwdErrors", "pwdFormVars");
// Did we find no errors? Ok, check the new passwords are the
// same, and that the current password is different.
// Then, check the current password.
if (count($_SESSION["pwdErrors"]) == 0)
{
if ($_SESSION["pwdFormVars"]["newPassword1"] !=
$_SESSION["pwdFormVars"]["newPassword2"])
$_SESSION["pwdErrors"]["newPassword1"] =
"The new passwords must match.";
elseif ($_SESSION["pwdFormVars"]["newPassword1"] ==
$_SESSION["pwdFormVars"]["currentPassword"])
$_SESSION["pwdErrors"]["newPassword1"] =
"The password must change.";
elseif (!authenticateUser($_SESSION["loginUsername"],
$_SESSION["pwdFormVars"]["currentPassword"],
$connection))
$_SESSION["pwdErrors"]["currentPassword"] =
"The current password is incorrect.";
}
// Now the script has finished the validation,
// check if there were any errors
if (count($_SESSION["pwdErrors"]) > 0)
{
// There are errors. Relocate back to the password form
header("Location: " . S_PASSWORD);
exit;
}
// Create the encrypted password
$stored_password = md5(trim($_SESSION["pwdFormVars"]["newPassword1"]));
// Update the user row
$query = "UPDATE users SET password = '$stored_password'
WHERE user_name = '{$_SESSION["loginUsername"]}'";
$result = $connection->query($query);
if (DB::isError($result))
trigger_error($result->getMessage( ), E_USER_ERROR);
// Clear the formVars so a future <form> is blank
unset($_SESSION["pwdFormVars"]);
unset($_SESSION["pwdErrors"]);
// Set a message that says
that the page has changed
$_SESSION["message"] = "Your password has been successfully changed.";
// Relocate to the customer details page
header("Location: " . S_DETAILS);
?>


/ 176