PHP日程重叠限制问题:现有代码无法检测全时段覆盖冲突
日程冲突检测代码漏洞修复
现有一段PHP日程添加代码,仅能检测部分时段重叠的日程冲突,但存在漏洞:当新增日程完全覆盖已有日程时(例如已存在7:00-8:30的日程,新增6:30-9:00的日程),代码无法识别冲突并会成功添加;而其他部分重叠场景(如6:30-7:30、7:30-9:30)能正常触发冲突报错。
原代码示例:
$d_start = strtotime($datetime_start); $d_end = strtotime($datetime_end); $roomID = $assembly_hall_id; $chk = $this->conn->query("SELECT * FROM `schedule_list` where (('{$d_start}' Between unix_timestamp(datetime_start) and unix_timestamp(datetime_end)) or ('{$d_end}' Between unix_timestamp(datetime_start) and unix_timestamp(datetime_end))) ".(($roomID > 0) ? " and assembly_hall_id ='{$roomID}' and sched_status = '1' " : ""))->num_rows; if($chk > 0 ){ $resp['status'] = 'failed'; $resp['err_msg'] = "The schedule is conflict with other schedules."; }elseif(strtotime($datetime_start) == null) { $resp['status'] = 'failed'; $resp['err_msg'] = "Date and Time Schedule is Invalid."; }
问题根源
原SQL查询只判断了新增日程的开始/结束时间是否落在已有日程的时段内,但完全覆盖已有日程的场景下,新增日程的开始时间早于已有日程的开始时间、结束时间晚于已有日程的结束时间,此时$d_start和$d_end都不在已有日程的时间区间内,导致查询不到冲突记录。
修复方案
需要覆盖所有时间区间重叠的场景:判断两个时间区间是否存在交集,即新增日程的开始时间 < 已有日程的结束时间,且新增日程的结束时间 > 已有日程的开始时间。
修复后的代码:
$d_start = strtotime($datetime_start); $d_end = strtotime($datetime_end); $roomID = $assembly_hall_id; // 重构冲突判断逻辑,覆盖所有重叠场景 $where = "WHERE unix_timestamp(datetime_start) < {$d_end} AND unix_timestamp(datetime_end) > {$d_start}"; if($roomID > 0){ $where .= " AND assembly_hall_id = '{$roomID}' AND sched_status = '1'"; } $chk = $this->conn->query("SELECT * FROM `schedule_list` {$where}")->num_rows; if($chk > 0 ){ $resp['status'] = 'failed'; $resp['err_msg'] = "该日程与已有日程冲突。"; }elseif($d_start === false || $d_end === false) // 同时校验开始/结束时间有效性 { $resp['status'] = 'failed'; $resp['err_msg'] = "日程日期或时间格式无效。"; }
额外优化建议
- 防范SQL注入:建议使用预处理语句替代直接变量拼接,示例:
if($roomID > 0){ $stmt = $this->conn->prepare("SELECT * FROM `schedule_list` WHERE unix_timestamp(datetime_start) < ? AND unix_timestamp(datetime_end) > ? AND assembly_hall_id = ? AND sched_status = '1'"); $stmt->bind_param("iii", $d_end, $d_start, $roomID); }else{ $stmt = $this->conn->prepare("SELECT * FROM `schedule_list` WHERE unix_timestamp(datetime_start) < ? AND unix_timestamp(datetime_end) > ?"); $stmt->bind_param("ii", $d_end, $d_start); } $stmt->execute(); $chk = $stmt->num_rows;
- 时间有效性校验:原代码仅校验了
datetime_start,补充校验datetime_end可避免无效时间导致的逻辑异常。
内容的提问来源于stack exchange,提问作者Jonjon Castilleja
相关产品推荐
相关产品推荐

