login
+---------------+-------------+------+-----+---------+----------------+
| Field | Type |
Null |
Key |
Default | Extra |
+---------------+-------------+------+-----+---------+----------------+
| loginid | int
(11) | NO | PRI |
NULL | auto_increment |
| loginnm | varchar
(64) | NO | | | |
| password | varchar
(32) | NO | | | |
| memberid | int
(11) | NO | | | |
| createddttm | datetime | NO | | | |
| validateddttm | datetime | YES | |
NULL | |
| lastlogindttm | datetime | YES | |
NULL | |
| activeflg | bit
(1) | NO | | | |
| memberlevel | int
(11) | YES | |
NULL | |
+---------------+-------------+------+-----+---------+----------------+
sessions
+----------------+-------------+------+-----+---------+-------+
| Field | Type |
Null |
Key |
Default | Extra |
+----------------+-------------+------+-----+---------+-------+
| phpsessid | varchar
(32) | NO | PRI | | |
| loginid | int
(11) | YES | |
NULL | |
| lastupdatedttm | datetime | NO | | | |
+----------------+-------------+------+-----+---------+-------+
<?
// db.php
// This file is used to connect to the MySQL database
// It also includes some useful/common database functions.
// hard-coded parameters: replace as needed for your setup
$dbhost =
"mysql.yourDomain.tld";
$dbuser =
"yourDatabaseUser";
$dbpass =
"yourPassword";
// dbConnect() function: called prior to making a query
function dbConnect
($db=
"yourDatabaseName") {
global $dbhost,
$dbuser,
$dbpass;
$dbcnx = @
mysql_connect($dbhost,
$dbuser,
$dbpass,
false,
65536)
or
die("The site database appears to be down.");
if ($db!=
"" and !@
mysql_select_db($db))
die("The site database is unavailable.");
return $dbcnx;
}
// The dbparse function will format input to help
// prevent SQL injection
function dbparse
($value)
{
// Stripslashes
if (get_magic_quotes_gpc()) {
$value=
stripslashes($value);
}
// Quote if not integer
if (!
is_numeric($value)) {
$value =
"'" .
mysql_real_escape_string($value) .
"'";
}
return $value;
}
// The execsql function is how we call queries.
// NOTE: every query I use is designed to return some values.
// Null or empty recordsets will return an error.
// Also note the hack around MySQL's inability to return user-defined
// error codes from stored routines (the 'unknown table' hack)
function execsql
($qry) {
global $errorCode,
$errorMsg;
$errorCode=
0;
$errorMsg=
"";
dbConnect
();
$result =
mysql_query($qry);
if(mysql_error()!=
"")
{
$errorCode =
-1;
$errorMsg =
mysql_error();
if(substr($errorMsg,
0,
15) ==
"Unknown table '")
{
$errorMsg =
substr($errorMsg,
strpos($errorMsg,
"'")+1,
(strlen($errorMsg)-
strpos($errorMsg,
"'"))-2);
}
unset($result);
}
else
{
if(!
$result)
{
error
("$_SERVER[PHP_SELF]\\nNo Result from query.");
}
if(mysql_num_rows($result)==
0)
{
error
("$_SERVER[PHP_SELF]\\nInvalid result set from query.");
}
}
return $result;
}
// The "error" function: pops up a window with the error message.
// I normally don't put this here, but I think it will work:
function error
($msg) {
?>
<html><head>
<script language=
"JavaScript">
<!--
alert
("<?=$msg?>");
history.back
();
//-->
</script>
</head><body></body></html>
<?
exit;
}
?>
<?
// hereiam.php
// This script maintains entries in the sessions
// table of the database. The sessions are used
// for security.
include_once 'path/to/db.php';
$myPhpsessid =
isset($_COOKIE['PHPSESSID']) ?
$_COOKIE['PHPSESSID'] :
'';
if($myPhpsessid!=
'') {
dbConnect
();
$qry=
sprintf("call prc_hereiam(%s)",dbparse
($myPhpsessid));
$result=
mysql_query($qry);
if(!
$result)
{
error
('HereIAm.php\\nNo Result from Database.');
}
$row =
mysql_fetch_row($result);
$sessionLoginId =
$row[0];
$sessionMemberLevel =
$row[1];
}
?>
begin
declare outLoginId int;
declare outMemberLevel int;
DELETE
FROM sessions
WHERE lastupdatedttm <= date_add(now(),interval -10 minute);
IF((SELECT count(*) FROM sessions WHERE phpsessid=varPHPSessID)>0) then
UPDATE sessions
SET lastupdatedttm = now()
WHERE phpsessid = varPHPSessID;
else
INSERT sessions (
phpsessid,
lastupdatedttm
)
VALUES (
varPHPSessID,
now()
);
end IF;
SELECT login.loginid,
login.memberlevel
INTO outLoginId,
outMemberLevel
FROM login,
sessions
WHERE sessions.loginid = login.loginid
AND sessions.phpsessid=varPHPSessID
AND login.activeflg = 1;
IF(isnull(outLoginId)=1) then
SET outLoginId = 0,
outMemberLevel = 0;
end IF;
SELECT outLoginId,
outMemberLevel;
commit;
end
<?
// secure1.php
// The basic security: user must be logged in and have a security level
// of 1 or higher. The $securityLevel is a hack - there's definately a
// better way to do this. But for pages that require a higher security
// level, this file could be coppied and $securityLevel changed to
// something higher.
include_once 'path/to/hereiam.php';
include_once 'path/to/processloginform.php';
$securityLevel =
1;
if($sessionLoginId==
0 ||
$sessionMemberLevel <
$securityLevel) {
if($errorMsg!=
"") {
?>
<div
class=
"error">
<?=
$errorMsg?>
</div>
<?
}
?>
<!--
This form uses div nodes and CSS to control the layout.
See the CSS
file to adjust the layout of the form.
-->
<div id=
"loginformdiv">
<form id=
"loginform" name=
"loginform" method=
"post" action=
"<?=$_SERVER['PHP_SELF']?>">
<div
class=
"insideform">
<div
class=
"loginformtitle">
<p>Members Login:</p>
</div>
<div
class=
"loginformrow">
<div
class=
"loginformcolleft">
Login Name:
</div>
<div
class=
"loginformcolright">
<input type=
"text" name=
"loginname" value=
"<?=$formloginname?>" />
</div>
</div>
<div
class=
"loginformrow">
<div
class=
"loginformcolleft">
Password:
</div>
<div
class=
"loginformcolright">
<input type=
"password" name=
"pass" value=
"<?=$formpassword?>"/>
</div>
</div>
<div
class=
"loginformrow">
<div
class=
"loginformcolleft">
</div>
<div
class=
"loginformcolright">
<input type=
"submit" name=
"submit" value=
"Login" />
</div>
</div>
</div>
</form>
</div>
<?
die;
// If the user is allowed to see the page, nothing is displayed.
}
?>
#loginformdiv {
float: left;
margin: 20px;
}
#loginformdiv div {
margin: 0px;
padding: 0px;
border: 0px;
}
#loginform{
width: 400px;
border-top: 2px solid #ddd;
border-left: 2px solid #ddd;
border-bottom: 2px solid #999;
border-right: 2px solid #999;
float: left;
}
#loginformdiv .loginformtitle {
background: #346800;
color: #fff;
border-bottom: 1px solid #ddd;
padding-left: 20px;
}
#loginformdiv .loginformrow {
background: #ddd;
float: left;
padding: 3px 0 3px 0;
}
#loginformdiv .loginformcolleft {
width: 150px;
text-align: right;
float: left;
}
#loginformdiv .loginformcolright {
width: 240px;
text-align: left;
float: right;
}
.error {
color: #f00;
background: #eee;
width: 80%;
padding: 2px;
margin: 2px;
border-top: 2px solid #aaa;
border-left: 2px solid #aaa;
border-right: 2px solid #333;
border-bottom: 2px solid #333;
}
<?
// processLoginForm.php
// This PHP file is responsible for processing the
// Login form and setting the value in the Sessions table
// It is called from the secure1.php file.
$postloginname =
isset($_POST['loginname']) ?
$_POST['loginname'] :
'';
$postpassword =
isset($_POST['pass']) ?
$_POST['pass'] :
'';
$postsubmit =
isset($_POST['submit']) ?
$_POST['submit'] :
'';
$myPhpsessid =
isset($_COOKIE['PHPSESSID']) ?
$_COOKIE['PHPSESSID'] :
'';
$formpassword =
$postpassword;
$formloginname =
$postloginname;
if($postsubmit!=
"" &&
$postloginname!=
"" &&
$postpassword !=
"")
{
$qry =
sprintf("call prc_login(%s, %s, %s)",
dbparse
($postloginname),
dbparse
($postpassword),
dbparse
($myPhpsessid));
$result=execsql
($qry);
if($result)
{
$row =
mysql_fetch_row($result);
$sessionLoginId =
$row[0];
$sessionMemberLevel =
$row[1];
}
}
?>
begin
declare varLoginId int;
SELECT loginid
INTO varLoginId
FROM login
WHERE loginnm = varLoginName
AND password(varPassword) = password
AND activeflg = 1
AND validateddttm IS NOT NULL;
IF (isnull(varLoginId)) then
DROP TABLE `Error: Invalid login name or password`;
end IF;
UPDATE sessions
SET loginid = varLoginId
WHERE phpsessid = varPHPSessId;
IF (isnull(varLoginId)=0) then
UPDATE login
SET lastlogindttm = now()
WHERE loginid = varLoginId;
end IF;
SELECT loginid,
memberlevel
FROM login
WHERE loginid = varLoginId;
commit;
end
So that's it. If you include secure1.php on any php page, the user must login to see the page. The user is logged out after 10 minutes of inactivity (the browser won't update after 10 mintues, but if they try to view a secure page, they'll be asked to login again). A secure2.php (or 3.php or 10.php) may also be created and included instead of secure1.php. A user may view pages with a security level equal to or below his own security level.
I know it's a lot. I've seen other people put up their "authentication" methods to be cut to shreds. SQL Injection, etc - everyone has their own concerns. This, I feel, is a tidy way to keep things secure. The session cookie is used, but holds no user-identifiable information. You'd need to read the database to find out what the session value means, and even then, you won't get a useful password.
Let me know what ya think. Peace.