RM新时代|国际平台

新聞
NEWS
網(wǎng)站想做在線(xiàn)預約功能?這段PHP代碼可以直接拿去改
  • 來(lái)源: 網(wǎng)站建設:www.xldmws.com
  • 時(shí)間:2026-06-18 10:45
  • 閱讀:48

在線(xiàn)預約系統是現代服務(wù)型網(wǎng)站常見(jiàn)的功能模塊,它允許訪(fǎng)客自助選擇時(shí)間、填寫(xiě)需求并提交申請,從而替代傳統電話(huà)或人工登記流程。對于許多中小型項目而言,從頭開(kāi)發(fā)一套完整的預約系統成本較高,而直接復用并改造一段穩定的PHP核心代碼,則是高效且經(jīng)濟的方案。本文提供一套基礎的預約處理邏輯,涵蓋數據庫設計、表單提交、時(shí)段校驗、沖突檢測及結果返回等關(guān)鍵環(huán)節,并預留了充分的擴展接口,方便您根據實(shí)際業(yè)務(wù)場(chǎng)景進(jìn)行調整。

一、功能定位與適用場(chǎng)景

本段代碼面向單資源、多時(shí)段的預約模型,例如:咨詢(xún)時(shí)段預約、工位使用申請、設備借用登記、課程試聽(tīng)報名等。其核心能力包括:

  • 展示當前可預約的日期與時(shí)間片;

  • 限制每個(gè)時(shí)段的最大預約人數;

  • 防止同一用戶(hù)重復提交(基于Session或IP簡(jiǎn)單限流);

  • 將預約記錄寫(xiě)入數據庫,并返回成功或失敗的狀態(tài)信息;

  • 基礎的時(shí)間沖突判斷(例如:已滿(mǎn)時(shí)段不再接受新單)。

若您的業(yè)務(wù)涉及多資源并行(如多個(gè)房間、多位服務(wù)人員)、周期性規則(如每周一閉館)、或復雜的價(jià)格計算,本文末尾會(huì )給出改造方向,但主體代碼依然可作為底層邏輯的起點(diǎn)。

二、運行環(huán)境與準備工作

在部署代碼前,請確保服務(wù)器滿(mǎn)足以下最低要求:

  • PHP版本 ≥ 7.4(推薦8.0及以上,以支持更嚴格的類(lèi)型聲明);

  • MySQL 5.7 或 MariaDB 10.3 以上,并開(kāi)啟PDO擴展;

  • Web服務(wù)器(Apache/Nginx)正確配置URL重寫(xiě)規則(非必須,但建議開(kāi)啟);

  • 網(wǎng)站已建立全局數據庫連接對象($db),且字符集統一為utf8mb4。

您需要預先創(chuàng )建一張預約記錄表,推薦結構如下(可根據實(shí)際字段增減):

sql

復制

下載

CREATE?TABLE?`appointments`?(
??`id`?int(11)?NOT?NULL?AUTO_INCREMENT,
??`user_name`?varchar(50)?NOT?NULL,
??`user_phone`?varchar(20)?NOT?NULL,
??`user_email`?varchar(100)?DEFAULT?NULL,
??`appoint_date`?date?NOT?NULL,
??`appoint_time_slot`?tinyint(2)?NOT?NULL?COMMENT?'時(shí)段編號:1上午?2下午?3晚間等',
??`remark`?text?DEFAULT?NULL,
??`status`?tinyint(1)?DEFAULT?1?COMMENT?'1有效?0取消',
??`created_at`?datetime?NOT?NULL?DEFAULT?CURRENT_TIMESTAMP,
??`ip_address`?varchar(45)?DEFAULT?NULL,
??`session_id`?varchar(64)?DEFAULT?NULL,
??PRIMARY?KEY?(`id`),
??UNIQUE?KEY?`unique_booking`?(`appoint_date`,`appoint_time_slot`,`user_phone`),
??KEY?`idx_date_slot`?(`appoint_date`,`appoint_time_slot`))?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;

其中unique_booking唯一索引防止同一手機號在同一天同一時(shí)段重復預約,您也可以改為user_email或去掉該約束,改為業(yè)務(wù)層檢測。

同時(shí),建議維護一個(gè)時(shí)段配置表(或直接寫(xiě)在PHP常量中),便于前端下拉渲染:

sql

復制

下載

CREATE?TABLE?`time_slots`?(
??`slot_id`?tinyint(2)?NOT?NULL,
??`slot_name`?varchar(20)?NOT?NULL,
??`start_time`?time?NOT?NULL,
??`end_time`?time?NOT?NULL,
??`max_capacity`?smallint(4)?DEFAULT?5,
??`is_active`?tinyint(1)?DEFAULT?1,
??PRIMARY?KEY?(`slot_id`))?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;

初始化幾條示例數據:1-上午(09:00-12:00,容量5人),2-下午(14:00-17:00,容量5人),3-晚間(19:00-21:00,容量3人)。

三、核心PHP代碼結構(可直接復制修改)

以下為預約提交處理的入口文件?booking_submit.php,采用面向過(guò)程風(fēng)格但清晰分層,方便封裝為類(lèi)。

php

復制

下載

<?php//?開(kāi)啟會(huì )話(huà)用于簡(jiǎn)單防刷if?(session_status()?===?PHP_SESSION_NONE)?{
????session_start();}//?引入數據庫連接(請根據實(shí)際路徑調整)require_once?__DIR__?.?'/db_connect.php';//?設置響應格式為JSON(適用于前后端分離或Ajax提交)header('Content-Type:?application/json;?charset=utf-8');//?僅接受POST請求if?($_SERVER['REQUEST_METHOD']?!==?'POST')?{
????http_response_code(405);
????echo?json_encode(['code'?=>?405,?'msg'?=>?'僅支持POST提交']);
????exit;}//?---?1.?獲取并過(guò)濾輸入?---$name?=?trim($_POST['user_name']????'');$phone?=?trim($_POST['user_phone']????'');$email?=?isset($_POST['user_email'])???trim($_POST['user_email'])?:?null;$date?=?$_POST['appoint_date']????'';$slotId?=?(int)($_POST['slot_id']????0);$remark?=?isset($_POST['remark'])???trim($_POST['remark'])?:?'';//?基礎驗證:必填項$errors?=?[];if?(mb_strlen($name)?<?2?||?mb_strlen($name)?>?30)?{
????$errors[]?=?'姓名請填寫(xiě)2~30個(gè)字符';}if?(!preg_match('/^1[3-9]\d{9}$/',?$phone))?{??//?簡(jiǎn)單手機號格式(可替換為更寬松規則)
????$errors[]?=?'手機號格式不正確';}if?($email?&&?!filter_var($email,?FILTER_VALIDATE_EMAIL))?{
????$errors[]?=?'郵箱格式無(wú)效';}if?(!preg_match('/^\d{4}-\d{2}-\d{2}$/',?$date))?{
????$errors[]?=?'日期格式錯誤,請使用YYYY-MM-DD';}if?($slotId?<?1)?{
????$errors[]?=?'請選擇有效的時(shí)段';}//?額外日期校驗:不能早于今天(允許當天,可根據業(yè)務(wù)修改)$today?=?date('Y-m-d');if?($date?<?$today)?{
????$errors[]?=?'預約日期不能早于今天';}//?可選:限制最大提前天數(例如30天)$maxDate?=?date('Y-m-d',?strtotime('+30?days'));if?($date?>?$maxDate)?{
????$errors[]?=?'僅支持未來(lái)30天內的預約';}if?(!empty($errors))?{
????echo?json_encode(['code'?=>?422,?'msg'?=>?'參數驗證失敗',?'detail'?=>?$errors]);
????exit;}//?---?2.?防刷與重復提交檢查(輕量級)?---$sessionId?=?session_id();$clientIp?=?$_SERVER['REMOTE_ADDR']????'0.0.0.0';//?同一會(huì )話(huà)或IP?10秒內只能提交一次(避免暴力點(diǎn)擊)$lockKey?=?'booking_lock_'?.?md5($sessionId?.?$clientIp);if?(isset($_SESSION[$lockKey])?&&?(time()?-?$_SESSION[$lockKey]?<?10))?{
????echo?json_encode(['code'?=>?429,?'msg'?=>?'提交過(guò)于頻繁,請稍后再試']);
????exit;}$_SESSION[$lockKey]?=?time();//?---?3.?事務(wù)內執行核心業(yè)務(wù)?---try?{
????$db->beginTransaction();

????//?3.1?查詢(xún)時(shí)段配置,獲取容量和有效性
????$slotStmt?=?$db->prepare("SELECT?slot_id,?max_capacity,?is_active?FROM?time_slots?WHERE?slot_id?=??");
????$slotStmt->execute([$slotId]);
????$slot?=?$slotStmt->fetch(PDO::FETCH_ASSOC);
????if?(!$slot?||?$slot['is_active']?!=?1)?{
????????throw?new?Exception('所選時(shí)段當前不可用');
????}
????$maxCap?=?(int)$slot['max_capacity'];

????//?3.2?統計該日期+時(shí)段已有的有效預約數
????$countStmt?=?$db->prepare("SELECT?COUNT(*)?AS?booked?FROM?appointments?
???????????????????????????????WHERE?appoint_date?=???AND?appoint_time_slot?=???AND?status?=?1");
????$countStmt->execute([$date,?$slotId]);
????$row?=?$countStmt->fetch(PDO::FETCH_ASSOC);
????$bookedCount?=?(int)$row['booked'];

????if?($bookedCount?>=?$maxCap)?{
????????throw?new?Exception('該時(shí)段預約已滿(mǎn),請選擇其他時(shí)間');
????}

????//?3.3?可選:同一手機號當天同時(shí)段是否已存在(與唯一索引互補,返回友好提示)
????$dupStmt?=?$db->prepare("SELECT?id?FROM?appointments?WHERE?appoint_date?=???AND?appoint_time_slot?=???AND?user_phone?=???AND?status?=?1");
????$dupStmt->execute([$date,?$slotId,?$phone]);
????if?($dupStmt->fetch())?{
????????throw?new?Exception('您已在該時(shí)段預約,請勿重復提交');
????}

????//?3.4?插入預約記錄
????$insertSql?=?"INSERT?INTO?appointments?
??????????????????(user_name,?user_phone,?user_email,?appoint_date,?appoint_time_slot,?remark,?ip_address,?session_id)?
??????????????????VALUES?(?,??,??,??,??,??,??,??)";
????$insertStmt?=?$db->prepare($insertSql);
????$result?=?$insertStmt->execute([
????????$name,
????????$phone,
????????$email,
????????$date,
????????$slotId,
????????$remark,
????????$clientIp,
????????$sessionId
????]);

????if?(!$result?||?$insertStmt->rowCount()?<?1)?{
????????throw?new?Exception('數據寫(xiě)入失敗,請重試');
????}

????//?提交事務(wù)
????$db->commit();

????//?返回成功信息(包含預約ID,便于后續查詢(xún))
????$newId?=?$db->lastInsertId();
????echo?json_encode([
????????'code'?=>?200,
????????'msg'?=>?'預約成功!',
????????'data'?=>?['appointment_id'?=>?$newId,?'date'?=>?$date,?'slot'?=>?$slotId]
????]);}?catch?(Exception?$e)?{
????$db->rollBack();
????//?記錄錯誤日志(建議寫(xiě)入文件,不暴露給前端)
????error_log('[Booking?Error]?'?.?$e->getMessage()?.?'?|?IP:?'?.?$clientIp);
????echo?json_encode(['code'?=>?500,?'msg'?=>?$e->getMessage()]);
????exit;}

四、前端調用示例與數據獲取

在實(shí)際項目中,您需要配套一個(gè)前端預約表單頁(yè)面,通過(guò)Ajax將數據提交至上述接口。最簡(jiǎn)單的HTML+JS片段如下(省略樣式):

html

復制

下載

運行

<form?id="bookingForm">
??<input?type="text"?name="user_name"?placeholder="您的姓名"?required>
??<input?type="tel"?name="user_phone"?placeholder="手機號"?required>
??<input?type="email"?name="user_email"?placeholder="郵箱(選填)">
??<input?type="date"?name="appoint_date"?min="<?=?date('Y-m-d')??>"?max="<?=?date('Y-m-d',?strtotime('+30?days'))??>">
??<select?name="slot_id">
????<option?value="1">上午?09:00-12:00</option>
????<option?value="2">下午?14:00-17:00</option>
????<option?value="3">晚間?19:00-21:00</option>
??</select>
??<textarea?name="remark"?placeholder="備注需求"></textarea>
??<button?type="submit">提交預約</button></form><script>document.getElementById('bookingForm').addEventListener('submit',?async?function(e)?{
??e.preventDefault();
??const?formData?=?new?FormData(this);
??const?resp?=?await?fetch('/booking_submit.php',?{?method:?'POST',?body:?formData?});
??const?result?=?await?resp.json();
??if?(result.code?===?200)?{
????alert(result.msg?+?'?預約編號:'?+?result.data.appointment_id);
??}?else?{
????alert('錯誤:'?+?(result.detail???result.detail.join('\n')?:?result.msg));
??}
});</script>

同時(shí),您可能還需要提供可預約時(shí)段查詢(xún)接口(例如:根據日期返回剩余名額),避免用戶(hù)反復提交后才發(fā)現已滿(mǎn)。該接口只需復用上述統計邏輯,以GET方式返回JSON,此處不再贅述。

五、改造與擴展方向(針對復雜業(yè)務(wù))

  1. 多資源并行預約
    在預約表中增加?resource_id?字段,并在統計容量時(shí)增加?AND resource_id = ??條件。前端需先選擇資源,再選時(shí)段。

  2. 周期性規則(如每周二、四開(kāi)放)
    可在時(shí)段配置表中增加?weekday_mask(如二進(jìn)制位表示周幾),在提交前校驗當前日期是否滿(mǎn)足規則。

  3. 支付或押金關(guān)聯(lián)
    在插入記錄后,可調用第三方支付接口生成預支付訂單,并將訂單號存入?payment_txn?字段,狀態(tài)改為“待支付”,支付成功后再變更為“有效”。

  4. 管理后臺審核
    增加?status?枚舉值(待審核、已確認、已取消),并在提交后發(fā)送郵件/短信通知管理員。此段代碼目前僅支持“有效/取消”兩種狀態(tài),可按需擴充。

  5. 郵件或短信提醒
    在事務(wù)提交成功后,異步調用消息隊列或直接發(fā)送(注意性能),提醒用戶(hù)預約詳情。

  6. 時(shí)區與節假日處理
    若面向多時(shí)區用戶(hù),統一存儲UTC時(shí)間,并在展示時(shí)轉換。節假日可維護一張閉館日期表,在驗證時(shí)排除。

  7. 防止并發(fā)超賣(mài)
    雖然使用了事務(wù)和唯一索引,但在極高并發(fā)下(如秒殺類(lèi)預約),建議增加?SELECT ... FOR UPDATE?行鎖,或使用Redis原子遞減庫存。本代碼適用于中小流量(每分鐘幾十次提交)。

  8. 日志與監控
    在?catch?塊中,除了?error_log,可接入更完善的日志庫,記錄請求參數和堆棧,便于排查。

六、安全加固建議(必須執行)

  • SQL注入防護:本代碼已使用PDO預處理,但仍需確保所有動(dòng)態(tài)字段均通過(guò)參數綁定,尤其注意?order by?或?表名?等無(wú)法綁定的位置。

  • XSS過(guò)濾:輸出到前端的用戶(hù)數據(如姓名、備注)需進(jìn)行?htmlspecialchars?轉義,本接口返回JSON,前端渲染時(shí)需自行防范。

  • CSRF防護:建議在表單中植入一次性令牌(Token),并在服務(wù)端校驗。

  • 敏感數據脫敏:日志中不應記錄完整手機號或郵箱,可部分掩碼。

  • 限制請求頻率:除Session鎖外,建議在Nginx或防火墻層設置IP限流(例如每分鐘10次)。

  • HTTPS強制:全程使用加密傳輸,避免中間人截獲預約信息。

七、部署與測試要點(diǎn)

  1. 將代碼放置于網(wǎng)站目錄,確保?db_connect.php?正確配置數據庫賬號密碼。

  2. 使用測試工具(如Postman)模擬POST請求,驗證正常提交、重復提交、滿(mǎn)額、日期越界等場(chǎng)景。

  3. 觀(guān)察數據庫記錄,檢查字符集是否亂碼,時(shí)區是否一致。

  4. 開(kāi)啟PHP錯誤日志,但關(guān)閉?display_errors,避免暴露路徑信息。

  5. 若使用緩存或CDN,注意動(dòng)態(tài)接口不應被緩存(添加?Cache-Control: no-cache?響應頭)。

八、維護與迭代記錄

建議將本代碼納入版本管理,并在每次修改時(shí)記錄變更日志。例如,當您調整時(shí)段容量或新增字段時(shí),同步更新數據表結構腳本。對于預約狀態(tài)的更新(如管理員取消),可另寫(xiě)?booking_update.php,僅允許授權身份訪(fǎng)問(wèn)。

結語(yǔ)

上述代碼提供了一套可運行、可修改的預約功能雛形,覆蓋了從數據驗證到事務(wù)寫(xiě)入的完整鏈路。您完全可以根據自己的業(yè)務(wù)規則,替換驗證正則、調整容量邏輯、增加額外字段,或將其重構為面向對象的類(lèi)結構。關(guān)鍵在于理解每一段代碼的職責,并依照實(shí)際需求進(jìn)行裁剪。切記在修改后,對邊界條件進(jìn)行充分測試,確保線(xiàn)上運行的穩定性。希望這段代碼能成為您構建在線(xiàn)預約系統的堅實(shí)基礎,讓您將更多精力投入到個(gè)性化體驗與運營(yíng)優(yōu)化之中。

分享 SHARE
在線(xiàn)咨詢(xún)
聯(lián)系電話(huà)

13463989299

RM新时代|国际平台
RM新时代-手机版 RM新时代APP官网网址 RM新时代app下载-首页 RM新时代官方 RM新时代官网网址-首页
RM新时代入口 rm新时代是什么时候开始的 新时代RM娱乐app软件 RM新时代官方网站 RM新时代还出款吗 RM新时代登录网址 新时代RM|国际平台 RM新时代是正规平台吗 RM新时代新项目-百度知道 rm新时代平台靠谱吗