How To Salt, Hash and Store Passwords Securely?

What is password hashing?

It turns a string (of any length) to a fixed length “fingerprint” that cannot be reversed. For example, my password is “i1love2coding3″, when hashed, it can be converted to a 60 character “ytwqwxpbx1oxbfvmpoaafckmat2zkdsjaxs…” which will be stored to the database.

RELATED: PHP Login Script with Session Tutorial – Step by Step Guide!

Why do we have to hash passwords?

I think the main reason why we have to hash passwords is to prevent passwords from being stolen or compromised.

You see, even if someone steal your database, they will never read your actual or cleartext password.

I know that some PHP frameworks or CMS already provide this functionality, but I believe that it is important for us to know how its implementation can be made.

php+hash+password+database+with+a+record

We are going to use a Portable PHP Password Hashing Framework called phpass (pronounced “pH pass”) recommended by a lot of forums and is used by some famous Web applications like phpBB3, WordPress, Drupal, Vanilla, etc.

This post will focus and provide you a quick grasp and basic idea on how to salt, hash and store passwords in a MySQL database. This is essential to your PHP login script.

Let’s Code

Our SQL table structure looks like this:

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(32) NOT NULL,
  `password` char(60) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

libs/PasswordHash.php – our password framework file, yes, it is just this one file. You can download it here.

libs/DbConnect.php – configuration to be connected to database.

register.php – The user registration page, this is where we are going to save the user’s password. On this example web app, we require these two fields only during registration.

<html>
    <head>
        <title>registration page - php salt and hash password - www.codeofaninja.com</title>
        <link type="text/css" rel="stylesheet" href="css/style.css" />
    </head>
<body>
 
<div id="loginForm">
 
    <?php
    // save the username and password
    if($_POST){
     
        try{
            // load database connection and password hasher library
            require 'libs/DbConnect.php';
            require 'libs/PasswordHash.php';
             
            /* 
             * -prepare password to be saved
             * -concatinate the salt and entered password 
             */
            $salt = "ipDaloveyBuohgGTZwcodeRJ1avofZ7HbZjzJbanDS8gtoninjaYj48CW" . $_POST['email'];
            $password = $salt . $_POST['password'];
             
            /* 
             * '8' - base-2 logarithm of the iteration count used for password stretching
             * 'false' - do we require the hashes to be portable to older systems (less secure)?
             */
            $hasher = new PasswordHash(8,false);
            $password = $hasher->HashPassword($password);
 
            // insert command
            $query = "INSERT INTO users SET email = ?, password = ?";
 
            $stmt = $con->prepare($query);
 
            $stmt->bindParam(1, $_POST['email']);
            $stmt->bindParam(2, $password);
 
            // execute the query
            if($stmt->execute()){
                echo "<div>Successful registration.</div>";
            }else{
                echo "<div>Unable to register. <a href='register.php'>Please try again.</a></div>";
            }
             
        }
         
        //to handle error
        catch(PDOException $exception){
            echo "Error: " . $exception->getMessage();
        }
    }
     
    // show the registration form
    else{
    ?>
 
    <!-- 
        -where the user will enter his email and password
        -required during registration
        -we are using HTML5 'email' type, 'required' keyword for a some validation, and a 'placeholder' for better UI
    -->
    <form action="register.php" method="post">
     
        <div id="formHeader">Registration Form</div>
         
        <div id="formBody">
            <div class="formField">
                <input type="email" name="email" required placeholder="Email" />
            </div>
             
            <div class="formField">
                <input type="password" name="password" required placeholder="Password" />
            </div>
         
            <div>
                <input type="submit" value="Register" class="customButton" />
            </div>
            <div id='userNotes'>
                Already have an account? <a href='login.php'>Login</a>
            </div>
        </div>
         
    </form>
     
    <?php
    }
    ?>
     
</div>
 
</body>
</html>

login.php – the user login page, we are going to check if the users’s password is valid or not .

<html>
    <head>
        <title>login page - php salt and hash password - www.codeofaninja.com</title>
        <link type="text/css" rel="stylesheet" href="css/style.css" />
    </head>
<body>
 
<div id="loginForm">
 
    <?php
    // form is submitted, check if acess will be granted
    if($_POST){
     
        try{
            // load database connection and password hasher library
            require 'libs/DbConnect.php';
            require 'libs/PasswordHash.php';
             
            // prepare query
            $query = "select email, password from users where email = ? limit 0,1";
            $stmt = $con->prepare( $query );
             
            // this will represent the first question mark
            $stmt->bindParam(1, $_POST['email']);
             
            // execute our query
            $stmt->execute();
             
            // count the rows returned
            $num = $stmt->rowCount();
             
            if($num==1){
                 
                //store retrieved row to a 'row' variable
                $row = $stmt->fetch(PDO::FETCH_ASSOC);
             
                // hashed password saved in the database
                $storedPassword = $row['password'];
                 
                // salt and entered password by the user
                $salt = "ipDaloveyBuohgGTZwcodeRJ1avofZ7HbZjzJbanDS8gtoninjaYj48CW";
                $postedPassword = $_POST['password'];
                $saltedPostedPassword = $salt . $postedPassword;
             
                // instantiate PasswordHash to check if it is a valid password
                $hasher = new PasswordHash(8,false);
                $check = $hasher->CheckPassword($saltedPostedPassword, $storedPassword);
                 
                /*
                 * access granted, for the next steps,
                 * you may use my php login script with php sessions tutorial :) 
                 */
                if($check){
                    echo "<div>Access granted.</div>";
                }
                 
                // $check variable is false, access denied.
                else{
                    echo "<div>Access denied. <a href='login.php'>Back.</a></div>";
                }
                 
            }
             
            // no rows returned, access denied
            else{
                echo "<div>Access denied. <a href='login.php'>Back.</a></div>";
            }
             
        }
        //to handle error
        catch(PDOException $exception){
            echo "Error: " . $exception->getMessage();
        }
     
         
    }
     
    // show the registration form
    else{
    ?>
 
    <!-- 
        -where the user will enter his email and password
        -required during login
        -we are using HTML5 'email' type, 'required' keyword for a some validation, and a 'placeholder' for better UI
    -->
    <form action="login.php" method="post">
     
        <div id="formHeader">Website Login</div>
         
        <div id="formBody">
            <div class="formField">
                <input type="email" name="email" required placeholder="Email" />
            </div>
             
            <div class="formField">
                <input type="password" name="password" required placeholder="Password" />
            </div>
         
            <div>
                <input type="submit" value="Login" class="customButton" />
            </div>
        </div>
        <div id='userNotes'>
            New here? <a href='register.php'>Register for free</a>
        </div>
    </form>
     
    <?php
    }
    ?>
     
</div>
 
</body>
</html>

css/style.css – just for some styling.

body{
    font: 20px "Lucida Grande", Tahoma, Verdana, sans-serif;
    color: #404040;
}
 
input[type=text],
input[type=password],
input[type=email]{
    padding:10px;
    width:100%;
}
 
#userNotes{
    font-size:0.7em;
    text-align:left;
    padding:10px;
}
 
#actions{
    padding:10px;
}
 
#infoMesssage{
    padding:10px;
    background-color:#BDE5F8;
    color:black;
    font-size:0.8em;
}
 
 
#successMessage{
    padding:10px;
    background-color:green;
    color:white;
}
 
#failedMessage{
    padding:10px;
    background-color:red;
    color:white;
    font-size:15px;
}
 
#formBody{
    padding:5px;
}
 
#loginForm{
     
    text-align:center;
    border:thin solid #000;
    width:300px;
    margin:7em auto 0 auto;
}
 
#formHeader{
    border-bottom:thin solid gray;
    padding:10px;
    background:#f3f3f3;
}
 
#loginForm{
     
}
 
.customButton {
    padding:5px;
    width:100%;
    -moz-box-shadow:inset 0px 1px 0px 0px #bbdaf7;
    -webkit-box-shadow:inset 0px 1px 0px 0px #bbdaf7;
    box-shadow:inset 0px 1px 0px 0px #bbdaf7;
    background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #79bbff), color-stop(1, #378de5) );
    background:-moz-linear-gradient( center top, #79bbff 5%, #378de5 100% );
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#79bbff', endColorstr='#378de5');
    background-color:#79bbff;
    -moz-border-radius:6px;
    -webkit-border-radius:6px;
    border-radius:6px;
    border:1px solid #84bbf3;
    display:inline-block;
    color:#ffffff;
    font-family:arial;
    font-size:15px;
    font-weight:bold;
    text-decoration:none;
    text-shadow:1px 1px 0px #528ecc;
    cursor:pointer;
}
 
.customButton:hover {
    background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #378de5), color-stop(1, #79bbff) );
    background:-moz-linear-gradient( center top, #378de5 5%, #79bbff 100% );
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#378de5', endColorstr='#79bbff');
    background-color:#378de5;
}
 
.customButton:active {
    position:relative;
    top:1px;
}
/* This imageless css button was generated by CSSButtonGenerator.com */

Demo Screenshots

Empty database.
Empty database.
Registration form.
Registration form.
Just a sample HTML5 validation.
Just a sample HTML5 validation.
After successful registration.
After successful registration.
Our database will have the record.  Notice the password field, it was hashed.
Our database will have the record.
Notice the password field, it was hashed.
Our login page.
Our login page.
Just an example HTML5 validation during login.
Just an example HTML5 validation during login.
Login with wrong credentials.
Login with wrong credentials.
After login with correct username and password.
After login with correct username and password.

Some references

Please note that password hashing is often wrongly referred to as “password encryption”. Hashing is a more appropriate term since encryption is something that is supposed to be easily reversible. ~ phpass

If there’s something you want to add, something wrong, or any questions, please let me know in the comments. Thanks a lot!

You can download all the code used in this tutorial for only $9.99 $5.55!
[purchase_link id="12455" text="Download Now" style="button" color="green"]

Thank you for learning from our post about: How To Salt, Hash and Store Passwords Securely?

RELATED: PHP Login Script with Session Tutorial – Step by Step Guide!

PHP Login System Tutorial – Step By Step Guide!

Previously, we learned how to create, read, update and delete database records on our PHP OOP CRUD tutorial.

Today we will build a secure and efficient PHP login system with admin features. By utilizing PHP sessions and MySQL database, we will walk you through creating a user-friendly login system that ensures the safety and protection of user data.

Overview

Login? Logout? Sign Up or Register? We see this functionality in almost every website we use today. Facebook, Gmail, and Twitter are just some examples.

If you want to become a web programmer, this is one of the most fundamental skills you need to learn. If you haven't, today is a great day for you. We have some good news.

This tutorial will teach us how to build a simple PHP login system. This will help you create the web app of your dreams.

We will cover creating a PHP login form, registration form, customer section, admin section, list of registered users, logout, and more. You will learn helpful web programming techniques as well.

Prepare the database

Create a database

Open a new browser tab and go to PhpMyadmin. The address is http://localhost/phpmyadmin.

Create a database. The database name is: php_login_system

Run SQL for users' table

In PhpMyAdmin, click the database name. Go to the SQL tab. Create the "users" table by running the following SQL statement.

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `firstname` varchar(32) NOT NULL,
  `lastname` varchar(32) NOT NULL,
  `email` varchar(64) NOT NULL,
  `contact_number` varchar(64) NOT NULL,
  `address` text NOT NULL,
  `password` varchar(512) NOT NULL,
  `access_level` varchar(16) NOT NULL,
  `access_code` text NOT NULL,
  `status` int(11) NOT NULL COMMENT '0=pending,1=confirmed',
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='admin and customer users';

Run SQL for users' accounts

Go to PhpMyAdmin's SQL tab again. Insert new records to the users table by running the following SQL statement.

INSERT INTO `users` (`id`, `firstname`, `lastname`, `email`, `contact_number`, `address`, `password`, `access_level`, `access_code`, `status`, `created`, `modified`) VALUES
(1, 'Mike', 'Dalisay', '[email protected]', '0999999999', 'Blk. 24 A, Lot 6, Ph. 3, Peace Village', '$2y$10$AUBptrm9sQF696zr8Hv31On3x4wqnTihdCLocZmGLbiDvyLpyokL.', 'Admin', '', 1, '0000-00-00 00:00:00', '2016-06-13 18:17:47'),
(2, 'Lauro', 'Abogne', '[email protected]', '08888888', 'Pasig City', '$2y$10$it4i11kRKrB19FfpPRWsRO5qtgrgajL7NnxOq180MsIhCKhAmSdDa', 'Customer', '', 1, '0000-00-00 00:00:00', '2015-03-24 07:00:21'),
(4, 'Darwin', 'Dalisay', '[email protected]', '9331868359', 'Blk 24 A Lot 6 Ph 3\r\nPeace Village, San Luis', '$2y$10$tLq9lTKDUt7EyTFhxL0QHuen/BgO9YQzFYTUyH50kJXLJ.ISO3HAO', 'Customer', 'ILXFBdMAbHVrJswNDnm231cziO8FZomn', 1, '2014-10-29 17:31:09', '2016-06-13 18:18:25'),
(7, 'Marisol Jane', 'Dalisay', '[email protected]', '09998765432', 'Blk. 24 A, Lot 6, Ph. 3, Peace Village', 'mariz', 'Customer', '', 1, '2015-02-25 09:35:52', '2015-03-24 07:00:21'),
(9, 'Marykris', 'De Leon', '[email protected]', '09194444444', 'Project 4, QC', '$2y$10$uUy7D5qmvaRYttLCx9wnU.WOD3/8URgOX7OBXHPpWyTDjU4ZteSEm', 'Customer', '', 1, '2015-02-27 14:28:46', '2015-03-24 06:51:03'),
(10, 'Merlin', 'Duckerberg', '[email protected]', '09991112333', 'Project 2, Quezon City', '$2y$10$VHY58eALB1QyYsP71RHD1ewmVxZZp.wLuhejyQrufvdy041arx1Kq', 'Admin', '', 1, '2015-03-18 06:45:28', '2015-03-24 07:00:21'),
(14, 'Charlon', 'Ignacio', '[email protected]', '09876543345', 'Tandang Sora, QC', '$2y$10$Fj6O1tPYI6UZRzJ9BNfFJuhURN9DnK5fQGHEsfol5LXRu.tCYYggu', 'Customer', '', 1, '2015-03-24 08:06:57', '2015-03-24 07:48:00'),
(15, 'Kobe Bro', 'Bryant', '[email protected]', '09898787674', 'Los Angeles, California', '$2y$10$fmanyjJxNfJ8O3p9jjUixu6EOHkGZrThtcd..TeNz2g.XZyCIuVpm', 'Customer', '', 1, '2015-03-26 11:28:01', '2015-03-26 03:39:52'),
(20, 'Tim', 'Duncan', '[email protected]', '9999999', 'San Antonio, Texas, USA', '$2y$10$9OSKHLhiDdBkJTmd3VLnQeNPCtyH1IvZmcHrz4khBMHdxc8PLX5G6', 'Customer', '0X4JwsRmdif8UyyIHSOUjhZz9tva3Czj', 1, '2016-05-26 01:25:59', '2016-05-25 17:25:59'),
(21, 'Tony', 'Parker', '[email protected]', '8888888', 'Blk 24 A Lot 6 Ph 3\r\nPeace Village, San Luis', '$2y$10$lBJfvLyl/X5PieaztTYADOxOQeZJCqETayF.O9ld17z3hcKSJwZae', 'Customer', 'THM3xkZzXeza5ISoTyPKl6oLpVa88tYl', 1, '2016-05-26 01:29:01', '2016-06-13 17:46:33');

Create database connection file

This class is used for connecting to a database.

I assume you are using XAMPP. Go to the root directory. In my case, it is the "C:\xampp\htdocs" directory.

We will create our project's folder. Create "php-login-script-level-1" folder. Open that folder.

Create "config" folder and open it. Create database.php file. Place the following code.

<?php
// used to get mysql database connection
class Database{
	// specify your own database credentials
	private $host = "localhost";
	private $db_name = "php_login_system";
	private $username = "root";
	private $password = "";
	public $conn;
	// get the database connection
	public function getConnection(){
		$this->conn = null;
		try{
			$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
		}catch(PDOException $exception){
			echo "Connection error: " . $exception->getMessage();
		}
		return $this->conn;
	}
}
?>

Prepare user object

This class is used for "user" object operations such as creating a user, deleting a user, and more. We will add several methods in this class along this tutorial.

We will just put the PHP class structure and necessary object properties.

Create an "objects" folder. Create "user.php" file. Place the following code.

<?php
// 'user' object
class User{
	// database connection and table name
	private $conn;
	private $table_name = "users";
	// object properties
	public $id;
	public $firstname;
	public $lastname;
	public $email;
	public $contact_number;
	public $address;
	public $password;
	public $access_level;
	public $access_code;
	public $status;
	public $created;
	public $modified;
	// constructor
	public function __construct($db){
		$this->conn = $db;
	}
}

Output

Congratulations! We just made the setup for our login system's database. We do not have an output on a webpage yet. Continue the tutorial below to achieve more output.

Prepare basic settings

Create config file

Using a config file is great for your app. It is a central place where you can set common variables such as your app's home URL, pagination settings, and more.

Open the "config" folder. Create "core.php" file. Place the following code.

<?php
// show error reporting
error_reporting(E_ALL);
// start php session
session_start();
// set your default time-zone
date_default_timezone_set('Asia/Manila');
// home page url
$home_url="http://localhost/php-login-script-level-1/";
// page given in URL parameter, default page is one
$page = isset($_GET['page']) ? $_GET['page'] : 1;
// set number of records per page
$records_per_page = 5;
// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;
?>

Create login checker file

A login checker file is used by our web app to identify if a user is logged in or not.

If a user is not logged in and he tries to access a page where a login is required, that user will be redirected to login page.

Also, if a logged in user tries to access a login page, he will be redirected to the dashboard because he is already logged in.

Back to root directory, create "login_checker.php" file. Place the following code.

<?php
// login checker for 'customer' access level
// if access level was not 'Admin', redirect him to login page
if(isset($_SESSION['access_level']) && $_SESSION['access_level']=="Admin"){
	header("Location: {$home_url}admin/index.php?action=logged_in_as_admin");
}
// if $require_login was set and value is 'true'
else if(isset($require_login) && $require_login==true){
	// if user not yet logged in, redirect to login page
	if(!isset($_SESSION['access_level'])){
		header("Location: {$home_url}login.php?action=please_login");
	}
}
// if it was the 'login' or 'register' or 'sign up' page but the customer was already logged in
else if(isset($page_title) && ($page_title=="Login" || $page_title=="Sign Up")){
	// if user not yet logged in, redirect to login page
	if(isset($_SESSION['access_level']) && $_SESSION['access_level']=="Customer"){
		header("Location: {$home_url}index.php?action=already_logged_in");
	}
}
else{
	// no problem, stay on current page
}
?>

Create .htaccess file

The .htaccess file is handy for making URLs pretty and easy to remember.

For example, the page on this URL "http://localhost/login.php" can be accessed using this URL "http://localhost/login".

Create ".htaccess" file. Place the following code.

#Fix Rewrite
Options -Multiviews
# Mod Rewrite
Options +FollowSymLinks
RewriteEngine On
RewriteBase /php-login-script-level-1/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# used for php pages such as "yoursite.com/login.php" will become "yoursite.com/login/"
RewriteRule ^([a-z_]+)\/?$ $1.php [NC]

To make the .htaccess file work, ensure the mod_rewrite Apache module is enabled on your server. Learn more here and here.

Output

Congratulations! We just made the basic setup of our login system. We do not have an output on a webpage yet. Continue the tutorial below to achieve more output.

Create the template files

Template files are beneficial because it saves us a lot of time. How? When you use template files, you won't have to repeat the common codes on each web page you are working on.

Examples of those common codes are the HTML tags on the 'head' and 'foot' of the web page. We will learn more about this concept as we go along this tutorial.

Create navigation bar

The navigation is where the user can click the home page link, logout button, and more.

Create "navigation.php" file. Place the following code.

<!-- navbar -->
<div class="navbar navbar-default navbar-static-top" role="navigation">
	<div class="container-fluid">
		<div class="navbar-header">
			<!-- to enable navigation dropdown when viewed in mobile device -->
			<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
			<span class="sr-only">Toggle navigation</span>
			<span class="icon-bar"></span>
			<span class="icon-bar"></span>
			<span class="icon-bar"></span>
			</button>
			<!-- Change "Your Site" to your site name -->
			<a class="navbar-brand" href="<?php echo $home_url; ?>">Your Site</a>
		</div>
		<div class="navbar-collapse collapse">
			<ul class="nav navbar-nav">
				<!-- link to the "Cart" page, highlight if current page is cart.php -->
				<li <?php echo $page_title=="Index" ? "class='active'" : ""; ?>>
					<a href="<?php echo $home_url; ?>">Home</a>
				</li>
			</ul>
			<?php
			// login and logout options will be here
			?>
		</div><!--/.nav-collapse -->
	</div>
</div>
<!-- /navbar -->

Show logout button

If the user was logged-in, the system will show them a logout button in the navigation bar.

Replace "// login and logout options will be here " of the previous section with the following code.

// check if users / customer was logged in
// if user was logged in, show "Edit Profile", "Orders" and "Logout" options
if(isset($_SESSION['logged_in']) && $_SESSION['logged_in']==true && $_SESSION['access_level']=='Customer'){
?>
<ul class="nav navbar-nav navbar-right">
	<li <?php echo $page_title=="Edit Profile" ? "class='active'" : ""; ?>>
		<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
			<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
			  <?php echo $_SESSION['firstname']; ?>
			  <span class="caret"></span>
		</a>
		<ul class="dropdown-menu" role="menu">
			<li><a href="<?php echo $home_url; ?>logout.php">Logout</a></li>
		</ul>
	</li>
</ul>
<?php
}
// show login and register options here

Show login and register buttons

If the user is not yet logged in, the system will show them the login and register buttons in the navigation bar.

Replace "// show login and register options here " of the previous section with the following code.

// if user was not logged in, show the "login" and "register" options
else{
?>
<ul class="nav navbar-nav navbar-right">
	<li <?php echo $page_title=="Login" ? "class='active'" : ""; ?>>
		<a href="<?php echo $home_url; ?>login">
			<span class="glyphicon glyphicon-log-in"></span> Log In
		</a>
	</li>
	<li <?php echo $page_title=="Register" ? "class='active'" : ""; ?>>
		<a href="<?php echo $home_url; ?>register">
			<span class="glyphicon glyphicon-check"></span> Register
		</a>
	</li>
</ul>
<?php
}

Create page header

Our PHP pages contain almost the same HTML header code. We do not want to copy and paste the same HTML header code for different PHP files every time.

What we will do is to put them in this one file. It can be used by different PHP files using PHP include_once statement.

Create "layout_head.php" file. Place the following code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<!-- set the page title, for seo purposes too -->
    <title><?php echo isset($page_title) ? strip_tags($page_title) : "Store Front"; ?></title>
    <!-- Bootstrap CSS -->
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" media="screen" />
	<!-- admin custom CSS -->
	<link href="<?php echo $home_url . "libs/css/customer.css" ?>" rel="stylesheet" />
</head>
<body>
	<!-- include the navigation bar -->
	<?php include_once 'navigation.php'; ?>
    <!-- container -->
    <div class="container">
		<?php
		// if given page title is 'Login', do not display the title
		if($page_title!="Login"){
		?>
		<div class='col-md-12'>
	        <div class="page-header">
	            <h1><?php echo isset($page_title) ? $page_title : "The Code of a Ninja"; ?></h1>
	        </div>
		</div>
		<?php
		}
		?>

The same concept with the page header file above, we do not want to copy and paste the same HTML footer code for different PHP files.

Create "layout_foot.php" file. Place the following code.

	</div>
	<!-- /container -->
<!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- end HTML page -->
</body>
</html>

Customer section custom CSS

We will customize the web page for the customer using this CSS file. You can add your own CSS here as well.

Create "libs" folder. Create "css" folder. Create "customer.css" file. Place the following code.

.margin-bottom-1em{ margin-bottom:1em; }
.width-30-percent{ width:30%; }
.margin-1em-zero{ margin:1em 0; }
.width-30-percent{ width:30%; }
.width-70-percent{ width:70%; }
.margin-top-40{ margin-top:40px; }
.text-align-center{ text-align:center; }
div#blueimp-gallery div.modal{ overflow: visible; }
.photo-thumb{
    width:214px;
    height:214px;
    float:left;
    border: thin solid #d1d1d1;
    margin:0 1em 1em 0;
}
.form-signin{
    max-width: 330px;
    padding: 15px;
    margin: 0 auto;
}
.form-signin .form-control{
    position: relative;
    font-size: 16px;
    height: auto;
    padding: 10px;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
.form-signin .form-control:focus{ z-index: 2; }
.form-signin input[type="text"]{
    margin-bottom: -1px;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}
.form-signin input[type="password"]{
    margin-bottom: 10px;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}
.account-wall{
    margin-top: 40px;
    padding: 40px 0px 20px 0px;
    background-color: #ffffff;
    box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.16);
}
.login-title{
    color: #555;
    font-size: 22px;
    font-weight: 400;
    display: block;
}
.profile-img{
    width: 96px;
    height: 96px;
    margin: 0 auto 10px;
    display: block;
    -moz-border-radius: 50%;
    -webkit-border-radius: 50%;
    border-radius: 50%;
}
.select-img{
    border-radius: 50%;
    display: block;
    height: 75px;
    margin: 0 30px 10px;
    width: 75px;
    -moz-border-radius: 50%;
    -webkit-border-radius: 50%;
    border-radius: 50%;
}
.select-name{
    display: block;
    margin: 30px 10px 10px;
}
.logo-img{
    width: 96px;
    height: 96px;
    margin: 0 auto 10px;
    display: block;
    -moz-border-radius: 50%;
    -webkit-border-radius: 50%;
    border-radius: 50%;
}

Output

Congratulations! We just made the set up for our web pages. Our login page, register page, index page and other pages will look more beautiful now.

We do not have an output on a webpage yet. Continue the tutorial below to achieve the output of our login page.

Create a PHP login form

Include basic settings

This file is where the user will enter his email and password.

Create "login.php" file. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// set page title
$page_title = "Login";
// include login checker
$require_login=false;
include_once "login_checker.php";
// default to false
$access_denied=false;
// post code will be here
// login form html will be here
?>

Login form HTML

Next, we will add the actual HTML form that contains the email field, password field and login button.

Replace "// login form html will be here" of the previous section with the following code.

// include page header HTML
include_once "layout_head.php";
echo "<div class='col-sm-6 col-md-4 col-md-offset-4'>";
	// alert messages will be here
	// actual HTML login form
	echo "<div class='account-wall'>";
		echo "<div id='my-tab-content' class='tab-content'>";
			echo "<div class='tab-pane active' id='login'>";
				echo "<img class='profile-img' src='images/login-icon.png'>";
				echo "<form class='form-signin' action='" . htmlspecialchars($_SERVER["PHP_SELF"]) . "' method='post'>";
					echo "<input type='text' name='email' class='form-control' placeholder='Email' required autofocus />";
					echo "<input type='password' name='password' class='form-control' placeholder='Password' required />";
					echo "<input type='submit' class='btn btn-lg btn-primary btn-block' value='Log In' />";
				echo "</form>";
			echo "</div>";
		echo "</div>";
	echo "</div>";
echo "</div>";
// footer HTML and JavaScript codes
include_once "layout_foot.php";

Login form output

Finally! We just made our first output. Open a new tab and go to http://localhost/php-login-script-level-1/login, you should see something like the following.

But our output does not work yet. Let's continue coding below.

Add alert message

These alert messages are shown based on the given action parameter. The system action was generated as a result of the activity the user has taken.

For example, the user tries to access a page where a login is required. The system will generate the "please_login" action that will be used to show a "Please login to access that page." message.

Replace "// alert messages will be here" of the previous section with the following code.

// get 'action' value in url parameter to display corresponding prompt messages
$action=isset($_GET['action']) ? $_GET['action'] : "";
// tell the user he is not yet logged in
if($action =='not_yet_logged_in'){
	echo "<div class='alert alert-danger margin-top-40' role='alert'>Please login.</div>";
}
// tell the user to login
else if($action=='please_login'){
	echo "<div class='alert alert-info'>
		<strong>Please login to access that page.</strong>
	</div>";
}
// tell the user email is verified
else if($action=='email_verified'){
	echo "<div class='alert alert-success'>
		<strong>Your email address have been validated.</strong>
	</div>";
}
// tell the user if access denied
if($access_denied){
	echo "<div class='alert alert-danger margin-top-40' role='alert'>
		Access Denied.<br /><br />
		Your username or password maybe incorrect
	</div>";
}

Alert message output

Here's a sample output if we added the previous section's code. The alert message below were seen if the user tries to access the customer index page http://localhost/php-login-script-level-1/ without logging in.

If user submitted the form

The following "if block" will execute a code when the user submitted the login form.

Find "// post code will be here" in "login.php" file. Replace it with the following code.

// if the login form was submitted
if($_POST){
	// email check will be here
}

Check if email exists

The code below will check if the submitted email address exists in the database. The $user->emailExists(); function will return true or false.

Replace "// email check will be here" of the previous section with the following code.

// include classes
include_once "config/database.php";
include_once "objects/user.php";
// get database connection
$database = new Database();
$db = $database->getConnection();
// initialize objects
$user = new User($db);
// check if email and password are in the database
$user->email=$_POST['email'];
// check if email exists, also get user details using this emailExists() method
$email_exists = $user->emailExists();
// login validation will be here

Add emailExists() method

The previous section will not work without the following method inside the user class. This method will read a user record from the database based on a given email address.

Open "objects" folder. Open "user.php" file. Place the following method in user class.

// check if given email exist in the database
function emailExists(){
	// query to check if email exists
	$query = "SELECT id, firstname, lastname, access_level, password, status
			FROM " . $this->table_name . "
			WHERE email = ?
			LIMIT 0,1";
	// prepare the query
	$stmt = $this->conn->prepare( $query );
	// sanitize
	$this->email=htmlspecialchars(strip_tags($this->email));
	// bind given email value
	$stmt->bindParam(1, $this->email);
	// execute the query
	$stmt->execute();
	// get number of rows
	$num = $stmt->rowCount();
	// if email exists, assign values to object properties for easy access and use for php sessions
	if($num>0){
		// get record details / values
		$row = $stmt->fetch(PDO::FETCH_ASSOC);
		// assign values to object properties
		$this->id = $row['id'];
		$this->firstname = $row['firstname'];
		$this->lastname = $row['lastname'];
		$this->access_level = $row['access_level'];
		$this->password = $row['password'];
		$this->status = $row['status'];
		// return true because email exists in the database
		return true;
	}
	// return false if email does not exist in the database
	return false;
}

Validate login credentials

The user will be allowed to login when $email_exists is true, the password matches and user status is equal to 1.

We used the built in PHP password_verify() function to match the submitted password with the hashed password in the database.

User status 1 means the user is verified. 0 means unverified. For this tutorial, we assume all users are verified.

Replace "// login validation will be here" of "login.php" with the following code.

// validate login
if ($email_exists && password_verify($_POST['password'], $user->password) && $user->status==1){
	// if it is, set the session value to true
	$_SESSION['logged_in'] = true;
	$_SESSION['user_id'] = $user->id;
	$_SESSION['access_level'] = $user->access_level;
	$_SESSION['firstname'] = htmlspecialchars($user->firstname, ENT_QUOTES, 'UTF-8') ;
	$_SESSION['lastname'] = $user->lastname;
	// if access level is 'Admin', redirect to admin section
	if($user->access_level=='Admin'){
		header("Location: {$home_url}admin/index.php?action=login_success");
	}
	// else, redirect only to 'Customer' section
	else{
		header("Location: {$home_url}index.php?action=login_success");
	}
}
// if username does not exist or password is wrong
else{
	$access_denied=true;
}

Customer's index page

This file is shown when the user was successfully logged in.

Create "index.php" file. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// set page title
$page_title="Index";
// include login checker
$require_login=true;
include_once "login_checker.php";
// include page header HTML
include_once 'layout_head.php';
echo "<div class='col-md-12'>";
	// to prevent undefined index notice
	$action = isset($_GET['action']) ? $_GET['action'] : "";
	// if login was successful
	if($action=='login_success'){
		echo "<div class='alert alert-info'>";
			echo "<strong>Hi " . $_SESSION['firstname'] . ", welcome back!</strong>";
		echo "</div>";
	}
	// if user is already logged in, shown when user tries to access the login page
	else if($action=='already_logged_in'){
		echo "<div class='alert alert-info'>";
			echo "<strong>You are already logged in.</strong>";
		echo "</div>";
	}
	// content once logged in
	echo "<div class='alert alert-info'>";
		echo "Content when logged in will be here. For example, your premium products or services.";
	echo "</div>";
echo "</div>";
// footer HTML and JavaScript codes
include 'layout_foot.php';
?>

Logout file

Here's how to logout the logged in user.

Create "logout.php" file. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// destroy session, it will remove ALL session settings
session_destroy();
//redirect to login page
header("Location: {$home_url}login.php");
?>

Output

The login form and logout should work at this point. When you try to login a customer account. Use the following login credentials.

Username: [email protected]
Password: darwin12qw!@QW

Once logged-in, you will see the following.

Create a PHP registration form

Create register page

The register page, also known as the "sign up" page, is where people will enter their information to be a registered user of the system.

Create "register.php" file. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// set page title
$page_title = "Register";
// include login checker
include_once "login_checker.php";
// include classes
include_once 'config/database.php';
include_once 'objects/user.php';
include_once "libs/php/utils.php";
// include page header HTML
include_once "layout_head.php";
echo "<div class='col-md-12'>";
	// registration form HTML will be here
echo "</div>";
// include page footer HTML
include_once "layout_foot.php";
?>

Create Utils class

This class is used for accessing common or general methods used by our application. This is a good practice. We will add this here so that it can be used later in this tutorial as well.

Open "libs" folder. Create "php" folder and open it. Create "utils.php" file. Place the following code.

<?php
class Utils{
}
?>

Registration form HTML

The register.php file does not have the registration form. We will place the registration form using the code below.

Replace "// registration form HTML will be here" of the previous section with the following code.

// code when form was submitted will be here
?>
<form action='register.php' method='post' id='register'>
	<table class='table table-responsive'>
		<tr>
			<td class='width-30-percent'>Firstname</td>
			<td><input type='text' name='firstname' class='form-control' required value="<?php echo isset($_POST['firstname']) ? htmlspecialchars($_POST['firstname'], ENT_QUOTES) : "";  ?>" /></td>
		</tr>
		<tr>
			<td>Lastname</td>
			<td><input type='text' name='lastname' class='form-control' required value="<?php echo isset($_POST['lastname']) ? htmlspecialchars($_POST['lastname'], ENT_QUOTES) : "";  ?>" /></td>
		</tr>
		<tr>
			<td>Contact Number</td>
			<td><input type='text' name='contact_number' class='form-control' required value="<?php echo isset($_POST['contact_number']) ? htmlspecialchars($_POST['contact_number'], ENT_QUOTES) : "";  ?>" /></td>
		</tr>
		<tr>
			<td>Address</td>
			<td><textarea name='address' class='form-control' required><?php echo isset($_POST['address']) ? htmlspecialchars($_POST['address'], ENT_QUOTES) : "";  ?></textarea></td>
		</tr>
		<tr>
			<td>Email</td>
			<td><input type='email' name='email' class='form-control' required value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email'], ENT_QUOTES) : "";  ?>" /></td>
		</tr>
		<tr>
			<td>Password</td>
			<td><input type='password' name='password' class='form-control' required id='passwordInput'></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<button type="submit" class="btn btn-primary">
					<span class="glyphicon glyphicon-plus"></span> Register
				</button>
			</td>
		</tr>
	</table>
</form>
<?php

If registration form was submitted

This is code where the system will catch the information submitted by the user. The code below will try to detect if the registration form was submitted. It also validates if the submitted email already exists or not.

Replace "// code when form was submitted will be here" of the previous section with the following code.

// if form was posted
if($_POST){
	// get database connection
	$database = new Database();
	$db = $database->getConnection();
	// initialize objects
	$user = new User($db);
	$utils = new Utils();
	// set user email to detect if it already exists
	$user->email=$_POST['email'];
	// check if email already exists
	if($user->emailExists()){
		echo "<div class='alert alert-danger'>";
			echo "The email you specified is already registered. Please try again or <a href='{$home_url}login'>login.</a>";
		echo "</div>";
	}
	else{
		// create user will be here
	}
}

Create new user

If the email does not exist, the program will create the user in the database. The code below will assign the submitted data to "user object" properties and then call the create() method.

Replace the comment "// create user will be here" of the previous section with the following code.

// set values to object properties
$user->firstname=$_POST['firstname'];
$user->lastname=$_POST['lastname'];
$user->contact_number=$_POST['contact_number'];
$user->address=$_POST['address'];
$user->password=$_POST['password'];
$user->access_level='Customer';
$user->status=1;
// create the user
if($user->create()){
	echo "<div class='alert alert-info'>";
		echo "Successfully registered. <a href='{$home_url}login'>Please login</a>.";
	echo "</div>";
	// empty posted values
	$_POST=array();
}else{
	echo "<div class='alert alert-danger' role='alert'>Unable to register. Please try again.</div>";
}

User object create() method

The create() method used in the previous section will not work without it in the user class. This method contains the INSERT query to the database, sanitizes the submitted data, binds the data and executes the query.

Open "objects" folder. Open "user.php" file. Add the following function inside the class.

// create new user record
function create(){
    // to get time stamp for 'created' field
    $this->created=date('Y-m-d H:i:s');
    // insert query
    $query = "INSERT INTO
                " . $this->table_name . "
            SET
				firstname = :firstname,
				lastname = :lastname,
				email = :email,
				contact_number = :contact_number,
				address = :address,
				password = :password,
				access_level = :access_level,
				status = :status,
				created = :created";
	// prepare the query
	$stmt = $this->conn->prepare($query);
	// sanitize
	$this->firstname=htmlspecialchars(strip_tags($this->firstname));
	$this->lastname=htmlspecialchars(strip_tags($this->lastname));
	$this->email=htmlspecialchars(strip_tags($this->email));
	$this->contact_number=htmlspecialchars(strip_tags($this->contact_number));
	$this->address=htmlspecialchars(strip_tags($this->address));
	$this->password=htmlspecialchars(strip_tags($this->password));
	$this->access_level=htmlspecialchars(strip_tags($this->access_level));
	$this->status=htmlspecialchars(strip_tags($this->status));
	// bind the values
	$stmt->bindParam(':firstname', $this->firstname);
	$stmt->bindParam(':lastname', $this->lastname);
	$stmt->bindParam(':email', $this->email);
	$stmt->bindParam(':contact_number', $this->contact_number);
	$stmt->bindParam(':address', $this->address);
	// hash the password before saving to database
	$password_hash = password_hash($this->password, PASSWORD_BCRYPT);
	$stmt->bindParam(':password', $password_hash);
	$stmt->bindParam(':access_level', $this->access_level);
	$stmt->bindParam(':status', $this->status);
	$stmt->bindParam(':created', $this->created);
	// execute the query, also check if query was successful
	if($stmt->execute()){
		return true;
	}else{
		$this->showError($stmt);
		return false;
	}
}

Add showError() method

The purpose of this method is to show additional details about an error.

public function showError($stmt){
	echo "<pre>";
		print_r($stmt->errorInfo());
	echo "</pre>";
}

Output

Run http://localhost/php-login-script-level-1/register, you should see an output the looks like the screenshot below. It will display appropriate alert message when the registration form was submitted.

Admin section

Create admin index page

Once the an admin user successfully logged in, this admin index page is where he will land.

Create "admin" folder. Create "index.php" file. Place the following code.

<?php
// core configuration
include_once "../config/core.php";
// check if logged in as admin
include_once "login_checker.php";
// set page title
$page_title="Admin Index";
// include page header HTML
include 'layout_head.php';
	echo "<div class='col-md-12'>";
		// get parameter values, and to prevent undefined index notice
		$action = isset($_GET['action']) ? $_GET['action'] : "";
		// tell the user he's already logged in
		if($action=='already_logged_in'){
			echo "<div class='alert alert-info'>";
				echo "<strong>You</strong> are already logged in.";
			echo "</div>";
		}
		else if($action=='logged_in_as_admin'){
			echo "<div class='alert alert-info'>";
				echo "<strong>You</strong> are logged in as admin.";
			echo "</div>";
		}
		echo "<div class='alert alert-info'>";
			echo "Contents of your admin section will be here.";
		echo "</div>";
	echo "</div>";
// include page footer HTML
include_once 'layout_foot.php';
?>

Create navigation bar

The admin section has its own navigation bar. The reason is the admin menu can be very different from the user menu.

Open "admin" folder. Create "navigation.php" file. Place the following code.

<!-- navbar -->
<div class="navbar navbar-default navbar-static-top" role="navigation">
	<div class="container-fluid">
		<div class="navbar-header">
			<!-- to enable navigation dropdown when viewed in mobile device -->
			<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
			<span class="sr-only">Toggle navigation</span>
			<span class="icon-bar"></span>
			<span class="icon-bar"></span>
			<span class="icon-bar"></span>
			</button>
			<!-- Change "Site Admin" to your site name -->
			<a class="navbar-brand" href="<?php echo $home_url; ?>admin/index.php">Admin</a>
		</div>
		<div class="navbar-collapse collapse">
			<ul class="nav navbar-nav">
				<!-- highlight for order related pages -->
				<li <?php echo $page_title=="Admin Index" ? "class='active'" : ""; ?>>
					<a href="<?php echo $home_url; ?>admin/index.php">Home</a>
				</li>
				<!-- highlight for user related pages -->
				<li <?php
						echo $page_title=="Users" ? "class='active'" : ""; ?> >
					<a href="<?php echo $home_url; ?>admin/read_users.php">Users</a>
				</li>
			</ul>
			<!-- options in the upper right corner of the page -->
			<ul class="nav navbar-nav navbar-right">
				<li>
					<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
						<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
						  <?php echo $_SESSION['firstname']; ?>
						  <span class="caret"></span>
					</a>
					<ul class="dropdown-menu" role="menu">
						<!-- log out user -->
						<li><a href="<?php echo $home_url; ?>logout.php">Logout</a></li>
					</ul>
				</li>
			</ul>
		</div><!--/.nav-collapse -->
	</div>
</div>
<!-- /navbar -->

Create page header

This page header file is for admin section only. This is where the navigation bar of the previous section was used.

Open "admin" folder. Create "layout_head.php" file. Place the following code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?php echo isset($page_title) ? strip_tags($page_title) : "Store Admin"; ?></title>
    <!-- Bootstrap CSS -->
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" media="screen" />
	<!-- admin custom CSS -->
	<link href="<?php echo $home_url . "libs/css/admin.css" ?>" rel="stylesheet" />
</head>
<body>
	<?php
	// include top navigation bar
	include_once "navigation.php";
	?>
    <!-- container -->
    <div class="container">
		<!-- display page title -->
        <div class="col-md-12">
            <div class="page-header">
                <h1><?php echo isset($page_title) ? $page_title : "The Code of a Ninja"; ?></h1>
            </div>
        </div>

This page footer file is for admin section only as well.

Open "admin" folder. Create "layout_foot.php" file. Place the following code.

	</div>
	<!-- /container -->
<!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- end the HTML page -->
</body>
</html>

Admin section custom CSS

There are differences in style in the admin section as well. For this reason, we need a different custom.css file.

Open "libs" folder. Open "css" folder. Create "admin.css" file. Place the following code.

.right-button-margin{
    margin: 0 0 1em 0;
    overflow: hidden;
}
.thumb-image {
    float:left;
    width: 150px;
    height: 150px;
    margin:.6em 1.2em 0 0;
    position:relative;
}
.thumb-image .delete-image {
    position:absolute;
    top:-10px;
    right:-10px;
}
.thumb-wrapper{
    border:thin solid #999;
    float:left;
    width: 150px;
    height: 150px;
    margin:.6em 1.2em 0 0;
    position:relative;
}
.width-30-percent{ width:30%; }
.margin-left-1em{ margin:0 1em 0 0; }
.width-20-em{ width: 20em; }
.width-13-em{ width: 13em; }
.margin-zero{ margin:0; }
.padding-zero{ padding:0; }
.btn-margin-right{ margin-right:.5em; }
.margin-bottom-1em{ margin-bottom:1em; }
.left-margin{ margin:0 .5em 0 0; }
.delete-image img{ width:25px; }
.thumb-wrapper img{ width:130px; height:130px; margin:10px; }
#html-btn { display:none; }
.delete-pdf{ margin-left:.5em; }
.delete-pdf img{ width:20px; cursor:pointer; }
.pdf-item{ padding:0 0 1em 0; }

Create login checker file

We choose to use a different login checker for the admin section. This is because there can be different redirects required by the admin section.

Open "admin" folder. Create "login_checker.php" file. Place the following code.

<?php
// login checker for 'admin' access level
// if the session value is empty, he is not yet logged in, redirect him to login page
if(empty($_SESSION['logged_in'])){
    header("Location: {$home_url}login.php?action=not_yet_logged_in");
}
// if access level was not 'Admin', redirect him to login page
else if($_SESSION['access_level']!="Admin"){
	header("Location: {$home_url}login.php?action=not_admin");
}
else{
	// no problem, stay on current page
}
?>

Output

Use the following login credentials to login an admin account.

Username: [email protected]
Password: ninja12qw!@QW

Once logged-in, you will see the following.

Show registered users

Create "read users" file

This file will is what was accessed in the browser to show the list of registered users.

Create read_users.php file. Place the following code.

<?php
// core configuration
include_once "../config/core.php";
// check if logged in as admin
include_once "login_checker.php";
// include classes
include_once '../config/database.php';
include_once '../objects/user.php';
// get database connection
$database = new Database();
$db = $database->getConnection();
// initialize objects
$user = new User($db);
// set page title
$page_title = "Users";
// include page header HTML
include_once "layout_head.php";
echo "<div class='col-md-12'>";
    // read all users from the database
    $stmt = $user->readAll($from_record_num, $records_per_page);
    // count retrieved users
    $num = $stmt->rowCount();
    // to identify page for paging
    $page_url="read_users.php?";
    // include products table HTML template
    include_once "read_users_template.php";
echo "</div>";
// include page footer HTML
include_once "layout_foot.php";
?>

Add readAll() method in user object

This method is needed by the previous section to retrieved records from the database.

Open "objects" folder. Open "user.php" file. Place the following code inside the class.

// read all user records
function readAll($from_record_num, $records_per_page){
	// query to read all user records, with limit clause for pagination
	$query = "SELECT
				id,
				firstname,
				lastname,
				email,
				contact_number,
				access_level,
				created
			FROM " . $this->table_name . "
			ORDER BY id DESC
			LIMIT ?, ?";
	// prepare query statement
	$stmt = $this->conn->prepare( $query );
	// bind limit clause variables
	$stmt->bindParam(1, $from_record_num, PDO::PARAM_INT);
	$stmt->bindParam(2, $records_per_page, PDO::PARAM_INT);
	// execute query
	$stmt->execute();
	// return values
	return $stmt;
}

Create "read users" template file

The HTML table is where the records are placed. We used a template file so that we can use the same layout for the search feature.

Create read_users_template.php file. Place the following code.

<?php
// display the table if the number of users retrieved was greater than zero
if($num>0){
	echo "<table class='table table-hover table-responsive table-bordered'>";
	// table headers
	echo "<tr>";
		echo "<th>Firstname</th>";
		echo "<th>Lastname</th>";
		echo "<th>Email</th>";
		echo "<th>Contact Number</th>";
		echo "<th>Access Level</th>";
	echo "</tr>";
	// loop through the user records
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		extract($row);
		// display user details
		echo "<tr>";
			echo "<td>{$firstname}</td>";
			echo "<td>{$lastname}</td>";
			echo "<td>{$email}</td>";
			echo "<td>{$contact_number}</td>";
			echo "<td>{$access_level}</td>";
		echo "</tr>";
        }
	echo "</table>";
	$page_url="read_users.php?";
	$total_rows = $user->countAll();
	// actual paging buttons
	include_once 'paging.php';
}
// tell the user there are no selfies
else{
	echo "<div class='alert alert-danger'>
		<strong>No users found.</strong>
	</div>";
}
?>

Add countAll() method in user object

The data returned by the countAll() method is used for calculating the correct pagination buttons.

Open "objects" folder. Open "user.php" file. Place the following code inside the class.

// used for paging users
public function countAll(){
	// query to select all user records
	$query = "SELECT id FROM " . $this->table_name . "";
	// prepare query statement
	$stmt = $this->conn->prepare($query);
	// execute query
	$stmt->execute();
	// get number of rows
	$num = $stmt->rowCount();
	// return row count
	return $num;
}

Paginate list of users

This pagination file renders the clickable page buttons. It can be used for different objects as well, not just users.

Create paging.php file. Place the following code.

<?php
echo "<ul class=\"pagination margin-zero\">";
// button for first page
if($page>1){
    echo "<li><a href='{$page_url}' title='Go to the first page.'>";
        echo "First Page";
    echo "</a></li>";
}
// calculate total number of pages
$total_pages = ceil($total_rows / $records_per_page);
// range of links to show
$range = 2;
// display links to 'range of pages' around 'current page'
$initial_num = $page - $range;
$condition_limit_num = ($page + $range)  + 1;
for ($x=$initial_num; $x<$condition_limit_num; $x++) {
    // be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
    if (($x > 0) && ($x <= $total_pages)) {
        // current page
        if ($x == $page) {
            echo "<li class='active'><a href=\"#\">$x <span class=\"sr-only\">(current)</span></a></li>";
        } 
        // not current page
        else {
            echo "<li><a href='{$page_url}page=$x'>$x</a></li>";
        }
    }
}
// button for last page
if($page<$total_pages){
    echo "<li><a href='" .$page_url . "page={$total_pages}' title='Last page is {$total_pages}.'>";
        echo "Last Page";
    echo "</a></li>";
}
echo "</ul>";
?>

Output

Login as admin and go to http://localhost/php-login-script-level-1/admin/read_users.php, you should see an output like the following.

How to validate email address?

This is a bonus section. This feature is not part of LEVEL 1 source code.

This feature needs a remote server where PHP mail function works. It does not work in localhost.

Change account status

If the user status is equal to 1, it means the email account is valid.

Since we want the user to validate his own email address, we will make it invalid (status equals to 0) the first time he register an account to our system.

Open register.php file and find:

Change the it to:

$user->status=1;

Add access code field

Access code is a unique string of characters that is needed for email validation process. Still in register.php, place the following code under the code of the previous section.

// access code for email verification
$access_code=$utils->getToken();
$user->access_code=$access_code;

Add getToken() method

This method will generate a unique string of characters for the access code field of the previous section.

Open "libs/php/utils.php" file and place the following code inside the class.

function getToken($length=32){
	$token = "";
	$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
	$codeAlphabet.= "0123456789";
	for($i=0;$i<$length;$i++){
		$token .= $codeAlphabet[$this->crypto_rand_secure(0,strlen($codeAlphabet))];
	}
	return $token;
}
function crypto_rand_secure($min, $max) {
	$range = $max - $min;
	if ($range < 0) return $min; // not so random...
	$log = log($range, 2);
	$bytes = (int) ($log / 8) + 1; // length in bytes
	$bits = (int) $log + 1; // length in bits
	$filter = (int) (1 << $bits) - 1; // set all lower bits to 1
	do {
		$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
		$rnd = $rnd & $filter; // discard irrelevant bits
	} while ($rnd >= $range);
	return $min + $rnd;
}

Change create() method

Since we added a new field, we need to change the create() method in the User class.

Open objects/user.php file. Replace the create() method with the new one below.

// create new user record
function create(){
    // to get time stamp for 'created' field
    $this->created=date('Y-m-d H:i:s');
    // insert query
    $query = "INSERT INTO " . $this->table_name . "
            SET
		firstname = :firstname,
		lastname = :lastname,
		email = :email,
		contact_number = :contact_number,
		address = :address,
		password = :password,
		access_level = :access_level,
                access_code = :access_code,
		status = :status,
		created = :created";
	// prepare the query
	$stmt = $this->conn->prepare($query);
	// sanitize
	$this->firstname=htmlspecialchars(strip_tags($this->firstname));
	$this->lastname=htmlspecialchars(strip_tags($this->lastname));
	$this->email=htmlspecialchars(strip_tags($this->email));
	$this->contact_number=htmlspecialchars(strip_tags($this->contact_number));
	$this->address=htmlspecialchars(strip_tags($this->address));
	$this->password=htmlspecialchars(strip_tags($this->password));
	$this->access_level=htmlspecialchars(strip_tags($this->access_level));
	$this->access_code=htmlspecialchars(strip_tags($this->access_code));
	$this->status=htmlspecialchars(strip_tags($this->status));
	// bind the values
	$stmt->bindParam(':firstname', $this->firstname);
	$stmt->bindParam(':lastname', $this->lastname);
	$stmt->bindParam(':email', $this->email);
	$stmt->bindParam(':contact_number', $this->contact_number);
	$stmt->bindParam(':address', $this->address);
	// hash the password before saving to database
	$password_hash = password_hash($this->password, PASSWORD_BCRYPT);
	$stmt->bindParam(':password', $password_hash);
	$stmt->bindParam(':access_level', $this->access_level);
	$stmt->bindParam(':access_code', $this->access_code);
	$stmt->bindParam(':status', $this->status);
	$stmt->bindParam(':created', $this->created);
	// execute the query, also check if query was successful
	if($stmt->execute()){
		return true;
	}else{
		$this->showError($stmt);
		return false;
	}
}

Add access_code property

The previous section will not work without this new "access_code" property. Open on objects/user.php file, find this line:

public $access_level;

And add the following code under it.

public $access_code;

11.6 Send verification email

Instead of just displaying "Successfully registered." message, we will send a verification link to user's email address.

This means we will use a new function and message saying "Verification link was sent to your email. Click that link to login.".

Open register.php file and find the following "if-else" statement.

// create the user
if($user->create()){
	echo "<div class='alert alert-info'>";
		echo "Successfully registered. <a href='{$home_url}login'>Please login</a>.";
	echo "</div>";
	// empty posted values
	$_POST=array();
}else{
	echo "<div class='alert alert-danger' role='alert'>Unable to register. Please try again.</div>";
}

Replace it with the following code.

// create the user
if($user->create()){
	// send confimation email
	$send_to_email=$_POST['email'];
	$body="Hi {$send_to_email}.<br /><br />";
	$body.="Please click the following link to verify your email and login: {$home_url}verify/?access_code={$access_code}";
	$subject="Verification Email";
	if($utils->sendEmailViaPhpMail($send_to_email, $subject, $body)){
		echo "<div class='alert alert-success'>
			Verification link was sent to your email. Click that link to login.
		</div>";
	}
	else{
		echo "<div class='alert alert-danger'>
			User was created but unable to send verification email. Please contact admin.
		</div>";
	}
	// empty posted values
	$_POST=array();
}else{
	echo "<div class='alert alert-danger' role='alert'>Unable to register. Please try again.</div>";
}

Add sendEmailViaPhpMail() method

This method will help send the email with verification link to the email address submitted by the user. It uses the built-in PHP mail() function.

Open "libs/php/utils.php" file. Place the following code inside the class.

// send email using built in php mail function
public function sendEmailViaPhpMail($send_to_email, $subject, $body){
	$from_name="Your Name";
	$from_email="[email protected]";
	$headers  = "MIME-Version: 1.0\r\n";
	$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
	$headers .= "From: {$from_name} <{$from_email}> \n";
	if(mail($send_to_email, $subject, $body, $headers)){
		return true;
	}
	return false;
}

Change the $from_name and $from_email variable values to your own.

Output

Try to register a new account. After submitting the form, you will see a message box like the following. Follow what the message says to validate the email address.

The verification email that the user will receive looks like the following. You can always change the copy of this message using the $subject and $body variables.

Create verification file

Once the user clicked the verification link, the system will change the status from 0 to 1.

He will be redirected to the login page with a confirmation message as well.

Create verify.php file in your project's main directory. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// include classes
include_once 'config/database.php';
include_once 'objects/user.php';
// get database connection
$database = new Database();
$db = $database->getConnection();
// initialize objects
$user = new User($db);
// set access code
$user->access_code=isset($_GET['access_code']) ? $_GET['access_code'] : "";
// verify if access code exists
if(!$user->accessCodeExists()){
	die("ERROR: Access code not found.");
}
// redirect to login
else{
	// update status
	$user->status=1;
	$user->updateStatusByAccessCode();
	// and the redirect
	header("Location: {$home_url}login.php?action=email_verified");
}
?>

Add accessCodeExists() method

This method will check the database if an access code already exists. It will return true if it found something, else, it will return false.

Open “objects/user.php” file. Add the following code inside the class.

// check if given access_code exist in the database
function accessCodeExists(){
	// query to check if access_code exists
	$query = "SELECT id
			FROM " . $this->table_name . "
			WHERE access_code = ?
			LIMIT 0,1";
	// prepare the query
	$stmt = $this->conn->prepare( $query );
	// sanitize
	$this->access_code=htmlspecialchars(strip_tags($this->access_code));
	// bind given access_code value
	$stmt->bindParam(1, $this->access_code);
	// execute the query
	$stmt->execute();
	// get number of rows
	$num = $stmt->rowCount();
	// if access_code exists
	if($num>0){
		// return true because access_code exists in the database
		return true;
	}
	// return false if access_code does not exist in the database
	return false;
}

Add updateStatusByAccessCode() method

Open "objects" folder. Open "user.php" file. Add the following method inside the class.

// used in email verification feature
function updateStatusByAccessCode(){
	// update query
	$query = "UPDATE " . $this->table_name . "
			SET status = :status
			WHERE access_code = :access_code";
	// prepare the query
	$stmt = $this->conn->prepare($query);
	// sanitize
	$this->status=htmlspecialchars(strip_tags($this->status));
	$this->access_code=htmlspecialchars(strip_tags($this->access_code));
	// bind the values from the form
	$stmt->bindParam(':status', $this->status);
	$stmt->bindParam(':access_code', $this->access_code);
	// execute the query
	if($stmt->execute()){
		return true;
	}
	return false;
}

Output

The previous code will redirect the user to the following page.

PHP forgot password

This is a bonus section. This feature is not part of LEVEL 1 source code.

This feature needs a remote server where PHP mail() function works. It does not work in localhost.

Open login.php file and find the login button. Look for a line that looks like the following code.

echo "<input type='submit' class='btn btn-lg btn-primary btn-block' value='Log In' />";

Once you found it, place the following code under it.

echo "<div class='margin-1em-zero text-align-center'>
	<a href='{$home_url}forgot_password'>Forgot password?</a>
</div>";

Login page new output

The login page will have the "Forgot password?" link after doing the code in the previous section.

Create "forgot password" page

This is the page where the user lands when he clicked the "Forgot password?" link on the login page.

Create forgot_password.php file in your project's main directory. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// set page title
$page_title = "Forgot Password";
// include login checker
include_once "login_checker.php";
// include classes
include_once "config/database.php";
include_once 'objects/user.php';
include_once "libs/php/utils.php";
// get database connection
$database = new Database();
$db = $database->getConnection();
// initialize objects
$user = new User($db);
$utils = new Utils();
// include page header HTML
include_once "layout_head.php";
// post code will be here
// show reset password HTML form
echo "<div class='col-md-4'></div>";
echo "<div class='col-md-4'>";
	echo "<div class='account-wall'>
		<div id='my-tab-content' class='tab-content'>
			<div class='tab-pane active' id='login'>
				<img class='profile-img' src='images/login-icon.png'>
				<form class='form-signin' action='" . htmlspecialchars($_SERVER["PHP_SELF"]) . "' method='post'>
					<input type='email' name='email' class='form-control' placeholder='Your email' required autofocus>
					<input type='submit' class='btn btn-lg btn-primary btn-block' value='Send Reset Link' style='margin-top:1em;' />
				</form>
			</div>
		</div>
	</div>";
echo "</div>";
echo "<div class='col-md-4'></div>";
// footer HTML and JavaScript codes
include_once "layout_foot.php";
?>

Forgot password page output

After doing the code above, run forget_password.php on your browser. You will see the following output.

Add post code

Once the user entered his email address and submitted the form, this code will be executed.

Replace "// post code will be here" with the following code.

// if the login form was submitted
if($_POST){
	echo "<div class='col-sm-12'>";
		// check if username and password are in the database
		$user->email=$_POST['email'];
		if($user->emailExists()){
			// update access code for user
			$access_code=$utils->getToken();
			$user->access_code=$access_code;
			if($user->updateAccessCode()){
				// send reset link
				$body="Hi there.<br /><br />";
				$body.="Please click the following link to reset your password: {$home_url}reset_password/?access_code={$access_code}";
				$subject="Reset Password";
				$send_to_email=$_POST['email'];
				if($utils->sendEmailViaPhpMail($send_to_email, $subject, $body)){
					echo "<div class='alert alert-info'>
							Password reset link was sent to your email.
							Click that link to reset your password.
						</div>";
				}
				// message if unable to send email for password reset link
				else{ echo "<div class='alert alert-danger'>ERROR: Unable to send reset link.</div>"; }
			}
			// message if unable to update access code
			else{ echo "<div class='alert alert-danger'>ERROR: Unable to update access code.</div>"; }
		}
		// message if email does not exist
		else{ echo "<div class='alert alert-danger'>Your email cannot be found.</div>"; }
	echo "</div>";
}

Add updateAccessCode() method

Open "objects" folder. Open "user.php" file. Add the following method inside the class.

// used in forgot password feature
function updateAccessCode(){
	// update query
	$query = "UPDATE
				" . $this->table_name . "
			SET
				access_code = :access_code
			WHERE
				email = :email";
	// prepare the query
	$stmt = $this->conn->prepare($query);
	// sanitize
	$this->access_code=htmlspecialchars(strip_tags($this->access_code));
	$this->email=htmlspecialchars(strip_tags($this->email));
	// bind the values from the form
	$stmt->bindParam(':access_code', $this->access_code);
	$stmt->bindParam(':email', $this->email);
	// execute the query
	if($stmt->execute()){
		return true;
	}
	return false;
}

Output

Here's a sample email sent after the user submitted his email address in using the "forgot password" form.

PHP reset password form

The "reset password" form is shown when the user clicked the link sent by the system after the "forgot password" request.

Create "reset password" page

If the use clicks the link on the email our system sent, he will land to this page where he will change his password.

Create reset_password.php file. Place the following code.

<?php
// core configuration
include_once "config/core.php";
// set page title
$page_title = "Reset Password";
// include login checker
include_once "login_checker.php";
// include classes
include_once "config/database.php";
include_once "objects/user.php";
// get database connection
$database = new Database();
$db = $database->getConnection();
// initialize objects
$user = new User($db);
// include page header HTML
include_once "layout_head.php";
echo "<div class='col-sm-12'>";
	// check acess code will be here
echo "</div>";
// include page footer HTML
include_once "layout_foot.php";
?>

Check access code

We need to check the access code to verify if the request came from the email generated by our system.

Replace the comment "// check acess code will be here" of the previous section with the following code.

// get given access code
$access_code=isset($_GET['access_code']) ? $_GET['access_code'] : die("Access code not found.");
// check if access code exists
$user->access_code=$access_code;
if(!$user->accessCodeExists()){
	die('Access code not found.');
}
else{
	// reset password form will be here
}

Add "reset password" form

If the access code exists, the page will render a form where the user can enter his new password.

Once the user submitted a new password, the database will be updated with this new password data.

Replace the comment "// reset password form will be here" of the previous section with the following code.

// post code will be here
echo "<form action='" . htmlspecialchars($_SERVER["PHP_SELF"]) . "?access_code={$access_code}' method='post'>
    <table class='table table-hover table-responsive table-bordered'>
		<tr>
            <td>Password</td>
            <td><input type='password' name='password' class='form-control' required></td>
        </tr>
        <tr>
            <td></td>
            <td><button type='submit' class='btn btn-primary'>Reset Password</button></td>
        </tr>
    </table>
</form>";

Add post code

Replace the comment "// post code will be here" of the previous section with the following code.

// if form was posted
if($_POST){
	// set values to object properties
	$user->password=$_POST['password'];
	// reset password
	if($user->updatePassword()){
		echo "<div class='alert alert-info'>Password was reset. Please <a href='{$home_url}login'>login.</a></div>";
	}
	else{
		echo "<div class='alert alert-danger'>Unable to reset password.</div>";
	}
}

Add updatePassword() method

This method will help update the password in the database. The previous section won't work without this method in the User class.

Open "objects/user.php" file. Add the following code inside the class.

// used in forgot password feature
function updatePassword(){
	// update query
	$query = "UPDATE " . $this->table_name . "
			SET password = :password
			WHERE access_code = :access_code";
	// prepare the query
	$stmt = $this->conn->prepare($query);
	// sanitize
	$this->password=htmlspecialchars(strip_tags($this->password));
	$this->access_code=htmlspecialchars(strip_tags($this->access_code));
	// bind the values from the form
	$password_hash = password_hash($this->password, PASSWORD_BCRYPT);
	$stmt->bindParam(':password', $password_hash);
	$stmt->bindParam(':access_code', $this->access_code);
	// execute the query
	if($stmt->execute()){
		return true;
	}
	return false;
}

Output

To run reset_password.php file, click the link sent to your email address via "forgot password" form.

Download source codes

Choose the source code with features that you need or want to learn.

FEATURESBASICPRO
PHP login form with email and password
PHP Sessions are used to identify logged-in and logged-out users.
Hashed password stored in the database
PHP registration form
Redirection to the login page if the user is not yet logged in
Customer access to the index page when logged in
Customer logout
Admin users list pagination
Admin logout
Require login in admin index and users list page
Bootstrap-enabled user interface
Password and confirm password fields-
Check if the password matches-
Sending of verification link to email-
Validation page or email link-
Check if the password is strong enough-
Forgot password page-
Password reset link sent to the email-
PHP password reset form-
Customer access to edit profile page when logged in-
Customer change password page-
Customer password and confirm password field when editing profile-
Customer logout-
Admin creates, reads, update, and deletes users-
Admin search user by email address-
Admin edit profile-
Admin change password page-
Admin can change user passwords-
Admin can manually change the status of users (pending or approved)-
Require login in admin index page, edit profile page and users CRUD pages.-
Use the buttons below to download. ↓BASICPRO

How To Run The Source Code?

After you download the source code, extract the zip file. There you will see a README.txt file. Read the exact instructions there about how to run the source code.

What’s Next?

For our next tutorial, we will learn how to create a simple PHP shopping cart that uses a MySQL database.

Click here to proceed to the next tutorial: PHP Shopping Cart Tutorial – Step By Step Guide!

What students say?

Don't just take our word for it. See what our students have to say about our tutorials and source codes. We are proud to have helped many individuals and businesses to build their own applications. Here are a few of the testimonials from our satisfied students.

★★★★★ “Wow, I love you guys! The best web programming tutorial I’ve ever seen. So comprehensive, yet easy to follow. I love how you combine all necessary elements in such a neat structure.” ~ Olaug Nessa

★★★★★ “The fact that you’ve put it all together saves so much time and its worth buying the code. Makes me feel good supporting a developer like yourself. Keep up the good work!” ~ Dan Hudson

★★★★★ “Thanks for making these awesome tutorials! I bought your source codes. To be honest, it’s very readable code and helps me understand a lot of things and how it’s done in PHP. Thanks for that again.” ~ Michael Lammens

★★★★★ “Hey Mike, my name is Leonardo from Argentina. I’ve been reading your blog since like 4 months from now, and I really must say: your tutorials are very good, they has helped me in many of my works… Well, thank you very much man. I really admire your work.” ~ Leonardo

★★★★★ “Words can’t express how grateful I am for the work and the articles you post, had some troubles with doing somethings but your articles as per usual hit the hammer right on the head. They are a great way for expanding upon later too!” ~ Jeremy Smith

Got comments?

At codeofaninja.com, we strive to provide our readers with accurate and helpful PHP Login System Tutorial – Step By Step Guide! Your feedback is essential in helping us achieve this goal.

If you have encountered any issues with the code, have suggestions for improvement, or wish to provide praise, we welcome you to leave a comment below. Please be as descriptive as possible to address your concerns effectively and include any relevant error messages, screenshots, or test URLs.

We request that comments remain on-topic and relevant to the article above. If your question or comment pertains to a different topic, we recommend seeking assistance elsewhere.

Furthermore, we ask that you review our code of conduct before commenting to ensure that your feedback is constructive and respectful.

Thank you for taking the time to provide feedback and for supporting codeofaninja.com. Your contributions help us improve our tutorials and serve the developer community better.

Subscribe for FREE!

Improve your web development skills and stay ahead of the competition by subscribing to our tutorial series. Sign up for FREE and access exclusive, cutting-edge content delivered straight to your inbox.

Take advantage of the chance to elevate your skills and advance your web development career. Subscribe now.

Thank You!

We hope you've found our PHP Login System Tutorial – Step By Step Guide! helpful and informative. We understand that learning new programming concepts can be challenging, but we're glad we could make it easier for you.

Thank you for choosing to learn with us and for supporting codeofaninja.com! Consider sharing this tutorial with your friends and colleagues who may also be interested in learning about PHP Login System Tutorial – Step By Step Guide!

The more people know about our tutorials, the more we can help the developer community grow. Keep learning, keep coding, and keep growing as a developer. We can't wait to see what you'll create next!

How To Create Dynamic Pie Chart in PHP or JavaScript with MySQL?

Graphical or visual representation of data is usually a requirement for a software, mostly, business apps. Today I'm going to show you the two and free ways to generate dynamic Pie Charts for your web applications.

We say "dynamic" because the data that will be shown in the pie chart were pulled from a database which can be updated frequently.

You can also create other types of charts such as bar charts, line charts, and many other types of charts, but in this post, we will cover pie charts only which can give you a good idea on how to create dynamic charts.

how to create dynamic pie chart in php or javascript

In this post, we will cover the following topics:

1.0 Dummy Database for Dynamic Pie Chart
2.0 Using LibChart to Create Dynamic Charts (PHP)
3.0 Using the Google Chart Tools (JavaScript)

The first way I will give you is generating a chart using PHP, and in the second way, we will use JavaScript.

Dummy Database for Dynamic Pie Chart

This will be our example table and data.

--
-- Table structure for table `programming_languages`
--
 
CREATE TABLE IF NOT EXISTS `programming_languages` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `ratings` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
 
--
-- Dumping data for table `programming_languages`
--
 
INSERT INTO `programming_languages` (`id`, `name`, `ratings`) VALUES
(1, 'C', 17),
(2, 'Java', 16),
(3, 'C++', 9),
(4, 'Objective-C', 9),
(5, 'C#', 7),
(6, 'Basic', 6),
(7, 'PHP', 5),
(8, 'Phyton', 3),
(9, 'Pearl', 2),
(10, 'Ruby', 1);

Using LibChart to Create Dynamic Charts (PHP)

We will do the first way using the LibChart, the simple and free PHP chart drawing library.

Here's a code:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Pie Chart Demo (LibChart)- https://codeofaninja.com/</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-15" />
</head>
<body>
 
<?php
    //include the library
    include "libchart/libchart/classes/libchart.php";
 
    //new pie chart instance
    $chart = new PieChart( 500, 300 );
 
    //data set instance
    $dataSet = new XYDataSet();
    
    //actual data
    //get data from the database
    
    //include database connection
    include 'db_connect.php';
 
    //query all records from the database
    $query = "select * from programming_languages";
 
    //execute the query
    $result = $mysqli->query( $query );
 
    //get number of rows returned
    $num_results = $result->num_rows;
 
    if( $num_results > 0){
    
        while( $row = $result->fetch_assoc() ){
            extract($row);
            $dataSet->addPoint(new Point("{$name} {$ratings})", $ratings));
        }
    
        //finalize dataset
        $chart->setDataSet($dataSet);
 
        //set chart title
        $chart->setTitle("Tiobe Top Programming Languages for June 2012");
        
        //render as an image and store under "generated" folder
        $chart->render("generated/1.png");
    
        //pull the generated chart where it was stored
        echo "<img alt='Pie chart'  src='generated/1.png' style='border: 1px solid gray;'/>";
    
    }else{
        echo "No programming languages found in the database.";
    }
?>
 
</body>
</html>

Some advantage of using the LibChart includes: Free, it will work even offline or if you're just debugging on your localhost, easy to use and can be used for multiple data sets.

Some disadvantages are: It is limited to Line, Bar and Pie charts only and it works with PHP5 only.

Using the Google Chart Tools (JavaScript)

Google chart tools are powerful, simple to use, and also free.

Our index.php code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
        <title>Pie Chart Demo (Google VAPI) - https://codeofaninja.com/</title>
    </head>
    
<body style="font-family: Arial;border: 0 none;">
    <!-- where the chart will be rendered -->
    <div id="visualization" style="width: 600px; height: 400px;"></div>
 
    <?php
 
    //include database connection
    include 'db_connect.php';
 
    //query all records from the database
    $query = "select * from programming_languages";
 
    //execute the query
    $result = $mysqli->query( $query );
 
    //get number of rows returned
    $num_results = $result->num_rows;
 
    if( $num_results > 0){
 
    ?>
        <!-- load api -->
        <script type="text/javascript" src="http://www.google.com/jsapi"></script>
        
        <script type="text/javascript">
            //load package
            google.load('visualization', '1', {packages: ['corechart']});
        </script>
 
        <script type="text/javascript">
            function drawVisualization() {
                // Create and populate the data table.
                var data = google.visualization.arrayToDataTable([
                    ['PL', 'Ratings'],
                    <?php
                    while( $row = $result->fetch_assoc() ){
                        extract($row);
                        echo "['{$name}', {$ratings}],";
                    }
                    ?>
                ]);
 
                // Create and draw the visualization.
                new google.visualization.PieChart(document.getElementById('visualization')).
                draw(data, {title:"Tiobe Top Programming Languages for June 2012"});
            }
 
            google.setOnLoadCallback(drawVisualization);
        </script>
    <?php
 
    }else{
        echo "No programming languages found in the database.";
    }
    ?>
    
</body>
</html>

The advantages of using Google chart tools include: Free, easy to use, multiple data sets, and has wide range of charts types that you can use, looks good and interactive.

I think the only disadvantage will be: you cannot use it when you don't have internet connection.

Download Source Code

You can download all the code used in this tutorial for only $9.99 $5.55!
[purchase_link id="12370" text="Download Now" style="button" color="green"]

How about you, do you have any other suggestions or solutions on how to create dynamic pie chart in PHP or JavaScript? Thanks for sharing it in the comments section below!

Append Subtitle/Caption Image Using PHP and Hide It with CSS

Note: People say it isn’t actually a watermark, the image appended can be called a “Caption” or “Hidden Subtitle”. So in this post, when I say “watermark”, it refers to the ”Caption” or “Hidden Subtitle”.
Nowadays I see many websites with image contents. Funny images, interesting images, cosplay, art and many more kinds of images. Many people don’t want to hotlink or copy the image link and share it to any social networking site such as Facebook, instead they copy or download the image (using browser’s “Save image as” option) and upload it to their own account without linking it to the source or website where they found it.

One solution websites do is to append a watermark on their images. The don’t want this watermark to be shown on their website but they want it to appear when the user went to the actual image link or when this image was copied or downloaded.
An example website the does this is 9gag.com. When you see the image on their site, it does not have any watermark. But when you try to save the image, the watermark will appear, appended at the bottom part of the image, it is in white background.
Today we’re going to do a code the does something like that.

DOWNLOAD CODE LIVE DEMO
  • Append a watermark at the bottom part of the image using PHP
  • Hide it using CSS

First, we need to prepare:

  • Sample image – the image you want to put a watermark
  • Watermark image – the image that will be put as watermark on the sample image

As for the sample image, we’re going to use this image of my pets (yes, my pets):

Append Subtitle/Caption Image Using PHP and Hide It with CSS

For the watermark image:

This will be appended on the main image
This will be appended on the main image

Some notes:

    • “sample.jpg” and “watermark.jpg” should be your variable
    • PHP GD library should be enabled on your server

Our index.php, we are going to have the following code:

<?php
 
    //set the header
    header( "Content-type: image/jpg" );
 
    //get image sizes first
    $image_size = getimagesize( "sample.jpg" );
    $watermark_size = getimagesize( "watermark.jpg" );
 
    $image_size_width = $image_size[0];
    $image_size_height = $image_size[1];
 
    $watermark_size_width = $watermark_size[0];
    $watermark_size_height = $watermark_size[1];
 
    //create images
    $main_img = imagecreatefromjpeg( "sample.jpg" );
    $watermark = imagecreatefromjpeg( "watermark.jpg" );
 
    //create canvas
    $canvas = imagecreatetruecolor(
 
        $image_size_width, //width of main image
        $image_size_height + $watermark_size_height //this is the new height, height of main image plus watermark image
    ) or die('Cannot Initialize new GD image stream.');
 
     
    //set white background of canvas
    $bg = imagecolorallocate( $canvas, 255, 255, 255 );
    imagefill ( $canvas, 0, 0, $bg );
 
 
    //paste main image to the canvas
    imagecopymerge(
        $canvas, 
        $main_img, 
        0, //main_img x coordinate ( distance from left side of main_img )
        0, //main_img y coordinate ( distance form top of main_img )
        0, //main_img x coordinate image ( distance from left side of main_img )
        0, //main_img y coordinate image ( distance from top side of main_img )
        $image_size_width, //main_img width
        $image_size_height, //main_img height
        100 //the opacity of main_img
 
    );
 
    //paste the watermark image to the canvas
    imagecopymerge(
        $canvas, 
        $watermark, 
        0, //watermark x coordinate ( distance from left side of main_img )
        $image_size_height, //watermark y coordinate ( distance form top of main_img )
        0, //watermark x coordinate image ( distance from left side of watermark )
        0, //watermark y coordinate image ( distance from top side of watermark ) 
        $watermark_size_width, //watermark width
        $watermark_size_height, //watermark height
        100 //the opacity of watermark
 
    );
 
    //show the new image
    imagejpeg( $canvas );
 
    //if you want to save it to your server directory, just add the second param
    //something like:
    //imagejpeg($canvas, 'your_directory/new_img.jpg');
 
    imagedestroy( $canvas );
    imagedestroy( $main_img );
    imagedestroy( $watermark );
 
?>
new_img

Now, we are going to the second part of this post. We are going to show the output image on a webpage, but the watermark is hidden using CSS.

Our page.php should have the following code:

<html>
 
    <head>
 
        <title></title>
 
    </head>
 
<body>
 
    <div style='font-weight:bold; font-size:18px;'>The image below has a watermark, but it was hidden.</div>
    <div style='margin:5px 0;'>Try to go to the actual image by doing 'open image in new tab' or downloading it.</div>
 
 
    <div style='overflow:hidden;'>
 
        <!-- -30px here is the height of our watermark -->
        <img src='new_img.jpg' style='margin:0 0 -30px 0;' />
 
    </div>
 
</body>
</html>

See the live demo for the output! :)

PHP CRUD Tutorial for Beginners – Step By Step Guide!

Previously, we learned how to make our application look good using the Bootstrap CSS framework. This time, we will learn CRUD operations with PHP and MySQL. CRUD stands for Create, Read, Update and Delete database records.

Overview

This tutorial is for your if:

  • You need a high quality and updated reference for a PHP CRUD tutorial.
  • You need to learn how to do CRUD operations in PHP and MySQL.
  • You are beginner in this kind of PHP web programming.

Coding CRUD with PHP and MySQL is one of the basics. PHP web programmers must be able to code it with less effort. We can perform this task using any of the three PHP Database extensions:

  1. Using the MySQL extension.
  2. Using the MySQLi extension.
  3. Using the PDO extension.

PHP 5.5 deprecated the MySQL extension. It is not recommended to use these days.

If you are programming with PHP, you'll have to use either MySQLi (i means improved) or PDO extension.

With that in mind, we will use the PDO extension. It is the newest and actively developed way of programming these CRUD grids.

Project file structure

Our PHP CRUD tutorial will contain the following main files.

  • dev/products.sql – contains the database table structure and sample data used in this project. Once you created your database in PhpMyAdmin, you can import this file.
  • config/database.php – used for database connection and configuration.
  • create.php – used for creating a new record. It contains an HTML form where the user can enter details for a new record.
  • index.php – used for reading records from the database. It uses an HTML table to display the data retrieved from the MySQL database.
  • read_one.php – used for reading one or single record from database. It uses an HTML table to display the data retrieved from the MySQL database.
  • update.php – used for updating a record. It uses an HTML form which will be filled out with data based on the given “id” parameter.
  • delete.php – used for deleting a record. It accepts an “id” parameter and deletes the record with it. Once it execute the delete query, it will redirect the user to the index.php page.

Prepare the database

Create the database

On your PhpMyAdmin, create a database named "php_beginner_crud_level_1".

If you're not sure how to do it, please take a look at the following example. Follow only the "create database" part.

Create the database table

Next, run the following SQL code. This is to create our products database table. If you're not sure how to do this, take a look at this resource.

--
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `description` text NOT NULL,
  `price` double NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

Dump sample data on the table

Again, run the following SQL code on your PhpMyAdmin. This will insert the sample data or record it on our products database table.

--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `name`, `description`, `price`, `created`, `modified`) VALUES
(1, 'Basketball', 'A ball used in the NBA.', 49.99, '2015-08-02 12:04:03', '2015-08-06 06:59:18'),
(3, 'Gatorade', 'This is a very good drink for athletes.', 1.99, '2015-08-02 12:14:29', '2015-08-06 06:59:18'),
(4, 'Eye Glasses', 'It will make you read better.', 6, '2015-08-02 12:15:04', '2015-08-06 06:59:18'),
(5, 'Trash Can', 'It will help you maintain cleanliness.', 3.95, '2015-08-02 12:16:08', '2015-08-06 06:59:18'),
(6, 'Mouse', 'Very useful if you love your computer.', 11.35, '2015-08-02 12:17:58', '2015-08-06 06:59:18'),
(7, 'Earphone', 'You need this one if you love music.', 7, '2015-08-02 12:18:21', '2015-08-06 06:59:18'),
(8, 'Pillow', 'Sleeping well is important.', 8.99, '2015-08-02 12:18:56', '2015-08-06 06:59:18');

As you may have noticed, steps 1 and 2 are both SQL queries. Yes, they can run at the same time. But I wanted it to be on separate steps to emphasize those SQL queries' purpose.

Create database connection file

This section will answer the question: how to connect to MySQL database with PDO?

  • Create php-beginner-crud-level-1 folder and open it.
  • Create config folder and open it.
  • Create database.php file.
  • Place the following code inside it.
<?php
// used to connect to the database
$host = "localhost";
$db_name = "php_beginner_crud_level_1";
$username = "root";
$password = "";
try {
    $con = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
}
// show error
catch(PDOException $exception){
    echo "Connection error: " . $exception->getMessage();
}
?>

Output

We have set up the database successfully! The only output we have so far is the database, database table, and sample records we set up via PhpMyAdmin.

Let's proceed to the next section below.

Create or insert record in PHP

HTML5 boilerplate for create.php

We use the Bootstrap user interface for this project. If you are not familiar with Bootstrap, please learn our Bootstrap Tutorial for Beginners.

  • Go back to php-beginner-crud-level-1 folder.
  • Create a new create.php file.
  • Place the code following code inside the create.php file.
<!DOCTYPE HTML>
<html>
<head>
    <title>PDO - Create a Record - PHP CRUD Tutorial</title>
    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
</head>
<body>
    <!-- container -->
    <div class="container">
        <div class="page-header">
            <h1>Create Product</h1>
        </div>
    <!-- html form to create product will be here -->
    </div> <!-- end .container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>

HTML form to input new record data

Now we are going to start answering the question: how to create a record with PDO?

The code below will create an HTML form with input fields that matches the fields in the database. Replace <!-- html form to create product will be here --> comment of the previous section with the following code.

<!-- PHP insert code will be here -->
<!-- html form here where the product information will be entered -->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">
	<table class='table table-hover table-responsive table-bordered'>
		<tr>
			<td>Name</td>
			<td><input type='text' name='name' class='form-control' /></td>
		</tr>
		<tr>
			<td>Description</td>
			<td><textarea name='description' class='form-control'></textarea></td>
		</tr>
		<tr>
			<td>Price</td>
			<td><input type='text' name='price' class='form-control' /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<input type='submit' value='Save' class='btn btn-primary' />
				<a href='index.php' class='btn btn-danger'>Back to read products</a>
			</td>
		</tr>
	</table>
</form>

Code to create a new record

We are still working on the create.php file. Once the user filled out the form and clicked the save button, the code below will save it to the MySQL database.

Replace <!-- PHP insert code will be here --> comment of the previous section with the following code.

<?php
if($_POST){
	// include database connection
	include 'config/database.php';
	try{
		// insert query
		$query = "INSERT INTO products SET name=:name, description=:description, price=:price, created=:created";
		// prepare query for execution
		$stmt = $con->prepare($query);
		// posted values
		$name=htmlspecialchars(strip_tags($_POST['name']));
		$description=htmlspecialchars(strip_tags($_POST['description']));
		$price=htmlspecialchars(strip_tags($_POST['price']));
		// bind the parameters
		$stmt->bindParam(':name', $name);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':price', $price);
		// specify when this record was inserted to the database
		$created=date('Y-m-d H:i:s');
		$stmt->bindParam(':created', $created);
		// Execute the query
		if($stmt->execute()){
			echo "<div class='alert alert-success'>Record was saved.</div>";
		}else{
			echo "<div class='alert alert-danger'>Unable to save record.</div>";
		}
	}
	// show error
	catch(PDOException $exception){
		die('ERROR: ' . $exception->getMessage());
	}
}
?>

Output

Congrats! For the first time, we can now see an output on a web page. Go to this URL:

http://localhost/php-beginner-crud-level-1/create.php

You will see the output that looks like the following images.

When the user fills out the form.

When the user submitted the form.

A new record added to the database.

Read records in PHP

Basic HTML code for index.php

Create a new index.php file. We prepare this to read records from the database. It answers the question: how to read records with PDO?

Place the following code inside the index.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Read Records - PHP CRUD Tutorial</title>
	<!-- Latest compiled and minified Bootstrap CSS -->
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
	<!-- custom css -->
	<style>
	.m-r-1em{ margin-right:1em; }
	.m-b-1em{ margin-bottom:1em; }
	.m-l-1em{ margin-left:1em; }
	.mt0{ margin-top:0; }
	</style>
</head>
<body>
    <!-- container -->
    <div class="container">
        <div class="page-header">
            <h1>Read Products</h1>
        </div>
        <!-- PHP code to read records will be here -->
    </div> <!-- end .container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- confirm delete record will be here -->
</body>
</html>

Read records from the database

This time we will read records from the database.

Replace <!-- PHP code to read records will be here --> comment of the previous section with the following code.

<?php
// include database connection
include 'config/database.php';
// delete message prompt will be here
// select all data
$query = "SELECT id, name, description, price FROM products ORDER BY id DESC";
$stmt = $con->prepare($query);
$stmt->execute();
// this is how to get number of rows returned
$num = $stmt->rowCount();
// link to create record form
echo "<a href='create.php' class='btn btn-primary m-b-1em'>Create New Product</a>";
//check if more than 0 record found
if($num>0){
	// data from database will be here
}
// if no records found
else{
	echo "<div class='alert alert-danger'>No records found.</div>";
}
?>

Add HTML table with heading

This is the HTML table that will hold and display data from the database.

Replace // data from database will be here comment of the previous section with the following code.

//start table
echo "<table class='table table-hover table-responsive table-bordered'>";
	//creating our table heading
	echo "<tr>
		<th>ID</th>
		<th>Name</th>
		<th>Description</th>
		<th>Price</th>
		<th>Action</th>
	</tr>";
	// table body will be here
// end table
echo "</table>";

Add HTML table body

This part is where we will loop through the list of records from the database. This loop will create the rows of data on our HTML table.

Replace // table body will be here comment of the previous section with the following code.

// retrieve our table contents
// fetch() is faster than fetchAll()
// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
	// extract row
	// this will make $row['firstname'] to
	// just $firstname only
	extract($row);
	// creating new table row per record
	echo "<tr>
		<td>{$id}</td>
		<td>{$name}</td>
		<td>{$description}</td>
		<td>${$price}</td>
		<td>";
			// read one record
			echo "<a href='read_one.php?id={$id}' class='btn btn-info m-r-1em'>Read</a>";
			// we will use this links on next part of this post
			echo "<a href='update.php?id={$id}' class='btn btn-primary m-r-1em'>Edit</a>";
			// we will use this links on next part of this post
			echo "<a href='#' onclick='delete_user({$id});'  class='btn btn-danger'>Delete</a>";
		echo "</td>";
	echo "</tr>";
}

Output

Go to this URL:

http://localhost/php-beginner-crud-level-1/index.php

You will see the records retrieved from the database. It will look like the image below.

Read one record in PHP

Basic HTML code for read_one.php

Create a new read_one.php file. This is where we will read and display the details of a single database record.

Place the following code inside the read_one.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Read One Record - PHP CRUD Tutorial</title>
    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
</head>
<body>
    <!-- container -->
    <div class="container">
        <div class="page-header">
            <h1>Read Product</h1>
        </div>
        <!-- PHP read one record will be here -->
        <!-- HTML read one record table will be here -->
	</div> <!-- end .container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>

Read one record from the database

The following code is how we retrieve a single database record.

Replace <!-- PHP read one record will be here --> comment of the previous section with the following code.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');
//include database connection
include 'config/database.php';
// read current record's data
try {
	// prepare select query
	$query = "SELECT id, name, description, price FROM products WHERE id = ? LIMIT 0,1";
	$stmt = $con->prepare( $query );
	// this is the first question mark
	$stmt->bindParam(1, $id);
	// execute our query
	$stmt->execute();
	// store retrieved row to a variable
	$row = $stmt->fetch(PDO::FETCH_ASSOC);
	// values to fill up our form
	$name = $row['name'];
	$description = $row['description'];
	$price = $row['price'];
}
// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

Display record details

The following HTML table will hold and display the details of a single database record.

Open read_one.php file.

Replace <!-- HTML read one record table will be here --> comment with the following code.

<!--we have our html table here where the record will be displayed-->
<table class='table table-hover table-responsive table-bordered'>
	<tr>
		<td>Name</td>
		<td><?php echo htmlspecialchars($name, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td>Description</td>
		<td><?php echo htmlspecialchars($description, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td>Price</td>
		<td><?php echo htmlspecialchars($price, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td></td>
		<td>
			<a href='index.php' class='btn btn-danger'>Back to read products</a>
		</td>
	</tr>
</table>

Output

To read one record from the database, try to click any Read button from our index.php file.

You can also go to this URL:

http://localhost/php-beginner-crud-level-1/read_one.php?id=9

You will see an output like the image below.

Update record in PHP

Basic HTML code for udpate.php

Create a new update.php file. We are preparing to update a selected record from the database.

This will answer the question: how to update a record with PDO?

Place the following code inside the new update.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Update a Record - PHP CRUD Tutorial</title>
    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
</head>
<body>
    <!-- container -->
    <div class="container">
        <div class="page-header">
            <h1>Update Product</h1>
        </div>
        <!-- PHP read record by ID will be here -->
        <!-- HTML form to update record will be here -->
    </div> <!-- end .container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>

Read a record by ID parameter

We have to get the record ID and store it in the $id variable. We access the $_GET['id'] variable to do it.

What we are trying to do here is to get the related data based on the given record ID. This is the way to auto-fill the HTML form with existing data from the database.

Replace <!-- PHP read record by ID will be here --> comment of the previous section with the following code.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');
//include database connection
include 'config/database.php';
// read current record's data
try {
	// prepare select query
	$query = "SELECT id, name, description, price FROM products WHERE id = ? LIMIT 0,1";
	$stmt = $con->prepare( $query );
	// this is the first question mark
	$stmt->bindParam(1, $id);
	// execute our query
	$stmt->execute();
	// store retrieved row to a variable
	$row = $stmt->fetch(PDO::FETCH_ASSOC);
	// values to fill up our form
	$name = $row['name'];
	$description = $row['description'];
	$price = $row['price'];
}
// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

HTML form to update a record

This form will show the data retrieved using the previous section's code.

We read a single record from the database, based on the given ID parameter.

Open update.php file. Replace <!-- HTML form to update record will be here --> comment with the following code.

<!-- PHP post to update record will be here -->
<!--we have our html form here where new record information can be updated-->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"] . "?id={$id}");?>" method="post">
	<table class='table table-hover table-responsive table-bordered'>
		<tr>
			<td>Name</td>
			<td><input type='text' name='name' value="<?php echo htmlspecialchars($name, ENT_QUOTES);  ?>" class='form-control' /></td>
		</tr>
		<tr>
			<td>Description</td>
			<td><textarea name='description' class='form-control'><?php echo htmlspecialchars($description, ENT_QUOTES);  ?></textarea></td>
		</tr>
		<tr>
			<td>Price</td>
			<td><input type='text' name='price' value="<?php echo htmlspecialchars($price, ENT_QUOTES);  ?>" class='form-control' /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<input type='submit' value='Save Changes' class='btn btn-primary' />
				<a href='index.php' class='btn btn-danger'>Back to read products</a>
			</td>
		</tr>
	</table>
</form>

Code to update the record

The following code will save the changes in the database.

That is if the user changes some value on the form and hits the Save Changes button.

Replace <!-- PHP post to update record will be here --> comment of the previous section with the following code.

<?php
// check if form was submitted
if($_POST){
	try{
		// write update query
		// in this case, it seemed like we have so many fields to pass and
		// it is better to label them and not use question marks
		$query = "UPDATE products
					SET name=:name, description=:description, price=:price
					WHERE id = :id";
		// prepare query for excecution
		$stmt = $con->prepare($query);
		// posted values
		$name=htmlspecialchars(strip_tags($_POST['name']));
		$description=htmlspecialchars(strip_tags($_POST['description']));
		$price=htmlspecialchars(strip_tags($_POST['price']));
		// bind the parameters
		$stmt->bindParam(':name', $name);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':price', $price);
		$stmt->bindParam(':id', $id);
		// Execute the query
		if($stmt->execute()){
			echo "<div class='alert alert-success'>Record was updated.</div>";
		}else{
			echo "<div class='alert alert-danger'>Unable to update record. Please try again.</div>";
		}
	}
	// show errors
	catch(PDOException $exception){
		die('ERROR: ' . $exception->getMessage());
	}
}
?>

Output

To update a database record, run the index.php file and click any Edit button.

Or, go to this URL:

http://localhost/php-beginner-crud-level-1/update.php?id=9

You will see the result like the images below.

Update record form.

Submitted form.

Changes in the database.

Delete record in PHP

Tell the user if record was deleted

This will tell the user if there is a deleted record after clicking the delete button and OK in the pop-up.

Open index.php file. Replace // delete message prompt will be here comment with the following code.

$action = isset($_GET['action']) ? $_GET['action'] : "";
// if it was redirected from delete.php
if($action=='deleted'){
	echo "<div class='alert alert-success'>Record was deleted.</div>";
}

JavaScript to confirm record deletion

The user clicks on the Delete button in index.php.

Next, he will verify the deletion by clicking OK on the pop-up.

That user activity will execute the following JavaScript code.

Open index.php file. Replace <!-- confirm delete record will be here --> comment with the following code.

<script type='text/javascript'>
// confirm record deletion
function delete_user( id ){
	var answer = confirm('Are you sure?');
	if (answer){
		// if user clicked ok,
		// pass the id to delete.php and execute the delete query
		window.location = 'delete.php?id=' + id;
	}
}
</script>

Delete record from the database

The code below will delete a record from the database using the given ID parameter.

This answers the question: how to delete a record with PDO?

Create a new delete.php file, place the following code and save it.

<?php
// include database connection
include 'config/database.php';
try {
	// get record ID
	// isset() is a PHP function used to verify if a value is there or not
	$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');
	// delete query
	$query = "DELETE FROM products WHERE id = ?";
	$stmt = $con->prepare($query);
	$stmt->bindParam(1, $id);
	if($stmt->execute()){
		// redirect to read records page and
		// tell the user record was deleted
		header('Location: index.php?action=deleted');
	}else{
		die('Unable to delete record.');
	}
}
// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

Output

Once the user clicks any Delete button, it will show a confirmation pop-up.

If the user clicks the "OK" button, the record will be deleted from the database. It will tell the user via message prompt that the record was deleted.

The record is gone in the database as well.

Pagination in PHP

Please note that this is a bonus section and is not included in the LEVEL 1 source code download. We will have to add or remove some codes we've done above so that pagination will work.

Set pagination variables

The following variables are used to calculate the correct numbers for the LIMIT clause of our SELECT query.

We will see how our SELECT query will change later.

Place the following code below include 'config/database.php'; line of index.php file.

// PAGINATION VARIABLES
// page is the current page, if there's nothing set, default is page 1
$page = isset($_GET['page']) ? $_GET['page'] : 1;
// set records or rows of data per page
$records_per_page = 5;
// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;

Add LIMIT clause in SELECT query

This will enable paginated requests to the database. Still on the index.php file, change the following code from:

$query = "SELECT id, name, description, price FROM products ORDER BY id DESC";
$stmt = $con->prepare($query);
$stmt->execute();

to:

// select data for current page
$query = "SELECT id, name, description, price FROM products ORDER BY id DESC
	LIMIT :from_record_num, :records_per_page";
$stmt = $con->prepare($query);
$stmt->bindParam(":from_record_num", $from_record_num, PDO::PARAM_INT);
$stmt->bindParam(":records_per_page", $records_per_page, PDO::PARAM_INT);
$stmt->execute();

Count total number of records

Counting the total number of records will help calculate the correct pagination numbers.

Below the closing table tag in the index.php file, add the following code.

// PAGINATION
// count total number of rows
$query = "SELECT COUNT(*) as total_rows FROM products";
$stmt = $con->prepare($query);
// execute query
$stmt->execute();
// get total rows
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$total_rows = $row['total_rows'];

Include paging file

Add the following code after the previous section's code.

// paginate records
$page_url="index.php?";
include_once "paging.php";

Why a $page_url variable is needed? Because we made paging.php re-usable. You can use it for other objects you want to paginate.

For example, you're trying to paginate your read_categories.php, you will need to do:

$page_url="read_categories.php?";

You will have to follow the code pattern of sections 10.1 to 10.3 when you use the paging.php file.

Create paging.php

Create a new paging.php file. Place the following code and save it.

<?php
echo "<ul class='pagination pull-left margin-zero mt0'>";
// first page button will be here
// clickable page numbers will be here
// last page button will be here
echo "</ul>";
?>

Add first page button

Replace // first page button will be here comment of the previous section with the following code.

// first page button
if($page>1){
	$prev_page = $page - 1;
	echo "<li>
		<a href='{$page_url}page={$prev_page}'>
			<span style='margin:0 .5em;'>«</span>
		</a>
	</li>";
}

Add clickable page numbers

Open paging.php file.

Replace // clickable page numbers will be here comment with the following code.

// clickable page numbers
// find out total pages
$total_pages = ceil($total_rows / $records_per_page);
// range of num links to show
$range = 1;
// display links to 'range of pages' around 'current page'
$initial_num = $page - $range;
$condition_limit_num = ($page + $range)  + 1;
for ($x=$initial_num; $x<$condition_limit_num; $x++) {
	// be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
	if (($x > 0) && ($x <= $total_pages)) {
		// current page
		if ($x == $page) {
			echo "<li class='active'>
				<a href='javascript::void();'>{$x}</a>
			</li>";
		}
		// not current page
		else {
			echo "<li>
				<a href='{$page_url}page={$x}'>{$x}</a> 
			</li>";
		}
	}
}

Add last page button

Open paging.php file.

Replace // last page button will be here comment with the following code.

// last page button
if($page<$total_pages){
	$next_page = $page + 1;
	echo "<li>
		<a href='{$page_url}page={$next_page}'>
			<span style='margin:0 .5em;'>»</span>
		</a>
	</li>";
}

Output

Run index.php file on the browser:

http://localhost/php-beginner-crud-level-1/index.php

You should see the pagination buttons like the images below.

Read records page 1.

Read records page 2.

File upload in PHP

Now we are going to add a file upload feature when creating a record.

Add HTML "file" field

Open the create.php file and scroll down to the form. Find the opening "form tag and enable the file upload by changing it to:

<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post" enctype="multipart/form-data">

Find the closing tr tag of the price field. Once found, add the following code after it.

<tr>
	<td>Photo</td>
	<td><input type="file" name="image" /></td>
</tr>

Add "image" field

Still in create.php file. Scroll up and change the insert SQL query.

It should look like the following code. The new image field will store the file name of the submitted file.

// insert query
$query = "INSERT INTO products
			SET name=:name, description=:description,
				price=:price, image=:image, created=:created";
// prepare query for execution
$stmt = $con->prepare($query);
$name=htmlspecialchars(strip_tags($_POST['name']));
$description=htmlspecialchars(strip_tags($_POST['description']));
$price=htmlspecialchars(strip_tags($_POST['price']));
// new 'image' field
$image=!empty($_FILES["image"]["name"])
		? sha1_file($_FILES['image']['tmp_name']) . "-" . basename($_FILES["image"]["name"])
		: "";
$image=htmlspecialchars(strip_tags($image));
// bind the parameters
$stmt->bindParam(':name', $name);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':price', $price);
$stmt->bindParam(':image', $image);
// specify when this record was inserted to the database
$created=date('Y-m-d H:i:s');
$stmt->bindParam(':created', $created);

Using PhpMyAdmin, add an "image" field in the products table as well.

Set variables for file upload

We will start the code for the file upload feature. Find the following line in the create.php file.

echo "<div class='alert alert-success'>Record was saved.</div>";

Under the code above, we will add the following code.

The if($image){ code will verify if there's an uploaded image.

If there is, inside the if statement, we will set the initial variables needed for the file upload.

// now, if image is not empty, try to upload the image
if($image){
	// sha1_file() function is used to make a unique file name
	$target_directory = "uploads/";
	$target_file = $target_directory . $image;
	$file_type = pathinfo($target_file, PATHINFO_EXTENSION);
	// error message is empty
	$file_upload_error_messages="";
}

Make sure submitted file is a real image

Now we will start validating the submitted file. The code below will identify if the submitted file is a real or fake image.

Place the following code under $file_upload_error_messages=""; of the previous section.

// make sure that file is a real image
$check = getimagesize($_FILES["image"]["tmp_name"]);
if($check!==false){
	// submitted file is an image
}else{
	$file_upload_error_messages.="<div>Submitted file is not an image.</div>";
}

Make sure certain file types are allowed

The following code will limit the allowed file types. Place it under the code of the previous section.

// make sure certain file types are allowed
$allowed_file_types=array("jpg", "jpeg", "png", "gif");
if(!in_array($file_type, $allowed_file_types)){
	$file_upload_error_messages.="<div>Only JPG, JPEG, PNG, GIF files are allowed.</div>";
}

Make sure file does not exist

There's a very small chance that the submitted file name will be the same as the one that exists in the server. This is because of the sha1_file() method we used in section 10.2 above.

But just in case there's a file with the same name, tell the user. Place the following code after the previous section's code.

// make sure file does not exist
if(file_exists($target_file)){
	$file_upload_error_messages.="<div>Image already exists. Try to change file name.</div>";
}

Make sure submitted file is not too large

Uploading a very large photo is not recommended in this case. So we will set the file size limit to less than 1 MB. Place the following code after the code of the previous section.

// make sure submitted file is not too large, can't be larger than 1 MB
if($_FILES['image']['size'] > (1024000)){
	$file_upload_error_messages.="<div>Image must be less than 1 MB in size.</div>";
}

Make sure the 'uploads' folder exists

The "uploads" folder is where we will put the submitted file. Make sure it exists by using the following code. Place it under the code of the previous section.

// make sure the 'uploads' folder exists
// if not, create it
if(!is_dir($target_directory)){
	mkdir($target_directory, 0777, true);
}

Try to upload the file

The move_uploaded_file built-in PHP function will place the uploaded file on the server directory.

Place the following code under the previous section's code.

// if $file_upload_error_messages is still empty
if(empty($file_upload_error_messages)){
	// it means there are no errors, so try to upload the file
	if(move_uploaded_file($_FILES["image"]["tmp_name"], $target_file)){
		// it means photo was uploaded
	}else{
		echo "<div class='alert alert-danger'>
			<div>Unable to upload photo.</div>
			<div>Update the record to upload photo.</div>
		</div>";
	}
}
// if $file_upload_error_messages is NOT empty
else{
	// it means there are some errors, so show them to user
	echo "<div class='alert alert-danger'>
		<div>{$file_upload_error_messages}</div>
		<div>Update the record to upload photo.</div>
	</div>";
}

Output

Form to create a product with file upload field.

When the form was submitted.

The "uploads" folder was created, with the uploaded file inside.

The file name was saved in the database.

Show uploaded image in PHP

Add image field in query

Open the read_one.php file and apply the following changes to the code.

Add image field to the $query variable. It should look like the following.

$query = "SELECT id, name, description, price, image FROM products WHERE id = ? LIMIT 0,1";

Add '$image' variable after the '$price' variable.

$image = htmlspecialchars($row['image'], ENT_QUOTES);

Add HTML image tag

Find the closing tr tag of the Price field in the HTML table and put the following code after it.

It will show the uploaded image or 'No image found.' if no image was uploaded.

<tr>
	<td>Image</td>
	<td>
	<?php echo $image ? "<img src='uploads/{$image}' style='width:300px;' />" : "No image found.";  ?>
	</td>
</tr>

Output

Click the Read One button of the record we created with a file upload.

You should see something like the images below.

Record with an image.

Record without image.

Download Source Codes

Unlock the full potential of your PHP and MySQL CRUD skills with our source code downloads.

Choose your download

Whether you're just starting or looking to take your knowledge to the next level, our BASIC and PRO options have everything you need to learn PHP CRUD operations.

Download our source codes today and accelerate your learning process. See the list of features below.

FEATURESBASICPRO
PDO extension used
Create product
Read product
Update product
Delete product
Bootstrap UI
Price display with a dollar sign
SQL file in the “dev” folder
HTML5 (font-end) validation for creating and updating a product-
Category selection for creating and updating a product.-
Buttons with Glyphicons-
Pagination-
Search products by name or description-
HTML5 (font-end) validation for search product-
Pagination in search-
Allow the user to enter the page number (read and search list)-
Export/download records to CSV-
Price display with comma and decimal point-
Multiple delete-
Create and update product records with file upload-
Bootstrap navigation bar-
Select and highlight a category in the navigation-
CRUD of product categories-
View products by category-
Search a category with pagination-
Server-side validation for creating and updating products & categories-
Sorting by fields with pagination-
Search product by date range with pagination-
jQuery UI calendar for picking a date-
Use the buttons below to download. ↓BASICPRO

Why download?

Our source code offers many benefits to help you master CRUD operations and take your skills to the next level. Here are a few of the many benefits you can expect:

  • Versatility: Use the skills you learn from our source code for multiple projects, saving you time and effort in the long run.
  • Time-saving: Forget spending hours learning Bootstrap and PHP on your own. Our code examples are direct and to the point, making them easy to understand and implement.
  • Clarity: Our source code is well explained and commented on, making it easy to follow and understand.
  • Support: Our fast and friendly email support is always available to help you with any questions.
  • Up-to-date: Our source code is constantly updated to ensure you always have access to the latest and most advanced features.

How To Run The Source Code?

After downloading and extracting the zip file, you will see a README.txt file. Open and follow the exact instructions on how to run the code.

If you have more questions, don't hesitate to contact our support team at [email protected].

Thanks for supporting our website and projects here at codeofaninja.com!

What's Next?

After learning from this PHP and MySQL CRUD tutorial for beginners, we can go one step higher. We can learn object-oriented programming (OOP) in PHP and MySQL.

Object-oriented programming (OOP) is a programming language model organized around objects rather than "actions" and data rather than logic. This is very exciting.

To learn more, we created the following tutorial just for you! Let's go and learn: PHP OOP CRUD Tutorial: Object-oriented programming with PHP & MySQL

Online Resources

What students say?

Don't just take our word for it. See what our students have to say about our tutorials and source codes. We are proud to have helped many individuals and businesses to build their own applications. Here are a few of the testimonials from our satisfied students.

★★★★★ “Wow, I love you guys! The best web programming tutorial I’ve ever seen. So comprehensive, yet easy to follow. I love how you combine all necessary elements in such a neat structure.” ~ Olaug Nessa

★★★★★ “The fact that you’ve put it all together saves so much time and its worth buying the code. Makes me feel good supporting a developer like yourself. Keep up the good work!” ~ Dan Hudson

★★★★★ “Thanks for making these awesome tutorials! I bought your source codes. To be honest, it’s very readable code and helps me understand a lot of things and how it’s done in PHP. Thanks for that again.” ~ Michael Lammens

★★★★★ “Hey Mike, my name is Leonardo from Argentina. I’ve been reading your blog since like 4 months from now, and I really must say: your tutorials are very good, they has helped me in many of my works… Well, thank you very much man. I really admire your work.” ~ Leonardo

★★★★★ “Words can’t express how grateful I am for the work and the articles you post, had some troubles with doing somethings but your articles as per usual hit the hammer right on the head. They are a great way for expanding upon later too!” ~ Jeremy Smith

Got comments?

At codeofaninja.com, we strive to provide our readers with accurate and helpful PHP CRUD Tutorial for Beginners – Step By Step Guide! Your feedback is essential in helping us achieve this goal.

If you have encountered any issues with the code, have suggestions for improvement, or wish to provide praise, we welcome you to leave a comment below. Please be as descriptive as possible to address your concerns effectively and include any relevant error messages, screenshots, or test URLs.

We request that comments remain on-topic and relevant to the article above. If your question or comment pertains to a different topic, we recommend seeking assistance elsewhere.

Furthermore, we ask that you review our code of conduct before commenting to ensure that your feedback is constructive and respectful.

Thank you for taking the time to provide feedback and for supporting codeofaninja.com. Your contributions help us improve our tutorials and serve the developer community better.

Subscribe for FREE!

Improve your web development skills and stay ahead of the competition by subscribing to our tutorial series. Sign up for FREE and access exclusive, cutting-edge content delivered straight to your inbox.

Take advantage of the chance to elevate your skills and advance your web development career. Subscribe now.

Thank You!

We hope you've found our PHP CRUD Tutorial for Beginners – Step By Step Guide! helpful and informative. We understand that learning new programming concepts can be challenging, but we're glad we could make it easier for you.

Thank you for choosing to learn with us and for supporting codeofaninja.com! Consider sharing this tutorial with your friends and colleagues who may also be interested in learning about PHP CRUD Tutorial for Beginners – Step By Step Guide!

The more people know about our tutorials, the more we can help the developer community grow. Keep learning, keep coding, and keep growing as a developer. We can't wait to see what you'll create next!

How To Customize reCAPTCHA

Have you ever received unsolicited (Spam) messages, comments, or notifications in your email, Facebook account, or to other services you are using online?

Probably yes. I think almost all people using the internet experienced it already. There are trillions of spam messages sent every year.

One effective way to prevent those spam messages to your form is using a “Completely Automated Public Turing test to tell Computers and Humans Apart” or CAPTCHA in short.

Google, Facebook, Yahoo, and other big internet companies uses this method. So today we are going to do a script that uses Google reCAPTCHA for our form.

This tool by Google is widely used on the internet, maybe you’re familiar with the red box image below:

"Home

Download the recaptcha library here.

We’re going the have the following code on our index.php file.

<html>
<head>
<title>https://www.codeofaninja.com/ - Customized reCAPTCHA For Your Form using PHP</title>
<style type='text/css'>    
/*
the customization of our recaptcha field
recaptcha_widget id is what we're customizing
*/
 
#recaptcha_widget{
    magin: 0;
}
 
#recaptcha_widget a{
    color: #000;
    text-decoration: none;
    font-family: Arial, Helvetica, sans-serif;
    font-weight: bold;
    margin: 15px 0 0 0;
    padding: 2px 4px 2px 4px;
    background-color: #F5DEB3;
}
 
#recaptcha_widget a:hover{
    background-color: #DEB887;
}
 
.text{
    margin: 0 0 5px 0;
}
 
/*
just some message box style
when form is submitted
*/
#error-box{
    border: 4px solid #FF0000; 
    background-color: #FA8072;
    color: #fff;
    font-family: Arial, Helvetica, sans-serif;
    width: 430px;
    margin: 0 0 5px 0;
    padding: 4px;
}
 
#success-box{
    border: 4px solid #32CD32; 
    background-color: #00FF7F;
    color: #000;
    font-family: Arial, Helvetica, sans-serif;
    width: 430px;
    margin: 0 0 5px 0;
    padding: 4px;
}
</style>
</head>
<body>
<?php
//defining indexes
isset( $_REQUEST['action'] ) ? $action = $_REQUEST['action'] : $action = '';
isset( $_REQUEST['email'] ) ? $email = $_REQUEST['email'] : $email = '';
isset( $_REQUEST['user_password'] ) ? $user_password = $_REQUEST['user_password'] : $user_password = '';
isset( $_REQUEST['recaptcha_challenge_field'] ) ? $recaptcha_challenge_field = $_REQUEST['recaptcha_challenge_field'] : $recaptcha_challenge_field='';
isset( $_REQUEST['recaptcha_response_field'] ) ? $recaptcha_response_field = $_REQUEST['recaptcha_response_field'] : $recaptcha_response_field='';
 
require 'recaptcha/recaptchalib.php'; 
/* ---------------------------recaptcha code----------------------- */
//use your own private key here
$privatekey = "6LdUOcYSAAAAAGT-EbCqOldQ54GJhqG3ZdMkwLBG";
$resp = recaptcha_check_answer ($privatekey,
                        $_SERVER["REMOTE_ADDR"],
                        $recaptcha_challenge_field,
                        $recaptcha_response_field);
 
if (!$resp->is_valid) {
    $recaptcha = 'wrong';
} else {
    $recaptcha = 'correct';
}
/* ---------------------------recaptcha code----------------------- */
     
//when the form is submitted
if( $action == "signup" ){
 
$error_msg = '';
 
//if( empty($email) || empty($user_password)){
if( $email == '' || $user_password == ''){
    $error_msg .= "<div>-{$email}{$user_password}Field cannot be empty.</div>";
}
 
if( $recaptcha == 'wrong' ){
    $error_msg .= "<div>-You should enter characters that match the word verification.</div>";
}
 
if( $error_msg != '' ){
    echo "<div id='error-box'>";
        echo $error_msg;
    echo "</div>";
}else{
    echo "<div id='success-box'>";
        echo "Form successfully submitted.";
    echo "</div>";
}
 
}
 
?>
 
<!-- 
-this script is needed since we
are customizing recaptcha 
-it comes first before the form tag - always
-->
<script type="text/javascript">
var RecaptchaOptions = {
    theme : 'custom',
    custom_theme_widget: 'recaptcha_widget'
};
</script>
 
<!-- form tag comes first before table tag - always. -->
<form action='#' method='post' class='form'>
<table>
    <tr>
        <td align='right'>Email:</td>    
        <td><input type='text' name='email' /></td>
    </tr>
    <tr>
        <td align='right'>Password:</td>
        <td><input type='text' name='user_password' /></td>
    </tr>
    <tr>
        <td valign='top'>Word Verification.: </td>
        <td>
         
<div style='margin: 0px auto; text-align: center; width: 360px;'>
     
 
        <div class="field-space" style='text-align: left;'>
         
<!-- the id recaptcha_widget is what we're customizing -->
<div id="recaptcha_widget" style="display:none">
 
    <div id="recaptcha_image"></div>
    <div class="recaptcha_only_if_incorrect_sol" style="color:red">Incorrect, please try again</div>
 
    <div class="recaptcha_only_if_image" style='margin-bottom: 10px;'>Enter the words above : </div>
    <span class="recaptcha_only_if_audio">Enter the numbers you hear:</span>
 
    <div><input type="text" id="recaptcha_response_field" name="recaptcha_response_field" size='30' class='text' /></div>
     
    <span><a href="javascript:Recaptcha.reload()">Get Another Challenge</a>  </span> 
    <span class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')">Try Audio</a>  </span>
    <span class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')">Try Image</a>  </span>
 
    <span><a href="javascript:Recaptcha.showhelp()">Help</a></span>
 
</div>
 
<!-- user your own public key after "k="-->
 
<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=6LdUOcYSAAAAALa38Uxegl8owzKXGomiSkV498n_"></script>
<noscript>
    <iframe src="http://www.google.com/recaptcha/api/noscript?k=6LdUOcYSAAAAALa38Uxegl8owzKXGomiSkV498n_" height="300" width="500" frameborder="0"></iframe>
    <br>
    <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
    <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
</noscript>
 
        </td>
    </tr>
    <tr>
        <td></td>
        <td>
             
        <!-- our hidden field and submit button here -->
        <div class="submit" style='float: left;'>
                <input type='hidden' name='action' value='signup' />
                <input type='submit' value='Sign Up!' />
        </div>
         
        </td>
    </tr>
</table>
</form>
 
</body>
</html>

That’s it! :)

How To Display Image from Database in PHP?

Someone asked me how to display an image saved in the database in PHP. Here’s how I did it. In this code, we will use two files – index.php and source.php and a database table with sample image data stored.

Please note that I used BLOB data type for storing my images, it can handle up to 64KiB of data. If you want larger storage for each of your images, you can use LONG BLOB that can handle up to 2,048 KiB of data.

Step 1. Create a "test" database and run the following SQL code on your PhpMyAdmin.

CREATE TABLE `images` (
  `id` int(11) NOT NULL,
  `name` varchar(32) NOT NULL,
  `data` longblob NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Go to PhpMyAdmin's insert tab to add sample data in the images table.

  • Enter ID as "1"
  • Enter Name as "sample image".
  • Enter Data by choosing a sample image from your computer.

Step 2. Create index.php file and place the following code. This file will call the image rendered by source.php file and put it as the source of img tag.

<html>
    <head>
        <title>PHP Tutorial</title>
    </head>
<body>
 
    <div>Here's the image from the database:</div>
 
    <!– "1" is the database id of the image to be selected –>
    <img src=”source.php?id=1” />
</body>
</html>

Step 3. Create db_connect.php and place the following code. This file will connect our program to the database.

<?php
$host = "localhost";
$db_name = "test";
$username = "root";
$password = "";
 
try{
    $con = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
}
 
catch(PDOException $exception){
    //to handle connection error
    echo "Connection error: " . $exception->getMessage();
}
?>

Step 4. Create source.php file and place the following code. This will do the query of selecting the image based on the given ID parameter.

<?php 
// include database connection 
include "db_connect.php"; 
 
// select the image 
$query = "select * from images WHERE id = ?"; 
$stmt = $con->prepare( $query );
 
// bind the id of the image you want to select
$stmt->bindParam(1, $_GET['id']);
$stmt->execute();
 
// to verify if a record is found
$num = $stmt->rowCount();
 
if( $num ){
    // if found
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    
    // specify header with content type,
    // you can do header("Content-type: image/jpg"); for jpg,
    // header("Content-type: image/gif"); for gif, etc.
    header("Content-type: image/png");
    
    //display the image data
    print $row['data'];
    exit;
}else{
    //if no image found with the given id,
    //load/query your default image here
}
?>

Step 5. The output will look like the following.

PHP: Display Image from Database

Step 6. How to resize this image? You can just do it by specifying the width and height properties of of the img tag.

<img src="source.php?id=1" width="300" height="300" />

Step 7. If you want to download the code of this tutorial, use the following button.

[purchase_link id="16411" text="Download Now" style="button" color="green"]

Thank you for using our tutorial about how to display image from database in PHP!

How To Send Email Using PHP Mail Function

php-mail-function-tutorial

Hi guys! Today we’ll be sending email using the PHPMail Function.

I think this is much easier than using a PHP library like PHPMailer.

You don’t have to specify your email address and password to sent email, just specify the “from” email address you want.

But you must have a live mail server.

By the way I had a previous post "How To Send Email Using PHPMailer and GMail"

<?php
$name = "Your Name";
$email = "[email protected]";
$subject = "Some subject here.";
$message = "Your message here.";
$recipient_email = "[email protected]";
 
$headers  = "MIME-Version: 1.0 \r\n";
$headers .= "Content-type: text/html; charset=iso-8859-1 \r\n";
$headers .= "From: $name <$email> \n";
 
$body = '<b>Name: </b> ' . $name . '<br />';
$body .= '<b>Email: </b>' . $email . '<br />';
$body .= '<b>Message: </b>' . $message . '<br /><br />';
$body .= 'You can add something here like signature.';
 
if( mail($recipient_email, $subject, $body, $headers) ){
    echo "Message has been successfully sent.";
}else{
    echo "Sending failed.";
}
?>

That's it, hope it helps. :)