%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/tjamichg/cursos.tjamich.gob.mx/vendor/kigkonsult/icalcreator/src/
Upload File :
Create Path :
Current File : /home/tjamichg/cursos.tjamich.gob.mx/vendor/kigkonsult/icalcreator/src/iCalXML.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;
use kigkonsult\iCalcreator\util\util;
use kigkonsult\iCalcreator\util\utilGeo;
/**
 * iCalcreator XML (rfc6321) support class
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.20.23 - 2017-02-25
 */
class iCalXML {
  private static $vcalendar      = 'vcalendar';
  private static $calProps       = ['version',
                                    'prodid',
                                    'calscale',
                                    'method'];
  private static $properties     = 'properties';
  private static $PARAMETERS     = 'parameters';
  private static $components     = 'components';
  private static $text           = 'text';
  private static $binary         = 'binary';
  private static $uri            = 'uri';
  private static $date           = 'date';
  private static $date_time      = 'date-time';
  private static $fbtype         = 'fbtype';
  private static $FBTYPE         = 'FBTYPE';
  private static $period         = 'period';
  private static $rstatus        = 'rstatus';
  private static $unknown        = 'unknown';
  private static $recur          = 'recur';
  private static $cal_address    = 'cal-address';
  private static $integer        = 'integer';
  private static $relatedStart   = 'relatedStart';
  private static $RELATED        = 'RELATED';
  private static $END            = 'END';
  private static $utc_offset     = 'utc-offset';
  private static $altrep         = 'altrep';
  private static $dir            = 'dir';
  private static $delegated_from = 'delegated-from';
  private static $delegated_to   = 'delegated-to';
  private static $member         = 'member';
  private static $sent_by        = 'sent-by';
  private static $rsvp           = 'rsvp';
  private static $bysecond       = 'bysecond';
  private static $byminute       = 'byminute';
  private static $byhour         = 'byhour';
  private static $bymonthday     = 'bymonthday';
  private static $byyearday      = 'byyearday';
  private static $byweekno       = 'byweekno';
  private static $bymonth        = 'bymonth';
  private static $bysetpos       = 'bysetpos';
  private static $byday          = 'byday';
  private static $freq           = 'freq';
  private static $count          = 'count';
  private static $interval       = 'interval';
  private static $wkst           = 'wkst';
  private static $code           = 'code';
  private static $statcode       = 'statcode';
  private static $extdata        = 'extdata';
  private static $data           = 'data';
  private static $time           = 'time';
  private static $latitude       = 'latitude';
  private static $longitude      = 'longitude';
/**
 * Return iCal XML (rfc6321) output, using PHP SimpleXMLElement
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.18.1 - 2013-08-18
 * @param vcalendar $calendar   iCalcreator vcalendar instance reference
 * @return string
 * @static
 */
 public static function iCal2XML( vcalendar $calendar ) {
  static $YMDTHISZ = 'Ymd\THis\Z';
  static $XMLstart = '<?xml version="1.0" encoding="utf-8"?><icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"><!-- created %s using kigkonsult.se %s iCal2XMl (rfc6321) --></icalendar>';
            /** fix an SimpleXMLElement instance and create root element */
  $xml          = new \SimpleXMLElement( sprintf( $XMLstart, gmdate( $YMDTHISZ ),
                                                             ICALCREATOR_VERSION ));
  $vcalendar    = $xml->addChild( self::$vcalendar );
            /** fix calendar properties */
  $properties   = $vcalendar->addChild( self::$properties );
  foreach( self::$calProps as $calProp ) {
    if( false !== ( $content = $calendar->getProperty( $calProp )))
      self::addXMLchild( $properties,
                         $calProp,
                         self::$text,
                         $content );
  }
  while( false !== ( $content = $calendar->getProperty( false, false, true )))
    self::addXMLchild( $properties,
                       $content[0],
                       self::$unknown,
                       $content[1][util::$LCvalue],
                       $content[1][util::$LCparams] );
  $langCal = $calendar->getConfig( util::$LANGUAGE );
            /** prepare to fix components with properties */
  $components   = $vcalendar->addChild( self::$components );
            /** fix component properties */
  while( false !== ( $component = $calendar->getComponent())) {
    $compName   = $component->objName;
    $child      = $components->addChild( $compName );
    $properties = $child->addChild( self::$properties );
    $langComp   = $component->getConfig( util::$LANGUAGE );
    $props      = $component->getConfig( util::$SETPROPERTYNAMES );
    foreach( $props as $pix => $prop ) {
      switch( strtoupper( $prop )) {
        case util::$ATTACH:          // may occur multiple times, below
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            $type = ( util::isParamsValueSet( $content, util::$BINARY ))
                  ? self::$binary : self::$uri;
            unset( $content[util::$LCparams][util::$VALUE] );
            self::addXMLchild( $properties,
                               $prop,
                               $type,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$ATTENDEE:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            if( isset( $content[util::$LCparams][util::$CN] ) &&
              ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
              if( $langComp )
                $content[util::$LCparams][util::$LANGUAGE] = $langComp;
              elseif( $langCal )
                $content[util::$LCparams][util::$LANGUAGE] = $langCal;
            }
            self::addXMLchild( $properties,
                               $prop,
                               self::$cal_address,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$EXDATE:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            $type = ( util::isParamsValueSet( $content, util::$DATE ))
                  ? self::$date : self::$date_time;
            unset( $content[util::$LCparams][util::$VALUE] );
            self::addXMLchild( $properties,
                               $prop,
                               $type,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$FREEBUSY:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            if( is_array( $content ) &&
                isset( $content[util::$LCvalue][self::$fbtype] )) {
              $content[util::$LCparams][self::$FBTYPE] = $content[util::$LCvalue][self::$fbtype];
              unset( $content[util::$LCvalue][self::$fbtype] );
            }
            self::addXMLchild( $properties,
                               $prop,
                               self::$period,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$REQUEST_STATUS:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            if( ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
              if( $langComp )
                $content[util::$LCparams][util::$LANGUAGE] = $langComp;
              elseif( $langCal )
                $content[util::$LCparams][util::$LANGUAGE] = $langCal;
            }
            self::addXMLchild( $properties,
                               $prop,
                               self::$rstatus,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$RDATE:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            $type = self::$date_time;
            if(     util::isParamsValueSet( $content, util::$DATE ))
              $type = self::$date;
            elseif( util::isParamsValueSet( $content, util::$PERIOD ))
              $type = self::$period;
            unset( $content[util::$LCparams][util::$VALUE] );
            self::addXMLchild( $properties,
                               $prop,
                               $type,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$CATEGORIES:
        case util::$COMMENT:
        case util::$CONTACT:
        case util::$DESCRIPTION:
        case util::$RELATED_TO:
        case util::$RESOURCES:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
            if(( util::$RELATED_TO != $prop ) &&
                ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
              if( $langComp )
                $content[util::$LCparams][util::$LANGUAGE] = $langComp;
              elseif( $langCal )
                $content[util::$LCparams][util::$LANGUAGE] = $langCal;
            }
            self::addXMLchild( $properties,
                               $prop,
                               self::$text,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$X_PROP:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true )))
            self::addXMLchild( $properties,
                               $content[0],
                               self::$unknown,
                               $content[1][util::$LCvalue],
                               $content[1][util::$LCparams] );
          break;
        case util::$CREATED:         // single occurence below, if set
        case util::$COMPLETED:
        case util::$DTSTAMP:
        case util::$LAST_MODIFIED:
        case util::$DTSTART:
        case util::$DTEND:
        case util::$DUE:
        case util::$RECURRENCE_ID:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true ))) {
            $type = ( util::isParamsValueSet( $content, util::$DATE ))
                  ? self::$date : self::$date_time;
            unset( $content[util::$LCparams][util::$VALUE] );
            if(( isset( $content[util::$LCparams][util::$TZID] ) &&
                 empty( $content[util::$LCparams][util::$TZID] )) ||
              @is_null( $content[util::$LCparams][util::$TZID] ))
              unset( $content[util::$LCparams][util::$TZID] );
            self::addXMLchild( $properties,
                               $prop,
                               $type,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$DURATION:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true )))
            self::addXMLchild( $properties,
                               $prop,
                               strtolower( util::$DURATION ),
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          break;
        case util::$EXRULE:
        case util::$RRULE:
          while( false !== ( $content = $component->getProperty( $prop,
                                                                 false,
                                                                 true )))
            self::addXMLchild( $properties,
                               $prop,
                               self::$recur,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          break;
        case util::$CLASS:
        case util::$LOCATION:
        case util::$STATUS:
        case util::$SUMMARY:
        case util::$TRANSP:
        case util::$TZID:
        case util::$UID:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true ))) {
            if((( util::$LOCATION == $prop ) ||
                ( util::$SUMMARY == $prop )) &&
                 ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
              if( $langComp )
                $content[util::$LCparams][util::$LANGUAGE] = $langComp;
              elseif( $langCal )
                $content[util::$LCparams][util::$LANGUAGE] = $langCal;
            }
            self::addXMLchild( $properties,
                               $prop,
                               self::$text,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$GEO:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true )))
            self::addXMLchild( $properties,
                               $prop,
                               strtolower( util::$GEO ),
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          break;
        case util::$ORGANIZER:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true ))) {
            if( isset( $content[util::$LCparams][util::$CN] ) &&
              ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
              if( $langComp )
                $content[util::$LCparams][util::$LANGUAGE] = $langComp;
              elseif( $langCal )
                $content[util::$LCparams][util::$LANGUAGE] = $langCal;
            }
            self::addXMLchild( $properties,
                               $prop,
                               self::$cal_address,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          }
          break;
        case util::$PERCENT_COMPLETE:
        case util::$PRIORITY:
        case util::$SEQUENCE:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true )))
            self::addXMLchild( $properties,
                               $prop,
                               self::$integer,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          break;
        case util::$TZURL:
        case util::$URL:
          if( false !== ( $content = $component->getProperty( $prop,
                                                              false,
                                                              true )))
            self::addXMLchild( $properties,
                               $prop,
                               self::$uri,
                               $content[util::$LCvalue],
                               $content[util::$LCparams] );
          break;
      } // end switch( $prop )
    } // end foreach( $props as $pix => $prop )
            /** fix subComponent properties, if any */
    while( false !== ( $subcomp = $component->getComponent())) {
      $subCompName  = $subcomp->objName;
      $child2       = $child->addChild( $subCompName );
      $properties   = $child2->addChild( self::$properties );
      $langComp     = $subcomp->getConfig( util::$LANGUAGE );
      $subCompProps = $subcomp->getConfig( util::$SETPROPERTYNAMES );
      foreach( $subCompProps as $pix2 => $prop ) {
        switch( strtoupper( $prop )) {
          case util::$ATTACH:          // may occur multiple times, below
            while( false !== ( $content = $subcomp->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
              $type = ( util::isParamsValueSet( $content, util::$BINARY ))
                    ? self::$binary : self::$uri;
              unset( $content[util::$LCparams][util::$VALUE] );
              self::addXMLchild( $properties,
                                 $prop,
                                 $type,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$ATTENDEE:
            while( false !== ( $content = $subcomp->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
              if( isset( $content[util::$LCparams][util::$CN] ) &&
                ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
                if( $langComp )
                  $content[util::$LCparams][util::$LANGUAGE] = $langComp;
                elseif( $langCal )
                  $content[util::$LCparams][util::$LANGUAGE] = $langCal;
              }
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$cal_address,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$COMMENT:
          case util::$TZNAME:
            while( false !== ( $content = $subcomp->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
              if( ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
                if( $langComp )
                  $content[util::$LCparams][util::$LANGUAGE] = $langComp;
                elseif( $langCal )
                  $content[util::$LCparams][util::$LANGUAGE] = $langCal;
              }
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$text,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$RDATE:
            while( false !== ( $content = $subcomp->getProperty( $prop,
                                                                 false,
                                                                 true ))) {
              $type = self::$date_time;
              if( isset( $content[util::$LCparams][util::$VALUE] )) {
                if(     util::isParamsValueSet( $content, util::$DATE ))
                  $type = self::$date;
                elseif( util::isParamsValueSet( $content, util::$PERIOD ))
                  $type = self::$period;
              }
              unset( $content[util::$LCparams][util::$VALUE] );
              self::addXMLchild( $properties,
                                 $prop,
                                 $type,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$X_PROP:
            while( false !== ( $content = $subcomp->getProperty( $prop,
                                                                 false,
                                                                 true )))
              self::addXMLchild( $properties,
                                 $content[0],
                                 self::$unknown,
                                 $content[1][util::$LCvalue],
                                 $content[1][util::$LCparams] );
            break;
          case util::$ACTION:      // single occurence below, if set
          case util::$DESCRIPTION:
          case util::$SUMMARY:
            if( false !== ( $content = $subcomp->getProperty( $prop,
                                                              false,
                                                              true ))) {
              if(( util::$ACTION != $prop ) &&
                  ! isset( $content[util::$LCparams][util::$LANGUAGE] )) {
                if( $langComp )
                  $content[util::$LCparams][util::$LANGUAGE] = $langComp;
                elseif( $langCal )
                  $content[util::$LCparams][util::$LANGUAGE] = $langCal;
              }
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$text,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$DTSTART:
            if( false !== ( $content = $subcomp->getProperty( $prop,
                                                              false,
                                                              true ))) {
              unset( $content[util::$LCvalue][util::$LCtz],
                     $content[util::$LCparams][util::$VALUE] ); // always local time
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$date_time,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$DURATION:
            if( false !== ( $content = $subcomp->getProperty( $prop,
                                                              false,
                                                              true )))
              self::addXMLchild( $properties,
                                 $prop,
                                 strtolower( util::$DURATION ),
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            break;
          case util::$REPEAT:
            if( false !== ( $content = $subcomp->getProperty( $prop,
                                                              false,
                                                              true )))
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$integer,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            break;
          case util::$TRIGGER:
            if( false !== ( $content = $subcomp->getProperty( $prop,
                                                              false,
                                                              true ))) {
              if( isset( $content[util::$LCvalue][util::$LCYEAR] )   &&
                  isset( $content[util::$LCvalue][util::$LCMONTH] )  &&
                  isset( $content[util::$LCvalue][util::$LCDAY] ))
                $type = self::$date_time;
              else {
                $type = strtolower( util::$DURATION );
                if( ! isset( $content[util::$LCvalue][self::$relatedStart] ) ||
                  ( true !== $content[util::$LCvalue][self::$relatedStart] ))
                  $content[util::$LCparams][self::$RELATED] = self::$END;
              }
              self::addXMLchild( $properties,
                                 $prop,
                                 $type,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            }
            break;
          case util::$TZOFFSETFROM:
          case util::$TZOFFSETTO:
            if( false !== ( $content = $subcomp->getProperty( $prop,
                                                              false,
                                                              true )))
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$utc_offset,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            break;
          case util::$RRULE:
            while( false !== ( $content = $subcomp->getProperty( $prop,
                                                                 false,
                                                                 true )))
              self::addXMLchild( $properties,
                                 $prop,
                                 self::$recur,
                                 $content[util::$LCvalue],
                                 $content[util::$LCparams] );
            break;
        } // switch( $prop )
      } // end foreach( $subCompProps as $pix2 => $prop )
    } // end while( false !== ( $subcomp = $component->getComponent()))
  } // end while( false !== ( $component = $calendar->getComponent()))
  return $xml->asXML();
 }
/**
 * Add XML (rfc6321) children to a SimpleXMLelement
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.23.8 - 2017-04-17
 * @param SimpleXMLElement $parent   a SimpleXMLelement node
 * @param string $name     new element node name
 * @param string $type     content type, subelement(-s) name
 * @param string $content  new subelement content
 * @param array  $params   new element 'attributes'
 * @access private
 * @static
 */
 private static function addXMLchild( \SimpleXMLElement & $parent, $name, $type, $content, $params=[] ) {
  static $FMTYMD    = '%04d-%02d-%02d';
  static $FMTYMDHIS = '%04d-%02d-%02dT%02d:%02d:%02d';
  static $PLUSMINUSARR = ['+', '-'];
  static $BOOLEAN   = 'boolean';
  static $UNTIL     = 'until';
  static $START     = 'start';
  static $END       = 'end';
  static $BEFORE    = 'before';
  static $SP0       = '';
            /** create new child node */
  $name  = strtolower( $name );
  $child = $parent->addChild( $name );
  if( ! empty( $params )) {
    $parameters = $child->addChild( self::$PARAMETERS );
    foreach( $params as $param => $parVal ) {
      if( util::$VALUE == $param ) {
        if( strtolower( $type ) != strtolower( $parVal ))
          $type = strtolower( $parVal );
        continue;
      }
      $param = strtolower( $param );
      if( util::isXprefixed( $param )) {
        $p1 = $parameters->addChild( $param );
        $p2 = $p1->addChild( self::$unknown, htmlspecialchars( $parVal ));
      }
      else {
        $p1 = $parameters->addChild( $param );
        switch( $param ) {
          case self::$altrep:
          case self::$dir:
            $ptype = self::$uri;
            break;
          case self::$delegated_from:
          case self::$delegated_to:
          case self::$member:
          case self::$sent_by:
            $ptype = self::$cal_address;
            break;
          case self::$rsvp:
            $ptype = $BOOLEAN;
            break ;
          default:
            $ptype = self::$text;
            break;
        }
        if( is_array( $parVal )) {
          foreach( $parVal as $pV )
            $p2 = $p1->addChild( $ptype, htmlspecialchars( $pV ));
        }
        else
          $p2 = $p1->addChild( $ptype, htmlspecialchars( $parVal ));
      }
    }
  } // end if( ! empty( $params ))
  if(( empty( $content ) && ( util::$ZERO != $content )) ||
       ( ! is_array( $content) &&
       ( util::$MINUS != $content[0] ) &&
       ( 0 > $content )))
    return;
            /** store content */
  switch( $type ) {
    case self::$binary:
      $v = $child->addChild( $type, $content );
      break;
    case $BOOLEAN:
      break;
    case self::$cal_address:
      $v = $child->addChild( $type, $content );
      break;
    case self::$date:
      if( array_key_exists( util::$LCYEAR, $content ))
        $content = [$content];
      foreach( $content as $date ) {
        $str = sprintf( $FMTYMD, (int) $date[util::$LCYEAR],
                                 (int) $date[util::$LCMONTH],
                                 (int) $date[util::$LCDAY] );
        $v = $child->addChild( $type, $str );
      }
      break;
    case self::$date_time:
      if( array_key_exists( util::$LCYEAR, $content ))
        $content = [$content];
      foreach( $content as $dt ) {
        if( ! isset( $dt[util::$LCHOUR] )) $dt[util::$LCHOUR] = 0;
        if( ! isset( $dt[util::$LCMIN] ))  $dt[util::$LCMIN]  = 0;
        if( ! isset( $dt[util::$LCSEC] ))  $dt[util::$LCSEC]  = 0;
        $str = sprintf( $FMTYMDHIS,  (int) $dt[util::$LCYEAR],
                                     (int) $dt[util::$LCMONTH],
                                     (int) $dt[util::$LCDAY],
                                     (int) $dt[util::$LCHOUR],
                                     (int) $dt[util::$LCMIN],
                                     (int) $dt[util::$LCSEC] );
        if(      isset( $dt[util::$LCtz] ) &&
          ( util::$Z == $dt[util::$LCtz] ))
          $str .= util::$Z;
        $v = $child->addChild( $type, $str );
      }
      break;
    case strtolower( util::$DURATION ):
      $output = (( strtolower( util::$TRIGGER ) == $name ) &&
                 ( false !== $content[$BEFORE] )) ? util::$MINUS : null;
      $v = $child->addChild( $type, $output . util::duration2str( $content ));
      break;
    case strtolower( util::$GEO ):
      if( ! empty( $content )) {
        $v1 = $child->addChild( utilGeo::$LATITUDE,
                                utilGeo::geo2str2( $content[utilGeo::$LATITUDE],
                                                            utilGeo::$geoLatFmt ));
        $v1 = $child->addChild( utilGeo::$LONGITUDE,
                                utilGeo::geo2str2( $content[utilGeo::$LONGITUDE],
                                                            utilGeo::$geoLongFmt ));
      }
      break;
    case self::$integer:
      $v = $child->addChild( $type, (string) $content );
      break;
    case self::$period:
      if( ! is_array( $content ))
        break;
      foreach( $content as $period ) {
        $v1 = $child->addChild( $type );
        $str = sprintf( $FMTYMDHIS, (int) $period[0][util::$LCYEAR],
                                    (int) $period[0][util::$LCMONTH],
                                    (int) $period[0][util::$LCDAY],
                                    (int) $period[0][util::$LCHOUR],
                                    (int) $period[0][util::$LCMIN],
                                    (int) $period[0][util::$LCSEC] );
        if(      isset( $period[0][util::$LCtz] ) &&
          ( util::$Z == $period[0][util::$LCtz] ))
          $str .= util::$Z;
        $v2 = $v1->addChild( $START, $str );
        if( array_key_exists( util::$LCYEAR, $period[1] )) {
          $str = sprintf( $FMTYMDHIS, (int) $period[1][util::$LCYEAR],
                                      (int) $period[1][util::$LCMONTH],
                                      (int) $period[1][util::$LCDAY],
                                      (int) $period[1][util::$LCHOUR],
                                      (int) $period[1][util::$LCMIN],
                                      (int) $period[1][util::$LCSEC] );
          if(       isset($period[1][util::$LCtz] ) &&
            ( util::$Z == $period[1][util::$LCtz] ))
            $str .= util::$Z;
          $v2 = $v1->addChild( $END, $str );
        }
        else
          $v2 = $v1->addChild( strtolower( util::$DURATION ),
                               util::duration2str( $period[1] ));
      }
      break;
    case self::$recur:
      $content = array_change_key_case( $content );
      foreach( $content as $rulelabel => $rulevalue ) {
        switch( $rulelabel ) {
          case $UNTIL:
            if( isset( $rulevalue[util::$LCHOUR] ))
              $str = sprintf( $FMTYMDHIS, (int) $rulevalue[util::$LCYEAR],
                                          (int) $rulevalue[util::$LCMONTH],
                                          (int) $rulevalue[util::$LCDAY],
                                          (int) $rulevalue[util::$LCHOUR],
                                          (int) $rulevalue[util::$LCMIN],
                                          (int) $rulevalue[util::$LCSEC] ) . util::$Z;
            else
              $str = sprintf( $FMTYMD,    (int) $rulevalue[util::$LCYEAR],
                                          (int) $rulevalue[util::$LCMONTH],
                                          (int) $rulevalue[util::$LCDAY] );
            $v = $child->addChild( $rulelabel, $str );
            break;
          case self::$bysecond:
          case self::$byminute:
          case self::$byhour:
          case self::$bymonthday:
          case self::$byyearday:
          case self::$byweekno:
          case self::$bymonth:
          case self::$bysetpos: {
            if( is_array( $rulevalue )) {
              foreach( $rulevalue as $vix => $valuePart )
                $v = $child->addChild( $rulelabel, $valuePart );
            }
            else
              $v = $child->addChild( $rulelabel, $rulevalue );
            break;
          }
          case self::$byday: {
            if( isset( $rulevalue[util::$DAY] )) {
              $str  = ( isset( $rulevalue[0] )) ? $rulevalue[0] : null;
              $str .= $rulevalue[util::$DAY];
              $p    = $child->addChild( $rulelabel, $str );
            }
            else {
              foreach( $rulevalue as $valuePart ) {
                if( isset( $valuePart[util::$DAY] )) {
                  $str  = ( isset( $valuePart[0] )) ? $valuePart[0] : null;
                  $str .= $valuePart[util::$DAY];
                  $p    = $child->addChild( $rulelabel, $str );
                }
                else
                  $p    = $child->addChild( $rulelabel, $valuePart );
              }
            }
            break;
          }
          case self::$freq:
          case self::$count:
          case self::$interval:
          case self::$wkst:
          default:
            $p = $child->addChild( $rulelabel, $rulevalue );
            break;
        } // end switch( $rulelabel )
      } // end foreach( $content as $rulelabel => $rulevalue )
      break;
    case self::$rstatus:
      $v = $child->addChild( self::$code,
                             number_format((float) $content[self::$statcode],
                                            2,
                                            util::$DOT,
                                            $SP0 ));
      $v = $child->addChild( strtolower( util::$DESCRIPTION ),
                             htmlspecialchars( $content[self::$text] ));
      if( isset( $content[self::$extdata] ))
        $v = $child->addChild( self::$data,
                               htmlspecialchars( $content[self::$extdata] ));
      break;
    case self::$text:
      if( ! is_array( $content ))
        $content = [$content];
      foreach( $content as $part )
        $v = $child->addChild( $type, htmlspecialchars( $part ));
      break;
    case self::$time:
      break;
    case self::$uri:
      $v = $child->addChild( $type, $content );
      break;
    case self::$utc_offset:
      if( in_array( $content[0], $PLUSMINUSARR )) {
        $str     = $content[0];
        $content = substr( $content, 1 );
      }
      else
        $str     = util::$PLUS;
      $str .= substr( $content, 0, 2 ) . util::$COLON . substr( $content, 2, 2 );
      if( 4 < strlen( $content ))
        $str .= util::$COLON . substr( $content, 4 );
      $v = $child->addChild( $type, $str );
      break;
    case self::$unknown:
    default:
      if( is_array( $content ))
        $content = implode( $content );
      $v = $child->addChild( self::$unknown, htmlspecialchars( $content ));
      break;
  }
 }
/**
 * Parse (rfc6321) XML file into iCalcreator instance
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.16.22 - 2013-06-18
 * @param  string $xmlfile
 * @param  array  $iCalcfg iCalcreator config array (opt)
 * @return mixediCalcreator instance or false on error
 * @static
 */
 public static function XMLfile2iCal( $xmlfile, $iCalcfg=[] ) {
  if( false === ( $xmlstr = file_get_contents( $xmlfile )))
    return false;
  return self::xml2iCal( $xmlstr, $iCalcfg );
 }
/**
 * Parse (rfc6321) XML string into iCalcreator instance, alias of XML2iCal
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.16.22 - 2013-06-18
 * @param  string $xmlstr
 * @param  array  $iCalcfg iCalcreator config array (opt)
 * @return mixed  iCalcreator instance or false on error
 * @static
 */
 public static function XMLstr2iCal( $xmlstr, $iCalcfg=[] ) {
  return self::XML2iCal( $xmlstr, $iCalcfg);
 }
/**
 * Parse (rfc6321) XML string into iCalcreator instance
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.20.23 - 2017-02-25
 * @param  string $xmlstr
 * @param  array  $iCalcfg iCalcreator config array (opt)
 * @return mixed  iCalcreator instance or false on error
 * @static
 */
 public static function XML2iCal( $xmlstr, $iCalcfg=[] ) {
  static $CRLF = ["\r\n", "\n\r", "\n", "\r"];
  $xmlstr  = str_replace( $CRLF, null, $xmlstr );
  $xml     = self::XMLgetTagContent1( $xmlstr, self::$vcalendar, $endIx );
  $iCal    = new vcalendar( $iCalcfg );
  self::XMLgetComps( $iCal, $xmlstr );
  return $iCal;
 }
/**
 * Parse (rfc6321) XML string into iCalcreator components
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.23.8 - 2017-04-14
 * @param object $iCal   iCalcreator vcalendar or component object instance
 * @param string $xml
 * @return object
 * @access private
 * @static
 */
 private static function XMLgetComps( $iCal, $xml ) {
  static $PROPSTAG   = '<properties>';
  static $COMPSTAG   = '<components>';
  $len     = strlen( $xml );
  $sx      = 0;
  while((( $sx + 12 ) < $len ) &&
        ( $PROPSTAG != substr( $xml, $sx, 12 )) &&
        ( $COMPSTAG != substr( $xml, $sx, 12 )))
    $sx   += 1;
  if(( $sx + 11 ) >= $len )
    return false;
  if( $PROPSTAG == substr( $xml, $sx, 12 )) {
    $xml2  = self::XMLgetTagContent1( $xml, self::$properties, $endIx );
    self::XMLgetProps( $iCal, $xml2 );
    $xml   = substr( $xml, $endIx );
  }
  if( $COMPSTAG == substr( $xml, 0, 12 ))
    $xml     = self::XMLgetTagContent1( $xml, self::$components, $endIx );
  while( ! empty( $xml )) {
    $xml2  = self::XMLgetTagContent2( $xml, $tagName, $endIx );
    if( in_array( strtolower( $tagName ), util::$ALLCOMPS ) &&
       ( false !== ( $subComp = $iCal->newComponent( $tagName ))))
      self::XMLgetComps( $subComp, $xml2 );
    $xml   = substr( $xml, $endIx);
  } // end while( ! empty( $xml ))
  return $iCal;
 }
/**
 * Parse (rfc6321) XML into iCalcreator properties
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.23.3 - 2017-03-19
 * @param  object $iCal iCalcreator calendar/component instance
 * @param  string $xml
 * @access private
 * @static
 */
 private static function XMLgetProps( $iCal, $xml) {
  static $PARAMENDTAG = '<parameters/>';
  static $PARAMTAG    = '<parameters>';
  static $DATETAGST   = '<date';
  static $PERIODTAG   = '<period>';
  while( ! empty( $xml )) {
    $xml2         = self::XMLgetTagContent2( $xml, $propName, $endIx );
    $propName     = strtoupper( $propName );
    if( empty( $xml2 ) && ( util::$ZERO != $xml2 )) {
      $iCal->setProperty( $propName );
      $xml        = substr( $xml, $endIx);
      continue;
    }
    $params       = [];
    if( $PARAMENDTAG == substr( $xml2, 0, 13 ))
      $xml2       = substr( $xml2, 13 );
    elseif( $PARAMTAG == substr( $xml2, 0, 12 )) {
      $xml3       = self::XMLgetTagContent1( $xml2, self::$PARAMETERS, $endIx2 );
      while( ! empty( $xml3 )) {
        $xml4     = self::XMLgetTagContent2( $xml3, $paramKey, $endIx3 );
        $pType    = false; // skip parameter valueType
        $paramKey = strtoupper( $paramKey );
        if( in_array( $paramKey, util::$ATTENDEEPARKEYS )) {
          while( ! empty( $xml4 )) {
            $paramValue = self::XMLgetTagContent1( $xml4, self::$cal_address, $endIx4 );
            if( ! isset( $params[$paramKey] ))
              $params[$paramKey]   = [$paramValue];
            else
              $params[$paramKey][] = $paramValue;
            $xml4     = substr( $xml4, $endIx4 );
          }
        } // end if( in_array( $paramKey, util::$ATTENDEEPARKEYS ))
        else {
          $paramValue = html_entity_decode( self::XMLgetTagContent2( $xml4, $pType, $endIx4 ));
          if( ! isset( $params[$paramKey] ))
            $params[$paramKey]  = $paramValue;
          else
            $params[$paramKey] .= util::$COMMA . $paramValue;
        }
        $xml3     = substr( $xml3, $endIx3 );
      }
      $xml2       = substr( $xml2, $endIx2 );
    } // end elseif
    $valueType    = false;
    $value        = ( ! empty( $xml2 ) || ( util::$ZERO == $xml2 ))
                  ? self::XMLgetTagContent2( $xml2, $valueType, $endIx3 ) : null;
    switch( $propName ) {
      case util::$CATEGORIES:
      case util::$RESOURCES:
        $tValue      = [];
        while( ! empty( $xml2 )) {
          $tValue[]  = html_entity_decode( self::XMLgetTagContent2( $xml2,
                                                                    $valueType,
                                                                    $endIx4 ));
          $xml2      = substr( $xml2, $endIx4 );
        }
        $value       = $tValue;
        break;
      case util::$EXDATE:   // multiple single-date(-times) may exist
      case util::$RDATE:
        if( self::$period != $valueType ) {
          if( self::$date == $valueType )
            $params[util::$VALUE] = util::$DATE;
          $t         = [];
          while( ! empty( $xml2 ) &&
                ( $DATETAGST == substr( $xml2, 0, 5 ))) {
            $t[]     = self::XMLgetTagContent2( $xml2,
                                                $pType,
                                                $endIx4 );
            $xml2    = substr( $xml2, $endIx4 );
          }
          $value = $t;
          break;
        }
      case util::$FREEBUSY:
        if( util::$RDATE == $propName )
          $params[util::$VALUE] = util::$PERIOD;
        $value       = [];
        while( ! empty( $xml2 ) &&
              ( $PERIODTAG == substr( $xml2, 0, 8 ))) {
          $xml3      = self::XMLgetTagContent1( $xml2,
                                                self::$period,
                                                $endIx4 ); // period
          $t         = [];
          while( ! empty( $xml3 )) {
            $t[]     = self::XMLgetTagContent2( $xml3,
                                                $pType,
                                                $endIx5 ); // start - end/duration
            $xml3    = substr( $xml3, $endIx5 );
          }
          $value[]   = $t;
          $xml2      = substr( $xml2, $endIx4 );
        }
        break;
      case util::$TZOFFSETTO:
      case util::$TZOFFSETFROM:
        $value       = str_replace( util::$COLON, null, $value );
        break;
      case util::$GEO:
        $tValue      = [utilGeo::$LATITUDE => $value];
        $tValue[utilGeo::$LONGITUDE] = self::XMLgetTagContent1( substr( $xml2, $endIx3 ),
                                                                utilGeo::$LONGITUDE,
                                                                $endIx3 );
        $value       = $tValue;
        break;
      case util::$EXRULE:
      case util::$RRULE:
        $tValue      = [$valueType => $value];
        $xml2        = substr( $xml2, $endIx3 );
        $valueType   = false;
        while( ! empty( $xml2 )) {
          $t         = self::XMLgetTagContent2( $xml2,
                                                $valueType,
                                                $endIx4 );
          switch( strtoupper( $valueType )) {
            case util::$FREQ:
            case util::$COUNT:
            case util::$UNTIL:
            case util::$INTERVAL:
            case util::$WKST:
              $tValue[$valueType] = $t;
              break;
            case util::$BYDAY:
              if( 2 == strlen( $t ))
                $tValue[$valueType][] = [util::$DAY => $t];
              else {
                $day = substr( $t, -2 );
                $key = substr( $t, 0, ( strlen( $t ) - 2 ));
                $tValue[$valueType][] = [$key, util::$DAY => $day];
              }
              break;
            default:
              $tValue[$valueType][] = $t;
          }
          $xml2      = substr( $xml2, $endIx4 );
        }
        $value       = $tValue;
        break;
      case util::$REQUEST_STATUS:
        $tValue      = [];
        while( ! empty( $xml2 )) {
          $t         = html_entity_decode( self::XMLgetTagContent2( $xml2,
                                                                    $valueType,
                                                                    $endIx4 ));
          $tValue[$valueType] = $t;
          $xml2      = substr( $xml2, $endIx4 );
        }
        if( ! empty( $tValue ))
          $value     = $tValue;
        else
          $value     = [self::$code                      => null,
                        strtolower( util::$DESCRIPTION ) => null];
        break;
      default:
        switch( $valueType ) {
          case self::$binary :
            $params[util::$VALUE] = util::$BINARY;
            break;
          case self::$date :
            $params[util::$VALUE] = util::$DATE;
            break;
          case self::$date_time :
            $params[util::$VALUE] = util::$DATE_TIME;
            break;
          case self::$text :
          case self::$unknown :
            $value = html_entity_decode( $value );
            break;
          default :
            if( util::isXprefixed( $propName ) &&
              ( self::$unknown != strtolower( $valueType )))
              $params[util::$VALUE] = strtoupper( $valueType );
            break;
        }
        break;
    } // end switch( $propName )
    if( util::$FREEBUSY == $propName ) {
      $fbtype        = $params[self::$FBTYPE];
      unset( $params[self::$FBTYPE] );
      $iCal->setProperty( $propName, $fbtype, $value, $params );
    }
    elseif( util::$GEO == $propName ) {
      $iCal->setProperty( $propName, $value[self::$latitude],
                                     $value[self::$longitude],
                                     $params );
    }
    elseif( util::$REQUEST_STATUS == $propName ) {
      if( ! isset( $value[self::$data] ))
        $value[self::$data] = false;
      $iCal->setProperty( $propName, $value[self::$code],
                                     $value[strtolower( util::$DESCRIPTION )],
                                     $value[self::$data], $params );
    }
    else {
      if( empty( $value ) && ( is_array( $value ) || ( util::$ZERO > $value )))
        $value = null;
      $iCal->setProperty( $propName, $value, $params );
    }
    $xml             = substr( $xml, $endIx);
  } // end while( ! empty( $xml ))
 }
/**
 * Fetch a specific XML tag content
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.23.8 - 2017-04-17
 * @param string $xml
 * @param string $tagName
 * @param int    $endIx
 * @return mixed
 * @access private
 * @static
 */
 private static function XMLgetTagContent1( $xml, $tagName, & $endIx=0 ) {
  static $FMT0 = '<%s>';
  static $FMT1 = '<%s />';
  static $FMT2 = '<%s/>';
  static $FMT3 = '</%s>';
  $tagName   = strtolower( $tagName );
  $strLen    = strlen( $tagName );
  $xmlLen    = strlen( $xml );
  $sx1       = 0;
  while( $sx1 < $xmlLen ) {
    if((( $sx1 + $strLen + 1 ) < $xmlLen ) &&
       ( sprintf( $FMT0, $tagName ) == strtolower( substr( $xml, $sx1, ( $strLen + 2 )))))
      break;
    if((( $sx1 + $strLen + 3 ) < $xmlLen ) &&
       ( sprintf( $FMT1, $tagName ) == strtolower( substr( $xml, $sx1, ( $strLen + 4 ))))) {
      $endIx = $strLen + 5;
      return null; // empty tag
    }
    if((( $sx1 + $strLen + 2 ) < $xmlLen ) &&
       ( sprintf( $FMT2, $tagName ) == strtolower( substr( $xml, $sx1, ( $strLen + 3 ))))) {
      $endIx = $strLen + 4;
      return null; // empty tag
    }
    $sx1    += 1;
  } // end while...
  if( false === substr( $xml, $sx1, 1 )) {
    $endIx   = ( empty( $sx )) ? 0 : $sx - 1; // ??
    return null;
  }
  $endTag    = sprintf( $FMT3, $tagName );
  if( false === ( $pos = stripos( $xml, $endTag ))) { // missing end tag??
    $endIx   = $xmlLen + 1;
    return null;
  }
  $endIx     = $pos + $strLen + 3;
  return substr( $xml, ( $sx1 + $strLen + 2 ), ( $pos - $sx1 - 2 - $strLen ));
 }
/**
 * Fetch next (unknown) XML tagname AND content
 *
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @since 2.23.8 - 2017-04-17
 * @param string $xml
 * @param string $tagName
 * @param int $endIx
 * @return mixed
 * @access private
 * @static
 */
 private static function XMLgetTagContent2( $xml, & $tagName, & $endIx ) {
  static $LT          = '<';
  static $CMTSTART    = '<!--';
  static $EMPTYTAGEND = '/>';
  static $GT          = '>';
  static $DURATION    = 'duration';
  static $DURATIONTAG = '<duration>';
  static $DURENDTAG   = '</duration>';
  static $FMTTAG      = '</%s>';
  $xmlLen      = strlen( $xml );
  $endIx       = $xmlLen + 1; // just in case.. .
  $sx1         = 0;
  while( $sx1 < $xmlLen ) {
    if( $LT == substr( $xml, $sx1, 1 )) {
      if((( $sx1 + 3 ) < $xmlLen ) &&
         ( $CMTSTART == substr( $xml, $sx1, 4 ))) // skip comment
        $sx1  += 1;
      else
        break; // tagname start here
    }
    else
      $sx1    += 1;
  } // end while...
  $sx2         = $sx1;
  while( $sx2 < $xmlLen ) {
    if((( $sx2 + 1 ) < $xmlLen ) &&
       ( $EMPTYTAGEND == substr( $xml, $sx2, 2 ))) { // tag with no content
      $tagName = trim( substr( $xml, ( $sx1 + 1 ), ( $sx2 - $sx1 - 1 )));
      $endIx   = $sx2 + 2;
      return null;
    }
    if( $GT == substr( $xml, $sx2, 1 )) // tagname ends here
      break;
    $sx2      += 1;
  } // end while...
  $tagName     = substr( $xml, ( $sx1 + 1 ), ( $sx2 - $sx1 - 1 ));
  $endIx       = $sx2 + 1;
  if( $sx2 >= $xmlLen )
    return null;
  $strLen      = strlen( $tagName );
  if(( $DURATION == $tagName ) &&
     ( false !== ( $pos1 = stripos( $xml, $DURATIONTAG, $sx1+1  ))) &&
     ( false !== ( $pos2 = stripos( $xml, $DURENDTAG,   $pos1+1 ))) &&
     ( false !== ( $pos3 = stripos( $xml, $DURENDTAG,   $pos2+1 ))) &&
     ( $pos1 < $pos2 ) && ( $pos2 < $pos3 ))
    $pos = $pos3;
  elseif( false === ( $pos = stripos( $xml, sprintf( $FMTTAG, $tagName ), $sx2 )))
    return null;
  $endIx       = $pos + $strLen + 3;
  return substr( $xml, ( $sx1 + $strLen + 2 ), ( $pos - $strLen - 2 ));
 }
}

Zerion Mini Shell 1.0