纯PHP&MySQL构建AMP预约系统:如何限制datetime输入显示可用时段?
仅用PHP/MySQL实现AMP预约系统的时段限制方案
刚好遇到过类似的AMP环境下的预约系统需求,完全不能碰JS确实有点限制,但靠PHP和MySQL完全能搞定。先给你梳理下核心问题的解决思路,还有几个额外的实现方向:
核心问题:限制datetime输入仅显示可用时段
因为AMP禁止任何脚本,前端没法动态过滤已占用的时间,最靠谱的两种方式如下:
方案1:PHP预生成可用时段下拉列表(推荐)
直接放弃原生的datetime-local输入框,用PHP从数据库查询已预约时段,然后生成所有符合你规则的可用时段,渲染成下拉选项。用户只能选预设的可用时间,从根源避免冲突。
举个实际的代码例子,假设你的服务是工作日9:00-18:00,每小时一个时段,未来7天可预约:
<form method="post" action="your-submit-handler.php"> <label>Service:</label> <select name="service"> <?php $sql = 'select c.name service from services c order by c.name'; $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { // 用htmlspecialchars防止XSS echo '<option>' . htmlspecialchars($row["service"]) . "</option>" ; } } ?> </select> <br><br> <label>Preferred Time Slot:</label> <select name="date"> <?php // 1. 定义你的预约规则:未来7天,工作日9-18点,每小时一个时段 $startDate = new DateTime(); $endDate = (new DateTime())->modify('+7 days'); $hourlyInterval = new DateInterval('PT1H'); $dateRange = new DatePeriod($startDate, $hourlyInterval, $endDate); // 2. 从requests表获取所有已预约的时段,转成统一格式方便对比 $bookedSlots = []; $sql = "SELECT datetime FROM requests"; $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { $bookedSlots[] = DateTime::createFromFormat('Y-m-d h:i:A', $row['datetime'])->format('Y-m-d\TH:i'); } } // 3. 遍历生成可用时段选项 foreach ($dateRange as $date) { $currentHour = (int)$date->format('H'); // 跳过非工作时间和周末 if ($currentHour < 9 || $currentHour >= 18 || $date->format('N') >= 6) { continue; } $inputValue = $date->format('Y-m-d\TH:i'); $displayText = $date->format('Y-m-d h:i A'); // 未被预约的时段才生成选项 if (!in_array($inputValue, $bookedSlots)) { echo "<option value=\"$inputValue\">$displayText</option>"; } } ?> </select> <br><br> <label>Your Name:</label> <input type="text" name="client" required> <br><br> <input type="submit" value="Book Now"> </form>
方案2:保留datetime-local+后端强验证
如果一定要用datetime-local输入框,可以通过PHP设置min、max和step属性引导用户选择合理范围,然后在表单提交时后端严格校验该时段是否已被占用。这种方式前端没法阻止用户选已占用的时间,但后端可以直接拒绝并返回提示。
示例表单代码:
<form method="post" action="your-submit-handler.php"> <label>Service:</label> <select name="service"> <?php $sql = 'select c.name service from services c order by c.name'; $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { echo '<option>' . htmlspecialchars($row["service"]) . "</option>" ; } } ?> </select> <br><br> <label>Preferred Date & Time:</label> <?php // 设置可选范围:当前时间到未来7天,步长1小时 $minDateTime = (new DateTime())->format('Y-m-d\TH:i'); $maxDateTime = (new DateTime())->modify('+7 days')->format('Y-m-d\TH:i'); ?> <input name="date" type="datetime-local" min="<?php echo $minDateTime; ?>" max="<?php echo $maxDateTime; ?>" step="3600" required > <br><br> <label>Your Name:</label> <input type="text" name="client" required> <br><br> <input type="submit" value="Book Now"> </form>
对应的后端验证逻辑(your-submit-handler.php):
<?php // 假设你已经有数据库连接$conn if ($_SERVER['REQUEST_METHOD'] === 'POST') { $selectedDateTime = $_POST['date']; $selectedService = $_POST['service']; $clientName = $_POST['client']; // 转换格式匹配数据库中的存储格式 $formattedDateTime = DateTime::createFromFormat('Y-m-d\TH:i', $selectedDateTime)->format('Y-m-d h:i:A'); // 检查该时段是否已被同服务预约 $checkSql = "SELECT request_id FROM requests WHERE datetime = ? AND service_name = ?"; $stmt = $conn->prepare($checkSql); $stmt->bind_param("ss", $formattedDateTime, $selectedService); $stmt->execute(); $stmt->store_result(); if ($stmt->num_rows > 0) { echo "<p style='color: red;'>Sorry, this time slot is already taken. Please choose another one.</p>"; } else { // 插入新预约记录 $insertSql = "INSERT INTO requests (datetime, service_name, client) VALUES (?, ?, ?)"; $insertStmt = $conn->prepare($insertSql); $insertStmt->bind_param("sss", $formattedDateTime, $selectedService, $clientName); if ($insertStmt->execute()) { echo "<p style='color: green;'>Your booking has been confirmed successfully!</p>"; } else { echo "<p style='color: red;'>Error: " . $insertStmt->error . "</p>"; } } } ?>
其他实用实现思路
- 分步选择日期+时段:先让用户选择日期,提交后跳转到该日期的专属预约页面,PHP查询该日期的已预约时段,生成可用选项。这种分步方式更清晰,也更符合AMP的无脚本特性。
- 适配服务时长:如果不同服务的时长不同(比如Service1是1小时,Service2是2小时),可以在
services表中添加duration字段,生成可用时段时要考虑时段的占用长度,避免时间重叠(比如一个2小时的服务会占用两个连续的1小时时段)。 - 时段锁定机制:提交预约时可以加个短暂的锁定(比如用数据库临时表),防止同一时段被多个用户同时提交(高并发场景下有用)。
内容的提问来源于stack exchange,提问作者Iustin Beceneagă
相关产品推荐
相关产品推荐

