<?php
class Calendar {
private $year;
private $month;
private $start_weekday; // 該月 1 號是星期幾 (0=日)
private $days; // 該月總天數
public function __construct() {
$this->year = isset($_GET['year']) ? (int)$_GET['year'] : date('Y');
$this->month = isset($_GET['month']) ? (int)$_GET['month'] : date('m');
$this->start_weekday = date('w', mktime(0,0,0, $this->month, 1, $this->year));
$this->days = date('t', mktime(0,0,0, $this->month, 1, $this->year));
}
public function out() {
echo '<table align="center">';
$this->chageDate("test.php");
$this->weeksList();
$this->daysList();
echo '</table>';
}
private function weeksList() {
$week = ['日','一','二','三','四','五','六'];
echo '<tr>';
foreach ($week as $w) echo '<th class="fontb">'.$w.'</th>';
echo '</tr>';
}
private function daysList() {
echo '<tr>';
// 前置空格
for ($j=0; $j<$this->start_weekday; $j++) echo '<td> </td>';
for ($k=1; $k<=$this->days; $k++) {
$j++;
if ($k == date('d') && $this->month == date('m') && $this->year == date('Y'))
echo '<td class="fontb">'.$k.'</td>'; // 高亮今日
else
echo '<td>'.$k.'</td>';
if ($j % 7 == 0) echo '</tr><tr>';
}
// 尾部填滿
while ($j % 7 !== 0) {
echo '<td> </td>';
$j++;
}
echo '</tr>';
}
// 導航連結產生:上一年、上個月、下一年、下個月
private function prevYear($y,$m) { $y--; if($y<1970)$y=1970; return "year=$y&month=$m"; }
private function prevMonth($y,$m) { if($m==1){$y--;if($y<1970)$y=1970;$m=12;}else{$m--;} return "year=$y&month=$m"; }
private function nextYear($y,$m) { $y++; if($y>2038)$y=2038; return "year=$y&month=$m"; }
private function nextMonth($y,$m) { if($m==12){$y++;if($y>2100)$y=2100;$m=1;}else{$m++;} return "year=$y&month=$m"; }
private function chageDate($url="") {
echo '<tr>';
echo '<td><a href="?'.$this->prevYear($this->year,$this->month).'"><<</a></td>';
echo '<td><a href="?'.$this->prevMonth($this->year,$this->month).'"><</a></td>';
echo '<td colspan="3">';
echo '<form>';
// 年份下拉選單
echo '<select name="year" onchange="window.location=\''.$url.'?year=\'+this.options[this.selectedIndex].value+\'&month='.$this->month.'\'">';
for($sy=1970;$sy<=2100;$sy++){
$sel = ($sy==$this->year)?'selected':'';
echo '<option '.$sel.' value="'.$sy.'">'.$sy.'</option>';
}
echo '</select>';
// 月份下拉選單
echo '<select name="month" onchange="window.location=\''.$url.'?year='.$this->year.'&month=\'+this.options[this.selectedIndex].value+\'">';
for($sm=1;$sm<=12;$sm++){
$sel = ($sm==$this->month)?'selected':'';
echo '<option '.$sel.' value="'.$sm.'">'.$sm.'</option>';
}
echo '</select>';
echo '</form>';
echo '</td>';
echo '<td><a href="?'.$this->nextYear($this->year,$this->month).'">>></a></td>';
echo '<td><a href="?'.$this->nextMonth($this->year,$this->month).'">></a></td>';
echo '</tr>';
}
}
?>
<?php
require_once 'calendar.class.php';
$cal = new Calendar();
$cal->out();
?>
mktime + date('w') 取得月初星期、date('t') 取得月天數。<td> 對齊星期。date('d')、date('m')、date('Y') 三者皆同步。year、month,下拉選單 onchange 直接跳轉。mktime 限制)。DateTime 類別突破 2038 年限制。這個輕量級月曆類別展示了 PHP 日期運算與 HTML 表格生成的經典結合,適合嵌入後台管理、預約系統等場景。代碼結構清晰,易於擴充與樣式客製化。