MySQL and PHP simple login system 05-08-2013, 07:01 PM
#1
Code:
#############################################################
## Setting up a simple MySQL database and a PHP login page ##
## PHP and MySQL tutorial by noize ##
#############################################################
In this paper I'm going to show you how to set up a PHP login page, a MySQL database and a table for the user records.
First of all, you'll need a database. I suppose you already know how to get one. If you'd like to use a free web-host, I'd suggest Altervista.
If you're using a free web-host you should easily find your way to create a database. On Altervista, for instance, you can click on Database under the File management tab (I think) in the nav bar. Choose to get a new free database, and then click again on the database tab in the nav bar. Now, follow the link to PHPMyAdmin's control panel, enter the same credentials that you use to enter the Altervista control panel and you're in.
You shouldn't either have a hard time finding the SQL query input box.
When you find it, enter this SQL statement:
Code:
CREATE TABLE users (
id int NOT NULL AUTO_INCREMENT,
username varchar(250),
password varchar(50),
is_admin tinyint(1) DEFAULT 0,
PRIMARY KEY(id)
);
A "users" table should appear. But let's take a deeper look into the query.
We're telling the database to create a table called "users", which should have 4 columns. Those columns are "id", "username", "password" and "is_admin". We're also defining the column types. The ID column will contain integers, always different from NULL and auto-incremential. So, let's say we've got a signup page, and a user signs up. He enters his username and password, and the database automatically gives him an ID which will be 1. The second user will have ID 2. Even if we now cleared those rows from the table, the third user would still have ID 3. We could reset or change the auto-incremential int point manually, or using TRUNCATE TABLE (resets the whole table) or DROP TABLE (deletes the table). After this, we're saying that the username can be up to 250 characters long, while password can hold up to 50 chars only. TINYINT(1), for "is_admin", says that it can be an integer between 0 and 255 (or between -128 and 127, being either signed or unsigned). We're in the end defining "id" as the primary key. Now, each table must have a primary key, and each table must have only one primary key. The primary key is the key which the table is sorted by. So, we will have something like this:
id username password is_admin
1 admin admin 1
2 name pass 0
3 user pass 0
Now, let's insert a user in the table, so we'll be able to log in.
Enter the following query:
Code:
INSERT INTO users(username,password) VALUES ('user','test');
or replace the VALUES with what you'd prefer.
Now, let's go to the login part. First, you'd better make a connect.php page (or call it whatever you like) containing this script (or you might just hardcode them in the login page, but it's not advised):
PHP Code:
<?php
DEFINE ('DB_USER', 'YOURUSERNAME');
DEFINE ('DB_PASSWORD', '');
DEFINE ('DB_HOST', 'localhost');
DEFINE ('DB_NAME', 'YOURDBNAME');
$con = @mysql_connect (DB_HOST, DB_USER, DB_PASSWORD) OR die ('Failed to connect to MySQL: ' . mysql_error());
@mysql_select_db (DB_NAME) OR die('Failed to select the database: ' . mysql_error() );
?>
The above code establishes a connection with the database using the login credentials (if you are using Altervista, your username is the one you use to login, you don't have any password and your database name is your username after a "my_" (e.g: my_yourname)).
Why is it useful to leave this code in a separate page and to call it from all of the pages who need it? Let's say you'll change the password, you won't have to change the hardcoded password in all of the files requiring a connection to the database, but just in this one, as in others you'll just use this code:
PHP Code:
require_once('connect.php');
You can use require_once() for nav bars, side menus, or pretty much anything required in all/most of the pages on your website. This way it's like having a template in a few files, which is used by all other pages.
Now, to the login.
PHP Code:
<?php
require_once('connect.php'); // connects to the db
if (isset($_POST['submit'])) { // if the user clicked on the submit button
session_start();
$username = $_POST['user'];
$password = $_POST['pass'];
$query = sprintf("SELECT COUNT(id) FROM users WHERE UPPER(username) = UPPER('%s') AND password='%s'",
mysql_real_escape_string($username),
mysql_real_escape_string($password));
$result = mysql_query($query);
list($count) = mysql_fetch_row($result);
if ($count == 1) { // if we found the user/pass combination
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $username;
$query = sprintf("SELECT is_admin FROM users WHERE UPPER(username) = UPPER('%s') AND password='%s'",mysql_real_escape_string($username),mysql_real_escape_string(($password)));
$result = mysql_query($query);
list($is_admin) = mysql_fetch_row($result);
if ($is_admin == 0) {
header('Location: user.php');
} else {
header('Location: admin/index.php');
}
} else { // we didn't find the user/pass combination
?>
<span style='color:red'>Error: username/password combination does not exist!</span>
<?php
}
}
$username = $_SESSION['username'];
if ($username) {
echo 'You are logged in as ' . htmlentities($username) . '.'; // by using htmlentities() we replace special characters with their respective HTML entities to prevent XSS
} else {
?>
<form method="post" action="">
<input type="text" name="user" />
<input type="password" name="pass" />
<input type="submit" value="Log in" />
<input type="hidden" name="submit" />
</form>
<?php
}
?>
Demo video here: http://www.youtube.com/watch?edit=vd&v=SCi_ks8ug88 .
Thanks to @Psycho_Coder for syntax correction and demo uploading (which thing I was apparently too lazy to do).
You could have a post-log-in page with something like this:
PHP Code:
<?php
require_once 'connect.php' ;
$username = $_SESSION['username'];
echo "You are logged in as " . $username . ".";
?>
Save the above script as user.php and then try logging in from login.php.
And what if you have page.php, and you want only logged users to access it? I call the following check.php. You shall require it in each page where only logged in users can access.
PHP Code:
<?php
require_once 'connect.php';
session_start();
$query = sprintf("SELECT id FROM users WHERE UPPER(username) = UPPER('%s')",
mysql_real_escape_string($_SESSION['username']));
$result = mysql_query($query);
list($userID) = mysql_fetch_row($result);
if (!$userID) { // user ain't logged
header('Location: login.php'); // we take him to the login.php page
}
// else, if he's logged in, we retrieve his privilege level and set it to the
// variable $is_admin, so we could use it in all pages where this is required
$username = $_SESSION['username'];
$result = mysql_query("SELECT * from users WHERE username='$username'");
$row = mysql_fetch_array($result);
$is_admin = $row['is_admin'];
?>
Many complained that this is not secure at all. It's not and it's not supposed to be either. It's just a login system, but 'cause of all these comments, I'm going to provide a safe code for the login.php page:
PHP Code:
<?
require_once('connect.php'); // connects to the db
if (isset($_POST['submit'])) { // if the user clicked on the submit button
session_start();
$username = $_POST['user'];
$password = md5($_POST['pass']);
$query = sprintf("SELECT COUNT(id) FROM users WHERE UPPER(username) = UPPER('%s') AND password='%s'",
mysql_real_escape_string($username),
mysql_real_escape_string($password));
$result = mysql_query($query);
list($count) = mysql_fetch_row($result);
if ($count == 1) { // if we found the user/pass combination
$_SESSION['authenticated'] = true;
$_SESSION['username'] = htmlentities($username);
$query = sprintf("SELECT is_admin FROM users WHERE UPPER(username) = UPPER('%s') AND password='%s'",mysql_real_escape_string($username),mysql_real_escape_string($password));
$result = mysql_query($query);
list($is_admin) = mysql_fetch_row($result);
if ($is_admin == 0) {
header('Location: user.php');
} else {
header('Location: admin/index.php');
}
} else { // we didn't find the user/pass combination
?>
<span style='color:red'>Error: username/password combination does not exist!</span>
<?php
}
}
$username = $_SESSION['username'];
if ($username) {
echo 'You are logged in as ' . htmlentities($username) . '.'; // by using htmlentities() we replace special characters with their respective HTML entities to prevent XSS
} else {
?>
<form method="post" action="">
<input type="text" name="user" />
<input type="password" name="pass" />
<input type="submit" value="Log in" />
<input type="hidden" name="submit" />
</form>
<?php
}
?>
A few security measures were already implemented in the first script, but here some (fundamental ones) have been added.
A look over all of the security measures used in this latest script:
- retrieved username and password are passed to the database only after having been filtered using mysql_real_escape_string(), which avoids SQL injection possibilities by filtering special SQL characters;
- retrieved password is stored only after having been hashed using the MD5 algorithm, so that if an attacker should get access to your database, he still wouldn't have the users' passwords (hashing algorithms are not reversable, only crackable);
- we're filtering the $username variable, which might be later output from you for any reason, using htmlentities() to prevent cross-site scripting.
My Bitcoin address: 1AtxVsSSG2Z8JfjNy9KNFDUN6haeKr7LiP
Give me money by visiting www.google.com here: http://coin-ads.com/6Ol83U
If you want a Bitcoin URL shortener/advertiser, please, use this referral: http://coin-ads.com/register.php?refid=noize
Give me money by visiting www.google.com here: http://coin-ads.com/6Ol83U
If you want a Bitcoin URL shortener/advertiser, please, use this referral: http://coin-ads.com/register.php?refid=noize