Simple PHP/MySQL authentication/login class
Here is a simple PHP/MySQL authentication/login script (class) that is secure and easy to use. The class features:
- Login form
- Password recovery with basic email injection protection
- Optional md5 password encryption
- MySQL logon table creation
- MySQL injection protection
- Page password protection
MySQL table
The only requirement for the table is that the username stores emails, because it is used for password recovery.
CREATE TABLE `logon` ( `userid` int(11) NOT NULL auto_increment, `useremail` varchar(50) NOT NULL default '', `password` varchar(50) NOT NULL default '', `userlevel` int(1) NOT NULL default '0', PRIMARY KEY (`userid`) ) TYPE=MyISAM
PHP Class (class.login.php)
IMPORTANT: Make sure to fill in the database info. See comments for the details.
<?php
//For security reasons, don't display any errors or warnings. Comment out in DEV.
error_reporting(0);
//start session
session_start();
class logmein {
//database setup
//MAKE SURE TO FILL IN DATABASE INFO
var $hostname_logon = 'localhost'; //Database server LOCATION
var $database_logon = ''; //Database NAME
var $username_logon = ''; //Database USERNAME
var $password_logon = ''; //Database PASSWORD
//table fields
var $user_table = 'logon'; //Users table name
var $user_column = 'useremail'; //USERNAME column (value MUST be valid email)
var $pass_column = 'password'; //PASSWORD column
var $user_level = 'userlevel'; //(optional) userlevel column
//encryption
var $encrypt = false; //set to true to use md5 encryption for the password
//connect to database
function dbconnect(){
$connections = mysql_connect($this->hostname_logon, $this->username_logon, $this->password_logon) or die ('Unabale to connect to the database');
mysql_select_db($this->database_logon) or die ('Unable to select database!');
return;
}
//login function
function login($table, $username, $password){
//conect to DB
$this->dbconnect();
//make sure table name is set
if($this->user_table == ""){
$this->user_table = $table;
}
//check if encryption is used
if($this->encrypt == true){
$password = md5($password);
}
//execute login via qry function that prevents MySQL injections
$result = $this->qry("SELECT * FROM ".$this->user_table." WHERE ".$this->user_column."='?' AND ".$this->pass_column." = '?';" , $username, $password);
$row=mysql_fetch_assoc($result);
if($row != "Error"){
if($row[$this->user_column] !="" && $row[$this->pass_column] !=""){
//register sessions
//you can add additional sessions here if needed
$_SESSION['loggedin'] = $row[$this->pass_column];
//userlevel session is optional. Use it if you have different user levels
$_SESSION['userlevel'] = $row[$this->user_level];
return true;
}else{
session_destroy();
return false;
}
}else{
return false;
}
}
//prevent injection
function qry($query) {
$this->dbconnect();
$args = func_get_args();
$query = array_shift($args);
$query = str_replace("?", "%s", $query);
$args = array_map('mysql_real_escape_string', $args);
array_unshift($args,$query);
$query = call_user_func_array('sprintf',$args);
$result = mysql_query($query) or die(mysql_error());
if($result){
return $result;
}else{
$error = "Error";
return $result;
}
}
//logout function
function logout(){
session_destroy();
return;
}
//check if loggedin
function logincheck($logincode, $user_table, $pass_column, $user_column){
//conect to DB
$this->dbconnect();
//make sure password column and table are set
if($this->pass_column == ""){
$this->pass_column = $pass_column;
}
if($this->user_column == ""){
$this->user_column = $user_column;
}
if($this->user_table == ""){
$this->user_table = $user_table;
}
//exectue query
$result = $this->qry("SELECT * FROM ".$this->user_table." WHERE ".$this->pass_column." = '?';" , $logincode);
$rownum = mysql_num_rows($result);
//return true if logged in and false if not
if($row != "Error"){
if($rownum > 0){
return true;
}else{
return false;
}
}
}
//reset password
function passwordreset($username, $user_table, $pass_column, $user_column){
//conect to DB
$this->dbconnect();
//generate new password
$newpassword = $this->createPassword();
//make sure password column and table are set
if($this->pass_column == ""){
$this->pass_column = $pass_column;
}
if($this->user_column == ""){
$this->user_column = $user_column;
}
if($this->user_table == ""){
$this->user_table = $user_table;
}
//check if encryption is used
if($this->encrypt == true){
$newpassword_db = md5($newpassword);
}else{
$newpassword_db = $newpassword;
}
//update database with new password
$qry = "UPDATE ".$this->user_table." SET ".$this->pass_column."='".$newpassword_db."' WHERE ".$this->user_column."='".stripslashes($username)."'";
$result = mysql_query($qry) or die(mysql_error());
$to = stripslashes($username);
//some injection protection
$illegals=array("%0A","%0D","%0a","%0d","bcc:","Content-Type","BCC:","Bcc:","Cc:","CC:","TO:","To:","cc:","to:");
$to = str_replace($illegals, "", $to);
$getemail = explode("@",$to);
//send only if there is one email
if(sizeof($getemail) > 2){
return false;
}else{
//send email
$from = $_SERVER['SERVER_NAME'];
$subject = "Password Reset: ".$_SERVER['SERVER_NAME'];
$msg = "
Your new password is: ".$newpassword."
";
//now we need to set mail headers
$headers = "MIME-Version: 1.0 rn" ;
$headers .= "Content-Type: text/html; \r\n" ;
$headers .= "From: $from \r\n" ;
//now we are ready to send mail
$sent = mail($to, $subject, $msg, $headers);
if($sent){
return true;
}else{
return false;
}
}
}
//create random password with 8 alphanumerical characters
function createPassword() {
$chars = "abcdefghijkmnopqrstuvwxyz023456789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= 7) {
$num = rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
//login form
function loginform($formname, $formclass, $formaction){
//conect to DB
$this->dbconnect();
echo'
<form name="'.$formname.'" method="post" id="'.$formname.'" class="'.$formclass.'" enctype="application/x-www-form-urlencoded" action="'.$formaction.'">
<div><label for="username">Username</label>
<input name="username" id="username" type="text"></div>
<div><label for="password">Password</label>
<input name="password" id="password" type="password"></div>
<input name="action" id="action" value="login" type="hidden">
<div>
<input name="submit" id="submit" value="Login" type="submit"></div>
</form>
';
}
//reset password form
function resetform($formname, $formclass, $formaction){
//conect to DB
$this->dbconnect();
echo'
<form name="'.$formname.'" method="post" id="'.$formname.'" class="'.$formclass.'" enctype="application/x-www-form-urlencoded" action="'.$formaction.'">
<div><label for="username">Username</label>
<input name="username" id="username" type="text"></div>
<input name="action" id="action" value="resetlogin" type="hidden">
<div>
<input name="submit" id="submit" value="Reset Password" type="submit"></div>
</form>
';
}
//function to install logon table
function cratetable($tablename){
//conect to DB
$this->dbconnect();
$qry = "CREATE TABLE IF NOT EXISTS ".$tablename." (
userid int(11) NOT NULL auto_increment,
useremail varchar(50) NOT NULL default '',
password varchar(50) NOT NULL default '',
userlevel int(11) NOT NULL default '0',
PRIMARY KEY (userid)
)";
$result = mysql_query($qry) or die(mysql_error());
return;
}
}
?>
Usage
This class can be used in many different scenarios, from traditional redirection to AJAX implementation.
Instantiate the Class
Make sure to include and instantiate the class on every page you use it.
include("class.login.php");
$log = new logmein(); //Instentiate the class
$log->dbconnect(); //Connect to the database
$log->encrypt = true; //set to true if password is md5 encrypted. Default is false.
Create Log on Table
Run this code only once to create the log on table.
include("class.login.php");
$log = new logmein();
$log->cratetable('logon');
Display Login Form
The login form takes in Class and ID parameters for easy styling with CSS, and form action parameter. If needed the form includes a hidden field “action” set to “log in“.
include("class.login.php");
$log = new logmein();
$log->encrypt = true; //set encryption
//parameters here are (form name, form id and form action)
$log->loginform("loginformname", "loginformid", "form_action.php");
Display Password Reset Form
Just like the login form, the password reset form takes in Class, ID and form action parameters. If needed the form includes a hidden field “action” set to “resetlogin“.
include("class.login.php");
$log = new logmein();
$log->encrypt = true; //set encryption
//parameters here are (form name, form id and form action)
$log->resetform("resetformname", "resetformid", "form_action.php");
Password Protect a Page
Place this code on top of every page you want to password protect.
include("class.login.php");
$log = new logmein();
$log->encrypt = true; //set encryption
//parameters are(SESSION, name of the table, name of the password field, name of the username field)
if($log->logincheck($_SESSION['loggedin'], "logon", "password", "useremail") == false){
//do something if NOT logged in. For example, redirect to login page or display message.
}else{
//do something else if logged in.
}
Login
Place this code inside the form action script. For example, in this tutorial I am using “form_action.php” as my form action script.
//instantiate if needed
include("class.login.php");
$log = new logmein();
$log->encrypt = true; //set encryption
if($_REQUEST['action'] == "login"){
if($log->login("logon", $_REQUEST['username'], $_REQUEST['password']) == true){
//do something on successful login
}else{
//do something on FAILED login
}
}
Log out
Place this code inside the script that is executed when user want’s to log out.
include("class.login.php");
$log = new logmein();
$log->encrypt = true; //set encryption
//Log out
$log->logout();
//do something
Reset Password
Place this code inside the script that will run when password recovery is requested.
include("class.login.php");
$log = new logmein();
$log->encrypt = true; //set encryption
if($_REQUEST['action'] == "resetlogin"){
if($log->passwordreset($_REQUEST['username'], "logon", "password", "useremail") == true){
//do something on successful password reset
}else{
//do something on failed password reset
}
}
Download Class
Do you like this script? Download updated packaged file:

MAWMTZF
HOW ARE YOU, YOURE TUTORIAL LOOKS INTERESTING, BUT IT NEEDS MORE FILES ON THE DOWNLOAD,BUT I DONT SEE NO FORM THAT ACCTUALLY GOT THE INPUT SPACES. AND HOW IT WILL BE LINKED? IF YOU CAN ANSWER ILL APPRITIATTE! CHEERS!
MAWMTZF
AND THE TABLE , SHOULD BE IN A PHP DOCUMENT RIGHT?.
eplicanic
Yes. Everything you need is in the class. Reference examples above for help. Cheers!
db
Thanks for the script! I’m currently using it but noticed a few problems I had to correct.
1. When resetting the password it doesn’t seem verify that the user exists within the database. This allows password reset emails to be sent out to anyone as long as their email address is typed in the password reset box.
2. If using the MD5 hash password, the password reset email includes the hashed password, not the plain text one. Simple enough fix though…
Thanks again for the script! I’m loving it
eplicanic
Thanks db! I’ll make some edits and repost!
Dan
First of all, very nice script! I cannot tell by looking at your code, but is there any way the user can change their password? Especially if they forget it, and have it reset. The reset password is likely not easy to remember. I will take a closer look at your code and I guess adding that functinoality myself shouldn’t be too much trouble.
eplicanic
Thanks Dan! And you are right that function would add value to this script. I’ll try to add it in as soon as I get some free time!
Michael
I’ve tried the script and in the “form_action” page I receive an error telling me that there is an unexpected ‘{‘ on line 7. Thoughts?
Chris
You’re a legend! You’ve just saved me so much work. What might otherwise have taken me potentially weeks took me 4 hours.
Cheers!
eplicanic
Thank! You just made my day
Francois
Looks promising, I’ll give it a try. HOWEVER…
* do not use the word “encryption” when you mean “hashing”.
* PLEASE do not use or store MD5. This is weak.
* replace the md5() function by hash_hmac() and
* use a strong hash algo (none of MD*. SHA256 is a good start).
* use a 32 char secret (256 bit key)
* Never do a DB authentication by doing a select with the password in the WHERE clause. Instead fetch the password from the DB and compare it programatically against what was provided.
* You do a dbconnect in each and every function, is this necessary?
* Any plans on using mysqli API instead?
eplicanic
Thanks for your feedback! I totally agree that the class can be improved and when I initially wrote it, it was to help people implement something SIMPLE, hence the name of the class
Data Grid Control – AJAX/PHP »
[...] also added an authentication piece which I found some base code here: Authentication Class Posted by nightshadow at 9:38 [...]
Woozle
Just supported your software but didn’t get a link or anything for the “package”
Emir plicanic
Thanks for your support! Sometimes it can take some time for the server to generate your download link. If you didn’t get it, let me know and I’ll email it to you.
Chavewain
Excelent script, but need hosted examples to use it
Luciano
I’m having problems with the code. I get the following error:
Error in query: SELECT *, MATCH (title,desc) AGAINST (‘LUCHO’) AS score FROM logon WHERE MATCH (title,desc) AGAINST (‘+LUCHO’ IN BOOLEAN MODE) HAVING score > 0.01 ORDER BY score DESC. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘desc) AGAINST (‘LUCHO’) AS score FROM logon WHERE MATCH (title,desc) AGAINST (‘+’ at line 1
Could you please help me ?
Thank you.
Clayton Smith
Thanks so much, I learned a lot about sessions, authentication and sql injection prevention all from your script.
Cheers!
-Clayton
John
I like your authentication and im buying it soon. i would like to ask if i can enable access level? let say i have a page where i cant a level 2 access then another page that need a level 4 as admin. can i do that in your script? thanks a lot.
John
emir please answer my question if the script can support access level. thanks
eplicanic
A table column “userlevel” stores that info. What you need to add is the code that sends users to their level pages. Sorry I can’t be more helpful and for the late response! I’m on the road riding my bicycle across the US (http://theuntour.com)
steve
can i integrate this into phpbb3 or wordpress?
Ross Ackland
Hi, only thing missing is a method to create a **new** user.
Jesse Z
Emir, this is great – just what I’ve been looking for. My only request would be adding the account creation form + code to insert the new user into the database. I know you are away, so I’m going to attempt to write this. If I get a decent version done I’ll send it to you.
Basic access authentication application using xcode
[...] know is from the server side what i need to create is it a web application to handle this request ? like this Link can any one provide me with this information ? i don’t have experience in [...]
Tommy
Dude… THANKYOU. You just saved me a good few hours.
A site I’m developing uses a CMS, but the admin area only relies on one user, and the username/password was read from a config file.
This was insanely easy to implement into the existing code.
Thanks!
Tom
Rob
I am getting the following error. Any ideas why?
Undefined variable: row at /home/site/public_html/trade/class.login.php (107), timed at 09-Jan-2012 09:57:41
Array
(
[logincode] => tenty23
[user_table] => logon
[pass_column] => password
[user_column] => useremail
[result] => Resource id #4
[rownum] => 5
)
Darrell
I purchased and downloaded the script. I’m not great with code… more of a designer. After making changes to the script to connect to database I received the following error messages:
Just loading the page without doing anything i got this:
Search Error
Your keyword has to be at least two characters long!
I entered a search word ( item in database ) and I get this error message:
Error in query: SELECT *, MATCH (product,brand) AGAINST (‘Samsung’) AS score FROM sample_db WHERE MATCH (product,brand) AGAINST (‘+Samsung’ IN BOOLEAN MODE) HAVING score > 0.01 ORDER BY score DESC. Can’t find FULLTEXT index matching the column list
Not sure what to do at this point. Please help.
Dave
I just purchased —- how do I DL?
Basil
Please can you show me how can i used your class with Ajax.
Omar
Well i want to try it but the recent comments say that people had trouble DLing
eplicanic
Payment processing is done by PayPal and download link is generated dynamically. It can take few minutes for the link to be emailed to the purchaser. The comments about downloading are from people who didn’t wait enough to get it. Thus, rest assured that everyone who purchased the script also got it!
Remi
Hello eplicanic,
I paid for this script and no more news from PayPal or you.
What can I do to get what I paid for?
eplicanic
Remi, you should have received an email with a download link. Please check your junk mail folders. It usually takes fee minutes from the time PayPal processes the payment to when the download link is generated and sent to you.
Remi
OK found it now!
Thanks a lot