不依賴任何擴展,純 PHP 實現月曆表格生成,支持閏年判斷、今日高亮、上下月導航鏈接。適合嵌入後台面板、簡單預約系統、日期選擇器後端渲染。
<?php
date_default_timezone_set('Asia/Shanghai'); // 設置時區
header('Content-Type: text/html; charset=utf-8');
class Calendar {
private $year, $month, $day;
private $daysInMonth = [
1=>31, 2=>28, 3=>31, 4=>30, 5=>31, 6=>30,
7=>31, 8=>31, 9=>30, 10=>31, 11=>30, 12=>31
];
/** 設置當前日期 (時間戳) */
public function set(int $timestamp = 0): self {
$ts = $timestamp ?: time();
$this->year = (int)date('Y', $ts);
$this->month = (int)date('n', $ts);
$this->day = (int)date('j', $ts);
return $this;
}
/** 判斷閏年 */
private function isLeapYear(): bool {
$y = $this->year;
return ($y % 400 === 0) || ($y % 4 === 0 && $y % 100 !== 0);
}
/** 獲取本月天數 */
private function getDaysInMonth(): int {
if ($this->month === 2 && $this->isLeapYear()) return 29;
return $this->daysInMonth[$this->month];
}
/** 獲取本月 1 號是星期幾 (0=周日 ... 6=周六) */
private function getFirstWeekday(): int {
return (int)date('w', mktime(0, 0, 0, $this->month, 1, $this->year));
}
/** 生成 HTML 表格 */
public function render(): string {
$days = $this->getDaysInMonth();
$firstW = $this->getFirstWeekday();
$today = $this->day;
$html = '<table class="calendar" style="border-collapse:collapse; width:100%; font-size:14px;">';
// 表頭:年月 + 導航
$prev = mktime(0,0,0,$this->month-1,1,$this->year);
$next = mktime(0,0,0,$this->month+1,1,$this->year);
$html .= '<tr><th colspan="7" style="padding:10px; background:#f5f5f5;">';
$html .= '<a href="?t='.$prev.'" style="float:left;">« 上月</a>';
$html .= '<span style="font-weight:bold;">'.$this->year.'年 '.$this->month.'月</span>';
$html .= '<a href="?t='.$next.'" style="float:right;">下月 »</a>';
$html .= '</th></tr>';
// 星期行
$weeks = ['日','一','二','三','四','五','六'];
$html .= '<tr style="background:#eee;">';
foreach ($weeks as $w) $html .= '<th style="padding:5px;">'.$w.'</th>';
$html .= '</tr>';
// 日期單元格
$html .= '<tr>';
// 1號前空單元格
for ($i=0; $i<$firstW; $i++) $html .= '<td style="padding:5px; border:1px solid #ddd;"></td>';
// 日期循環
for ($d=1; $d<=$days; $d++) {
$style = ($d === $today) ? 'background:#007bff; color:#fff; font-weight:bold;' : '';
$html .= '<td style="padding:8px; border:1px solid #ddd; text-align:center; '.$style.'">'.$d.'</td>';
// 換行邏輯:(當前格子索引 + 1) % 7 == 0 且不是最後一天
if (($firstW + $d) % 7 === 0 && $d < $days) {
$html .= '</tr><tr>';
}
}
// 末尾補齊空單元格
$lastCell = ($firstW + $days) % 7;
if ($lastCell !== 0) {
for ($i=$lastCell; $i<7; $i++) $html .= '<td style="padding:5px; border:1px solid #ddd;"></td>';
}
$html .= '</tr></table>';
return $html;
}
}
// 使用示例
$cal = new Calendar();
$cal->set(isset($_GET['t']) ? (int)$_GET['t'] : time());
echo $cal->render();
?>
date()、mktime()、time() 核心函數。t。| 需求 | 實現方向 |
|---|---|
| 多語言星期/月份 | 構造函數注入 $locale,使用 IntlDateFormatter 或自定義數組 |
| 農曆/節氣顯示 | 引入 php-lunar 庫或自行實現農曆算法 |
| 事件/備註掛載 | render() 參數傳入 [$date => '事件描述'],單元格內追加渲染 |
| AJAX 無刷新翻月 | 前端攔截鏈接 fetch() 替換容器 innerHTML |
| 日期範圍選擇器 | 單元格添加 data-date、onclick 回調傳遞選中日期 |
| 響應式佈局 | CSS Grid/Flex 替代表格,媒體查詢調整字體/間距 |