Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

3 Steps Simple PHP Reservation System

INTRODUCTION
ONLINE RESERVATION

Welcome to a tutorial on how to create a simple PHP Reservation system. So you are offering a service and want to open up for online reservations? Or maybe you want to open up a room available for renting online? Fear not – This guide will walk you through the steps on how to create a reservation system. Read on!

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

CONFESSION
AN HONEST DISCLOSURE

Quick, hide your wallets! I am an affiliate partner of Google, eBay, Adobe, Bluehost, Clickbank, and more. There are affiliate links and advertisements throughout this website. Whenever you buy things from the evil links that I recommend, I will make a commission. Nah. These are just things to keep the blog going, and allows me to give more good stuff to you guys - for free. So thank you if you decide to pick up my recommendations!

NAVIGATION
TABLE OF CONTENTS

Prelude
Overview & Assumptions

Step 1
The Database

Step 2
Server-Side Scripts

Step 3
Client-Side Scripts

Extra
Download & More

Closing
What’s Next?

PRELUDE
OVERVIEW & ASSUMPTIONS

Before we go into the actual scripts, here is a small section on the overview of the simple system, and some assumptions that I have made – So you know what to expect from this guide.

ASSUMPTIONS

Some of you guys here probably have an existing project or website, and planning to build a reservation system on top of it. So we are not going to reinvent the wheel and create yet another admin panel on top of your existing one. This will be a pure “reservation only”, and for those of you who are starting fresh, I will leave the link on how to create an admin panel at the end of this guide.

Also, I shall assume that most of you guys are already established code ninjas. Comfortable with PHP, Javascript, AJAX, CSS, and SQL – I will not go into “boring mode” to explain every tiny detail such as “how does AJAX work”.

OVERVIEW

There are 3 parts to this project:

  • The database – We need somewhere to store the reservations now, do we?
  • Server-side scripts – Processes the user requests, stores reservation into the database, send email, etc…
  • Client-side scripts – The reservation page itself.

Now, everyone here probably has different reservation requirements – Whole day reservation, date range reservation, time slot reservation, the next day only, within 30 days only, etc… It is impossible to deal with all the possible cases, so this guide will only cover 3 of the most common scenarios –

  • Whole day reservation
  • Time slot reservation
  • Date range reservation

You will have to implement the specific rules and restrictions yourself.
 

PROJECT FOLDERS

If you have downloaded the zip file at the end of this guide, there will be 2 folders in this project. If you are following up step-by-step, just create the following folders to better organize things.

  • lib – Contains all the PHP library files.
  • public – Where we put all the public client-side CSS, Javascript, and images.

Optionally, you can create a .htaccess file in the lib folder to stop public access to the library files… Actually, I will highly recommend doing this to protect your system.

lib/.htaccess
Deny from all

STEP 1
THE DATABASE

Now that we have all the basics out of the way, let us start by building the foundation of the project – By creating a database reservation table.

RESERVATION TABLE

lib/reserve.sql
CREATE TABLE `reservations` (
  `res_id` int(11) NOT NULL,
  `res_name` varchar(255) NOT NULL,
  `res_email` varchar(255) NOT NULL,
  `res_tel` varchar(60) NOT NULL,
  `res_notes` text,
  `res_date` date DEFAULT NULL,
  `res_slot` varchar(4) DEFAULT NULL,
  `res_start` date DEFAULT NULL,
  `res_end` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `reservations`
  ADD PRIMARY KEY (`res_id`),
  ADD KEY `res_name` (`res_name`),
  ADD KEY `res_email` (`res_email`),
  ADD KEY `res_tel` (`res_tel`),
  ADD KEY `res_date` (`res_date`),
  ADD KEY `res_slot` (`res_slot`),
  ADD KEY `res_start` (`res_start`),
  ADD KEY `res_end` (`res_end`);

ALTER TABLE `reservations`
  MODIFY `res_id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;

THE FIELDS

FieldDescription
res_idReservation ID. Primary key, auto-increment.
res_nameName of the customer.
res_emailEmail of the customer.
res_telThe telephone number of customer.
res_noteReservation notes, if any.
res_dateFor whole day or time slot booking – You can remove this field if you are doing date range booking.
res_slotFor time slot booking – You can remove this field if you are doing whole day or date range booking.
res_startStart date for date range – You can remove this field if you are doing a single day booking.
res_endEnd date for date range – You can remove this field if you are doing a single day booking.

STEP 2
SERVER-SIDE SCRIPT

Now that we are done with the database foundation, let us create the server-side scripts that will process the reservations.

CONFIG FILE

lib/config.php

First, let us create a config file to safely keep all the database and settings in – Do remember to change the database settings to your own.

DATABASE LIBRARY

lib/lib-db.php
pdo = new PDO(
        $str, DB_USER, DB_PASSWORD, [
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
          PDO::ATTR_EMULATE_PREPARES => false
        ]
      );
      return true;
    }

    // ERROR - DO SOMETHING HERE
    // THROW ERROR MESSAGE OR SOMETHING
    catch (Exception $ex) {
      print_r($ex);
      die();
    }
  }

  function __destruct() {
  // __destruct() : close connection when done

    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }

  function exec($sql, $data=null) {
  // exec() : run insert, replace, update, delete query
  // PARAM $sql : SQL query
  //       $data : array of data
 
    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($data);
      $this->lastID = $this->pdo->lastInsertId();
    } catch (Exception $ex) {
      $this->error = $ex;
      return false;
    }
    $this->stmt = null;
    return true;
  }

  function fetch($sql, $cond=null, $key=null, $value=null) {
  // fetch() : perform select query
  // PARAM $sql : SQL query
  //       $cond : array of conditions
  //       $key : sort in this $key=>data order, optional
  //       $value : $key must be provided, sort in $key=>$value order

    $result = false;
    try {
      $this->stmt = $this->pdo->prepare($sql);
      $this->stmt->execute($cond);
      if (isset($key)) {
        $result = array();
        if (isset($value)) {
          while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) {
            $result[$row[$key]] = $row[$value];
          }
        } else {
          while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) {
            $result[$row[$key]] = $row;
          }
        }
      } else {
        $result = $this->stmt->fetchAll();
      }
    } catch (Exception $ex) {
      $this->error = $ex;
      return false;
    }
    $this->stmt = null;
    return $result;
  }
}
?>

Now, this is a “lazy database library” script that I have been using for almost every one of my projects and tutorials – This is nothing much, but a pretty simple PDO database script that you can reuse in your own projects if you want.

FunctionDescription
__constructThe constructor, automatically connects to the database when the object is being created.
__destructThe destructor, automatically closes the database when the object is being destroyed.
execRun an insert, replace, update, or delete query.
fetchRun a select query

RESERVATION LIBRARY

lib/lib-res.php
fetch($sql, $cond);
    if (count($check)>0) {
      $this->error = $email . " has already reserved " . $date;
      return false;
    }

    // Process reservation
    $sql = "INSERT INTO `reservations` (`res_name`, `res_email`, `res_tel`, `res_notes`, `res_date`) VALUES (?,?,?,?,?)";
    $cond = [$name, $email, $tel, $notes, $date];
    return $this->exec($sql, $cond);
  }

  /* [TIME SLOT BOOKING] */
  function bookSlot ($name, $email, $tel, $date, $slot, $notes="") {
  // bookSlot() : reserve for the time slot

    // Check if customer already booked on the time slot
    $sql = "SELECT * FROM `reservations` WHERE `res_email`=? AND `res_date`=? AND `res_slot`=?";
    $cond = [$email, $date, $slot];
    $check = $this->fetch($sql, $cond);
    if (count($check)>0) {
      $this->error = $email . " has already reserved " . $date . " " . $slot;
      return false;
    }

    // Process reservation
    $sql = "INSERT INTO `reservations` (`res_name`, `res_email`, `res_tel`, `res_notes`, `res_date`, `res_slot`) VALUES (?,?,?,?,?,?)";
    $cond = [$name, $email, $tel, $notes, $date, $slot];
    return $this->exec($sql, $cond);
  }

  /* [DATE RANGE BOOKING] */
  function bookRange ($name, $email, $tel, $start, $end, $notes="") {
  // bookRange() : reserve for the date range
    // Check if customer already booked within the date range
    $sql = "SELECT * FROM `reservations` WHERE (`res_start` BETWEEN ? AND ?) OR (`res_end` BETWEEN ? AND ?)";
    $cond = [$start, $end, $start, $end];
    $check = $this->fetch($sql, $cond);
    if (count($check)>0) {
      $this->error = $email . " has already reserved between " . $start . " and " . $end;
      return false;
    }
    // Process reservation
    $sql = "INSERT INTO `reservations` (`res_name`, `res_email`, `res_tel`, `res_notes`, `res_start`, `res_end`) VALUES (?,?,?,?,?,?)";
    $cond = [$name, $email, $tel, $notes, $start, $end];
    return $this->exec($sql, $cond);
  }

   /* [GET RESERVATION] */
  // @TODO - There are 101 ways to get/search for the reservations
  // This is a simple example that will get all reservations within a selected date range
  // Please do build your own functions in this library!
  function bookGet ($start, $end) {
  // bookGet() : get reservation for selected month/year
    $search = $this->fetch(
      "SELECT * FROM `reservations` WHERE `res_date` BETWEEN ? AND ?",
      [$start, $end]
    );
    return count($search)==0 ? false : $search ;
  }
}

Next, we build a library to store and retrieve the reservations from the database. This is sort of a barebones one, and you might want to further beef it up with your own functions.

FunctionDescription
bookDayUse this if you are doing single full-day booking, remove it if not using.
bookSlotUse this if you are doing single day, time slot booking, remove it if not using.
bookRangeUse this if you are doing date range booking, remove it if not using.
bookGetA sample function on how you can use the database library to retrieve the reservations.

AJAX HANDLER

ajax-reserve.php

session_start();
if (!is_array($_SESSION['user'])) {
  die(json_encode([
    "status" => 0,
    "message" => "You must be signed in first"
  ]));
}
*/

// HANDLE AJAX REQUEST
if ($_POST['req']) { switch ($_POST['req']) {
  // INVALID REQUEST
  default :
    echo json_encode([
      "status" => 0,
      "message" => "Invalid request"
    ]);
    break;

  // SHOW CALENDAR OR DATE SELECTOR
  case "show-cal":
    // Selected month and year + Various date yoga
    // * Will take current server time if not provided
    $thisMonth = (is_numeric($_POST['month']) && $_POST['month']>=1 && $_POST['month']1];
    }}

    // Days that have already past are not selectable
    // Earliest selectable is next day - Change this if you want
    $inow = 1;
    if ($thisYear==$yearNow && $thisMonth==$monthNow) {
      for ($inow=1; $inow$inow, "b"=>1];
      }
    }

    // Populate the rest of the selectable days
    for ($inow; $inow$inow];
    }

    /* This is an alternate version to show how you can put in date restrictions
     * For example, close off Sat & Sun reservations
    $dayNow = date("N", strtotime(sprintf("%s-%02u-%02u", $thisYear, $thisMonth, $inow)));
    for ($inow; $inow$inow, "b"=>1]; }
      else { $squares[] = ["d"=>$inow]; }
      $dayNow++;
      if ($dayNow==8) { $dayNow = 1; }
    }
    */

    // If the last day of the month is not Saturday, pad with blanks
    if ($endDay != 6) {
      $blanks = $endDay==7 ? 6 : 6-$endDay;
      for ($i=0; $i1];
      }
    }

    // Draw calendar - Limit your selectable periods here if you want
    // Month selector
    $months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    echo "";

    // Year selector
    echo "";

    // Dates
    echo "";

    // First row - Days of week
    $days = ["Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
    foreach ($days as $d) { echo ""; }
    echo "";

    // Following rows - Days in month
    $total = count($squares);
    $first = true;
    for ($i=0; $i";
      if ($squares[$i]['d']) { echo $squares[$i]['d']; }
      echo "";
      if ($i!=0 && ($i+1)%7==0) {
        echo "";
      }
    }
    echo "
$d
"; break; // SHOW TIME SLOT SELECTOR case "show-slot": /* Do your own time slot logic here - AM/PM, Hourly, Bi-hourly, etc... // You can use the $_POST['date'] variable to restrict // E.g. AM slots for Sat & Sun $selected = date("N", strtotime($_POST['date'])); $weekend = $selected==6 || $selected==7; if ($weekend) { RESTRICT } else { AS USUAL } */ ?> bookDay( $_POST['name'], $_POST['email'], $_POST['tel'], $_POST['date'], $_POST['notes'] ? $_POST['notes'] : "" ); /* You can send an email if you want if ($pass) { $message = ""; foreach ($_POST as $k=>$v) { $message .= $k . " - " . $v; } @mail("[email protected]", "Reservation receieved", $message); } */ // Server response echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $reslib->error ]); break; // ADD NEW RESERVATION - TIME SLOT BOOKING case "book-slot": // Save reservation to database $pass = $reslib->bookSlot( $_POST['name'], $_POST['email'], $_POST['tel'], $_POST['date'], $_POST['slot'], $_POST['notes'] ? $_POST['notes'] : "" ); /* You can send an email if you want if ($pass) { $message = ""; foreach ($_POST as $k=>$v) { $message .= $k . " - " . $v; } @mail("[email protected]", "Reservation receieved", $message); } */ // Server response echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $reslib->error ]); break; // ADD NEW RESERVATION - DATE RANGE BOOKING case "book-range": // Save reservation to database $pass = $reslib->bookRange( $_POST['name'], $_POST['email'], $_POST['tel'], $_POST['start'], $_POST['end'], $_POST['notes'] ? $_POST['notes'] : "" ); /* You can send an email if you want if ($pass) { $message = ""; foreach ($_POST as $k=>$v) { $message .= $k . " - " . $v; } @mail("[email protected]", "Reservation receieved", $message); } */ // Server response echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $reslib->error ]); break; }}

Finally, the library files will not do anything on their own, thus the reason for this seemingly crazy AJAX handler script… It looks confusing, but it’s really nothing too much.

WHAT THE AJAX!?

How the AJAX handler works is pretty straightforward. You send a $_POST['req'] request to this script (on what you want to process), followed by the required parameters.

RequestDescription
show-calGenerates an HTML date picker for the given period $_POST['month'] and $_POST['year']. Used by all 3 different booking scenarios, will go into further details below.
show-slotShows the available time slots for the given date $_POST['date'], this is just a simple AM/PM selector. Modify this to fit your own project – Could be different hourly slots, or maybe even bi-hourly.
book-dayUsed for full-day booking, you can remove this if you are offering timeslot or date range booking. Requires name, email, telephone, date, and an optional note.
book-slotUsed for timeslot booking, you can remove this if you are offering full-day or date range booking. Requires name, email, telephone, date, timeslot, and an optional note.
book-rangeUsed for date range booking, you can remove this if you are offering full-day or timeslot booking. Requires name, email, telephone, start date, end date, and an optional note.

So there you go – You can actually remove a few sections of this script that you don’t use, and it really isn’t as complicated.

THE CRAZY CALENDAR

The craziest part of the server-side script is probably generating the selectable dates for a given month. We will walk through this section of the AJAX handler here in more details.

  • The top part of the script does a lot of days, month, and year calculations – The first day of the selected period, last day, days in the month, etc…
  • Do take note that if you don’t pass a $_POST['month'] and $_POST['year'], the script will take the current time on the server by default.
  • Before the generation of the HTML calendar, we will use an array $squares to contain all the render information.
  • For a start, there are many months that don’t start on a Sunday. For example, the first day of the month may be a Tuesday, and we will need to pad the calendar with blank squares from Sunday to Monday – To do that we simply use $squares[] = ["b"=>1] twice to pad the empty squares.
  • Following up are the days within the month itself – Which we pad with $squares[] = ["d"=>DAY]
  • If you want to block certain days from being available, you can use $squares[] = ["d"=>DAY, "b"=>1]
  • Then, many months don’t end on a Saturday, so we do the same empty padding trick.
  • Finally, we will render the HTML calendar from the information contained in $squares.

STEP 3
CLIENT-SIDE SCRIPT

Finally, we only need to complete the puzzle by building the actual HTML reservation page itself – We will run through each of the 3 different scenarios here… Feel free to skip the ones that do not apply to you.

FULL DAY BOOKING

THE HTML

reserve.day.html


  
    
      PHP Reservation Demo - Single Full Day Booking
    

RESERVATION

This should be pretty easy to understand – Just a normal HTML reservation form. But take note of two things here –

  • We will load the date selector into
    via AJAX. This way, we can do all the proper restrictions and checks on the server-side first.
  • The submit button is disabled. We will only enable this when the date picker is fully loaded.
  • THE JAVASCRIPT

    public/reserve-day.js
    var res = {
      cal : function () {
      // res.cal() : show calendar
    
        // Disable submit first
        document.getElementById("res_go").disabled = true;
    
        // AJAX data
        var data = new FormData();
        data.append('req', 'show-cal');
    
        // Get selected month & year - If they exist
        var select = document.querySelector("#res_date select.month");
        if (select!=null) {
          data.append('month', select.value);
          select = document.querySelector("#res_date select.year");
          data.append('year', select.value);
        }
    
        // AJAX call
        var xhr = new XMLHttpRequest();
        xhr.open('POST', "ajax-reserve.php", true);
        xhr.onload = function(){
          // Set contents, click, change actions
          document.getElementById("res_date").innerHTML = this.response;
          select = document.querySelector("#res_date select.month");
          select.addEventListener("change", res.cal);
          select = document.querySelector("#res_date select.year");
          select.addEventListener("change", res.cal);
          select = document.querySelectorAll("#res_date .pick, #res_date .active");
          for (var i of select) {
            i.addEventListener("click", res.pick);
          }
          // Enable submit
          document.getElementById("res_go").disabled = false;
        };
        xhr.send(data);
      },
    
      pick : function () {
      // res.pick() : change selected date
    
        var select = document.querySelector("#res_date .active");
        if (select!=this) {
          select.classList.remove("active");
          select.classList.add("pick");
          this.classList.remove("pick");
          this.classList.add("active");
        }
      },
    
      save : function () {
      // res.save() : save the reservation
    
        // Selected date
        var select = document.querySelector("#res_date td.active").innerHTML;
        if (select.length==1) { select = "0" + select; }
        select = document.querySelector("#res_date select.month").value + "-" + select;
        select = document.querySelector("#res_date select.year").value + "-" + select;
    
        // AJAX data
        var data = new FormData();
        data.append('req', 'book-day');
        data.append('name', document.getElementById("res_name").value);
        data.append('email', document.getElementById("res_email").value);
        data.append('tel', document.getElementById("res_tel").value);
        data.append('notes', document.getElementById("res_notes").value);
        data.append('date', select);
    
        // AJAX call
        var xhr = new XMLHttpRequest();
        xhr.open('POST', "ajax-reserve.php", true);
        xhr.onload = function(){
          var res = JSON.parse(this.response);
          // OK - Redirect to thank you page
          if (res.status==1) {
            location.href = "thank-you.html";
          }
          // ERROR - show error
          else {
            alert(res.message);
          }
        };
        xhr.send(data);
        return false;
      }
    };
    
    window.addEventListener("load", res.cal);

    This Javascript looks complicated, but actually, there are only 3 functions here.

    FunctionDescription
    res.cal()This function will fire up when the page is initially loaded, and whenever the user changes the month/year. It will do an AJAX call to the server to render the calendar for the selected period.
    res.pick()This function is fired when the user clicks on a date on the calendar. It simply updates the HTML to the newly selected date.
    res.save()Submit and process the reservation form.

    TIMESLOT BOOKING

    THE HTML

    reserve-slot.html
    
    
      
        
          PHP Reservation Demo - Single Time Slot Booking
        

    RESERVATION

    The HTML of the timeslot reservation is pretty much the same as full-day – This is but a simple HTML form, but take note:

    • The date selector will be loaded into
      via AJAX.
    • Following up, the timeslot selector will be loaded into
      via AJAX.
    • The submit button is disabled. We will only enable this when both the date picker and timeslot picker are fully loaded.
    • THE JAVASCRIPT

      public/reserve-slot.js
      var res = {
        cal : function () {
        // res.cal() : show calendar
      
          // Disable submit first
          document.getElementById("res_go").disabled = true;
      
          // AJAX data
          var data = new FormData();
          data.append('req', 'show-cal');
      
          // Get selected month & year - If they exist
          var select = document.querySelector("#res_date select.month");
          if (select!=null) {
            data.append('month', select.value);
            select = document.querySelector("#res_date select.year");
            data.append('year', select.value);
          }
      
          // AJAX call
          var xhr = new XMLHttpRequest();
          xhr.open('POST', "ajax-reserve.php", true);
          xhr.onload = function(){
            // Set contents, click, change actions
            document.getElementById("res_date").innerHTML = this.response;
            select = document.querySelector("#res_date select.month");
            select.addEventListener("change", res.cal);
            select = document.querySelector("#res_date select.year");
            select.addEventListener("change", res.cal);
            select = document.querySelectorAll("#res_date .pick, #res_date .active");
            for (var i of select) {
              i.addEventListener("click", res.pick);
            }
      
            // Load time slots
            res.slot();
          };
          xhr.send(data);
        },
      
        slot : function () {
        // res.slot() : load time slot selector
      
          // Disable submit first
          document.getElementById("res_go").disabled = true;
      
          // Selected date
          var select = document.querySelector("#res_date td.active").innerHTML;
          if (select.length==1) { select = "0" + select; }
          select = document.querySelector("#res_date select.month").value + "-" + select;
          select = document.querySelector("#res_date select.year").value + "-" + select;
      
          // AJAX data
          var data = new FormData();
          data.append('req', 'show-slot');
          data.append('date', select);
      
          // AJAX call
          var xhr = new XMLHttpRequest();
          xhr.open('POST', "ajax-reserve.php", true);
          xhr.onload = function(){
            // Set contents
            document.getElementById("res_slot").innerHTML = this.response;
            // Enable submit
            document.getElementById("res_go").disabled = false;
          };
          xhr.send(data);
        },
      
        pick : function () {
        // res.pick() : change selected date
      
          var select = document.querySelector("#res_date .active");
          if (select!=this) {
            select.classList.remove("active");
            select.classList.add("pick");
            this.classList.remove("pick");
            this.classList.add("active");
            res.slot();
          }
        },
      
        save : function () {
        // res.save() : save the reservation
      
          // Selected date
          var select = document.querySelector("#res_date td.active").innerHTML;
          if (select.length==1) { select = "0" + select; }
          select = document.querySelector("#res_date select.month").value + "-" + select;
          select = document.querySelector("#res_date select.year").value + "-" + select;
      
          // AJAX data
          var data = new FormData();
          data.append('req', 'book-slot');
          data.append('name', document.getElementById("res_name").value);
          data.append('email', document.getElementById("res_email").value);
          data.append('tel', document.getElementById("res_tel").value);
          data.append('notes', document.getElementById("res_notes").value);
          data.append('date', select);
          data.append('slot', document.querySelector("#res_slot select").value);
      
          // AJAX call
          var xhr = new XMLHttpRequest();
          xhr.open('POST', "ajax-reserve.php", true);
          xhr.onload = function(){
            var res = JSON.parse(this.response);
            // OK - Redirect to thank you page
            if (res.status==1) {
              location.href = "thank-you.html";
            }
            // ERROR - show error
            else {
              alert(res.message);
            }
          };
          xhr.send(data);
          return false;
        }
      };
      
      window.addEventListener("load", res.cal);
      

      Complicated Javascript? Nope. There are only 4 AJAX functions here.

      FunctionDescription
      res.cal()Fires up when the page is initially loaded, and whenever the user changes the month/year. It will do an AJAX call to the server to render the calendar for the selected period.
      res.slot()Follows up after res.cal, or whenever the user chooses a different date. This will load the timeslot selector via an AJAX call.
      res.pick()Fires up when the user picks a different date. Updates the HTML interface, and calls the res.slot function to refresh the available timeslots for the selected date.
      res.save()Proceed to process the reservation.

      DATE RANGE BOOKING

      THE HTML

      reserve-range.html
      
      
        
          
            PHP Reservation Demo - Date Range Booking
          

      RESERVATION

      Simple HTML form here, but with a few small twists:

      • The start and end date selectors will be loaded via AJAX.
      • The submit button is disabled by default. We will enable it only when both date selectors are loaded.

      THE JAVASCRIPT

      public/reserve-range.js
      var res = {
        calstart : function () {
        // res.calstart() : show calendar for date start
      
          res.cal("start");
        },
      
        calend : function () {
        // res.calend() : show calendar for date end
      
          res.cal("end");
        },
      
        cal : function (target) {
        // res.cal() : show calendar
        // target : start or end
      
          // Disable submit first
          document.getElementById("res_go").disabled = true;
      
          // Target event handlers
          var calchange = target=="start" ? res.calstart : res.calend ;
          var picker = target=="start" ? res.pickstart : res.pickend ;
      
          // AJAX data
          var data = new FormData();
          data.append('req', 'show-cal');
      
          // Get selected month & year - If they exist
          var select = document.querySelector("#res_" + target +" select.month");
          if (select!=null) {
            data.append('month', select.value);
            select = document.querySelector("#res_" + target + " select.year");
            data.append('year', select.value);
          }
      
          // AJAX call
          var xhr = new XMLHttpRequest();
          xhr.open('POST', "ajax-reserve.php", true);
          xhr.onload = function(){
            // Set contents, click, change actions
            document.getElementById("res_" + target).innerHTML = this.response;
            select = document.querySelector("#res_" + target + " select.month");
            select.addEventListener("change", calchange);
            select = document.querySelector("#res_" + target + " select.year");
            select.addEventListener("change", calchange);
            select = document.querySelectorAll("#res_" + target + " .pick, #res_" + target + " .active");
            for (var i of select) {
              i.addEventListener("click", picker);
            }
      
            // Enable submit
            document.getElementById("res_go").disabled = false;
          };
          xhr.send(data);
        },
      
        pickstart : function () {
        // res.pickstart() : change selected date for date start
      
          res.pick('start', this);
        },
      
        pickend : function () {
        // res.pickend() : change selected date for date end
      
          res.pick('end', this);
        },
      
        pick : function (target, picked) {
        // res.pick() : change selected date
        // target : start or end
        // picked : current element being clicked on
      
          var select = document.querySelector("#res_" + target + " .active");
          if (select!=picked) {
            select.classList.remove("active");
            select.classList.add("pick");
            picked.classList.remove("pick");
            picked.classList.add("active");
          }
        },
      
        save : function () {
        // res.save() : save the reservation
      
          // Selected start date
          var start = document.querySelector("#res_start td.active").innerHTML;
          if (start.length==1) { start = "0" + start; }
          start = document.querySelector("#res_start select.month").value + "-" + start;
          start = document.querySelector("#res_start select.year").value + "-" + start;
      
          // Selected end date
          var end = document.querySelector("#res_end td.active").innerHTML;
          if (end.length==1) { end = "0" + end; }
          end = document.querySelector("#res_end select.month").value + "-" + end;
          end = document.querySelector("#res_end select.year").value + "-" + end;
      
          // End date must be after start date
          if (Date.parse(start)>=Date.parse(end)) {
            alert("End date cannot be earlier than start date!");
          } else {
            // AJAX data
            var data = new FormData();
            data.append('req', 'book-range');
            data.append('name', document.getElementById("res_name").value);
            data.append('email', document.getElementById("res_email").value);
            data.append('tel', document.getElementById("res_tel").value);
            data.append('notes', document.getElementById("res_notes").value);
            data.append('start', start);
            data.append('end', end);
      
            // AJAX call
            var xhr = new XMLHttpRequest();
            xhr.open('POST', "ajax-reserve.php", true);
            xhr.onload = function(){
              var res = JSON.parse(this.response);
              // OK - Redirect to thank you page
              if (res.status==1) {
                location.href = "thank-you.html";
              }
              // ERROR - show error
              else {
                alert(res.message);
              }
            };
            xhr.send(data);
          }
          return false;
        }
      };
      
      window.addEventListener("load", function(){
        res.calstart();
        res.calend();
      });
      FunctionDescription
      res.cal()Loads the calendar via AJAX. Either for the start or end date.
      res.calstart()Fires up on page load, or when the user changes the month/date of the start date. Calls res.cal to load the calendar.
      res.calend()Fires up on page load, or when the user changes the month/date of the end date. Calls res.cal to load the calendar.
      res.pick()Updates the HTML calendar to show a newly selected date.
      res.pickstart()Fires when the user clicks on a date on the start date. Calls res.pick to update the interface.
      res.pickend()Fires when the user clicks on a date on the end date. Calls res.pick to update the interface.
      res.save()Proceed to save the reservation on the server.

      THE CSS

      public/theme.css
      /* [CALENDAR] */
      /* Month & year selector */
      div.calendar select {
        width: 50% !important;
        padding: 5px
      }
      div.calendar table {
        width: 100%;
        border-collapse: seperate;
        margin-top: 10px;
      }
      /* All the cells in general */
      div.calendar table td {
        width: 14%;
        padding: 5px;
        text-align: center;
      }
      /* First row - days of week */
      div.calendar table tr.days td {
        background: #888;
        color: #fff;
        font-weight: bold;
      }
      /* Currently chosen date */
      div.calendar table td.active {
        background: #d64646;
        color: #fff;
      }
      /* Dates you can choose */
      div.calendar table td.pick:hover {
        cursor: pointer;
        background: #ffe5d3;
      }
      /* Blank cells */
      div.calendar td.blank {
        background: #ddd;
      }
      
      /* [DOES NOT MATTER] */
      html, body {
        font-family: arial, sans-serif;
      }
      #res_form {
        padding: 15px;
        max-width: 400px;
        background: #f2f2f2;
      }
      #res_form label, #res_form input, #res_form button, #res_form select {
        font-size: 16px;
        width: 100%;
        box-sizing: border-box;
      }
      #res_form label, #res_form input, #res_form button {
        display: block;
      }
      #res_form label {
        color: #555;
        margin: 5px 0;
      }
      #res_form input, #res_form select {
        padding: 5px;
      }
      #res_form button {
        margin-top: 10px;
        background: #b53732;
        color: #fff;
        padding: 10px;
        border: 0;
      }

      Just some cosmetics for this example, the only usable part for your project is probably the styles of the calendar.

      THANK YOU PAGE

      thank-you.html
      
      
        
          
            PHP Reservation Demo - Thank You Page
          

      THANK YOU!

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur mollis erat nec tortor efficitur, non pulvinar ligula scelerisque.

      Vestibulum facilisis quis quam id lobortis. Nullam bibendum aliquet ultrices. Aliquam elementum neque quis massa tristique cursus.

      Well, a thank-you page… Please do make a proper one for yourself.

      EXTRA
      DOWNLOAD & MORE

      That’s all for the code, and here is the download link as promised – Plus a few small extras that may be useful to you.

      TODO LIST

      That’s it for this simple system, but it is still a skeleton. Your client or business probably has 101 more different requirements, so here is a small list of stuff that you will want to build on top of this guide:

      • Beef up the reservation library and AJAX handler – Put in your own restrictions and rules on the reservation dates and slots.
      • Close the loop – What happens after the user submits the reservation. Send an email? Call them to confirm? Check your own availability first? Ask for deposit payment?
      • Quite a lot of cosmetics – To fit your own project.
      • Proper integration into your existing website or build a new admin panel.
      • Complete administration and reports – Extract the reservations for a given period, export to spreadsheet, etc…

      ADDITIONAL FIELDS OR MODIFICATIONS?

      So you want to add some fields, or maybe make some modifications to this system? Just remember the 3 parts of this guide, tackle them piece-by-piece and you will do just fine:

      • Database – First update the database table, create or remove the fields that you want.
      • Server-side script – Update the reservation library file, create your own functions if you must. Also, remember to update the AJAX handler script to include your new fields.
      • Client-side script – Finally, update the HTML and Javascript.

      ADMIN PANEL & LOGIN

      For you guys who start out on a fresh project. You may have a booking system, but it still needs a proper user database, login mechanism, and admin panel –

      3 Steps Simple PHP Admin Panel (Source Code Included)

      SOURCE CODE DOWNLOAD

      Click here to download the 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.
       

      CLOSING
      WHAT’S NEXT?

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

      The post 3 Steps Simple PHP Reservation System appeared first on Code Boxx.



This post first appeared on Xxxxxxxxx, please read the originial post: here

Share the post

3 Steps Simple PHP Reservation System

Email
Facebook
Pinterest
Twitter
×

Subscribe to Xxxxxxxxx

Get updates delivered right to your inbox!

Thank you for your subscription

×