汽车租赁系统开发问题:如何筛选指定日期可用车辆
汽车租赁系统:日期查询与可用车辆筛选解决方案
原代码核心问题
- 日期处理遗漏年份:仅保留
m-d格式,会导致跨年预订的判断错误(如12-30至01-02的预订,与次年12-30的查询会误判无冲突)。 - 表关联逻辑混乱:嵌套循环遍历所有预订和车辆,且
stmt2遍历一次后无法重复获取数据,导致后续循环失效。 - 冲突判断逻辑不全:现有条件无法覆盖所有时间段重叠场景,无法准确识别占用车辆。
- 效率低下:全量查询后在PHP中筛选,数据量大时性能极差。
- 缺乏安全防护:未使用参数化查询,存在SQL注入风险。
一、正确的日期冲突判断逻辑
用户选择的时间段(pickupDate-returnDate)与已有预订(start_date-end_date)存在冲突的判定规则:
用户取车日期 ≤ 预订结束日期 且 用户还车日期 ≥ 预订开始日期
反过来,可用车辆即为:没有任何预订满足上述冲突条件的车辆,或从未被预订过的车辆。
二、修正后的完整代码
<!--Car Cover--> <?php if(isset($_POST['submit'])) { // 获取用户输入 $pickupDate = $_POST['pickupDate']; $returnDate = $_POST['returnDate']; // 非空验证 if(empty($pickupDate)) { $_SESSION['ErrorMessage'] = "取车日期不能为空"; TakeTo("index"); } elseif(empty($returnDate)) { $_SESSION['ErrorMessage'] = "还车日期不能为空"; TakeTo("index"); } // 转换为DateTime对象,保留完整日期(含年份) $startDt = new DateTime($pickupDate); $endDt = new DateTime($returnDate); // 日期逻辑验证 if($startDt->format('Y-m-d') === $endDt->format('Y-m-d')) { $_SESSION['ErrorMessage'] = "租车时长至少1天"; TakeTo("index"); } elseif($endDt < $startDt) { $_SESSION['ErrorMessage'] = "还车日期不能早于取车日期"; TakeTo("index"); } // 参数化SQL:直接从数据库筛选可用车辆 $sql = " SELECT c.* FROM cars c LEFT JOIN reservations r ON c.id = r.selected_car WHERE r.selected_car IS NULL OR NOT ( :pickup_date <= r.end_date AND :return_date >= r.start_date ) GROUP BY c.id "; // 执行参数化查询,防止SQL注入 $stmt = $con->prepare($sql); $stmt->bindParam(':pickup_date', $pickupDate); $stmt->bindParam(':return_date', $returnDate); $stmt->execute(); // 输出结果 echo "搜索日期:{$pickupDate} 至 {$returnDate}<br>"; if($stmt->rowCount() > 0) { while($car = $stmt->fetch()) { echo "车辆名称:{$car['car_name']} - 生产年份:{$car['production_year']} - 发动机:{$car['engine']} - 车辆ID:{$car['id']}<br>"; } } else { echo "该时间段内没有可用车辆"; } } ?>
代码关键说明
- 日期处理优化:保留
Y-m-d完整日期格式,用DateTime对象直接比较,避免跨年判断错误。 - 参数化查询:通过
prepare和bindParam绑定用户输入,彻底规避SQL注入风险。 - SQL关联筛选:
- 左连接
cars与reservations表,通过车辆ID关联数据; r.selected_car IS NULL筛选从未被预订的车辆;NOT (...)排除存在冲突预订的车辆;GROUP BY c.id确保同一车辆仅返回一次。
- 左连接
- 逻辑简化:直接从数据库获取结果,无需在PHP中遍历全量数据,代码更简洁高效。
额外优化建议
- 数据库中
reservations表的start_date、end_date设置为DATE类型,保证日期存储规范; - 给
reservations.selected_car与cars.id建立外键约束,维护数据一致性; - 增加日期格式验证(如用
DateTime::createFromFormat),确保用户输入合法日期。
内容的提问来源于stack exchange,提问作者Dit
相关产品推荐
相关产品推荐

