Overview

Packages

  • awl
    • caldav-client-v2
    • RRule
  • davical
    • authentication
      • drivers
    • caldav
    • DAViCalSession
    • DAVTicket
    • external-bind
    • feed
    • HTTPAuthSession
    • iSchedule
    • iSchedule-POST
    • logging
    • metrics
    • Principal
    • propfind
    • PublicSession
    • Request
    • Resource
    • tzservice
  • None
  • PHP

Functions

  • expand_timezone_onsets
  • Overview
  • Package
  • Function
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3: * DAViCal Timezone Service handler - capabilitis
  4: *
  5: * @package   davical
  6: * @subpackage   tzservice
  7: * @author    Andrew McMillan <andrew@morphoss.com>
  8: * @copyright Morphoss Ltd
  9: * @license   http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
 10: */
 11: 
 12: require_once('vCalendar.php');
 13: require_once('RRule.php');
 14: 
 15: if ( empty($format) ) $format = 'text/calendar';
 16: if ( $format != 'text/calendar' ) {
 17:   $request->PreconditionFailed(403, 'supported-format', 'This server currently only supports text/calendar format.', 'urn:ietf:params:xml:ns:timezone-service' );
 18: }
 19: 
 20: if ( empty($start) ) $start = sprintf( '%04d-01-01', date('Y'));
 21: if ( empty($end) )   $end   = sprintf( '%04d-12-31', date('Y') + 10);
 22: 
 23: $sql = 'SELECT our_tzno, tzid, active, olson_name, vtimezone, etag, ';
 24: $sql .= 'to_char(last_modified,\'Dy, DD Mon IYYY HH24:MI:SS "GMT"\') AS last_modified ';
 25: $sql .= 'FROM timezones WHERE tzid=:tzid';
 26: $params = array( ':tzid' => $tzid );
 27: $qry = new AwlQuery($sql,$params);
 28: if ( !$qry->Exec() ) exit(1);
 29: if ( $qry->rows() < 1 ) {
 30:   $sql = 'SELECT our_tzno, tzid, active, olson_name, vtimezone, etag, ';
 31:   $sql .= 'to_char(last_modified,\'Dy, DD Mon IYYY HH24:MI:SS "GMT"\') AS last_modified ';
 32:   $sql .= 'FROM timezones JOIN tz_aliases USING(our_tzno) WHERE tzalias=:tzid';
 33:   if ( !$qry->Exec() ) exit(1);
 34:   if ( $qry->rows() < 1 ) $request->DoResponse(404);
 35: }
 36: 
 37: $tz = $qry->Fetch();
 38: 
 39: // define( 'DEBUG_EXPAND', true);
 40: define( 'DEBUG_EXPAND', false );
 41: 
 42: 
 43: /**
 44: * Expand the instances for a STANDARD or DAYLIGHT component of a VTIMEZONE
 45: *
 46: * @param object $vResource is a VCALENDAR with a VTIMEZONE containing components needing expansion
 47: * @param object $range_start A RepeatRuleDateTime which is the beginning of the range for events.
 48: * @param object $range_end A RepeatRuleDateTime which is the end of the range for events.
 49: * @param int $offset_from The offset from UTC in seconds at the onset time.
 50: *
 51: * @return array of onset datetimes with UTC from/to offsets
 52: */
 53: function expand_timezone_onsets( vCalendar $vResource, RepeatRuleDateTime $range_start, RepeatRuleDateTime $range_end ) {
 54:   global $c;
 55:   $vtimezones = $vResource->GetComponents();
 56:   $vtz = $vtimezones[0];
 57:   $components = $vtz->GetComponents();
 58: 
 59:   $instances = array();
 60:   $dtstart = null;
 61:   $is_date = false;
 62:   $has_repeats = false;
 63:   $zone_tz = $vtz->GetPValue('TZID');
 64: 
 65:   foreach( $components AS $k => $comp ) {
 66:     if ( DEBUG_EXPAND ) {
 67:       printf( "Starting TZ expansion for component '%s' in timezone '%s'\n", $comp->GetType(), $zone_tz);
 68:       foreach( $instances AS $k => $v ) {
 69:         print ' : '.$k;
 70:       }
 71:       print "\n";
 72:     }
 73:     $dtstart_prop = $comp->GetProperty('DTSTART');
 74:     if ( !isset($dtstart_prop) ) continue;
 75:     $dtstart = new RepeatRuleDateTime( $dtstart_prop );
 76:     $dtstart->setTimeZone('UTC');
 77:     $offset_from = $comp->GetPValue('TZOFFSETFROM');
 78:     $offset_from = (($offset_from / 100) * 3600) + ((abs($offset_from) % 100) * 60 * ($offset_from < 0 ? -1 : 0));
 79:     $offset_from *= -1;
 80:     $offset_from = "$offset_from seconds";
 81:     dbg_error_log( 'tz/update', "%s of offset\n", $offset_from);
 82:     $dtstart->modify($offset_from);
 83:     $is_date = $dtstart->isDate();
 84:     $instances[$dtstart->UTC('Y-m-d\TH:i:s\Z')] = $comp;
 85:     $rrule = $comp->GetProperty('RRULE');
 86:     $has_repeats = isset($rrule);
 87:     if ( !$has_repeats ) continue;
 88: 
 89:     $recur = $comp->GetProperty('RRULE');
 90:     if ( isset($recur) ) {
 91:       $recur = $recur->Value();
 92:       $this_start = clone($dtstart);
 93:       $rule = new RepeatRule( $this_start, $recur, $is_date );
 94:       $i = 0;
 95:       $result_limit = 1000;
 96:       while( $date = $rule->next() ) {
 97:         $instances[$date->UTC('Y-m-d\TH:i:s\Z')] = $comp;
 98:         if ( $i++ >= $result_limit || $date > $range_end ) break;
 99:       }
100:       if ( DEBUG_EXPAND ) {
101:         print( "After rrule_expand");
102:         foreach( $instances AS $k => $v ) {
103:           print ' : '.$k;
104:         }
105:         print "\n";
106:       }
107:     }
108: 
109:     $properties = $comp->GetProperties('RDATE');
110:     if ( count($properties) ) {
111:       foreach( $properties AS $p ) {
112:         $timezone = $p->GetParameterValue('TZID');
113:         $rdate = $p->Value();
114:         $rdates = explode( ',', $rdate );
115:         foreach( $rdates AS $k => $v ) {
116:           $rdate = new RepeatRuleDateTime( $v, $timezone, $is_date);
117:           if ( $return_floating_times ) $rdate->setAsFloat();
118:           $instances[$rdate->UTC('Y-m-d\TH:i:s\Z')] = $comp;
119:           if ( $rdate > $range_end ) break;
120:         }
121:       }
122: 
123:       if ( DEBUG_EXPAND ) {
124:         print( "After rdate_expand");
125:         foreach( $instances AS $k => $v ) {
126:           print ' : '.$k;
127:         }
128:         print "\n";
129:       }
130:     }
131:   }
132: 
133:   ksort($instances);
134: 
135:   $onsets = array();
136:   $start_utc = $range_start->UTC('Y-m-d\TH:i:s\Z');
137:   $end_utc = $range_end->UTC('Y-m-d\TH:i:s\Z');
138:   foreach( $instances AS $utc => $comp ) {
139:     if ( $utc > $end_utc ) {
140:       if ( DEBUG_EXPAND ) printf( "We're done: $utc is out of the range.\n");
141:       break;
142:     }
143: 
144:     if ( $utc < $start_utc ) {
145:       continue;
146:     }
147:     $onsets[$utc] = array(
148:       'from' => $comp->GetPValue('TZOFFSETFROM'),
149:       'to' => $comp->GetPValue('TZOFFSETTO'),
150:       'name' => $comp->GetPValue('TZNAME'),
151:       'type' => $comp->GetType()
152:     );
153:   }
154: 
155:   return $onsets;
156: }
157: 
158: header( 'ETag: "'.$tz->etag.'"' );
159: header( 'Last-Modified', $tz->last_modified );
160: header('Content-Type: application/xml; charset="utf-8"');
161: 
162: $vtz = new vCalendar($tz->vtimezone);
163: 
164: $response = new XMLDocument(array("urn:ietf:params:xml:ns:timezone-service" => ""));
165: $timezones = $response->NewXMLElement('urn:ietf:params:xml:ns:timezone-service:timezones');
166: $qry = new AwlQuery('SELECT to_char(max(last_modified),\'YYYY-MM-DD"T"HH24:MI:SS"Z"\') AS dtstamp FROM timezones');
167: if ( $qry->Exec('tz/list',__LINE__,__FILE__) && $qry->rows() > 0 ) {
168:   $row = $qry->Fetch();
169:   $timezones->NewElement('dtstamp', $row->dtstamp);
170: }
171: else {
172:   $timezones->NewElement('dtstamp', gmdate('Y-m-d\TH:i:s\Z'));
173: }
174: 
175: $from = new RepeatRuleDateTime($start);
176: $until = new RepeatRuleDateTime($end);
177: 
178: $observances = expand_timezone_onsets($vtz, $from, $until);
179: $tzdata = array();
180: $tzdata[] = new XMLElement( 'tzid', $tzid );
181: $tzdata[] = new XMLElement( 'calscale', 'Gregorian' );
182: 
183: foreach( $observances AS $onset => $details ) {
184:   $tzdata[] = new XMLElement( 'observance', array(
185:     new XMLElement('name', (empty($details['name']) ? $details['type'] : $details['name'] ) ),
186:     new XMLElement('onset', $onset ),
187:     new XMLElement('utc-offset-from', substr($details['from'],0,-2).':'.substr($details['from'],-2) ),
188:     new XMLElement('utc-offset-to', substr($details['to'],0,-2).':'.substr($details['to'],-2) )
189:   ));
190: }
191: 
192: $timezones->NewElement('tzdata', $tzdata );
193: echo $response->Render($timezones);
194: 
195: exit(0);
196: 
DAViCal API documentation generated by ApiGen 2.8.0