Ejemplo n.º 1
0
 /**
  * remakes a recur pattern to an array of dates
  *
  * if missing, UNTIL is set 1 year from startdate (emergency break)
  *
  * @author Kjell-Inge Gustafsson, kigkonsult <*****@*****.**>
  * @since 2.9.10 - 2011-07-07
  * @param array $result, array to update, array([timestamp] => timestamp)
  * @param array $recur, pattern for recurrency (only value part, params ignored)
  * @param array $wdate, component start date
  * @param array $startdate, start date
  * @param array $enddate, optional
  * @return array of recurrence (start-)dates as index
  * @todo BYHOUR, BYMINUTE, BYSECOND, ev. BYSETPOS due to ambiguity, WEEKLY at year end/start
  */
 public static function _recur2date(&$result, $recur, $wdate, $startdate, $enddate = FALSE)
 {
     foreach ($wdate as $k => $v) {
         if (ctype_digit($v)) {
             $wdate[$k] = (int) $v;
         }
     }
     $wdateStart = $wdate;
     $wdatets = iCal_UtilityFunctions::_date2timestamp($wdate);
     $startdatets = iCal_UtilityFunctions::_date2timestamp($startdate);
     if (!$enddate) {
         $enddate = $startdate;
         $enddate['year'] += 1;
     }
     // echo "recur __in_ comp start ".implode('-',$wdate)." period start ".implode('-',$startdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test###
     $endDatets = iCal_UtilityFunctions::_date2timestamp($enddate);
     // fix break
     if (!isset($recur['COUNT']) && !isset($recur['UNTIL'])) {
         $recur['UNTIL'] = $enddate;
     }
     // create break
     if (isset($recur['UNTIL'])) {
         $tdatets = iCal_UtilityFunctions::_date2timestamp($recur['UNTIL']);
         if ($endDatets > $tdatets) {
             $endDatets = $tdatets;
             // emergency break
             $enddate = iCal_UtilityFunctions::_timestamp2date($endDatets, 6);
         } else {
             $recur['UNTIL'] = iCal_UtilityFunctions::_timestamp2date($endDatets, 6);
         }
     }
     if ($wdatets > $endDatets) {
         // echo "recur out of date ".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
         return array();
         // nothing to do.. .
     }
     if (!isset($recur['FREQ'])) {
         // "MUST be specified.. ."
         $recur['FREQ'] = 'DAILY';
     }
     // ??
     $wkst = isset($recur['WKST']) && 'SU' == $recur['WKST'] ? 24 * 60 * 60 : 0;
     // ??
     $weekStart = (int) date('W', $wdatets + $wkst);
     if (!isset($recur['INTERVAL'])) {
         $recur['INTERVAL'] = 1;
     }
     $countcnt = !isset($recur['BYSETPOS']) ? 1 : 0;
     // DTSTART counts as the first occurrence
     /* find out how to step up dates and set index for interval count */
     $step = array();
     if ('YEARLY' == $recur['FREQ']) {
         $step['year'] = 1;
     } elseif ('MONTHLY' == $recur['FREQ']) {
         $step['month'] = 1;
     } elseif ('WEEKLY' == $recur['FREQ']) {
         $step['day'] = 7;
     } else {
         $step['day'] = 1;
     }
     if (isset($step['year']) && isset($recur['BYMONTH'])) {
         $step = array('month' => 1);
     }
     if (empty($step) && isset($recur['BYWEEKNO'])) {
         // ??
         $step = array('day' => 7);
     }
     if (isset($recur['BYYEARDAY']) || isset($recur['BYMONTHDAY']) || isset($recur['BYDAY'])) {
         $step = array('day' => 1);
     }
     $intervalarr = array();
     if (1 < $recur['INTERVAL']) {
         $intervalix = iCal_UtilityFunctions::_recurIntervalIx($recur['FREQ'], $wdate, $wkst);
         $intervalarr = array($intervalix => 0);
     }
     if (isset($recur['BYSETPOS'])) {
         // save start date + weekno
         $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array();
         // echo "bysetposXold_start=$bysetposYold $bysetposMold $bysetposDold<br />\n"; // test ###
         if (is_array($recur['BYSETPOS'])) {
             foreach ($recur['BYSETPOS'] as $bix => $bval) {
                 $recur['BYSETPOS'][$bix] = (int) $bval;
             }
         } else {
             $recur['BYSETPOS'] = array((int) $recur['BYSETPOS']);
         }
         if ('YEARLY' == $recur['FREQ']) {
             $wdate['month'] = $wdate['day'] = 1;
             // start from beginning of year
             $wdatets = iCal_UtilityFunctions::_date2timestamp($wdate);
             iCal_UtilityFunctions::_stepdate($enddate, $endDatets, array('year' => 1));
             // make sure to count whole last year
         } elseif ('MONTHLY' == $recur['FREQ']) {
             $wdate['day'] = 1;
             // start from beginning of month
             $wdatets = iCal_UtilityFunctions::_date2timestamp($wdate);
             iCal_UtilityFunctions::_stepdate($enddate, $endDatets, array('month' => 1));
             // make sure to count whole last month
         } else {
             iCal_UtilityFunctions::_stepdate($enddate, $endDatets, $step);
         }
         // make sure to count whole last period
         // echo "BYSETPOS endDat++ =".implode('-',$enddate).' step='.var_export($step,TRUE)."<br />\n";//test###
         $bysetposWold = (int) date('W', $wdatets + $wkst);
         $bysetposYold = $wdate['year'];
         $bysetposMold = $wdate['month'];
         $bysetposDold = $wdate['day'];
     } else {
         iCal_UtilityFunctions::_stepdate($wdate, $wdatets, $step);
     }
     $year_old = null;
     $daynames = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
     /* MAIN LOOP */
     // echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test
     while (TRUE) {
         if (isset($endDatets) && $wdatets > $endDatets) {
             break;
         }
         if (isset($recur['COUNT']) && $countcnt >= $recur['COUNT']) {
             break;
         }
         if ($year_old != $wdate['year']) {
             $year_old = $wdate['year'];
             $daycnts = array();
             $yeardays = $weekno = 0;
             $yeardaycnt = array();
             for ($m = 1; $m <= 12; $m++) {
                 // count up and update up-counters
                 $daycnts[$m] = array();
                 $weekdaycnt = array();
                 foreach ($daynames as $dn) {
                     $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
                 }
                 $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year']));
                 for ($d = 1; $d <= $mcnt; $d++) {
                     $daycnts[$m][$d] = array();
                     if (isset($recur['BYYEARDAY'])) {
                         $yeardays++;
                         $daycnts[$m][$d]['yearcnt_up'] = $yeardays;
                     }
                     if (isset($recur['BYDAY'])) {
                         $day = date('w', mktime(0, 0, 0, $m, $d, $wdate['year']));
                         $day = $daynames[$day];
                         $daycnts[$m][$d]['DAY'] = $day;
                         $weekdaycnt[$day]++;
                         $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day];
                         $yeardaycnt[$day]++;
                         $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day];
                     }
                     if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') {
                         $daycnts[$m][$d]['weekno_up'] = (int) date('W', mktime(0, 0, $wkst, $m, $d, $wdate['year']));
                     }
                 }
             }
             $daycnt = 0;
             $yeardaycnt = array();
             if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') {
                 $weekno = null;
                 for ($d = 31; $d > 25; $d--) {
                     // get last weekno for year
                     if (!$weekno) {
                         $weekno = $daycnts[12][$d]['weekno_up'];
                     } elseif ($weekno < $daycnts[12][$d]['weekno_up']) {
                         $weekno = $daycnts[12][$d]['weekno_up'];
                         break;
                     }
                 }
             }
             for ($m = 12; $m > 0; $m--) {
                 // count down and update down-counters
                 $weekdaycnt = array();
                 foreach ($daynames as $dn) {
                     $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
                 }
                 $monthcnt = 0;
                 $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year']));
                 for ($d = $mcnt; $d > 0; $d--) {
                     if (isset($recur['BYYEARDAY'])) {
                         $daycnt -= 1;
                         $daycnts[$m][$d]['yearcnt_down'] = $daycnt;
                     }
                     if (isset($recur['BYMONTHDAY'])) {
                         $monthcnt -= 1;
                         $daycnts[$m][$d]['monthcnt_down'] = $monthcnt;
                     }
                     if (isset($recur['BYDAY'])) {
                         $day = $daycnts[$m][$d]['DAY'];
                         $weekdaycnt[$day] -= 1;
                         $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day];
                         $yeardaycnt[$day] -= 1;
                         $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day];
                     }
                     if (isset($recur['BYWEEKNO']) || $recur['FREQ'] == 'WEEKLY') {
                         $daycnts[$m][$d]['weekno_down'] = $daycnts[$m][$d]['weekno_up'] - $weekno - 1;
                     }
                 }
             }
         }
         /* check interval */
         if (1 < $recur['INTERVAL']) {
             /* create interval index */
             $intervalix = iCal_UtilityFunctions::_recurIntervalIx($recur['FREQ'], $wdate, $wkst);
             /* check interval */
             $currentKey = array_keys($intervalarr);
             $currentKey = end($currentKey);
             // get last index
             if ($currentKey != $intervalix) {
                 $intervalarr = array($intervalix => $intervalarr[$currentKey] + 1);
             }
             if ($recur['INTERVAL'] != $intervalarr[$intervalix] && 0 != $intervalarr[$intervalix]) {
                 /* step up date */
                 // echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
                 iCal_UtilityFunctions::_stepdate($wdate, $wdatets, $step);
                 continue;
             } else {
                 // continue within the selected interval
                 $intervalarr[$intervalix] = 0;
             }
             // echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
         }
         $updateOK = TRUE;
         if ($updateOK && isset($recur['BYMONTH'])) {
             $updateOK = iCal_UtilityFunctions::_recurBYcntcheck($recur['BYMONTH'], $wdate['month'], $wdate['month'] - 13);
         }
         if ($updateOK && isset($recur['BYWEEKNO'])) {
             $updateOK = iCal_UtilityFunctions::_recurBYcntcheck($recur['BYWEEKNO'], $daycnts[$wdate['month']][$wdate['day']]['weekno_up'], $daycnts[$wdate['month']][$wdate['day']]['weekno_down']);
         }
         if ($updateOK && isset($recur['BYYEARDAY'])) {
             $updateOK = iCal_UtilityFunctions::_recurBYcntcheck($recur['BYYEARDAY'], $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up'], $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down']);
         }
         if ($updateOK && isset($recur['BYMONTHDAY'])) {
             $updateOK = iCal_UtilityFunctions::_recurBYcntcheck($recur['BYMONTHDAY'], $wdate['day'], $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down']);
         }
         // echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test###
         if ($updateOK && isset($recur['BYDAY'])) {
             $updateOK = FALSE;
             $m = $wdate['month'];
             $d = $wdate['day'];
             if (isset($recur['BYDAY']['DAY'])) {
                 // single day, opt with year/month day order no
                 $daynoexists = $daynosw = $daynamesw = FALSE;
                 if ($recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY']) {
                     $daynamesw = TRUE;
                 }
                 if (isset($recur['BYDAY'][0])) {
                     $daynoexists = TRUE;
                     if (isset($recur['FREQ']) && $recur['FREQ'] == 'MONTHLY' || isset($recur['BYMONTH'])) {
                         $daynosw = iCal_UtilityFunctions::_recurBYcntcheck($recur['BYDAY'][0], $daycnts[$m][$d]['monthdayno_up'], $daycnts[$m][$d]['monthdayno_down']);
                     } elseif (isset($recur['FREQ']) && $recur['FREQ'] == 'YEARLY') {
                         $daynosw = iCal_UtilityFunctions::_recurBYcntcheck($recur['BYDAY'][0], $daycnts[$m][$d]['yeardayno_up'], $daycnts[$m][$d]['yeardayno_down']);
                     }
                 }
                 if ($daynoexists && $daynosw && $daynamesw || !$daynoexists && !$daynosw && $daynamesw) {
                     $updateOK = TRUE;
                 }
                 // echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
             } else {
                 foreach ($recur['BYDAY'] as $bydayvalue) {
                     $daynoexists = $daynosw = $daynamesw = FALSE;
                     if (isset($bydayvalue['DAY']) && $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY']) {
                         $daynamesw = TRUE;
                     }
                     if (isset($bydayvalue[0])) {
                         $daynoexists = TRUE;
                         if (isset($recur['FREQ']) && $recur['FREQ'] == 'MONTHLY' || isset($recur['BYMONTH'])) {
                             $daynosw = iCal_UtilityFunctions::_recurBYcntcheck($bydayvalue['0'], $daycnts[$m][$d]['monthdayno_up'], $daycnts[$m][$d]['monthdayno_down']);
                         } elseif (isset($recur['FREQ']) && $recur['FREQ'] == 'YEARLY') {
                             $daynosw = iCal_UtilityFunctions::_recurBYcntcheck($bydayvalue['0'], $daycnts[$m][$d]['yeardayno_up'], $daycnts[$m][$d]['yeardayno_down']);
                         }
                     }
                     // echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
                     if ($daynoexists && $daynosw && $daynamesw || !$daynoexists && !$daynosw && $daynamesw) {
                         $updateOK = TRUE;
                         break;
                     }
                 }
             }
         }
         // echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ###
         /* check BYSETPOS */
         if ($updateOK) {
             if (isset($recur['BYSETPOS']) && in_array($recur['FREQ'], array('YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY'))) {
                 if (isset($recur['WEEKLY'])) {
                     if ($bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up']) {
                         $bysetposw1[] = $wdatets;
                     } else {
                         $bysetposw2[] = $wdatets;
                     }
                 } else {
                     if (isset($recur['FREQ']) && 'YEARLY' == $recur['FREQ'] && $bysetposYold == $wdate['year'] || isset($recur['FREQ']) && 'MONTHLY' == $recur['FREQ'] && ($bysetposYold == $wdate['year'] && $bysetposMold == $wdate['month']) || isset($recur['FREQ']) && 'DAILY' == $recur['FREQ'] && ($bysetposYold == $wdate['year'] && $bysetposMold == $wdate['month'] && $bysetposDold == $wdate['day'])) {
                         // echo "bysetposymd1[]=".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
                         $bysetposymd1[] = $wdatets;
                     } else {
                         // echo "bysetposymd2[]=".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
                         $bysetposymd2[] = $wdatets;
                     }
                 }
             } else {
                 /* update result array if BYSETPOS is set */
                 $countcnt++;
                 if ($startdatets <= $wdatets) {
                     // only output within period
                     $result[$wdatets] = TRUE;
                     // echo "recur ".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
                 }
                 // echo "recur undate ".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))." okdatstart ".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$startdatets),6))."<br />\n";//test
                 $updateOK = FALSE;
             }
         }
         /* step up date */
         iCal_UtilityFunctions::_stepdate($wdate, $wdatets, $step);
         /* check if BYSETPOS is set for updating result array */
         if ($updateOK && isset($recur['BYSETPOS'])) {
             $bysetpos = FALSE;
             if (isset($recur['FREQ']) && 'YEARLY' == $recur['FREQ'] && $bysetposYold != $wdate['year']) {
                 $bysetpos = TRUE;
                 $bysetposYold = $wdate['year'];
             } elseif (isset($recur['FREQ']) && ('MONTHLY' == $recur['FREQ'] && ($bysetposYold != $wdate['year'] || $bysetposMold != $wdate['month']))) {
                 $bysetpos = TRUE;
                 $bysetposYold = $wdate['year'];
                 $bysetposMold = $wdate['month'];
             } elseif (isset($recur['FREQ']) && 'WEEKLY' == $recur['FREQ']) {
                 $weekno = (int) date('W', mktime(0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year']));
                 if ($bysetposWold != $weekno) {
                     $bysetposWold = $weekno;
                     $bysetpos = TRUE;
                 }
             } elseif (isset($recur['FREQ']) && 'DAILY' == $recur['FREQ'] && ($bysetposYold != $wdate['year'] || $bysetposMold != $wdate['month'] || $bysetposDold != $wdate['day'])) {
                 $bysetpos = TRUE;
                 $bysetposYold = $wdate['year'];
                 $bysetposMold = $wdate['month'];
                 $bysetposDold = $wdate['day'];
             }
             if ($bysetpos) {
                 if (isset($recur['BYWEEKNO'])) {
                     $bysetposarr1 =& $bysetposw1;
                     $bysetposarr2 =& $bysetposw2;
                 } else {
                     $bysetposarr1 =& $bysetposymd1;
                     $bysetposarr2 =& $bysetposymd2;
                 }
                 // echo 'test före out startYMD (weekno)='.$wdateStart['year'].':'.$wdateStart['month'].':'.$wdateStart['day']." ($weekStart) "; // test ###
                 foreach ($recur['BYSETPOS'] as $ix) {
                     if (0 > $ix) {
                         // both positive and negative BYSETPOS allowed
                         $ix = count($bysetposarr1) + $ix + 1;
                     }
                     $ix--;
                     if (isset($bysetposarr1[$ix])) {
                         if ($startdatets <= $bysetposarr1[$ix]) {
                             // only output within period
                             //                $testdate   = iCal_UtilityFunctions::_timestamp2date( $bysetposarr1[$ix], 6 );                // test ###
                             //                $testweekno = (int) date( 'W', mktime( 0, 0, $wkst, $testdate['month'], $testdate['day'], $testdate['year'] )); // test ###
                             // echo " testYMD (weekno)=".$testdate['year'].':'.$testdate['month'].':'.$testdate['day']." ($testweekno)";   // test ###
                             $result[$bysetposarr1[$ix]] = TRUE;
                             // echo " recur ".implode('-',iCal_UtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$bysetposarr1[$ix]),6)); // test ###
                         }
                         $countcnt++;
                     }
                     if (isset($recur['COUNT']) && $countcnt >= $recur['COUNT']) {
                         break;
                     }
                 }
                 // echo "<br />\n"; // test ###
                 $bysetposarr1 = $bysetposarr2;
                 $bysetposarr2 = array();
             }
         }
     }
 }