예제 #1
0
 /**
  * This method will try to find out the correct timezone for an iCalendar
  * date-time value.
  *
  * You must pass the contents of the TZID parameter, as well as the full
  * calendar.
  *
  * If the lookup fails, this method will return UTC.
  *
  * @param string $tzid
  * @param Sabre\VObject\Component $vcalendar
  * @return DateTimeZone
  */
 public static function getTimeZone($tzid, Component $vcalendar = null)
 {
     // First we will just see if the tzid is a support timezone identifier.
     try {
         return new \DateTimeZone($tzid);
     } catch (\Exception $e) {
     }
     // Next, we check if the tzid is somewhere in our tzid map.
     if (isset(self::$map[$tzid])) {
         return new \DateTimeZone(self::$map[$tzid]);
     }
     if ($vcalendar) {
         // If that didn't work, we will scan VTIMEZONE objects
         foreach ($vcalendar->select('VTIMEZONE') as $vtimezone) {
             if ((string) $vtimezone->TZID === $tzid) {
                 // Some clients add 'X-LIC-LOCATION' with the olson name.
                 if (isset($vtimezone->{'X-LIC-LOCATION'})) {
                     try {
                         return new \DateTimeZone($vtimezone->{'X-LIC-LOCATION'});
                     } catch (\Exception $e) {
                     }
                 }
                 // Microsoft may add a magic number, which we also have an
                 // answer for.
                 if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
                     if (isset(self::$microsoftExchangeMap[(int) $vtimezone->{'X-MICROSOFT-CDO-TZID'}->value])) {
                         return new \DateTimeZone(self::$microsoftExchangeMap[(int) $vtimezone->{'X-MICROSOFT-CDO-TZID'}->value]);
                     }
                 }
             }
         }
     }
     // If we got all the way here, we default to UTC.
     return new \DateTimeZone(date_default_timezone_get());
 }
예제 #2
0
 /**
  * This method will try to find out the correct timezone for an iCalendar
  * date-time value.
  *
  * You must pass the contents of the TZID parameter, as well as the full
  * calendar.
  *
  * If the lookup fails, this method will return the default PHP timezone
  * (as configured using date_default_timezone_set, or the date.timezone ini
  * setting).
  *
  * Alternatively, if $failIfUncertain is set to true, it will throw an
  * exception if we cannot accurately determine the timezone.
  *
  * @param string $tzid
  * @param SabreForRainLoop\VObject\Component $vcalendar
  * @return DateTimeZone
  */
 public static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false)
 {
     // First we will just see if the tzid is a support timezone identifier.
     try {
         return new \DateTimeZone($tzid);
     } catch (\Exception $e) {
     }
     // Next, we check if the tzid is somewhere in our tzid map.
     if (isset(self::$map[$tzid])) {
         return new \DateTimeZone(self::$map[$tzid]);
     }
     // Maybe the author was hyper-lazy and just included an offset. We
     // support it, but we aren't happy about it.
     if (preg_match('/^GMT(\\+|-)([0-9]{4})$/', $tzid, $matches)) {
         return new \DateTimeZone('Etc/GMT' . $matches[1] . ltrim(substr($matches[2], 0, 2), '0'));
     }
     if ($vcalendar) {
         // If that didn't work, we will scan VTIMEZONE objects
         foreach ($vcalendar->select('VTIMEZONE') as $vtimezone) {
             if ((string) $vtimezone->TZID === $tzid) {
                 // Some clients add 'X-LIC-LOCATION' with the olson name.
                 if (isset($vtimezone->{'X-LIC-LOCATION'})) {
                     $lic = (string) $vtimezone->{'X-LIC-LOCATION'};
                     // Libical generators may specify strings like
                     // "SystemV/EST5EDT". For those we must remove the
                     // SystemV part.
                     if (substr($lic, 0, 8) === 'SystemV/') {
                         $lic = substr($lic, 8);
                     }
                     try {
                         return new \DateTimeZone($lic);
                     } catch (\Exception $e) {
                     }
                 }
                 // Microsoft may add a magic number, which we also have an
                 // answer for.
                 if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
                     $cdoId = (int) $vtimezone->{'X-MICROSOFT-CDO-TZID'}->getValue();
                     // 2 can mean both Europe/Lisbon and Europe/Sarajevo.
                     if ($cdoId === 2 && strpos((string) $vtimezone->TZID, 'Sarajevo') !== false) {
                         return new \DateTimeZone('Europe/Sarajevo');
                     }
                     if (isset(self::$microsoftExchangeMap[$cdoId])) {
                         return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
                     }
                 }
             }
         }
     }
     if ($failIfUncertain) {
         throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: ' . $tzid);
     }
     // If we got all the way here, we default to UTC.
     return new \DateTimeZone(date_default_timezone_get());
 }
예제 #3
0
 /**
  * This method will try to find out the correct timezone for an iCalendar
  * date-time value.
  *
  * You must pass the contents of the TZID parameter, as well as the full
  * calendar.
  *
  * If the lookup fails, this method will return the default PHP timezone
  * (as configured using date_default_timezone_set, or the date.timezone ini
  * setting).
  *
  * Alternatively, if $failIfUncertain is set to true, it will throw an
  * exception if we cannot accurately determine the timezone.
  *
  * @param string $tzid
  * @param Sabre\VObject\Component $vcalendar
  * @return DateTimeZone
  */
 public static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false)
 {
     // First we will just see if the tzid is a support timezone identifier.
     //
     // The only exception is if the timezone starts with (. This is to
     // handle cases where certain microsoft products generate timezone
     // identifiers that for instance look like:
     //
     // (GMT+01.00) Sarajevo/Warsaw/Zagreb
     //
     // Since PHP 5.5.10, the first bit will be used as the timezone and
     // this method will return just GMT+01:00. This is wrong, because it
     // doesn't take DST into account.
     if ($tzid[0] !== '(') {
         // PHP has a bug that logs PHP warnings even it shouldn't:
         // https://bugs.php.net/bug.php?id=67881
         //
         // That's why we're checking if we'll be able to successfull instantiate
         // \DateTimeZone() before doing so. Otherwise we could simply instantiate
         // and catch the exception.
         $tzIdentifiers = \DateTimeZone::listIdentifiers();
         try {
             if (in_array($tzid, $tzIdentifiers) || preg_match('/^GMT(\\+|-)([0-9]{4})$/', $tzid, $matches) || in_array($tzid, self::getIdentifiersBC())) {
                 return new \DateTimeZone($tzid);
             }
         } catch (\Exception $e) {
         }
     }
     self::loadTzMaps();
     // Next, we check if the tzid is somewhere in our tzid map.
     if (isset(self::$map[$tzid])) {
         return new \DateTimeZone(self::$map[$tzid]);
     }
     // Maybe the author was hyper-lazy and just included an offset. We
     // support it, but we aren't happy about it.
     if (preg_match('/^GMT(\\+|-)([0-9]{4})$/', $tzid, $matches)) {
         // Note that the path in the source will never be taken from PHP 5.5.10
         // onwards. PHP 5.5.10 supports the "GMT+0100" style of format, so it
         // already gets returned early in this function. Once we drop support
         // for versions under PHP 5.5.10, this bit can be taken out of the
         // source.
         // @codeCoverageIgnoreStart
         return new \DateTimeZone('Etc/GMT' . $matches[1] . ltrim(substr($matches[2], 0, 2), '0'));
         // @codeCoverageIgnoreEnd
     }
     if ($vcalendar) {
         // If that didn't work, we will scan VTIMEZONE objects
         foreach ($vcalendar->select('VTIMEZONE') as $vtimezone) {
             if ((string) $vtimezone->TZID === $tzid) {
                 // Some clients add 'X-LIC-LOCATION' with the olson name.
                 if (isset($vtimezone->{'X-LIC-LOCATION'})) {
                     $lic = (string) $vtimezone->{'X-LIC-LOCATION'};
                     // Libical generators may specify strings like
                     // "SystemV/EST5EDT". For those we must remove the
                     // SystemV part.
                     if (substr($lic, 0, 8) === 'SystemV/') {
                         $lic = substr($lic, 8);
                     }
                     return self::getTimeZone($lic, null, $failIfUncertain);
                 }
                 // Microsoft may add a magic number, which we also have an
                 // answer for.
                 if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
                     $cdoId = (int) $vtimezone->{'X-MICROSOFT-CDO-TZID'}->getValue();
                     // 2 can mean both Europe/Lisbon and Europe/Sarajevo.
                     if ($cdoId === 2 && strpos((string) $vtimezone->TZID, 'Sarajevo') !== false) {
                         return new \DateTimeZone('Europe/Sarajevo');
                     }
                     if (isset(self::$microsoftExchangeMap[$cdoId])) {
                         return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
                     }
                 }
             }
         }
     }
     if ($failIfUncertain) {
         throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: ' . $tzid);
     }
     // If we got all the way here, we default to UTC.
     return new \DateTimeZone(date_default_timezone_get());
 }
예제 #4
0
 /**
  * Creates the iterator
  *
  * You should pass a VCALENDAR component, as well as the UID of the event
  * we're going to traverse.
  *
  * @param Component $vcal
  * @param string|null $uid
  */
 public function __construct(Component $vcal, $uid = null)
 {
     if (is_null($uid)) {
         if ($vcal instanceof Component\VCalendar) {
             throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well');
         }
         $components = array($vcal);
         $uid = (string) $vcal->uid;
     } else {
         $components = $vcal->select('VEVENT');
     }
     foreach ($components as $component) {
         if ((string) $component->uid == $uid) {
             if (isset($component->{'RECURRENCE-ID'})) {
                 $this->overriddenEvents[$component->DTSTART->getDateTime()->getTimeStamp()] = $component;
                 $this->overriddenDates[] = $component->{'RECURRENCE-ID'}->getDateTime();
             } else {
                 $this->baseEvent = $component;
             }
         }
     }
     if (!$this->baseEvent) {
         // No base event was found. CalDAV does allow cases where only
         // overridden instances are stored.
         //
         // In this barticular case, we're just going to grab the first
         // event and use that instead. This may not always give the
         // desired result.
         if (!count($this->overriddenEvents)) {
             throw new \InvalidArgumentException('Could not find an event with uid: ' . $uid);
         }
         ksort($this->overriddenEvents, SORT_NUMERIC);
         $this->baseEvent = array_shift($this->overriddenEvents);
     }
     $this->startDate = clone $this->baseEvent->DTSTART->getDateTime();
     $this->endDate = null;
     if (isset($this->baseEvent->DTEND)) {
         $this->endDate = clone $this->baseEvent->DTEND->getDateTime();
     } else {
         $this->endDate = clone $this->startDate;
         if (isset($this->baseEvent->DURATION)) {
             $this->endDate->add(DateTimeParser::parse((string) $this->baseEvent->DURATION));
         } elseif (!$this->baseEvent->DTSTART->hasTime()) {
             $this->endDate->modify('+1 day');
         }
     }
     $this->currentDate = clone $this->startDate;
     $rrule = $this->baseEvent->RRULE;
     // If no rrule was specified, we create a default setting
     if (!$rrule) {
         $this->frequency = 'daily';
         $this->count = 1;
     } else {
         foreach ($rrule->getParts() as $key => $value) {
             switch ($key) {
                 case 'FREQ':
                     if (!in_array(strtolower($value), array('secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'))) {
                         throw new \InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value));
                     }
                     $this->frequency = strtolower($value);
                     break;
                 case 'UNTIL':
                     $this->until = DateTimeParser::parse($value);
                     // In some cases events are generated with an UNTIL=
                     // parameter before the actual start of the event.
                     //
                     // Not sure why this is happening. We assume that the
                     // intention was that the event only recurs once.
                     //
                     // So we are modifying the parameter so our code doesn't
                     // break.
                     if ($this->until < $this->baseEvent->DTSTART->getDateTime()) {
                         $this->until = $this->baseEvent->DTSTART->getDateTime();
                     }
                     break;
                 case 'COUNT':
                     $this->count = (int) $value;
                     break;
                 case 'INTERVAL':
                     $this->interval = (int) $value;
                     if ($this->interval < 1) {
                         throw new \InvalidArgumentException('INTERVAL in RRULE must be a positive integer!');
                     }
                     break;
                 case 'BYSECOND':
                     $this->bySecond = (array) $value;
                     break;
                 case 'BYMINUTE':
                     $this->byMinute = (array) $value;
                     break;
                 case 'BYHOUR':
                     $this->byHour = (array) $value;
                     break;
                 case 'BYDAY':
                     $this->byDay = (array) $value;
                     break;
                 case 'BYMONTHDAY':
                     $this->byMonthDay = (array) $value;
                     break;
                 case 'BYYEARDAY':
                     $this->byYearDay = (array) $value;
                     break;
                 case 'BYWEEKNO':
                     $this->byWeekNo = (array) $value;
                     break;
                 case 'BYMONTH':
                     $this->byMonth = (array) $value;
                     break;
                 case 'BYSETPOS':
                     $this->bySetPos = (array) $value;
                     break;
                 case 'WKST':
                     $this->weekStart = strtoupper($value);
                     break;
             }
         }
     }
     // Parsing exception dates
     if (isset($this->baseEvent->EXDATE)) {
         foreach ($this->baseEvent->EXDATE as $exDate) {
             foreach (explode(',', (string) $exDate) as $exceptionDate) {
                 $this->exceptionDates[] = DateTimeParser::parse($exceptionDate, $this->startDate->getTimeZone());
             }
         }
     }
 }
 /**
  * Creates the iterator
  *
  * You should pass a VCALENDAR component, as well as the UID of the event
  * we're going to traverse.
  *
  * @param Component $vcal
  * @param string|null $uid
  */
 public function __construct(Component $vcal, $uid = null)
 {
     if (is_null($uid)) {
         if ($vcal->name === 'VCALENDAR') {
             throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well');
         }
         $components = array($vcal);
         $uid = (string) $vcal->uid;
     } else {
         $components = $vcal->select('VEVENT');
     }
     foreach ($components as $component) {
         if ((string) $component->uid == $uid) {
             if (isset($component->{'RECURRENCE-ID'})) {
                 $this->overriddenEvents[$component->DTSTART->getDateTime()->getTimeStamp()] = $component;
                 $this->overriddenDates[] = $component->{'RECURRENCE-ID'}->getDateTime();
             } else {
                 $this->baseEvent = $component;
             }
         }
     }
     if (!$this->baseEvent) {
         throw new \InvalidArgumentException('Could not find a base event with uid: ' . $uid);
     }
     $this->startDate = clone $this->baseEvent->DTSTART->getDateTime();
     $this->endDate = null;
     if (isset($this->baseEvent->DTEND)) {
         $this->endDate = clone $this->baseEvent->DTEND->getDateTime();
     } else {
         $this->endDate = clone $this->startDate;
         if (isset($this->baseEvent->DURATION)) {
             $this->endDate->add(DateTimeParser::parse($this->baseEvent->DURATION->value));
         } elseif ($this->baseEvent->DTSTART->getDateType() === Property\DateTime::DATE) {
             $this->endDate->modify('+1 day');
         }
     }
     $this->currentDate = clone $this->startDate;
     $rrule = (string) $this->baseEvent->RRULE;
     $parts = explode(';', $rrule);
     // If no rrule was specified, we create a default setting
     if (!$rrule) {
         $this->frequency = 'daily';
         $this->count = 1;
     } else {
         foreach ($parts as $part) {
             list($key, $value) = explode('=', $part, 2);
             switch (strtoupper($key)) {
                 case 'FREQ':
                     if (!in_array(strtolower($value), array('secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'))) {
                         throw new \InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value));
                     }
                     $this->frequency = strtolower($value);
                     break;
                 case 'UNTIL':
                     $this->until = DateTimeParser::parse($value);
                     // In some cases events are generated with an UNTIL=
                     // parameter before the actual start of the event.
                     //
                     // Not sure why this is happening. We assume that the
                     // intention was that the event only recurs once.
                     //
                     // So we are modifying the parameter so our code doesn't
                     // break.
                     if ($this->until < $this->baseEvent->DTSTART->getDateTime()) {
                         $this->until = $this->baseEvent->DTSTART->getDateTime();
                     }
                     break;
                 case 'COUNT':
                     $this->count = (int) $value;
                     break;
                 case 'INTERVAL':
                     $this->interval = (int) $value;
                     if ($this->interval < 1) {
                         throw new \InvalidArgumentException('INTERVAL in RRULE must be a positive integer!');
                     }
                     break;
                 case 'BYSECOND':
                     $this->bySecond = explode(',', $value);
                     break;
                 case 'BYMINUTE':
                     $this->byMinute = explode(',', $value);
                     break;
                 case 'BYHOUR':
                     $this->byHour = explode(',', $value);
                     break;
                 case 'BYDAY':
                     $this->byDay = explode(',', strtoupper($value));
                     break;
                 case 'BYMONTHDAY':
                     $this->byMonthDay = explode(',', $value);
                     break;
                 case 'BYYEARDAY':
                     $this->byYearDay = explode(',', $value);
                     break;
                 case 'BYWEEKNO':
                     $this->byWeekNo = explode(',', $value);
                     break;
                 case 'BYMONTH':
                     $this->byMonth = explode(',', $value);
                     break;
                 case 'BYSETPOS':
                     $this->bySetPos = explode(',', $value);
                     break;
                 case 'WKST':
                     $this->weekStart = strtoupper($value);
                     break;
             }
         }
     }
     // Parsing exception dates
     if (isset($this->baseEvent->EXDATE)) {
         foreach ($this->baseEvent->EXDATE as $exDate) {
             foreach (explode(',', (string) $exDate) as $exceptionDate) {
                 $this->exceptionDates[] = DateTimeParser::parse($exceptionDate, $this->startDate->getTimeZone());
             }
         }
     }
 }