Apr
10

Hotel reservations with PHP and MySQL

10 Apr 2009 by tonie in MySQL, PHP

Recently I had to figure out a solution to the following problem: A client of mine, who owns a restaurant wanted his customers to be able to make real time online table reservations. Before I start, let me tell you that this is a very basic example to show you how you can use PHP to create a reservation system. The actual script I wrote for my client was more complex than this, since it required better time management of the restaurant's tables, cell phone message notification, more extensive error handling, etc.

So, first thing is first. Here's the database structure we are going to use for our application:

CREATE DATABASE `hotel` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `reservations` (
  `id` int(11) NOT NULL auto_increment,
  `roomnum` int(4),
  `status` varchar(35),
  `checkin_date` int(11),
  `checkout_date` int(2),
  `name` varchar(50),
  `telephone` varchar(20),
  `email` varchar(50),
  `code` varchar(50),
  PRIMARY KEY  (`id`)
) DEFAULT CHARSET=utf8

Now that we have our database set up, let's see how this system will work. To make it easier for the user, we are going to create 4 steps, through which they will go to make a room reservation. You might want to separate each step in a different file, like I'll be showing, or put everything in a single one. In the first step we will ask them about the check-in date and the number of nights they wish to spend in our hotel. Step number 2 will produce a scheme of available rooms for that period. Once the user has selected the rooms they want to reserve for the selected number of nights, they will be directed to step number 3 to fill some personal data and contact information. At the fourth step the script will notify the user if their reservation was successful and will print out a confirmation code, which will be later copied and pasted in confirm.php (or you can make it fancier by sending an e-mail with the confirmation code and a confirmation link). Let's go ahead and connect to our database db_config.php

<?php
$user="mysql_user";
$password="mysql_pass";
$database = "hotel";
$link=mysql_connect(localhost,$user,$password);
mysql_select_db($database) or die('Unable to select database!');
?>

Then here's a basic css file which I made for testing purposes. Feel free to change whatever you like.

body {
    background-color:#F3F3F3;
    font-family:Verdana, Arial, Helvetica, sans-serif;
    font-size: 12px;
    color:#444444;
}
h1 {
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 16px;
    font-weight: bold;
}
div.available, div.unavailable {
    margin: 5px 2px;
    width: 100px;
    padding: 15px 5px;
    float: left;
    border: 1px solid #888888;
}
div.available {
    background-color:#83F273;
}
div.unavailable {
    background-color:#FF8282;
    color:#990000;
}
div.clear {
    clear: both;
}

The first step

We proceed to our first part of the script: step1.php. Here we will collect the most important information and that is the date our guests would like to book a room and the number of nights they wish to spend in our hotel. Remember to call a session in each of the four steps.

<?php
session_start();
?>
<form method="post" action="step2.php">
<label for="month">Your preferred check-in date: </label>
<select name="month" id="month">
   <option value="0">Month</option>
   <option value="1">Jan</option>
   <option value="2">Feb</option>
   <option value="3">Mar</option>
   <option value="4">Apr</option>
   <option value="5">May</option>
   <option value="6">June</option>
   <option value="7">July</option>
   <option value="8">Aug</option>
   <option value="9">Sep</option>
   <option value="10">Oct</option>
   <option value="11">Nov</option>
   <option value="12">Dec</option>
</select>
<label for="day">/</label>
<select name="day" id="day">
   <option value="0">Day</option>
<?php
// print out 31 days
for ($i=1;$i<32;$i++) {
    echo '<option value="'.$i.'">'.$i.'</option>';
}
?>
</select>
<label for="year">/</label>
<select name="year" id="year">
   <option value="0">Year</option>
   <option value="<?=date('Y')?>"><?=date('Y')?></option>
   <option value="<?=date('Y')+1?>"><?=date('Y')+1?></option>
</select>
<p>
<label for="stayPeriod">Number of nights you wish to spend: </label>
<input type="text" name="stayPeriod" id="stayPeriod" maxlength="2" style="width: 20px;" />
</p>
<p><input type="submit" name="goToStep2" value="Next Step" /></p>
</form>

Here you can play with your form elements, add JavaScript functions to check the corresponding number of days in each month or check the current date, so that the user is not able to select a date before the day they are booking their room. I left this part for you to figure out and play around error checking procedures Wink.

Step 2

I would like to think of this as the heart of the script, as it deals with timestamps and converts them into dates. It also figures out the very important check out date. To do this, we will convert the number of nights our guest will be spending in the hotel into seconds, so we can add them to the check-in timestamp and find the check-out timestamp. The other important function of the "heart" of the script is printing out which rooms will be available and which will be not for the selected period of time. So let's see how we can do that.

<?php
session_start();
include('db_config.php');
// create a timestamp for the check-in date
$_SESSION['check-in']=mktime(0,0,0,$_POST['month'],$_POST['day'],$_POST['year']);
// convert number of days to seconds
// X days * 24 hrs a day * 60 mins per hr * 60 secs per min
// yields the total number of seconds in X days
$_SESSION['stayPeriod']=$_POST['stayPeriod']*24*60*60;
// add the check-in date with stayPeriod yields the check-out date
$_SESSION['check-out']=$_SESSION['check-in']+$_SESSION['stayPeriod'];
?>
<p>
</p>
<form method="post" action="step3.php">
Available rooms for the period:
<?=date('m/d/Y',$_SESSION['check-in'])?> -
<?=date('m/d/Y',$_SESSION['check-out'])?>
<p>Please select the rooms you would like to book:</p>
<p>
<?php
// we have 15 rooms - 5 rooms on each of the 3 floors
// room numbers are as follows: 101, 102, 103 ... 503, 504, 505
// check if each room is available for the given period
// initialize variables
$floor=0;
$restart_counter=0;
$rooms_per_floor=5;
$total_rooms=15;
//check each room
for ($i=0;$i<$total_rooms;$i++) {
    if (!($i%$rooms_per_floor)) {
        //go to the next floor
        $floor++;
        $restart_counter=0;
        echo '<div class="clear"></div>';
    }
    $restart_counter++;
    // give rooms a number
    $roomnum=$floor.'0'.$restart_counter;
    //room is always available unless proven otherwise
    $available=true;
    // select the room and make sure it is not "deleted" or "cancelled"
    $query="SELECT * FROM `reservations` WHERE roomnum = '$roomnum' AND status!='deleted' AND status!='cancelled'";
    $result=mysql_query($query);
    if (mysql_num_rows($result)) {
        while ($object=mysql_fetch_object($result)){
            $check_in=$object->checkin_date;
            $check_out=$object->checkout_date;
            if ($check_in < $_SESSION['check-out'] and $check_out > $_SESSION['check-in']) {
                // there is a reservation for that room
                // the check-in date is before the desired checkout date
                // and the checkout date is after the desired check-in date
                // so this indicates that the room is not available
                // for the desired period
                $available=false;
            }
        }
    }
    if ($available) {
        echo '<div class="available">
        <input type="checkbox" name="'.$i.'" value="'.$roomnum.'">Room '.$roomnum.'</div>';
    } else {
        echo '<div class="unavailable">
        <input type="checkbox" disabled="disabled">Room '.$roomnum.'</div>';
    }
}
?>
</p>
<div class="clear"></div>
<p><input type="submit" name="goToStep3" value="Next Step" /></p>
</form>

Play around with $rooms_per_floor and $total_rooms to change the number of floors and the whole diagram that prints out. Again here you can add a if (isset()) clause to make sure the sure will go through step #1 first. You might have already noticed that I have skipped any precaution functions in all of the files. Well, I guess I'm too lazy to write them Laughing.

step3.php

This simplest part of the whole concept. Collects the numbers of all the checked rooms in the previous step and puts them in $_SESSION['rooms']. Then prints out a form to collect personal information (again, no error checking Tongue out)

<?php
session_start();
?>
<form method="post" action="step4.php">
You have chosen the following room(s):<br />
<?php
$total_rooms=15;
$_SESSION['rooms']=array();
for ($i=0;$i<$total_rooms;$i++){
    if ($_POST[$i]) {
        echo 'Room #'.$_POST[$i].'<br/>';
        // we are pushing the selected rooms in an array
        array_push($_SESSION['rooms'],$_POST[$i]);
    }
}
?>
<p>Please Enter your details below:</p>
<p>Name: <input type="text" name="name" /></p>
<p>Telephone: <input type="text" name="telephone" /></p>
<p>E-mail: <input type="text" name="email" /></p>
<p><input type="submit" name="goToStep4" value="Finish" /></p>
</form>

The final step

To sum up, what we've done so far was to collect all the information that is needed to create a record in our database. The final step does exactly this. It records the reservation and gives it a "pending" status. In this part of the script I was too lazy to create a function that sends an e-mail to our guest, containing the information on his reservation and an activation link. Instead, I slothfully gave them the confirmation code and make them confirm their reservation manually.

<?php
session_start();
include('db_config.php');
if (isset($_POST['goToStep4'])) {
    $name=($_POST['name']);
    $telephone=addslashes($_POST['telephone']);
    $email=addslashes($_POST['email']);
    $code=md5($email.time());
    foreach ($_SESSION['rooms'] as $key => $value) {
        mysql_query("INSERT INTO `reservations` VALUES(
        '',
        '".$value."',
        'pending',
        '".$_SESSION['check-in']."',
        '".$_SESSION['check-out']."',
        '".$name."',
        '".$telephone."',
        '".$email."',
        '".$code."'
        )");
    }
    // here you can choose to send the confirmation code via
    // email and have your customers click an activation link
    // I chose to do it like this because it is simpler :)
    echo '<p>Your reservation was successful!</p>';
    echo '<p>Your confirmation code is <b>'.$code.'</b></p>';
    echo '<p>Please copy it and enter it <a href="confirm.php">here</a> to complete your reservation.</p>';
}
?>

Again I didn't do any error checking activities - something without which the script is somehow incomplete. But I gave you the basic idea of how to pull of a simple online booking system. Drill your brain a little to complete it, adding other ideas (and error checking!). And here's the code for confirm.php

<?php
session_start();
include('db_config.php');
?>
<form action="" method="post">
    Code: <input type="text" name="code" /> <input type="submit" name="confirm" value="Confirm" />
</form>
<?php
// wow! "error-checking!"
if (isset($_POST['confirm'])) {
    $code=addslashes($_POST['code']);
    mysql_query("LOCK TABLES `reservations` WRITE");
    mysql_query("UPDATE `reservations` SET status='confirmed' WHERE code='$code'");
    mysql_query("UNLOCK TABLES");
    echo 'Your reservation was confirmed. Thank you.';
}
// you can also use php's mail() function to send a mail with an activation link
// which points to www.hotel.com/confirm.php?code=$code
// then you can $_GET['code'] instead of $_POST['code'] it
// and again use it to change the status of the reservation(s) to "confirmed"
?>

What now?

Well, that seems like a reasonable question. As I already said several times - start with error handling. Make sure that your guests cannot select an already reserved room (when having many users, this is not unlikely). If you want to send confirmation codes through e-mail, create a JavaScript (or PHP) function to validate the entered e-mail. You can also extend you hotel. Create another table `accommodation`, where you can store you hotel rooms with their according properties: people it can accommodate, type of room (apartment), facilities, floor number, etc. Also think about the managers of your hotel. You can create and administration module and have your receptionist pull real-time statistics on how many times Room # 505 has been booked, or which room has the most bookings for a given period of time. Possibilities from here on are endless.

php, mysql, hotel, reservations, system, tutorial

Speak your mind ( 13 Comments)

#1 by AndrewBoldman on 4/6/09

da best. Keep it going! Thank you

#2 by fairytale89 on 2/4/10

hey, this is a really good article. something i've been look up for my final projects.:)

#3 by tonie on 4/4/10

Always glad to help m8

#4 by Robin Awal on 29/5/10

Great tutorial. but it would be much better if you extend the part after What's now section. and it would be great if you put a Demo for each tutorial on this site.

Anyway Thanks alot and help people with more tutorials.

#5 by tonie on 29/5/10

@Robin Awal Thank you for the insight.

#6 by Robin Awal on 27/6/10

plz update this useful tutorial. plz give full functional search form and search listing php page too.

#7 by George 4 weeks ago

Hello!
i am a newbie in php and mysql
Please could you tell me, how i will connect all this?
which file i will run?

#8 by george 4 weeks ago

i get the following errors:

a)In step1.php i cant see the years. It's just blank choices

b)In step2.php:
Warning: mktime() expects parameter 6 to be long, string given in C:\wamp\www\step2.php on line 5
line 5 is: $_SESSION['check-in']=mktime(0,0,0,$_POST['month'],$_POST['day'],$_POST['year']);

c)In step3.php:

Notice: Undefined offset: 1 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 2 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 3 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 4 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 5 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 6 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 7 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 8 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 9 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 10 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 11 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 12 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 13 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 14 in C:\wamp\www\step3.php on line 10

Line 10 is: if ($_POST[$i]) {

#9 by tonie 3 weeks, 6 days ago

@George Well, it's simple stuff, really. First go ahead and set up your database and create the tables I've shown above. Then create all the necessary "step" files and copy/paste the corresponding code for each file. Finally, drop everything under your htdocs or www directory and run step1.php. That's it :D

#10 by tonie 3 weeks, 6 days ago

@George The root of your problem seems to be in step1.php. Something went wrong when parsing the reservation form. Try creating a static form and hard code the dates, years and months manually instead of using a loop and it should work.

#11 by George 3 weeks, 6 days ago

I changed to:

<label for="day">/</label>
<select name="day" id="day">
<option value="0">Day</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>

etc etc


and

<label for="year">/</label>
<select name="year" id="year">
<option value="0">Year</option>
<option value="2010">2010</option>
</select>

etc etc


but same error exist:
Notice: Undefined offset: 0 in C:\wamp\www\step3.php on line 10
Room #102
Notice: Undefined offset: 2 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 3 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 4 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 5 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 6 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 7 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 8 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 9 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 10 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 11 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 12 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 13 in C:\wamp\www\step3.php on line 10
Notice: Undefined offset: 14 in C:\wamp\www\step3.php on line 10

line 10 is: if ($_POST[$i]) {



also i did a reservation on 2 Feb 2010 for 2 days
in sql database checkin_date is: 1265068800 and checkout_date is: 1265241600
How can i understand which date is checkin and checkout from this number ?

Thanks in advance my friend!

#12 by george 3 weeks, 6 days ago

problem in step3.php with line 10
''solved'' when i put in the code the line: ini_set('display_errors', 0);

Is it easy to tell me how the reservation form could work with only one file?
how can i put them all together to the file: reservation.php

#13 by tonie 3 weeks, 6 days ago

Hey George,
you could put everything in one file and submit form information to one and the same file every time. Then, based on what has been submitted, you could render different output. I strongly suggest you keep files separated as it is easier to read and maintain. Information in the DB is stored in a unix timestamp format, that is why it doesn't make sense. You can easily format this information with PHP's built in date() function, like so:
<?php echo date('m/d/Y',$checkin_date); ?>
Assuming your checkin_date field equals 1265068800, the code above should print out "02/02/2010".

If you liked the article and want to contribute to it, please feel free to leave your comment. HTML tags are not allowed, but you can use the following BBCode to enhance your message: [url] [quote] [code] [b] [i] [u] [color].