有关PHP SQL预订系统的问题

时间:2015-08-06 00:36:42

标签: php mysqli

所以我正在建造一个假日综合体的预订系统(类似于酒店,但不是房间有各种各样的公寓)。为避免双重预订,系统需要检查特定公寓是否在潜在客人选择的日期范围内预订,如果没有任何问题则继续进行,或者如果选择的日期是其中一部分,则通知他们更改日期或公寓一组日期。我试图弄清楚如何检查所选日期是否属于先前选择的日期范围 例如:如果已预订日期范围08/09/2015 - 08/12/2015,然后选择日期范围08/10/2015 - 08/15/2015,则客人会收到选择新的通知日期或其他公寓,否则如果选择的日期范围是08/15/2015 - 08/20/2015,则表格将被处理。

到目前为止我的预订系统:

<?php
if ($_POST) {
if (isset($_POST['proceedtopaypal'])){
    $apartment = $_POST['apartment'];
    $name = $_POST['name'];
    $surname = $_POST['surname'];
    $email = $_POST['email'];
    $address = $_POST['address'];
    $mobile = $_POST['mobile'];
    $pax = $_POST['pax'];
    $address = $_POST['address'];
    $remarks = $_POST['remarks'];
    $day_from = $_POST['day_from'];
    $month_from = $_POST['month_from'];
    $year_from = $_POST['year_from'];
    $booking_from = $year_from."-".$month_from."-".$day_from;
    $day_to = $_POST['day_to'];
    $month_to = $_POST['month_to'];
    $year_to = $_POST['year_to'];
    $booking_to = $year_to."-".$month_to."-".$day_to;
    $no_of_nights = abs(strtotime($booking_to) -   strtotime($booking_from));       
    $days = floor($no_of_nights / (60*60*24));

    printf("%d nights\n", $days);
    $validdate = false;
    $buttonpressed = false;
    $nodate='<p>date does not exist.</p>\n';
    $noinfo='<p>please fill in the missing information.</p>\n';
    $baddate='<p>selected dates is already booked.</p>\n';
    $thankyou='<p>thank you for your reservation.<br>a confirmation     email will be sent shortly</p>\n';
      $window = '';

    function IsInjected($str)
    { 
       $injections = array('(\n+)',
                   '(\r+)',
                   '(\t+)',
                   '(%0A+)',
                   '(%0D+)',
                   '(%08+)',
                   '(%09+)'
                   );
       $inject = join('|', $injections);
      $inject = "/$inject/i";
      if(preg_match($inject,$str))
        {
        return true;
      }
      else
        {
        return false;
      }
    }

    if ($booking_from == (($day_from == "31") && ($month_from == "2"))  || (($day_from == "31") && ($month_from == "4")) || (($day_from == "31") && ($month_from == "6")) || (($day_from == "31") && ($month_from == "9")) || (($day_from == "31") && ($month_from == "11")) || (($day_from == "30") && ($month_from == "2")) || (($day_from == "29") && ($month_from == "2") &&  ($year_from %4 != 0))   ) {
        //$window=$nodate; 
        echo "Date does not exist";
        $validdate = true;
    } 
     else if ($booking_to == (($day_to == "31") && ($month_to == "2"))     || (($day_to == "31") && ($month_to == "4")) || (($day_to == "31") && ($month_to == "6")) || (($day_to == "31") && ($month_to == "9")) || (($day_to == "31") && ($month_to == "11")) || (($day_to == "30") && ($month_to == "2")) || (($day_to == "29") && ($month_to == "2") && ($year_to %4 != 0))   ) {
        //$window=$nodate; 
        echo "Date does not exist";
        $validdate = true;
    } 
    else if  (($name == "Name") || ($surname == "surname") || ($email == "Email") || ($address == "Address")) {
        //$window=$noinfo;
        echo "Missing information";
    }
    else if (IsInjected($email)) {
        echo '<script language="javascript">';
        echo 'alert("Email")';
        echo '</script>';
    }

    else if ($validdate == false) {
        $final = true;
        include 'connect.php';
        $sql = "SELECT * FROM booking WHERE ($booking_from  BETWEEN date_from AND date_to) OR ($booking_to BETWEEN date_from AND date_to)";
        $result = $conn->query($sql);
        while ($row = $result->fetch_assoc()) {
            if ($apartment == $row['apartmentID']  && $booking_from >= $row['date_from'] && $booking_to <= $row['date_to']){
                //$window=$badtime;
                echo "Apartment is taken";
                $final = false;
            }
            else {
                echo "All OK";
            } 
        }
    }
}

}

SQL表具有以下设置:

> BookingID - int
> ApartmentID - int
> ClientID - int
> date_from - date (Format: yyyy-mm-dd)
> date_to - date  (Format: yyyy-mm-dd)
> no of nights - int (achieved by subtracting date_from from date_to)
> pax - int (number of people)
> paid - int

可见代码:

<form action="" method="post" id="bookstay">
                    <input type="hidden" name="apartment" value="<?php get_apartment_text("SELECT apartmentID from apartment_details WHERE apartmentID = ?", "apartmentID"); ?>"/>
                    <input name='name' class="short-input" type="text" value="Name" onFocus="this.value = ''" />
                    <input  name= 'surname' class="short-input" type="text" value="surname" onFocus="this.value = ''" />
                    <input  name='email' class="long-input" type="text" value="Email" onFocus="this.value = ''"  />
                    <input name='address' class="long-input" type="text" value="Address" onFocus="this.value = ''" />
                    <input name='mobile'  class="short-input" type="text" value="mobile" onFocus="this.value = ''"  />
                    <div class="select" id="peopletostay">
                        <select name="pax" class="short-input">
                            <option value="0">people to stay</option>
                            <option value="1">1</option>
                            <option value="2">2</option>
                            <option value="3">3</option>
                            <option value="4">4</option>
                            <option value="5">5</option>
                            <option value="6">6</option>
                        </select>
                    </div>
                    <div id="dateofarrival">
                    date of arrival<br>                 
                    <?php include 'date-from.php'; ?>
                   </div>
                     <div id="dateofdeparture">
                    date of departure<br>                 
                    <?php include 'date-to.php'; ?>
                   </div>
                   <textarea name='remarks'>Extra Remarks</textarea>
                   </div>
                  <button type='submit' name='proceedtopaypal'>
                  </form>

1 个答案:

答案 0 :(得分:2)

我不会在booking表格中包含所有内容,而是制作以下单独的表格:

  • bookings - 请注意,使用复数而不是单数是非常标准的,所以如果它没有太多工作,我会改变它。你可以从中删除apartmentIdnumber_of_nights。第一个将由room_nights表(下面)处理,第二个表示存储在数据库中毫无意义,因为它可以很容易地计算出来。
  • apartments - 我认为这已经完成了。只需在此处添加有关每间公寓的信息,例如房间数量,描述等。
  • clients - 我也认为这已经完成了。在此处添加有关客户端的任何信息。
  • room_nights - 这可以追踪任何一个晚上的完整公寓。您将在每晚公寓满员时添加一个条目。这应仅包含datebooking_idapartment_id
  • blocked_rooms(可选) - 这与room_nights的工作方式相同,但是它允许您跟踪您想要阻止预订的任何日期而无需实际预订(例如,维护)。

然后在任何给定的夜晚查询公寓是否已满,您可以执行以下操作:

SELECT COUNT(*) FROM room_nights
WHERE date >= :check_in 
AND date < :check_out
AND apartment_id = ?

如果您还想使用blocked_rooms,您可以像上面一样使用UNION在一个查询中完成所有操作。

然后,您可以轻松地将其输出到日历表,其中y轴为公寓,x轴为日期,以显示已预订/空/被阻止的公寓。这就是我在我的程序中所做的:

enter image description here

现在,如果你想让公寓有动态费率,这就是我用过的桌面结构:

rates表:

您可以在此处输入费率名称以及一些限制。

CREATE TABLE `rates` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `rate_name` varchar(50) NOT NULL,
 `days_advance_min` int(11) NOT NULL,
 `days_advance_max` int(11) NOT NULL,
 `booking_date_start` datetime NOT NULL,
 `booking_date_end` datetime NOT NULL,
 `booking_date_end_unlimited` bit(1) NOT NULL,
 `min_people` int(11) NOT NULL,
 `max_people` int(11) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `rate_name` (`rate_name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

days_advance_*列是可用费率的最高/最高天数。 booking_date_*列用于确定何时可以预订此费率。因此,如果您只希望它在特定日期开始使用,那么就把它放在那里。如果没有最终预订日期,booking_date_end_unlimited只是为了跟踪。您可能不希望将BIT(1)用于该列,因为它更难以使用。

rates_apartments

将费率与公寓ID相关联的关系表

rate_dates

这是实际的&#34;率&#34;进去。你每天都有一个房价。在任何地方都不需要开始/结束日期,因为您可以在此处添加任何日期:

CREATE TABLE `rate_dates` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `rate_id` int(11) NOT NULL,
 `date` date NOT NULL,
 `single` decimal(13,4) NOT NULL,
 `second_adult` decimal(13,4) NOT NULL,
 `third_adult` decimal(13,4) NOT NULL,
 `fourth_adult` decimal(13,4) NOT NULL,
 `extra_adult` decimal(13,4) NOT NULL,
 `extra_child` decimal(13,4) NOT NULL,
 `min_nights` int(11) NOT NULL,
 `max_nights` int(11) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `rate_id` (`rate_id`,`date`),
 UNIQUE KEY `rate_id_3` (`rate_id`,`date`),
 KEY `rate_id_2` (`rate_id`),
 KEY `date` (`date`),
 CONSTRAINT `rate_dates_ibfk_1` FOREIGN KEY (`rate_id`) REFERENCES `rates` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3219 DEFAULT CHARSET=utf8

我认为这里的一切都应该是不言自明的。通过添加single + second_adult + third_adult等来计算费率,具体取决于人数。如果您不想根据人数改变费率,只需设置一个&#34; rate&#34;价值,你也可以摆脱rates表中的最小/最大人数。

最后,这是我用来实际获得费率的查询:

// Get available rates for each night
$placeholders = substr(str_repeat('?,', count($dates_stayed)), 0, -1);

$query = "
    SELECT
        r.id as rate_id,
        rrt.room_type_id,
        date,
        single,
        second_adult,
        third_adult,
        fourth_adult,
        extra_adult,
        extra_child,
        r.min_people as rates_min_people,
        r.max_people as rates_max_people,
        crt.min_people as crt_min_people,
        crt.max_people as crt_max_people
    FROM rate_dates rd
    LEFT JOIN rates r
        ON rd.rate_id = r.id
    LEFT JOIN rates_room_types rrt
        ON r.id = rrt.rate_id
    LEFT JOIN config_room_types crt
        ON rrt.room_type_id = crt.id
    WHERE
        rd.date IN ( $placeholders )
        AND booking_date_start <= NOW()
        AND (
            booking_date_end >= NOW()
            OR booking_date_end_unlimited = b'1'
        )
        AND DATEDIFF(?, NOW()) >= days_advance_min
        AND (
            days_advance_max = -1
            OR DATEDIFF(?, NOW()) <= days_advance_max
        )
        AND min_nights <= ?
        AND min_nights <= ?
        AND (
            max_nights >= ?
            OR max_nights = -1
        )
    HAVING
        ? >= rates_min_people
        AND ? <= rates_max_people
        AND ? >= crt_min_people
        AND ? <= crt_max_people";

$stmt = $this->dbh->prepare($query);

config_room_types表与您的apartments表类似,因为您可以在费率级别和房间级别限制最小/最大人数。