如何在PHP日历代码中实现单日多个事件的显示
PHP日历单日多事件显示修复方案
问题根源
原代码通过mysqli_fetch_assoc($events)仅读取数据库返回的第一条事件记录,导致同一天的后续事件无法被加载和展示。
修复步骤
1. 预加载当月所有事件(性能优化)
避免在日期循环内逐天查询数据库,一次性获取当月所有事件并按日期分组:
// 在日期循环前添加,预加载当月事件 $monthEvents = []; $eventsQuery = mysqli_query($connect, "SELECT id, title, day FROM `posts` WHERE SUBSTR(date,7,4)='$cYear' AND month='$cMonth'"); while ($eventRow = mysqli_fetch_assoc($eventsQuery)) { $eventDay = intval($eventRow['day']); if (!isset($monthEvents[$eventDay])) { $monthEvents[$eventDay] = []; } $monthEvents[$eventDay][] = $eventRow; }
2. 修改日期循环内的事件读取逻辑
替换原单条事件读取代码,从预加载数组中获取当日所有事件:
// 替换原有的数据库查询及单条记录读取代码 $dailyEvents = isset($monthEvents[$d]) ? $monthEvents[$d] : []; $hasEvents = !empty($dailyEvents);
3. 调整显示逻辑,支持多事件展示
修改单元格样式和内容输出,让单日多事件可见:
- 调整单元格垂直对齐为顶部,增加内边距
- 日期下方列出所有事件的短标题链接
完整修改后的代码
<?php $cMonth = isset($_REQUEST["month"]) ? intval($_REQUEST["month"]) : date("m"); $cYear = isset($_REQUEST["year"]) ? intval($_REQUEST["year"]) : date("Y"); $prev_year = $cYear; $prev_year2 = $cYear-1; $next_year = $cYear; $next_year2 = $cYear+1; $prev_month = $cMonth-1; $next_month = $cMonth+1; if ($cMonth == 12 ) { $next_month = 1; $next_year = $next_year2; } elseif ($cMonth == 1 ) { $prev_month = 12; $prev_year = $prev_year2; } $short_days = array('1'=>'Sun', '2'=>'Mon', '3'=>'Tue', '4'=>'Wed', '5'=>'Thu', '6'=>'Fri', '7'=>'Sat'); $day=intval(date('d')); $endDate=date('t',mktime(0,0,0,$cMonth,$day,$cYear)); // 预加载当月所有事件,按日期分组 $monthEvents = []; $eventsQuery = mysqli_query($connect, "SELECT id, title, day FROM `posts` WHERE SUBSTR(date,7,4)='$cYear' AND month='$cMonth'"); while ($eventRow = mysqli_fetch_assoc($eventsQuery)) { $eventDay = intval($eventRow['day']); if (!isset($monthEvents[$eventDay])) { $monthEvents[$eventDay] = []; } $monthEvents[$eventDay][] = $eventRow; } echo "<table width='100%' align='center' border='0' cellpadding='0' cellspacing='5'><tr bgcolor='white'> "; echo "<td align='left'><a class='caldate3' href='".$_SERVER['PHP_SELF']."?month=$prev_month&year=$prev_year' title='Previous Month'> <big>««</big> Prev</a></td> "; echo "<td align='center'><a class='mcaldate2' href='#' title='Current Month'> ".date("F Y",strtotime($cYear."-".$cMonth."-01"))." </a></td> "; echo "<td align='right'><a class='caldate3' href='".$_SERVER['PHP_SELF']."?month=$next_month&year=$next_year' title='Next Month'>Next <big>»»</big> </a></td></tr> "; echo "<tr><td colspan='3' height='5'></td> "; echo "</tr></table> "; echo "<table width='100%' align='center' border='0' cellpadding='0' cellspacing='0'><tr><td class='norm'> "; echo "<table width='100%' align='center' border='0' cellpadding='2' cellspacing='1'><tr bgcolor='#000' height='20'> "; foreach ($short_days as $key=>$val) { echo "<td width='14%' align='center'><span style='font-size:14px; color:#ffff00;'><b>".$val."</b></span></td> "; } echo "</tr><tr> "; $s=date('w', mktime (0,0,0,$cMonth,1,$cYear)); for ($ds=1; $ds<=$s; $ds++) { echo "<td class='norm' height='20' align='center' valign='middle'></td> "; } for ($d=1; $d<=$endDate; $d++) { if (date('w',mktime (0,0,0,$cMonth,$d,$cYear)) == 0) { echo "</tr><tr> "; } // 获取当日所有事件 $dailyEvents = isset($monthEvents[$d]) ? $monthEvents[$d] : []; $hasEvents = !empty($dailyEvents); // 确定单元格样式 if ($hasEvents) { echo "<td class='event' align='center' valign='top' style='padding:4px;'>"; } elseif ($d == $day && $cMonth == intval(date('m'))) { echo "<td class='today' align='center' valign='top' style='padding:4px;'>"; } else { echo "<td class='norm' align='center' valign='top' style='padding:4px;'>"; } $dPadded = str_pad($d,2,'0',STR_PAD_LEFT); // 输出日期数字 echo "<span class='date-number'>$dPadded</span><br>"; // 输出所有事件链接 if ($hasEvents) { foreach ($dailyEvents as $event) { // 截断标题避免过长 $shortTitle = strlen($event['title']) > 12 ? substr($event['title'], 0, 12) . "..." : $event['title']; echo "<a class='event-link' href='post.php?id=" . $event['id'] . "' title='" . htmlspecialchars($event['title']) . "'>$shortTitle<br></a>"; } } echo "</td> "; if (date('w',mktime (0,0,0,$cMonth,$d,$cYear)) == 6) { echo "</tr>"; } } echo "</table></td></tr><tr><td height='8'></td> "; echo "</tr></table> "; echo "</td></tr></table> "; ?>
额外说明
- 新增
htmlspecialchars()处理事件标题,避免XSS注入风险 - 调整单元格布局,优化多事件的展示空间
- 预加载事件的方式减少了数据库查询次数,提升日历加载效率
内容的提问来源于stack exchange,提问作者veeger9
相关产品推荐
相关产品推荐

