Simple Membership System With PHP MYSQL (Free Download)

Welcome to a tutorial on how to create a membership system with PHP and MySQL. Planning to open a “members only” section on your website? There are a couple of things that we need to cover – Database, registration, login, and more. Read on for the step-by-step guide!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Notes Member System Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

If you just want to quickstart and trace the code on your own:

  • Create a database and import 1-members.sql.
  • Make sure that the PDO extension is enabled in php.ini.
  • Open 2-core.php and change the settings to your own.
  • Launch 4-register.php to register a new user, 5-login.php to sign in.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

PHP MYSQL MEMBER SYSTEM

All right, let us now get into the steps of constructing a membership system.

 

STEP 1) MEMBERS DATABASE

1-members.sql
CREATE TABLE `members` (
  `id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `start` datetime NOT NULL DEFAULT current_timestamp(),
  `till` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
ALTER TABLE `members`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `email` (`email`),
  ADD KEY `name` (`name`);
 
ALTER TABLE `members`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

First, we start by creating a table to store all the members:

  • id Member ID, primary key.
  • name Member’s name.
  • email Member’s email, unique to prevent duplicates.
  • password Login password.
  • start Member since.
  • till Up to you to decide – Remove this if the membership does not have an expiry date.

Feel free to add more fields as required – Maybe a “member level” if you offer different tiers.

 

STEP 2) CORE SETTINGS

2-core.php
<?php
// (A) ERROR REPORTING
error_reporting(E_ALL & ~E_NOTICE);
ini_set("display_errors", 1);
 
// (B) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHARSET", "utf8");
define("DB_USER", "root");
define("DB_PASSWORD", "");
 
// (C) START SESSION
session_start();

Next, we have a script to hold and do all the system settings. I normally keep this in a protected folder, you may also want to do the same in your own project.

  • Create a lib folder, move 2-core.php inside.
  • For the Apache users, create a .htaccess in the lib folder with this line – deny from all.
  • That’s all. People who try to access http://site.com/lib/2-core.php directly will get a 403 unauthorized error, but PHP can still access the scripts.
  • IIS and NGINX users – You can also put this restriction in place. Do your own research.

 

 

STEP 3) MEMBER LIBRARY

3-lib-member.php
<?php
class Member {
  // (A) CONSTRUCTOR - CONNECT TO THE DATABASE
  private $pdo = null;
  private $stmt = null;
  public $error;
  function __construct () {
    try {
      $this->pdo = new PDO(
        "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET,
        DB_USER, DB_PASSWORD, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
      ]);
    } catch (Exception $ex) { exit($ex->getMessage()); }
  }
 
  // (B) DESTRUCTOR - CLOSE DATABSE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }
 
 // (C) EXECUTE SQL QUERY
 function exec ($sql, $data=null) {
    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($data);
      return true;
    } catch (Exception $ex) {
      $this->error = $ex->getMessage();
      return false;
    }
  }
 
  // (D) FETCH (SINGLE ROW)
  function fetch ($sql, $data=null) {
    if ($this->exec($sql, $data) === false) { return false; }
    return $this->stmt->fetch();
  }
 
  // (E) FETCH ALL (MULTIPLE ROWS)
  function fetchAll ($sql, $data=null) {
    if ($this->exec($sql, $data) === false) { return false; }
    return $this->stmt->fetchAll();
  }
}
 
// (Z) START!
$MEM = new Member();

This library looks difficult at first, but keep calm and study carefully:

  • (A & B) When new Member() is created, the constructor automatically connects to the database. The destructor closes the connection.
  • (C) exec() Runs an SQL statement.
  • (D & E) fetch() Runs a SELECT query, returns a single row. fetchAll() Returns multiple rows.

Easy? Put this into the lib folder as well – Protect all your libraries and important files.

 

STEP 4) MEMBER REGISTRATION

REGISTRATION PAGE

4-register.php
<?php
// (A) PROCESS REGISTRATION
if (isset($_POST["name"])) {
  require "2-core.php";
  require "3-lib-member.php";
  if ($MEM->add($_POST["name"], $_POST["email"], $_POST["password"])) {
    header("Location: X-welcome.html");
    exit();
  }
} ?>
 
<!-- (B) REGISTRATION FORM -->
<?php
if (isset($MEM)) { echo "<div class='error'>".$MEM->error."</div>"; }
?>
<form method="post" class="form">
  <input type="text" name="name" placeholder="Name" required/>
  <input type="email" name="email" placeholder="Email" required/>
  <input type="password" name="password" placeholder="Password" required/>
  <input type="submit" value="Register"/>
</form>

Now that the database and system settings are in place, let us build the registration page. It will be easier to start from the bottom first:

  • (B) HTML registration form. DUH.
  • (A) When the form is submitted, we will load and use the member library to process the registration.
    • If successful, we redirect the user to a welcome page.
    • If it fails, we show the error message.

 

 

REGISTRATION FUNCTION

3-lib-member.php
// (F) GET MEMBER BY ID OR EMAIL
function get ($id) {
  $sql = sprintf("SELECT * FROM `members` WHERE `%s`=?",
    is_numeric($id) ? "id" : "email"
  );
  return $this->fetch($sql, [$id]);
}
 
 // (G) REGISTER NEW MEMBER
function add ($name, $email, $password) {
  // (G1) CHECK IF REGISTERED
  $check = $this->get($email);
  if (is_array($check)) {
    $this->error = "$email is already registered";
    return false;
  }
 
  // (G2) REGISTER MEMBER
  return $this->exec(
    "INSERT INTO `members` (`name`, `email`, `password`) VALUES (?,?,?)",
    [$name, $email, password_hash($password, PASSWORD_DEFAULT)]
  );
}

How do we deal with the registration? Add 2 new functions to the member library.

  • get() Get a member with the given ID or email address.
  • add() Use get() to check if the email address is registered. Then register the user – Which is nothing more than a simple INSERT SQL.

If you want to impose an expiry date, do it here.

  • $expiry = strtotime("+1 year");
  • "INSERT INTO `members` (`name`, `email`, `password, `till`) VALUES (?,?,?,?)"
  • [$name, $email, password_hash($password, PASSWORD_DEFAULT), date("Y-m-d H:i:s", $expiry)]

Yep, also send a confirmation email if you want.

 

STEP 5) MEMBER LOGIN

LOGIN PAGE

5-login.php
<?php
// (A) LOAD CORE
require "2-core.php";
 
// (B) CHECK LOGIN CREDENTIALS
if (isset($_POST["email"])) {
  require "3-lib-member.php";
  $MEM->verify($_POST["email"], $_POST["password"]);
}
 
// (C) REDIRECT IF SIGNED IN
if (isset($_SESSION["member"])) {
  header("Location: 6-protected.php");
  exit();
} ?>
 
<!-- (D) LOGIN FORM -->
<?php
if (isset($MEM)) { echo "<div class='error'>".$MEM->error."</div>"; }
?>
<form method="post" class="form">
  <input type="email" name="email" required/>
  <input type="password" name="password" required/>
  <input type="submit" value="Login"/>
</form>

With the registration complete, the next obvious step is to deal with the login. Again, it is easier to start from the bottom:

  • (D) The login form. DUH.
  • (A & B) When the login form is submitted, we load the library and do a verification check.
  • (C) On a valid sign-in, we redirect the user to the “members only” section; Users who are already signed in will be redirected, they won’t get to see the login page.

 

VERIFICATION FUNCTION

3-lib-member.php
 // (H) VERIFICATION - SESSION MUST BE STARTED!
function verify ($email, $password) {
  // (H1) GET MEMBER
  $member = $this->get($email);
  $pass = is_array($member);
 
  // (H2) CHECK PASSWORD
  if ($pass) { $pass = password_verify($password, $member["password"]); }
 
  // (H3) REGISTER MEMBER INTO SESSION
  if ($pass) {
    foreach ($member as $k=>$v) { $_SESSION["member"][$k] = $v; }
    unset($_SESSION["member"]["password"]);
  }
 
  // (H4) RESULT
  if (!$pass) { $this->error = "Invalid email/password"; }
  return $pass;
}

This should be self-explanatory if you trace through. Get the user, check the password, register the user into $_SESSION["member"]. If you have imposed an expiry date, do your checks here as well:

  • $now = strtotime("now");
  • if (strtotime($member["till"]) >= $now) { MEMBERSHIP EXPIRED - RETURN FALSE }

 

 

STEP 6) PROTECTED PAGES

6-protected.php
<?php
// (A) NOT SIGNED IN - BACK TO LOGIN PAGE
require "2-core.php";
if (!isset($_SESSION["member"])) {
  header("Location: 5-login.php");
  exit();
}
?>

In all your “members-only” pages, simply redirect them back to the login page if they are not signed in.

 

STEP 7) LOGOUT

7-logout.php
<?php
if (isset($_POST["out"])) {
  require "2-core.php";
  unset($_SESSION["member"]);
  header("Location: 5-login.php");
  exit();
} ?>
 
<form method="post">
  <input type="submit" value="Logout" name="out"/>
</form>

How do we logout? Simply unset($_SESSION["member"]).

 

 

USEFUL BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

LINKS & REFERENCES

Congrats, you now have a skeletal membership system. Here are many more things you can consider adding:

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published.