| 1 |
<?php |
| 2 |
/** |
| 3 |
* Zap Calendar ical Helper Class |
| 4 |
* |
| 5 |
* @copyright Copyright (C) 2006 - 2016 by Dan Cogliano |
| 6 |
* @license GNU General Public License version 2 or later; see LICENSE.txt |
| 7 |
*/ |
| 8 |
|
| 9 |
// no direct access |
| 10 |
defined('_ZAPCAL') or die( 'Restricted access' ); |
| 11 |
|
| 12 |
/** |
| 13 |
* Object for storing an unfolded iCalendar line |
| 14 |
* |
| 15 |
* The ZCiCalDataNode class contains data from an unfolded iCalendar line |
| 16 |
* |
| 17 |
*/ |
| 18 |
|
| 19 |
class ZCiCalDataNode { |
| 20 |
/** |
| 21 |
* The name of the node |
| 22 |
* |
| 23 |
* @var string |
| 24 |
*/ |
| 25 |
var $name = ""; |
| 26 |
|
| 27 |
/** |
| 28 |
* Node parameters (before the colon ":") |
| 29 |
* |
| 30 |
* @var array |
| 31 |
*/ |
| 32 |
var $parameter=array(); |
| 33 |
|
| 34 |
/** |
| 35 |
* Node values (after the colon ":") |
| 36 |
* |
| 37 |
* @var array |
| 38 |
*/ |
| 39 |
var $value=array(); |
| 40 |
|
| 41 |
/** |
| 42 |
* Create an object from an unfolded iCalendar line |
| 43 |
* |
| 44 |
* @param string $line An unfolded iCalendar line |
| 45 |
* |
| 46 |
* @return void |
| 47 |
* |
| 48 |
*/ |
| 49 |
function ZCiCalDataNode( $line ) { |
| 50 |
//echo "ZCiCalDataNode($line)<br/>\n"; |
| 51 |
//separate line into parameters and value |
| 52 |
// look for colon separating name or parameter and value |
| 53 |
// first change any escaped colons temporarily to make it easier |
| 54 |
$tline = str_replace("\\:", "`~", $line); |
| 55 |
// see if first colon is inside a quoted string |
| 56 |
$i = 0; |
| 57 |
$datafind = false; |
| 58 |
$inquotes = false; |
| 59 |
while(!$datafind && ($i < strlen($tline))) { |
| 60 |
//echo "$i: " . $tline{$i} . ", ord() = " . ord($tline{$i}) . "<br>\n"; |
| 61 |
if(!$inquotes && $tline{$i} == ':') |
| 62 |
$datafind=true; |
| 63 |
else{ |
| 64 |
$i += 1; |
| 65 |
if(substr($tline,$i,1) == '"') |
| 66 |
$inquotes = !$inquotes; |
| 67 |
} |
| 68 |
} |
| 69 |
if($datafind){ |
| 70 |
$value = str_replace("`~","\\:",substr($line,$i+1)); |
| 71 |
// fix escaped characters (don't see double quotes in spec but Apple apparently uses it in iCal) |
| 72 |
$value = str_replace(array('\\N' , '\\n', '\\"' ), array("\n", "\n" , '"'), $value); |
| 73 |
$tvalue = str_replace("\\,", "`~", $value); |
| 74 |
//echo "value: " . $tvalue . "<br>\n"; |
| 75 |
$tvalue = explode(",",$tvalue); |
| 76 |
$value = str_replace("`~","\\,",$tvalue); |
| 77 |
$this->value = $value; |
| 78 |
} |
| 79 |
|
| 80 |
$parameter = trim(substr($line,0,$i)); |
| 81 |
|
| 82 |
$parameter = str_replace("\\;", "`~", $parameter); |
| 83 |
$parameters = explode(";", $parameter); |
| 84 |
$parameters = str_replace("`~", "\\;", $parameters); |
| 85 |
$this->name = array_shift($parameters); |
| 86 |
foreach($parameters as $parameter){ |
| 87 |
$pos = strpos($parameter,"="); |
| 88 |
if($pos > 0){ |
| 89 |
$param = substr($parameter,0,$pos); |
| 90 |
$paramvalue = substr($parameter,$pos+1); |
| 91 |
$tvalue = str_replace("\\,", "`~", $paramvalue); |
| 92 |
//$tvalue = explode(",",$tvalue); |
| 93 |
$paramvalue = str_replace("`~","\\,",$tvalue); |
| 94 |
$this->parameter[strtolower($param)] = $paramvalue; |
| 95 |
//$this->paramvalue[] = $paramvalue; |
| 96 |
} |
| 97 |
} |
| 98 |
} |
| 99 |
|
| 100 |
/** |
| 101 |
* getName() |
| 102 |
* |
| 103 |
* Return the name of the object |
| 104 |
* |
| 105 |
* @return string |
| 106 |
*/ |
| 107 |
function getName(){ |
| 108 |
return $this->name; |
| 109 |
} |
| 110 |
|
| 111 |
/** |
| 112 |
* Get $ith parameter from array |
| 113 |
* @param int $i |
| 114 |
* |
| 115 |
* @return var |
| 116 |
*/ |
| 117 |
function getParameter($i){ |
| 118 |
return $this->parameter[$i]; |
| 119 |
} |
| 120 |
|
| 121 |
/** |
| 122 |
* Get parameter array |
| 123 |
* |
| 124 |
* @return array |
| 125 |
*/ |
| 126 |
function getParameters(){ |
| 127 |
return $this->parameter; |
| 128 |
} |
| 129 |
|
| 130 |
/** |
| 131 |
* Get comma separated values |
| 132 |
* |
| 133 |
* @return string |
| 134 |
*/ |
| 135 |
function getValues(){ |
| 136 |
return implode(",",$this->value); |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
/** |
| 141 |
* Object for storing a list of unfolded iCalendar lines (ZCiCalDataNode objects) |
| 142 |
* |
| 143 |
*/ |
| 144 |
|
| 145 |
class ZCiCalNode { |
| 146 |
var $name=""; |
| 147 |
var $parentnode=null; |
| 148 |
var $child= array(); |
| 149 |
var $data= array(); |
| 150 |
var $next=null; |
| 151 |
var $prev=null; |
| 152 |
|
| 153 |
/** |
| 154 |
* Create ZCiCalNode |
| 155 |
* |
| 156 |
* @param string $_name Name of node |
| 157 |
* |
| 158 |
* @param object $_parent Parent node for this node |
| 159 |
* |
| 160 |
* @param bool $first Is this the first child for this parent? |
| 161 |
*/ |
| 162 |
function ZCiCalNode( $_name, & $_parent, $first = false) { |
| 163 |
$this->name = $_name; |
| 164 |
$this->parentnode = $_parent; |
| 165 |
if($_parent != null){ |
| 166 |
if(count($this->parentnode->child) > 0) { |
| 167 |
if($first) |
| 168 |
{ |
| 169 |
$first = & $this->parentnode->child[0]; |
| 170 |
$first->prev = & $this; |
| 171 |
$this->next = & $first; |
| 172 |
} |
| 173 |
else |
| 174 |
{ |
| 175 |
$prev =& $this->parentnode->child[count($this->parentnode->child)-1]; |
| 176 |
$prev->next =& $this; |
| 177 |
$this->prev =& $prev; |
| 178 |
} |
| 179 |
} |
| 180 |
if($first) |
| 181 |
{ |
| 182 |
array_unshift($this->parentnode->child, $this); |
| 183 |
} |
| 184 |
else |
| 185 |
{ |
| 186 |
$this->parentnode->child[] =& $this; |
| 187 |
} |
| 188 |
} |
| 189 |
/* |
| 190 |
echo "creating " . $this->getName(); |
| 191 |
if($_parent != null) |
| 192 |
echo " child of " . $_parent->getName() . "/" . count($this->parentnode->child); |
| 193 |
echo "<br/>"; |
| 194 |
*/ |
| 195 |
} |
| 196 |
|
| 197 |
/** |
| 198 |
* Return the name of the object |
| 199 |
* |
| 200 |
* @return string |
| 201 |
*/ |
| 202 |
function getName() { |
| 203 |
return $this->name; |
| 204 |
} |
| 205 |
|
| 206 |
/** |
| 207 |
* Add node to list |
| 208 |
* |
| 209 |
* @param object $node |
| 210 |
* |
| 211 |
*/ |
| 212 |
function addNode($node) { |
| 213 |
$this->data[$node->getName()] = $node; |
| 214 |
} |
| 215 |
|
| 216 |
/** |
| 217 |
* Get Attribute |
| 218 |
* |
| 219 |
* @param int $i array id of attribute to get |
| 220 |
* |
| 221 |
* @return string |
| 222 |
*/ |
| 223 |
function getAttrib($i) { |
| 224 |
return $this->attrib[$i]; |
| 225 |
} |
| 226 |
|
| 227 |
/** |
| 228 |
* Set Attribute |
| 229 |
* |
| 230 |
* @param string $value value of attribute to set |
| 231 |
* |
| 232 |
*/ |
| 233 |
function setAttrib($value) { |
| 234 |
$this->attrib[] = $value; |
| 235 |
} |
| 236 |
|
| 237 |
/** |
| 238 |
* Get the parent object of this object |
| 239 |
* |
| 240 |
* @return object parent of this object |
| 241 |
*/ |
| 242 |
function &getParent() { |
| 243 |
return $this->parentnode; |
| 244 |
} |
| 245 |
|
| 246 |
/** |
| 247 |
* Get the first child of this object |
| 248 |
* |
| 249 |
* @return object The first child |
| 250 |
*/ |
| 251 |
function &getFirstChild(){ |
| 252 |
static $nullguard = null; |
| 253 |
if(count($this->child) > 0) { |
| 254 |
//echo "moving from " . $this->getName() . " to " . $this->child[0]->getName() . "<br/>"; |
| 255 |
return $this->child[0]; |
| 256 |
} |
| 257 |
else |
| 258 |
return $nullguard; |
| 259 |
} |
| 260 |
|
| 261 |
/** |
| 262 |
* Print object tree in HTML for debugging purposes |
| 263 |
* |
| 264 |
* @param object $node select part of tree to print, or leave blank for full tree |
| 265 |
* |
| 266 |
* @param int $level Level of recursion (usually leave this blank) |
| 267 |
* |
| 268 |
* @return string - HTML formatted display of object tree |
| 269 |
*/ |
| 270 |
function printTree(& $node=null, $level=1){ |
| 271 |
$level += 1; |
| 272 |
$html = ""; |
| 273 |
if($node == null) |
| 274 |
$node = $this->parentnode; |
| 275 |
if($level > 5) |
| 276 |
{ |
| 277 |
die("levels nested too deep<br/>\n"); |
| 278 |
//return; |
| 279 |
} |
| 280 |
for($i = 0 ; $i < $level; $i ++) |
| 281 |
$html .= "+"; |
| 282 |
$html .= $node->getName() . "<br/>\n"; |
| 283 |
foreach ($node->child as $c){ |
| 284 |
$html .= $node->printTree($c,$level); |
| 285 |
} |
| 286 |
$level -= 1; |
| 287 |
return $html; |
| 288 |
} |
| 289 |
|
| 290 |
/** |
| 291 |
* export tree to icalendar format |
| 292 |
* |
| 293 |
* @param object $node Top level node to export |
| 294 |
* |
| 295 |
* @param int $level Level of recursion (usually leave this blank) |
| 296 |
* |
| 297 |
* @return string iCalendar formatted output |
| 298 |
*/ |
| 299 |
function export(& $node=null, $level=0){ |
| 300 |
$txtstr = ""; |
| 301 |
if($node == null) |
| 302 |
$node = $this; |
| 303 |
if($level > 5) |
| 304 |
{ |
| 305 |
//die("levels nested too deep<br/>\n"); |
| 306 |
throw new Exception("levels nested too deep"); |
| 307 |
} |
| 308 |
$txtstr .= "BEGIN:" . $node->getName() . "\r\n"; |
| 309 |
foreach ($node->data as $d){ |
| 310 |
$p = ""; |
| 311 |
$params = @$d->getParameters(); |
| 312 |
if(count($params) > 0) |
| 313 |
{ |
| 314 |
foreach($params as $key => $value){ |
| 315 |
$p .= ";" . strtoupper($key) . "=" . $value; |
| 316 |
} |
| 317 |
} |
| 318 |
$values = $d->getValues(); |
| 319 |
// don't think we need this, Sunbird does not like it in the EXDATE field |
| 320 |
//$values = str_replace(",", "\\,", $values); |
| 321 |
|
| 322 |
$line = $d->getName() . $p . ":" . $values; |
| 323 |
$line = str_replace(array("<br>","<BR>","<br/>","<BR/"),"\\n",$line); |
| 324 |
$line = str_replace(array("\r\n","\n\r","\n","\r"),'\n',$line); |
| 325 |
//$line = str_replace(array(',',';','\\'), array('\\,','\\;','\\\\'),$line); |
| 326 |
//$line =strip_tags($line); |
| 327 |
$linecount = 0; |
| 328 |
while (strlen($line) > 0) { |
| 329 |
$linewidth = ($linecount == 0? 75 : 74); |
| 330 |
$linesize = (strlen($line) > $linewidth? $linewidth: strlen($line)); |
| 331 |
if($linecount > 0) |
| 332 |
$txtstr .= " "; |
| 333 |
$txtstr .= substr($line,0,$linesize) . "\r\n"; |
| 334 |
$linecount += 1; |
| 335 |
$line = substr($line,$linewidth); |
| 336 |
} |
| 337 |
//echo $line . "\n"; |
| 338 |
} |
| 339 |
foreach ($node->child as $c){ |
| 340 |
$txtstr .= $node->export($c,$level + 1); |
| 341 |
} |
| 342 |
$txtstr .= "END:" . $node->getName() . "\r\n"; |
| 343 |
return $txtstr; |
| 344 |
} |
| 345 |
|
| 346 |
} |
| 347 |
|
| 348 |
/** |
| 349 |
* |
| 350 |
* The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes. |
| 351 |
* |
| 352 |
*/ |
| 353 |
class ZCiCal { |
| 354 |
var $tree=null; |
| 355 |
var $curnode=null; |
| 356 |
|
| 357 |
/** |
| 358 |
* The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes. |
| 359 |
* |
| 360 |
* use maxevents and startevent to read events in multiple passes (to save memory) |
| 361 |
* |
| 362 |
* @param string $data icalendar feed string (empty if creating new feed) |
| 363 |
* |
| 364 |
* @param int $maxevents maximum # of events to read |
| 365 |
* |
| 366 |
* @param int $startevent starting event to read |
| 367 |
* |
| 368 |
* @return void |
| 369 |
* |
| 370 |
* |
| 371 |
*/ |
| 372 |
function ZCiCal ($data = "", $maxevents = 1000000, $startevent = 0) { |
| 373 |
|
| 374 |
if($data != ""){ |
| 375 |
// unfold lines |
| 376 |
// first change all eol chars to "\n" |
| 377 |
$data = str_replace(array("\r\n", "\n\r", "\n", "\r"), "\n", $data); |
| 378 |
// now unfold lines |
| 379 |
//$data = str_replace(array("\n ", "\n "),"!?", $data); |
| 380 |
$data = str_replace(array("\n ", "\n "),"", $data); |
| 381 |
// replace special iCal chars |
| 382 |
$data = str_replace(array("\\\\","\,"),array("\\",","), $data); |
| 383 |
|
| 384 |
// parse each line |
| 385 |
$lines = explode("\n", $data); |
| 386 |
|
| 387 |
//echo $data; |
| 388 |
//exit; |
| 389 |
$linecount = 0; |
| 390 |
$eventcount = 0; |
| 391 |
$eventpos = 0; |
| 392 |
foreach($lines as $line) { |
| 393 |
//$line = str_replace("!?", "\n", $line); // add nl back into descriptions |
| 394 |
// echo ($linecount + 1) . ": " . $line . "<br/>"; |
| 395 |
if(substr($line,0,6) == "BEGIN:") { |
| 396 |
// start new object |
| 397 |
$name = substr($line,6); |
| 398 |
if($name == "VEVENT") |
| 399 |
{ |
| 400 |
if($eventcount < $maxevents && $eventpos >= $startevent) |
| 401 |
{ |
| 402 |
$this->curnode = new ZCiCalNode($name, $this->curnode); |
| 403 |
if($this->tree == null) |
| 404 |
$this->tree = $this->curnode; |
| 405 |
} |
| 406 |
} |
| 407 |
else |
| 408 |
{ |
| 409 |
$this->curnode = new ZCiCalNode($name, $this->curnode); |
| 410 |
if($this->tree == null) |
| 411 |
$this->tree = $this->curnode; |
| 412 |
} |
| 413 |
//echo "new node: " . $this->curnode->name . "<br/>\n"; |
| 414 |
/* |
| 415 |
if($this->curnode->getParent() != null) |
| 416 |
echo "parent of " . $this->curnode->getName() . " is " . $this->curnode->getParent()->getName() . "<br/>"; |
| 417 |
else |
| 418 |
echo "parent of " . $this->curnode->getName() . " is null<br/>"; |
| 419 |
*/ |
| 420 |
} |
| 421 |
else if(substr($line,0,4) == "END:") { |
| 422 |
$name = substr($line,4); |
| 423 |
if($name == "VEVENT") |
| 424 |
{ |
| 425 |
if($eventcount < $maxevents && $eventpos >= $startevent) |
| 426 |
{ |
| 427 |
$eventcount++; |
| 428 |
if($this->curnode->getName() != $name) { |
| 429 |
//panic, mismatch in iCal structure |
| 430 |
//die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead"); |
| 431 |
throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead"); |
| 432 |
} |
| 433 |
if($this->curnode->getParent() != null) { |
| 434 |
//echo "moving up from " . $this->curnode->getName() ; |
| 435 |
$this->curnode = & $this->curnode->getParent(); |
| 436 |
//echo " to " . $this->curnode->getName() . "<br/>"; |
| 437 |
//echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>"; |
| 438 |
} |
| 439 |
} |
| 440 |
$eventpos++; |
| 441 |
} |
| 442 |
else |
| 443 |
{ |
| 444 |
if($this->curnode->getName() != $name) { |
| 445 |
//panic, mismatch in iCal structure |
| 446 |
//die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead"); |
| 447 |
throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead"); |
| 448 |
} |
| 449 |
if($this->curnode->getParent() != null) { |
| 450 |
//echo "moving up from " . $this->curnode->getName() ; |
| 451 |
$this->curnode = & $this->curnode->getParent(); |
| 452 |
//echo " to " . $this->curnode->getName() . "<br/>"; |
| 453 |
//echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>"; |
| 454 |
} |
| 455 |
} |
| 456 |
} |
| 457 |
else { |
| 458 |
$datanode = new ZCiCalDataNode($line); |
| 459 |
if($this->curnode->getName() == "VEVENT") |
| 460 |
{ |
| 461 |
if($eventcount < $maxevents && $eventpos >= $startevent) |
| 462 |
{ |
| 463 |
if($datanode->getName() == "EXDATE") |
| 464 |
{ |
| 465 |
if(!array_key_exists($datanode->getName(),$this->curnode->data)) |
| 466 |
{ |
| 467 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 468 |
} |
| 469 |
else |
| 470 |
{ |
| 471 |
$this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0]; |
| 472 |
} |
| 473 |
} |
| 474 |
else |
| 475 |
{ |
| 476 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 477 |
} |
| 478 |
} |
| 479 |
} |
| 480 |
else |
| 481 |
{ |
| 482 |
if($datanode->getName() == "EXDATE") |
| 483 |
{ |
| 484 |
if(!array_key_exists($datanode->getName(),$this->curnode->data)) |
| 485 |
{ |
| 486 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 487 |
} |
| 488 |
else |
| 489 |
{ |
| 490 |
$this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0]; |
| 491 |
} |
| 492 |
} |
| 493 |
else |
| 494 |
{ |
| 495 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 496 |
} |
| 497 |
} |
| 498 |
} |
| 499 |
$linecount++; |
| 500 |
} |
| 501 |
} |
| 502 |
else { |
| 503 |
$name = "VCALENDAR"; |
| 504 |
$this->curnode = new ZCiCalNode($name, $this->curnode); |
| 505 |
$this->tree = $this->curnode; |
| 506 |
$datanode = new ZCiCalDataNode("VERSION:2.0"); |
| 507 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 508 |
|
| 509 |
$datanode = new ZCiCalDataNode("PRODID:-//ZContent.net//Zap Calendar 1.0//EN"); |
| 510 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 511 |
$datanode = new ZCiCalDataNode("CALSCALE:GREGORIAN"); |
| 512 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 513 |
$datanode = new ZCiCalDataNode("METHOD:PUBLISH"); |
| 514 |
$this->curnode->data[$datanode->getName()] = $datanode; |
| 515 |
} |
| 516 |
} |
| 517 |
|
| 518 |
/** |
| 519 |
* CountEvents() |
| 520 |
* |
| 521 |
* Return the # of VEVENTs in the object |
| 522 |
* |
| 523 |
* @return int |
| 524 |
*/ |
| 525 |
|
| 526 |
function countEvents() { |
| 527 |
$count = 0; |
| 528 |
if(isset($this->tree->child)){ |
| 529 |
foreach($this->tree->child as $child){ |
| 530 |
if($child->getName() == "VEVENT") |
| 531 |
$count++; |
| 532 |
} |
| 533 |
} |
| 534 |
return $count; |
| 535 |
} |
| 536 |
|
| 537 |
/** |
| 538 |
* CountVenues() |
| 539 |
* |
| 540 |
* Return the # of VVENUEs in the object |
| 541 |
* |
| 542 |
* @return int |
| 543 |
*/ |
| 544 |
|
| 545 |
function countVenues() { |
| 546 |
$count = 0; |
| 547 |
if(isset($this->tree->child)){ |
| 548 |
foreach($this->tree->child as $child){ |
| 549 |
if($child->getName() == "VVENUE") |
| 550 |
$count++; |
| 551 |
} |
| 552 |
} |
| 553 |
return $count; |
| 554 |
} |
| 555 |
|
| 556 |
/** |
| 557 |
* Export object to string |
| 558 |
* |
| 559 |
* This function exports all objects to an iCalendar string |
| 560 |
* |
| 561 |
* @return string an iCalendar formatted string |
| 562 |
*/ |
| 563 |
|
| 564 |
function export() { |
| 565 |
return $this->tree->export($this->tree); |
| 566 |
} |
| 567 |
|
| 568 |
/** |
| 569 |
* Get first event in object list |
| 570 |
* Use getNextEvent() to navigate through list |
| 571 |
* |
| 572 |
* @return object The first event, or null |
| 573 |
*/ |
| 574 |
function &getFirstEvent() { |
| 575 |
static $nullguard = null; |
| 576 |
if ($this->countEvents() > 0){ |
| 577 |
$child = $this->tree->child[0]; |
| 578 |
$event=false; |
| 579 |
while(!$event && $child != null){ |
| 580 |
if($child->getName() == "VEVENT") |
| 581 |
$event = true; |
| 582 |
else |
| 583 |
$child = $child->next; |
| 584 |
} |
| 585 |
return $child; |
| 586 |
} |
| 587 |
else |
| 588 |
return $nullguard; |
| 589 |
} |
| 590 |
|
| 591 |
/** |
| 592 |
* Get next event in object list |
| 593 |
* |
| 594 |
* @param object $event The current event object |
| 595 |
* |
| 596 |
* @return object Returns the next event or null if past last event |
| 597 |
*/ |
| 598 |
function &getNextEvent($event){ |
| 599 |
do{ |
| 600 |
$event = $event->next; |
| 601 |
} while($event != null && $event->getName() != "VEVENT"); |
| 602 |
return $event; |
| 603 |
} |
| 604 |
|
| 605 |
/** |
| 606 |
* Get first venue in object list |
| 607 |
* Use getNextVenue() to navigate through list |
| 608 |
* |
| 609 |
* @return object The first venue, or null |
| 610 |
*/ |
| 611 |
function &getFirstVenue() { |
| 612 |
static $nullguard = null; |
| 613 |
if ($this->countVenues() > 0){ |
| 614 |
$child = $this->tree->child[0]; |
| 615 |
$event=false; |
| 616 |
while(!$event && $child != null){ |
| 617 |
if($child->getName() == "VVENUE") |
| 618 |
$event = true; |
| 619 |
else |
| 620 |
$child = $child->next; |
| 621 |
} |
| 622 |
return $child; |
| 623 |
} |
| 624 |
else |
| 625 |
return $nullguard; |
| 626 |
} |
| 627 |
|
| 628 |
/** |
| 629 |
* Get next venue in object list |
| 630 |
* |
| 631 |
* @param object $venue The current venue object |
| 632 |
* |
| 633 |
* @return object Returns the next venue or null if past last venue |
| 634 |
*/ |
| 635 |
function &getNextVenue($venue){ |
| 636 |
do{ |
| 637 |
$venue = $venue->next; |
| 638 |
} while($venue != null && $venue->getName() != "VVENUE"); |
| 639 |
return $venue; |
| 640 |
} |
| 641 |
|
| 642 |
/** |
| 643 |
* Get first child in object list |
| 644 |
* Use getNextSibling() and getPreviousSibling() to navigate through list |
| 645 |
* |
| 646 |
* @param object $thisnode The parent object |
| 647 |
* |
| 648 |
* @return object The child object |
| 649 |
*/ |
| 650 |
function &getFirstChild(& $thisnode){ |
| 651 |
$nullvalue = null; |
| 652 |
if(count($thisnode->child) > 0) { |
| 653 |
//echo "moving from " . $thisnode->getName() . " to " . $thisnode->child[0]->getName() . "<br/>"; |
| 654 |
return $thisnode->child[0]; |
| 655 |
} |
| 656 |
else |
| 657 |
return $nullvalue; |
| 658 |
} |
| 659 |
|
| 660 |
/** |
| 661 |
* Get next sibling in object list |
| 662 |
* |
| 663 |
* @param object $thisnode The current object |
| 664 |
* |
| 665 |
* @return object Returns the next sibling |
| 666 |
*/ |
| 667 |
function &getNextSibling(& $thisnode){ |
| 668 |
return $thisnode->next; |
| 669 |
} |
| 670 |
|
| 671 |
/** |
| 672 |
* Get previous sibling in object list |
| 673 |
* |
| 674 |
* @param object $thisnode The current object |
| 675 |
* |
| 676 |
* @return object Returns the previous sibling |
| 677 |
*/ |
| 678 |
function &getPrevSibling(& $thisnode){ |
| 679 |
return $thisnode->prev; |
| 680 |
} |
| 681 |
|
| 682 |
/** |
| 683 |
* Read date/time in iCal formatted string |
| 684 |
* |
| 685 |
* @param string iCal formated date/time string |
| 686 |
* |
| 687 |
* @return int Unix timestamp |
| 688 |
*/ |
| 689 |
|
| 690 |
function toUnixDateTime($datetime){ |
| 691 |
$year = substr($datetime,0,4); |
| 692 |
$month = substr($datetime,4,2); |
| 693 |
$day = substr($datetime,6,2); |
| 694 |
$hour = 0; |
| 695 |
$minute = 0; |
| 696 |
$second = 0; |
| 697 |
if(strlen($datetime) > 8 && $datetime{8} == "T") { |
| 698 |
$hour = substr($datetime,9,2); |
| 699 |
$minute = substr($datetime,11,2); |
| 700 |
$second = substr($datetime,13,2); |
| 701 |
} |
| 702 |
$d1 = mktime($hour, $minute, $second, $month, $day, $year); |
| 703 |
|
| 704 |
} |
| 705 |
|
| 706 |
/** |
| 707 |
* fromUnixDateTime() |
| 708 |
* |
| 709 |
* Take Unix timestamp and format to iCal date/time string |
| 710 |
* |
| 711 |
* @param int $datetime Unix timestamp, leave blank for current date/time |
| 712 |
* |
| 713 |
* @return string formatted iCal date/time string |
| 714 |
*/ |
| 715 |
|
| 716 |
static function fromUnixDateTime($datetime = null){ |
| 717 |
date_default_timezone_set('UTC'); |
| 718 |
if($datetime == null) |
| 719 |
$datetime = time(); |
| 720 |
return date("Ymd\THis",$datetime); |
| 721 |
} |
| 722 |
|
| 723 |
|
| 724 |
/** |
| 725 |
* fromUnixDate() |
| 726 |
* |
| 727 |
* Take Unix timestamp and format to iCal date string |
| 728 |
* |
| 729 |
* @param int $datetime Unix timestamp, leave blank for current date/time |
| 730 |
* |
| 731 |
* @return string formatted iCal date string |
| 732 |
*/ |
| 733 |
|
| 734 |
static function fromUnixDate($datetime = null){ |
| 735 |
date_default_timezone_set('UTC'); |
| 736 |
if($datetime == null) |
| 737 |
$datetime = time(); |
| 738 |
return date("Ymd",$datetime); |
| 739 |
} |
| 740 |
|
| 741 |
/** |
| 742 |
* Format into iCal time format from SQL date or SQL date-time format |
| 743 |
* |
| 744 |
* @param string $datetime SQL date or SQL date-time string |
| 745 |
* |
| 746 |
* @return string iCal formatted string |
| 747 |
*/ |
| 748 |
static function fromSqlDateTime($datetime = ""){ |
| 749 |
if($datetime == "") |
| 750 |
$datetime = ZDateHelper::toSqlDateTime(); |
| 751 |
if(strlen($datetime) > 10) |
| 752 |
return sprintf('%04d%02d%02dT%02d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2), |
| 753 |
substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2)); |
| 754 |
else |
| 755 |
return sprintf('%04d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2)); |
| 756 |
} |
| 757 |
|
| 758 |
/** |
| 759 |
* Format iCal time format to either SQL date or SQL date-time format |
| 760 |
* |
| 761 |
* @param string $datetime icalendar formatted date or date-time |
| 762 |
* |
| 763 |
* @return string SQL date or SQL date-time string |
| 764 |
*/ |
| 765 |
static function toSqlDateTime($datetime = ""){ |
| 766 |
if($datetime == "") |
| 767 |
return ZDateHelper::toSqlDateTime(); |
| 768 |
if(strlen($datetime) > 10) |
| 769 |
return sprintf('%04d-%02d-%02d %02d:%02d:%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2), |
| 770 |
substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2)); |
| 771 |
else |
| 772 |
return sprintf('%04d-%02d-%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2)); |
| 773 |
} |
| 774 |
|
| 775 |
/** |
| 776 |
* Pull timezone data from node and put in array |
| 777 |
* |
| 778 |
* Returning array contains the following array keys: tzoffsetfrom, tzoffsetto, tzname, dtstart, rrule |
| 779 |
* |
| 780 |
* @param array $node timezone object |
| 781 |
* |
| 782 |
* @return array |
| 783 |
*/ |
| 784 |
static function getTZValues($node){ |
| 785 |
$tzvalues = array(); |
| 786 |
|
| 787 |
$tnode = @$node->data['TZOFFSETFROM']; |
| 788 |
if($tnode != null){ |
| 789 |
$tzvalues["tzoffsetfrom"] = $tnode->getValues(); |
| 790 |
} |
| 791 |
|
| 792 |
$tnode = @$node->data['TZOFFSETTO']; |
| 793 |
if($tnode != null){ |
| 794 |
$tzvalues["tzoffsetto"] = $tnode->getValues(); |
| 795 |
} |
| 796 |
|
| 797 |
$tnode = @$node->data['TZNAME']; |
| 798 |
if($tnode != null){ |
| 799 |
$tzvalues["tzname"] = $tnode->getValues(); |
| 800 |
} |
| 801 |
else |
| 802 |
$tzvalues["tzname"] = ""; |
| 803 |
|
| 804 |
$tnode = @$node->data['DTSTART']; |
| 805 |
if($tnode != null){ |
| 806 |
$tzvalues["dtstart"] = ZDateHelper::fromiCaltoUnixDateTime($tnode->getValues()); |
| 807 |
} |
| 808 |
|
| 809 |
$tnode = @$node->data['RRULE']; |
| 810 |
if($tnode != null){ |
| 811 |
$tzvalues["rrule"] = $tnode->getValues(); |
| 812 |
//echo "rule: " . $tzvalues["rrule"] . "<br/>\n"; |
| 813 |
} |
| 814 |
else{ |
| 815 |
// no rule specified, let's create one from based on the date |
| 816 |
$date = getdate($tzvalues["dtstart"]); |
| 817 |
$month = $date["mon"]; |
| 818 |
$day = $date["mday"]; |
| 819 |
$tzvalues["rrule"] = "FREQ=YEARLY;INTERVAL=1;BYMONTH=$month;BYMONTHDAY=$day"; |
| 820 |
} |
| 821 |
|
| 822 |
return $tzvalues; |
| 823 |
} |
| 824 |
|
| 825 |
/** |
| 826 |
* Escape slashes, commas and semicolons in strings |
| 827 |
* |
| 828 |
* @param string $content |
| 829 |
* |
| 830 |
* @return escaped string |
| 831 |
*/ |
| 832 |
static function formatContent($content) |
| 833 |
{ |
| 834 |
$content = str_replace(array('\\' , ',' , ';' ), array('\\\\' , '\\,' , '\\;' ),$content); |
| 835 |
return $content; |
| 836 |
} |
| 837 |
|
| 838 |
} |
| 839 |
|
| 840 |
?> |
| 841 |
|