PEAR::Calendar 0.5.4にバグ(レシピ075)

[レシピ075] カレンダーを表示したい(P.182~)のカレンダーの表示がおかしいというご指摘が読者の方よりありました。

確認したところ、本書のサンプルプログラム(03/03/14-1.php)では、例えば、2010年2月のカレンダーは以下のように表示され、正しくありませんでした。

正常な表示は、以下のようになります。

調査の結果、現在、以下が判明しています。

  • これは、PEAR::Calendar 0.5.4のCalendar_Month_Weeksのバグである。
  • PEAR::Calendarを0.5.3にすると正常に表示できる。
  • PEAR::Calendar 0.5.4でも、Calendar_Month_Weekdaysを使うと正常に表示できる。
  • PEAR::Calendar 0.5.4でも、2009年は正常に表示できる。

Calendar_Month_WeeksとCalendar_Month_Weekdaysを比較したサンプルコードは以下のようになります。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<link href="14-2.css" rel="stylesheet" type="text/css" />
<title>カレンダーを表示したい</title>
</head>
<body>
<h2>Calendar_Month_Weeks</h2>
<?php
//---------------------------------------------------------------------
// Calendar_Month_Weeks を利用する場合(サンプル通り)
//---------------------------------------------------------------------
require_once 'Calendar/Month/Weeks.php';

# 曜日に表示する文字列とCSSクラス名を設定します。
$weekdayDefines = array(array('日', 'sunday'),   array('月', 'monday'),
                         array('火', 'tuesday'),  array('水', 'wednesday'),
                         array('木', 'thursday'), array('金', 'friday'),
                         array('土', 'saturday'));

# カレンダーの左側に表示させる曜日を設定します。
$weekdayBase = 0;  // 0:日曜~6:土曜

# カレンダーに表示する年月を取得します。
// デフォルトの年月を設定
$year = (int) date('Y');
$month = (int) date('n');

// GETパラメータが指定されている場合は値を検証してから表示年月を取得
if (isset($_GET&#91;'year_month'&#93;)) {
  $yyyymm = trim($_GET&#91;'year_month'&#93;);

  // YYYYMM形式であれば年月を取得
  if (preg_match('/^(&#91;12&#93;\d{3})(1&#91;012&#93;|0&#91;1-9&#93;)$/', $yyyymm, $match)) {
    $year = (int) $match&#91;1&#93;;
    $month = (int) $match&#91;2&#93;;
  }
}

# カレンダーデータを生成します。
$calendar = new Calendar_Month_Weeks($year, $month, $weekdayBase);
$calendar->build();

# カレンダーの曜日部分を表示します。
$thisMonth = $calendar->thisMonth(TRUE);  //今月
$prevMonth = $calendar->prevMonth(TRUE);  //先月
$nextMonth = $calendar->nextMonth(TRUE);  //来月

$prevMonthUrl = '?year_month=' . date('Ym', $prevMonth);
$nextMonthUrl = '?year_month=' . date('Ym', $nextMonth);
$thisMonthText = date('Y/m', $thisMonth);
?>
<table border="1">
  <thead>
    <tr>
      <td><a href="<?php echo $prevMonthUrl;?>">&lt;&lt;</a></td>
      <th colspan="5"><?php echo $thisMonthText;?></th>
      <td><a href="<?php echo $nextMonthUrl;?>">&gt;&gt;</a></td>
    </tr>
    <tr>
<?php
for ($i = 0; $i < 7; $i++) {
  $weekday = ($weekdayBase + $i) % 7;
  $weekdayText  = $weekdayDefines&#91;$weekday&#93;&#91;0&#93;;
  $weekdayClass = $weekdayDefines&#91;$weekday&#93;&#91;1&#93;;

  echo '<th class="' . $weekdayClass . '">', $weekdayText, '</th>';
}
?>
    </tr>
  </thead>
  <tbody>
<?php
# カレンダーの日付部分を表示します。
while ($days = $calendar->fetch()) {
  $days->build();
  $weekday = 0;

  echo '<tr>';
  while ($day = $days->fetch()) {
    $weekdayClass = $weekdayDefines[$weekday][1];
    if ($day->isEmpty()) {
      $dayText = "&nbsp;";
    } else {
      $dayText = $day->thisDay();
    }

    echo '<td class="' . $weekdayClass . '">', $dayText, '</td>';

    $weekday++;
  }
  echo '</tr>';
}
?>
  </tbody>
</table>


<h2>Calendar_Month_Weekdays</h2>
<?php
//---------------------------------------------------------------------
// Calendar_Month_Weekdays を利用する場合
//---------------------------------------------------------------------
require_once 'Calendar/Month/Weekdays.php'; 

# 曜日に表示する文字列とCSSクラス名を設定します。
$weekdayDefines = array(array('日', 'sunday'),   array('月', 'monday'),
                         array('火', 'tuesday'),  array('水', 'wednesday'),
                         array('木', 'thursday'), array('金', 'friday'),
                         array('土', 'saturday'));

# カレンダーの左側に表示させる曜日を設定します。
$weekdayBase = 0;  // 0:日曜~6:土曜

# カレンダーに表示する年月を取得します。
// デフォルトの年月を設定
$year = (int) date('Y');
$month = (int) date('n');

// GETパラメータが指定されている場合は値を検証してから表示年月を取得
if (isset($_GET&#91;'year_month'&#93;)) {
  $yyyymm = trim($_GET&#91;'year_month'&#93;);

  // YYYYMM形式であれば年月を取得
  if (preg_match('/^(&#91;12&#93;\d{3})(1&#91;012&#93;|0&#91;1-9&#93;)$/', $yyyymm, $match)) {
    $year = (int) $match&#91;1&#93;;
    $month = (int) $match&#91;2&#93;;
  }
}

# カレンダーデータを生成します。
$calendar = new Calendar_Month_Weekdays($year, $month, $weekdayBase);
$calendar->build();

# カレンダーの曜日部分を表示します。
$thisMonth = $calendar->thisMonth(TRUE);  //今月
$prevMonth = $calendar->prevMonth(TRUE);  //先月
$nextMonth = $calendar->nextMonth(TRUE);  //来月

$prevMonthUrl = '?year_month=' . date('Ym', $prevMonth);
$nextMonthUrl = '?year_month=' . date('Ym', $nextMonth);
$thisMonthText = date('Y/m', $thisMonth);
?>
<table border="1">
  <thead>
    <tr>
      <td><a href="<?php echo $prevMonthUrl;?>">&lt;&lt;</a></td>
      <th colspan="5"><?php echo $thisMonthText;?></th>
      <td><a href="<?php echo $nextMonthUrl;?>">&gt;&gt;</a></td>
    </tr>
    <tr>
<?php
for ($i = 0; $i < 7; $i++) {
  $weekday = ($weekdayBase + $i) % 7;
  $weekdayText  = $weekdayDefines&#91;$weekday&#93;&#91;0&#93;;
  $weekdayClass = $weekdayDefines&#91;$weekday&#93;&#91;1&#93;;

  echo '<th class="' . $weekdayClass . '">', $weekdayText, '</th>';
}
?>
    </tr>
  </thead>
  <tbody>
<?php
# カレンダーの日付部分を表示します。
$weekday = 0;
while ($day = $calendar->fetch()) {
  if ($day->isFirst()) { 
    echo '<tr>'; 
  }
  
  $weekdayClass = $weekdayDefines[$weekday][1];
  if ($day->isEmpty()) { 
    $dayText = '&nbsp;'; 
  } else { 
    $dayText = $day->thisDay(); 
  } 
  echo '<td class="' . $weekdayClass . '">', $dayText, '</td>';

  if ($day->isLast()) { 
    echo '</tr>'; 
	$weekday = 0;
  } else {
	$weekday++;
  }
}
?>
    </tr>
  <tbody>
</table>
</body>
</html>

この件に関する正誤情報をどうするかは、現在、検討中です。

(2010/03/03) 正誤情報 が更新されました。

kenji posted at 2010-3-2 Category: 追加情報

Trackback URL

Leave a Reply

(Ctrl + Enter)

*