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