Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 3 /** 4 * BENNU - PHP iCalendar library 5 * (c) 2005-2006 Ioannis Papaioannou (pj@moodle.org). All rights reserved. 6 * 7 * Released under the LGPL. 8 * 9 * See http://bennu.sourceforge.net/ for more information and downloads. 10 * 11 * @author Ioannis Papaioannou 12 * @version $Id$ 13 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 14 */ 15 16 class iCalendar_property { 17 // Properties can have parameters, but cannot have other properties or components 18 19 var $parent_component = NULL; 20 var $value = NULL; 21 var $parameters = NULL; 22 var $valid_parameters = NULL; 23 24 // These are common for 95% of properties, so define them here and override as necessary 25 var $val_multi = false; 26 var $val_default = NULL; 27 28 /** @var int|null RFC2445_TYPE value. */ 29 protected $val_type; 30 31 /** @var string property name. */ 32 protected $name; 33 34 function __construct() { 35 $this->parameters = array(); 36 } 37 38 // If some property needs extra care with its parameters, override this 39 // IMPORTANT: the parameter name MUST BE CAPITALIZED! 40 function is_valid_parameter($parameter, $value) { 41 42 if(is_array($value)) { 43 if(!iCalendar_parameter::multiple_values_allowed($parameter)) { 44 return false; 45 } 46 foreach($value as $item) { 47 if(!iCalendar_parameter::is_valid_value($this, $parameter, $item)) { 48 return false; 49 } 50 } 51 return true; 52 } 53 54 return iCalendar_parameter::is_valid_value($this, $parameter, $value); 55 } 56 57 function invariant_holds() { 58 return true; 59 } 60 61 // If some property is very picky about its values, it should do the work itself 62 // Only data type validation is done here 63 function is_valid_value($value) { 64 if(is_array($value)) { 65 if(!$this->val_multi) { 66 return false; 67 } 68 else { 69 foreach($value as $oneval) { 70 if(!rfc2445_is_valid_value($oneval, $this->val_type)) { 71 return false; 72 } 73 } 74 } 75 return true; 76 } 77 return rfc2445_is_valid_value($value, $this->val_type); 78 } 79 80 function default_value() { 81 return $this->val_default; 82 } 83 84 function set_parent_component($componentname) { 85 if(class_exists('iCalendar_'.strtolower(substr($componentname, 1)))) { 86 $this->parent_component = strtoupper($componentname); 87 return true; 88 } 89 90 return false; 91 } 92 93 function set_value($value) { 94 if($this->is_valid_value($value)) { 95 // This transparently formats any value type according to the iCalendar specs 96 if(is_array($value)) { 97 foreach($value as $key => $item) { 98 $value[$key] = rfc2445_do_value_formatting($item, $this->val_type); 99 } 100 $this->value = implode(',', $value); 101 } 102 else { 103 $this->value = rfc2445_do_value_formatting($value, $this->val_type); 104 } 105 106 return true; 107 } 108 return false; 109 } 110 111 function get_value() { 112 // First of all, assume that we have multiple values 113 $valarray = explode('\\,', $this->value); 114 115 // Undo transparent formatting 116 $valtype = $this->val_type; 117 $replace_function = function($a) use ($valtype) { 118 return rfc2445_undo_value_formatting($a, $valtype); 119 }; 120 $valarray = array_map($replace_function, $valarray); 121 122 // Now, if this property cannot have multiple values, don't return as an array 123 if(!$this->val_multi) { 124 return $valarray[0]; 125 } 126 127 // Otherwise return an array even if it has one element, for uniformity 128 return $valarray; 129 130 } 131 132 function set_parameter($name, $value) { 133 134 // Uppercase 135 $name = strtoupper($name); 136 137 // Are we trying to add a valid parameter? 138 $xname = false; 139 if(!isset($this->valid_parameters[$name])) { 140 // If not, is it an x-name as per RFC 2445? 141 if(!rfc2445_is_xname($name)) { 142 return false; 143 } 144 // No more checks -- all components are supposed to allow x-name parameters 145 $xname = true; 146 } 147 148 if(!$this->is_valid_parameter($name, $value)) { 149 return false; 150 } 151 152 if(is_array($value)) { 153 foreach($value as $key => $element) { 154 $value[$key] = iCalendar_parameter::do_value_formatting($name, $element); 155 } 156 } 157 else { 158 $value = iCalendar_parameter::do_value_formatting($name, $value); 159 } 160 161 $this->parameters[$name] = $value; 162 163 // Special case: if we just changed the VALUE parameter, reflect this 164 // in the object's status so that it only accepts correct type values 165 if($name == 'VALUE') { 166 // TODO: what if this invalidates an already-set value? 167 $this->val_type = constant('RFC2445_TYPE_'.str_replace('-', '_', $value)); 168 } 169 170 return true; 171 172 } 173 174 function get_parameter($name) { 175 176 // Uppercase 177 $name = strtoupper($name); 178 179 if(isset($this->parameters[$name])) { 180 // If there are any double quotes in the value, invisibly strip them 181 if(is_array($this->parameters[$name])) { 182 foreach($this->parameters[$name] as $key => $value) { 183 if(substr($value, 0, 1) == '"') { 184 $this->parameters[$name][$key] = substr($value, 1, strlen($value) - 2); 185 } 186 } 187 return $this->parameters[$name]; 188 } 189 190 else { 191 if(substr($this->parameters[$name], 0, 1) == '"') { 192 return substr($this->parameters[$name], 1, strlen($this->parameters[$name]) - 2); 193 } 194 } 195 } 196 197 return NULL; 198 } 199 200 function serialize() { 201 $string = $this->name; 202 203 if(!empty($this->parameters)) { 204 foreach($this->parameters as $name => $value) { 205 $string .= ';'.$name.'='; 206 if(is_array($value)) { 207 $string .= implode(',', $value); 208 } 209 else { 210 $string .= $value; 211 } 212 } 213 } 214 215 $string .= ':'.$this->value; 216 217 return rfc2445_fold($string) . RFC2445_CRLF; 218 } 219 } 220 221 // 4.7 Calendar Properties 222 // ----------------------- 223 224 class iCalendar_property_calscale extends iCalendar_property { 225 226 var $name = 'CALSCALE'; 227 var $val_type = RFC2445_TYPE_TEXT; 228 229 function __construct() { 230 parent::__construct(); 231 $this->valid_parameters = array( 232 RFC2445_XNAME => RFC2445_OPTIONAL 233 ); 234 } 235 236 function is_valid_value($value) { 237 // This is case-sensitive 238 return ($value === 'GREGORIAN'); 239 } 240 } 241 242 class iCalendar_property_method extends iCalendar_property { 243 244 var $name = 'METHOD'; 245 var $val_type = RFC2445_TYPE_TEXT; 246 247 function __construct() { 248 parent::__construct(); 249 $this->valid_parameters = array( 250 RFC2445_XNAME => RFC2445_OPTIONAL 251 ); 252 } 253 254 function is_valid_value($value) { 255 // This is case-sensitive 256 // Methods from RFC 2446 257 $methods = array('PUBLISH', 'REQUEST', 'REPLY', 'ADD', 'CANCEL', 'REFRESH', 'COUNTER', 'DECLINECOUNTER'); 258 return in_array($value, $methods); 259 } 260 } 261 262 class iCalendar_property_prodid extends iCalendar_property { 263 264 var $name = 'PRODID'; 265 var $val_type = RFC2445_TYPE_TEXT; 266 var $val_default = NULL; 267 268 function __construct() { 269 parent::__construct(); 270 $this->val_default = '-//John Papaioannou/NONSGML Bennu '._BENNU_VERSION.'//EN'; 271 272 $this->valid_parameters = array( 273 RFC2445_XNAME => RFC2445_OPTIONAL 274 ); 275 } 276 } 277 278 class iCalendar_property_version extends iCalendar_property { 279 280 var $name = 'VERSION'; 281 var $val_type = RFC2445_TYPE_TEXT; 282 var $val_default = '2.0'; 283 284 function __construct() { 285 parent::__construct(); 286 $this->valid_parameters = array( 287 RFC2445_XNAME => RFC2445_OPTIONAL 288 ); 289 } 290 291 function is_valid_value($value) { 292 return($value === '2.0' || $value === 2.0); 293 } 294 295 } 296 297 // 4.8.1 Descriptive Component Properties 298 // -------------------------------------- 299 300 class iCalendar_property_attach extends iCalendar_property { 301 302 var $name = 'ATTACH'; 303 var $val_type = RFC2445_TYPE_URI; 304 305 function __construct() { 306 parent::__construct(); 307 $this->valid_parameters = array( 308 'FMTTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE, 309 'ENCODING' => RFC2445_OPTIONAL | RFC2445_ONCE, 310 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 311 RFC2445_XNAME => RFC2445_OPTIONAL 312 ); 313 } 314 315 function invariant_holds() { 316 if(isset($this->parameters['ENCODING']) && !isset($this->parameters['VALUE'])) { 317 return false; 318 } 319 if(isset($this->parameters['VALUE']) && !isset($this->parameters['ENCODING'])) { 320 return false; 321 } 322 323 return true; 324 } 325 326 function is_valid_parameter($parameter, $value) { 327 328 $parameter = strtoupper($parameter); 329 330 if(!parent::is_valid_parameter($parameter, $value)) { 331 return false; 332 } 333 334 if($parameter === 'ENCODING' && strtoupper($value) != 'BASE64') { 335 return false; 336 } 337 338 if($parameter === 'VALUE' && strtoupper($value) != 'BINARY') { 339 return false; 340 } 341 342 return true; 343 } 344 } 345 346 class iCalendar_property_categories extends iCalendar_property { 347 348 var $name = 'CATEGORIES'; 349 var $val_type = RFC2445_TYPE_TEXT; 350 var $val_multi = true; 351 352 function __construct() { 353 parent::__construct(); 354 $this->valid_parameters = array( 355 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 356 RFC2445_XNAME => RFC2445_OPTIONAL 357 ); 358 } 359 } 360 361 class iCalendar_property_class extends iCalendar_property { 362 363 var $name = 'CLASS'; 364 var $val_type = RFC2445_TYPE_TEXT; 365 var $val_default = 'PUBLIC'; 366 367 function __construct() { 368 parent::__construct(); 369 $this->valid_parameters = array( 370 RFC2445_XNAME => RFC2445_OPTIONAL 371 ); 372 } 373 374 function is_valid_value($value) { 375 // If this is not an xname, it is case-sensitive 376 return ($value === 'PUBLIC' || $value === 'PRIVATE' || $value === 'CONFIDENTIAL' || rfc2445_is_xname(strtoupper($value))); 377 } 378 } 379 380 class iCalendar_property_comment extends iCalendar_property { 381 382 var $name = 'COMMENT'; 383 var $val_type = RFC2445_TYPE_TEXT; 384 385 function __construct() { 386 parent::__construct(); 387 $this->valid_parameters = array( 388 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 389 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 390 RFC2445_XNAME => RFC2445_OPTIONAL 391 ); 392 } 393 } 394 395 class iCalendar_property_description extends iCalendar_property { 396 397 var $name = 'DESCRIPTION'; 398 var $val_type = RFC2445_TYPE_TEXT; 399 400 function __construct() { 401 parent::__construct(); 402 $this->valid_parameters = array( 403 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 404 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 405 RFC2445_XNAME => RFC2445_OPTIONAL 406 ); 407 } 408 } 409 410 class iCalendar_property_geo extends iCalendar_property { 411 412 var $name = 'GEO'; 413 var $val_type = RFC2445_TYPE_TEXT; 414 415 function __construct() { 416 parent::__construct(); 417 $this->valid_parameters = array( 418 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 419 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 420 RFC2445_XNAME => RFC2445_OPTIONAL 421 ); 422 } 423 424 function is_valid_value($value) { 425 // This MUST be two floats separated by a semicolon 426 if(!is_string($value)) { 427 return false; 428 } 429 430 $floats = explode(';', $value); 431 if(count($floats) != 2) { 432 return false; 433 } 434 435 return rfc2445_is_valid_value($floats[0], RFC2445_TYPE_FLOAT) && rfc2445_is_valid_value($floats[1], RFC2445_TYPE_FLOAT); 436 } 437 438 function set_value($value) { 439 // Must override this, otherwise the semicolon separating 440 // the two floats would get auto-quoted, which is illegal 441 if($this->is_valid_value($value)) { 442 $this->value = $value; 443 return true; 444 } 445 446 return false; 447 } 448 449 } 450 451 class iCalendar_property_location extends iCalendar_property { 452 453 var $name = 'LOCATION'; 454 var $val_type = RFC2445_TYPE_TEXT; 455 456 function __construct() { 457 parent::__construct(); 458 $this->valid_parameters = array( 459 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 460 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 461 RFC2445_XNAME => RFC2445_OPTIONAL 462 ); 463 } 464 } 465 466 class iCalendar_property_percent_complete extends iCalendar_property { 467 468 var $name = 'PERCENT-COMPLETE'; 469 var $val_type = RFC2445_TYPE_INTEGER; 470 471 function __construct() { 472 parent::__construct(); 473 $this->valid_parameters = array( 474 RFC2445_XNAME => RFC2445_OPTIONAL 475 ); 476 } 477 478 function is_valid_value($value) { 479 // Only integers between 0 and 100 inclusive allowed 480 if(!parent::is_valid_value($value)) { 481 return false; 482 } 483 $value = intval($value); 484 return ($value >= 0 && $value <= 100); 485 } 486 487 } 488 489 class iCalendar_property_priority extends iCalendar_property { 490 491 var $name = 'PRIORITY'; 492 var $val_type = RFC2445_TYPE_INTEGER; 493 494 function __construct() { 495 parent::__construct(); 496 $this->valid_parameters = array( 497 RFC2445_XNAME => RFC2445_OPTIONAL 498 ); 499 } 500 501 function is_valid_value($value) { 502 // Only integers between 0 and 9 inclusive allowed 503 if(!parent::is_valid_value($value)) { 504 return false; 505 } 506 507 $value = intval($value); 508 return ($value >= 0 && $value <= 9); 509 } 510 } 511 512 class iCalendar_property_resources extends iCalendar_property { 513 514 var $name = 'RESOURCES'; 515 var $val_type = RFC2445_TYPE_TEXT; 516 var $val_multi = true; 517 518 function __construct() { 519 parent::__construct(); 520 $this->valid_parameters = array( 521 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 522 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 523 RFC2445_XNAME => RFC2445_OPTIONAL 524 ); 525 } 526 } 527 528 class iCalendar_property_status extends iCalendar_property { 529 530 var $name = 'STATUS'; 531 var $val_type = RFC2445_TYPE_TEXT; 532 533 function __construct() { 534 parent::__construct(); 535 $this->valid_parameters = array( 536 RFC2445_XNAME => RFC2445_OPTIONAL 537 ); 538 } 539 540 function is_valid_value($value) { 541 // This is case-sensitive 542 switch ($this->parent_component) { 543 case 'VEVENT': 544 $allowed = array('TENTATIVE', 'CONFIRMED', 'CANCELLED'); 545 break; 546 case 'VTODO': 547 $allowed = array('NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED'); 548 break; 549 case 'VJOURNAL': 550 $allowed = array('DRAFT', 'FINAL', 'CANCELLED'); 551 break; 552 } 553 return in_array($value, $allowed); 554 555 } 556 557 } 558 559 class iCalendar_property_summary extends iCalendar_property { 560 561 var $name = 'SUMMARY'; 562 var $val_type = RFC2445_TYPE_TEXT; 563 564 function __construct() { 565 parent::__construct(); 566 $this->valid_parameters = array( 567 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 568 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 569 RFC2445_XNAME => RFC2445_OPTIONAL 570 ); 571 } 572 } 573 574 // 4.8.2 Date and Time Component Properties 575 // ---------------------------------------- 576 577 class iCalendar_property_completed extends iCalendar_property { 578 579 var $name = 'COMPLETED'; 580 var $val_type = RFC2445_TYPE_DATE_TIME; 581 582 function __construct() { 583 parent::__construct(); 584 $this->valid_parameters = array( 585 RFC2445_XNAME => RFC2445_OPTIONAL 586 ); 587 } 588 589 function is_valid_value($value) { 590 if(!parent::is_valid_value($value)) { 591 return false; 592 } 593 // Time MUST be in UTC format 594 return(substr($value, -1) == 'Z'); 595 } 596 } 597 598 class iCalendar_property_dtend extends iCalendar_property { 599 600 var $name = 'DTEND'; 601 var $val_type = RFC2445_TYPE_DATE_TIME; 602 603 function __construct() { 604 parent::__construct(); 605 $this->valid_parameters = array( 606 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 607 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE, 608 RFC2445_XNAME => RFC2445_OPTIONAL 609 ); 610 } 611 612 function is_valid_value($value) { 613 if(!parent::is_valid_value($value)) { 614 return false; 615 } 616 617 // If present in a FREEBUSY component, must be in UTC format 618 if($this->parent_component == 'VFREEBUSY' && substr($value, -1) != 'Z') { 619 return false; 620 } 621 622 return true; 623 624 } 625 626 function is_valid_parameter($parameter, $value) { 627 628 $parameter = strtoupper($parameter); 629 630 if(!parent::is_valid_parameter($parameter, $value)) { 631 return false; 632 } 633 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) { 634 return false; 635 } 636 637 return true; 638 } 639 } 640 641 class iCalendar_property_due extends iCalendar_property { 642 643 var $name = 'DUE'; 644 var $val_type = RFC2445_TYPE_DATE_TIME; 645 646 function __construct() { 647 parent::__construct(); 648 $this->valid_parameters = array( 649 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 650 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE, 651 RFC2445_XNAME => RFC2445_OPTIONAL 652 ); 653 } 654 655 function is_valid_value($value) { 656 if(!parent::is_valid_value($value)) { 657 return false; 658 } 659 660 // If present in a FREEBUSY component, must be in UTC format 661 if($this->parent_component == 'VFREEBUSY' && substr($value, -1) != 'Z') { 662 return false; 663 } 664 665 return true; 666 667 } 668 669 function is_valid_parameter($parameter, $value) { 670 671 $parameter = strtoupper($parameter); 672 673 if(!parent::is_valid_parameter($parameter, $value)) { 674 return false; 675 } 676 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) { 677 return false; 678 } 679 680 return true; 681 } 682 } 683 684 class iCalendar_property_dtstart extends iCalendar_property { 685 686 var $name = 'DTSTART'; 687 var $val_type = RFC2445_TYPE_DATE_TIME; 688 689 function __construct() { 690 parent::__construct(); 691 $this->valid_parameters = array( 692 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 693 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE, 694 RFC2445_XNAME => RFC2445_OPTIONAL 695 ); 696 } 697 698 // TODO: unimplemented stuff when parent is a VTIMEZONE component 699 700 function is_valid_value($value) { 701 if(!parent::is_valid_value($value)) { 702 return false; 703 } 704 705 // If present in a FREEBUSY component, must be in UTC format 706 if($this->parent_component == 'VFREEBUSY' && substr($value, -1) != 'Z') { 707 return false; 708 } 709 710 return true; 711 } 712 713 function is_valid_parameter($parameter, $value) { 714 715 $parameter = strtoupper($parameter); 716 717 if(!parent::is_valid_parameter($parameter, $value)) { 718 return false; 719 } 720 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) { 721 return false; 722 } 723 724 return true; 725 } 726 } 727 728 class iCalendar_property_duration extends iCalendar_property { 729 730 var $name = 'DURATION'; 731 var $val_type = RFC2445_TYPE_DURATION; 732 733 function __construct() { 734 parent::__construct(); 735 $this->valid_parameters = array( 736 RFC2445_XNAME => RFC2445_OPTIONAL 737 ); 738 } 739 740 function is_valid_value($value) { 741 if(!parent::is_valid_value($value)) { 742 return false; 743 } 744 745 // Value must be positive 746 return ($value[0] != '-'); 747 } 748 } 749 750 class iCalendar_property_freebusy extends iCalendar_property { 751 752 var $name = 'FREEBUSY'; 753 var $val_type = RFC2445_TYPE_PERIOD; 754 var $val_multi = true; 755 756 function __construct() { 757 parent::__construct(); 758 $this->valid_parameters = array( 759 'FBTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE, 760 RFC2445_XNAME => RFC2445_OPTIONAL 761 ); 762 } 763 764 function is_valid_value($value) { 765 if(!parent::is_valid_value($value)) { 766 return false; 767 } 768 769 $pos = strpos($value, '/'); // We know there's only one / in there 770 if($value[$pos - 1] != 'Z') { 771 // Start time MUST be in UTC 772 return false; 773 } 774 if($value[$pos + 1] != 'P' && substr($value, -1) != 'Z') { 775 // If the second part is not a period, it MUST be in UTC 776 return false; 777 } 778 779 return true; 780 } 781 782 // TODO: these properties SHOULD be shorted in ascending order (by start time and end time as tiebreak) 783 } 784 785 class iCalendar_property_transp extends iCalendar_property { 786 787 var $name = 'TRANSP'; 788 var $val_type = RFC2445_TYPE_TEXT; 789 var $val_default = 'OPAQUE'; 790 791 function __construct() { 792 parent::__construct(); 793 $this->valid_parameters = array( 794 RFC2445_XNAME => RFC2445_OPTIONAL 795 ); 796 } 797 798 function is_valid_value($value) { 799 return ($value === 'TRANSPARENT' || $value === 'OPAQUE'); 800 } 801 } 802 803 // TODO: 4.8.3 timezone component properties 804 805 806 // 4.8.4 Relationship Component Properties 807 // --------------------------------------- 808 809 class iCalendar_property_attendee extends iCalendar_property { 810 811 var $name = 'ATTENDEE'; 812 var $val_type = RFC2445_TYPE_CAL_ADDRESS; 813 814 // TODO: MUST NOT be specified when the calendar object has METHOD=PUBLISH 815 // TODO: standard has lots of detail here, make triple sure that we eventually conform 816 817 function __construct() { 818 parent::__construct(); 819 $this->valid_parameters = array( 820 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 821 'CN' => RFC2445_OPTIONAL | RFC2445_ONCE, 822 'ROLE' => RFC2445_OPTIONAL | RFC2445_ONCE, 823 'PARTSTAT' => RFC2445_OPTIONAL | RFC2445_ONCE, 824 'RSVP' => RFC2445_OPTIONAL | RFC2445_ONCE, 825 'CUTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE, 826 'MEMBER' => RFC2445_OPTIONAL | RFC2445_ONCE, 827 'DELEGATED-TO' => RFC2445_OPTIONAL | RFC2445_ONCE, 828 'DELEGATED-FROM' => RFC2445_OPTIONAL | RFC2445_ONCE, 829 'SENT-BY' => RFC2445_OPTIONAL | RFC2445_ONCE, 830 'DIR' => RFC2445_OPTIONAL | RFC2445_ONCE, 831 RFC2445_XNAME => RFC2445_OPTIONAL 832 ); 833 } 834 835 function set_parent_component($componentname) { 836 if(!parent::set_parent_component($componentname)) { 837 return false; 838 } 839 840 if($this->parent_component == 'VFREEBUSY' || $this->parent_component == 'VALARM') { 841 // Most parameters become invalid in this case, the full allowed set is now: 842 $this->valid_parameters = array( 843 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 844 RFC2445_XNAME => RFC2445_OPTIONAL 845 ); 846 } 847 848 return false; 849 } 850 851 } 852 853 class iCalendar_property_contact extends iCalendar_property { 854 855 var $name = 'CONTACT'; 856 var $val_type = RFC2445_TYPE_TEXT; 857 858 function __construct() { 859 parent::__construct(); 860 $this->valid_parameters = array( 861 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE, 862 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 863 RFC2445_XNAME => RFC2445_OPTIONAL 864 ); 865 } 866 } 867 868 class iCalendar_property_organizer extends iCalendar_property { 869 870 var $name = 'ORGANIZER'; 871 var $val_type = RFC2445_TYPE_CAL_ADDRESS; 872 873 function __construct() { 874 parent::__construct(); 875 $this->valid_parameters = array( 876 'CN' => RFC2445_OPTIONAL | RFC2445_ONCE, 877 'DIR' => RFC2445_OPTIONAL | RFC2445_ONCE, 878 'SENT-BY' => RFC2445_OPTIONAL | RFC2445_ONCE, 879 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 880 RFC2445_XNAME => RFC2445_OPTIONAL 881 ); 882 } 883 884 // TODO: 885 /* 886 Conformance: This property MUST be specified in an iCalendar object 887 that specifies a group scheduled calendar entity. This property MUST 888 be specified in an iCalendar object that specifies the publication of 889 a calendar user's busy time. This property MUST NOT be specified in 890 an iCalendar object that specifies only a time zone definition or 891 that defines calendar entities that are not group scheduled entities, 892 but are entities only on a single user's calendar. 893 */ 894 895 } 896 897 class iCalendar_property_recurrence_id extends iCalendar_property { 898 899 // TODO: can only be specified when defining recurring components in the calendar 900 /* 901 Conformance: This property can be specified in an iCalendar object 902 containing a recurring calendar component. 903 904 Description: The full range of calendar components specified by a 905 recurrence set is referenced by referring to just the "UID" property 906 value corresponding to the calendar component. The "RECURRENCE-ID" 907 property allows the reference to an individual instance within the 908 recurrence set. 909 */ 910 911 var $name = 'RECURRENCE-ID'; 912 var $val_type = RFC2445_TYPE_DATE_TIME; 913 914 function __construct() { 915 parent::__construct(); 916 $this->valid_parameters = array( 917 'RANGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 918 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE, 919 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 920 RFC2445_XNAME => RFC2445_OPTIONAL 921 ); 922 } 923 924 function is_valid_parameter($parameter, $value) { 925 926 $parameter = strtoupper($parameter); 927 928 if(!parent::is_valid_parameter($parameter, $value)) { 929 return false; 930 } 931 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) { 932 return false; 933 } 934 935 return true; 936 } 937 938 } 939 940 class iCalendar_property_related_to extends iCalendar_property { 941 942 var $name = 'RELATED-TO'; 943 var $val_type = RFC2445_TYPE_TEXT; 944 945 // TODO: the value of this property must reference another component's UID 946 947 function __construct() { 948 parent::__construct(); 949 $this->valid_parameters = array( 950 'RELTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE, 951 RFC2445_XNAME => RFC2445_OPTIONAL 952 ); 953 } 954 } 955 956 class iCalendar_property_url extends iCalendar_property { 957 958 var $name = 'URL'; 959 var $val_type = RFC2445_TYPE_URI; 960 961 function __construct() { 962 parent::__construct(); 963 $this->valid_parameters = array( 964 RFC2445_XNAME => RFC2445_OPTIONAL 965 ); 966 } 967 } 968 969 class iCalendar_property_uid extends iCalendar_property { 970 971 var $name = 'UID'; 972 var $val_type = RFC2445_TYPE_TEXT; 973 974 function __construct() { 975 parent::__construct(); 976 $this->valid_parameters = array( 977 RFC2445_XNAME => RFC2445_OPTIONAL 978 ); 979 980 // The exception to the rule: this is not a static value, so we 981 // generate it on-the-fly here. Guaranteed to be different for 982 // each instance of this property, too. Nice. 983 $this->val_default = Bennu::generate_guid(); 984 } 985 } 986 987 // 4.8.5 Recurrence Component Properties 988 // ------------------------------------- 989 990 class iCalendar_property_exdate extends iCalendar_property { 991 992 var $name = 'EXDATE'; 993 var $val_type = RFC2445_TYPE_DATE_TIME; 994 var $val_multi = true; 995 996 function __construct() { 997 parent::__construct(); 998 $this->valid_parameters = array( 999 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE, 1000 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1001 RFC2445_XNAME => RFC2445_OPTIONAL 1002 ); 1003 } 1004 1005 function is_valid_parameter($parameter, $value) { 1006 1007 $parameter = strtoupper($parameter); 1008 1009 if(!parent::is_valid_parameter($parameter, $value)) { 1010 return false; 1011 } 1012 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME')) { 1013 return false; 1014 } 1015 1016 return true; 1017 } 1018 1019 } 1020 1021 class iCalendar_property_exrule extends iCalendar_property { 1022 1023 var $name = 'EXRULE'; 1024 var $val_type = RFC2445_TYPE_RECUR; 1025 1026 function __construct() { 1027 parent::__construct(); 1028 $this->valid_parameters = array( 1029 RFC2445_XNAME => RFC2445_OPTIONAL 1030 ); 1031 } 1032 } 1033 1034 class iCalendar_property_rdate extends iCalendar_property { 1035 1036 var $name = 'RDATE'; 1037 var $val_type = RFC2445_TYPE_DATE_TIME; 1038 var $val_multi = true; 1039 1040 function __construct() { 1041 parent::__construct(); 1042 $this->valid_parameters = array( 1043 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE, 1044 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1045 RFC2445_XNAME => RFC2445_OPTIONAL 1046 ); 1047 } 1048 1049 function is_valid_parameter($parameter, $value) { 1050 1051 $parameter = strtoupper($parameter); 1052 1053 if(!parent::is_valid_parameter($parameter, $value)) { 1054 return false; 1055 } 1056 if($parameter == 'VALUE' && !($value == 'DATE' || $value == 'DATE-TIME' || $value == 'PERIOD')) { 1057 return false; 1058 } 1059 1060 return true; 1061 } 1062 1063 } 1064 1065 class iCalendar_property_rrule extends iCalendar_property { 1066 1067 var $name = 'RRULE'; 1068 var $val_type = RFC2445_TYPE_RECUR; 1069 1070 function __construct() { 1071 parent::__construct(); 1072 $this->valid_parameters = array( 1073 RFC2445_XNAME => RFC2445_OPTIONAL 1074 ); 1075 } 1076 } 1077 1078 // 4.8.6 Alarm Component Properties 1079 // ------------------------------------------- 1080 class iCalendar_property_action extends iCalendar_property { 1081 var $name = 'ACTION'; 1082 var $val_type = RFC2445_TYPE_TEXT; 1083 1084 function __construct() { 1085 parent::__construct(); 1086 $this->valid_parameters = array( 1087 RFC2445_XNAME => RFC2445_OPTIONAL 1088 ); 1089 } 1090 1091 function is_valid_value($value) { 1092 if(!parent::is_valid_value($value)) { 1093 return false; 1094 } 1095 1096 // Value must be one of the following, or an x-name. 1097 $valid_values = array('ACTION', 'DISPLAY', 'EMAIL', 'PROCEDURE'); 1098 return(in_array($value, $valid_values) || rfc2445_is_xname($value)); 1099 1100 } 1101 } 1102 1103 class iCalendar_property_repeat extends iCalendar_property { 1104 var $name = 'REPEAT'; 1105 var $val_type = RFC2445_TYPE_INTEGER; 1106 1107 function __construct() { 1108 parent::__construct(); 1109 $this->valid_parameters = array( 1110 RFC2445_XNAME => RFC2445_OPTIONAL 1111 ); 1112 } 1113 } 1114 1115 class iCalendar_property_trigger extends iCalendar_property { 1116 var $name = 'TRIGGER'; 1117 var $val_type = RFC2445_TYPE_TEXT; 1118 1119 function __construct() { 1120 parent::__construct(); 1121 $this->valid_parameters = array( 1122 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1123 'RELATED' => RFC2445_OPTIONAL | RFC2445_ONCE, 1124 RFC2445_XNAME => RFC2445_OPTIONAL 1125 ); 1126 } 1127 1128 function is_valid_value($value) { 1129 if(!parent::is_valid_value($value)) { 1130 return false; 1131 } 1132 // Must either be DURATION or DATE_TIME type 1133 return(rfc2445_is_valid_value($value, RFC2445_TYPE_DURATION) 1134 || rfc2445_is_valid_value($value, RFC2445_TYPE_DATE_TIME)); 1135 } 1136 } 1137 1138 1139 1140 // 4.8.7 Change Management Component Properties 1141 // -------------------------------------------- 1142 1143 class iCalendar_property_created extends iCalendar_property { 1144 1145 var $name = 'CREATED'; 1146 var $val_type = RFC2445_TYPE_DATE_TIME; 1147 1148 function __construct() { 1149 parent::__construct(); 1150 $this->valid_parameters = array( 1151 RFC2445_XNAME => RFC2445_OPTIONAL 1152 ); 1153 } 1154 1155 function is_valid_value($value) { 1156 if(!parent::is_valid_value($value)) { 1157 return false; 1158 } 1159 // Time MUST be in UTC format 1160 return(substr($value, -1) == 'Z'); 1161 } 1162 } 1163 1164 class iCalendar_property_dtstamp extends iCalendar_property { 1165 1166 var $name = 'DTSTAMP'; 1167 var $val_type = RFC2445_TYPE_DATE_TIME; 1168 1169 function __construct() { 1170 parent::__construct(); 1171 $this->valid_parameters = array( 1172 RFC2445_XNAME => RFC2445_OPTIONAL 1173 ); 1174 } 1175 1176 function is_valid_value($value) { 1177 if(!parent::is_valid_value($value)) { 1178 return false; 1179 } 1180 // Time MUST be in UTC format 1181 return(substr($value, -1) == 'Z'); 1182 } 1183 } 1184 1185 class iCalendar_property_last_modified extends iCalendar_property { 1186 1187 var $name = 'LAST-MODIFIED'; 1188 var $val_type = RFC2445_TYPE_DATE_TIME; 1189 1190 function __construct() { 1191 parent::__construct(); 1192 $this->valid_parameters = array( 1193 RFC2445_XNAME => RFC2445_OPTIONAL 1194 ); 1195 } 1196 1197 function is_valid_value($value) { 1198 if(!parent::is_valid_value($value)) { 1199 return false; 1200 } 1201 // Time MUST be in UTC format 1202 return(substr($value, -1) == 'Z'); 1203 } 1204 } 1205 1206 class iCalendar_property_sequence extends iCalendar_property { 1207 1208 var $name = 'SEQUENCE'; 1209 var $val_type = RFC2445_TYPE_INTEGER; 1210 var $val_default = 0; 1211 1212 function __construct() { 1213 parent::__construct(); 1214 $this->valid_parameters = array( 1215 RFC2445_XNAME => RFC2445_OPTIONAL 1216 ); 1217 } 1218 1219 function is_valid_value($value) { 1220 if(!parent::is_valid_value($value)) { 1221 return false; 1222 } 1223 $value = intval($value); 1224 return ($value >= 0); 1225 } 1226 } 1227 1228 // 4.8.8 Miscellaneous Component Properties 1229 // ---------------------------------------- 1230 1231 class iCalendar_property_x extends iCalendar_property { 1232 1233 var $name = RFC2445_XNAME; 1234 var $val_type = NULL; 1235 1236 function __construct() { 1237 parent::__construct(); 1238 $this->valid_parameters = array( 1239 // X-ALT-DESC (Description) can have FMTTYPE declaration of text/html is a property for HTML content. 1240 'FMTTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1241 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1242 RFC2445_XNAME => RFC2445_OPTIONAL 1243 ); 1244 } 1245 1246 function set_name($name) { 1247 1248 $name = strtoupper($name); 1249 1250 if(rfc2445_is_xname($name)) { 1251 $this->name = $name; 1252 return true; 1253 } 1254 1255 return false; 1256 } 1257 } 1258 1259 class iCalendar_property_request_status extends iCalendar_property { 1260 1261 // IMPORTANT NOTE: This property value includes TEXT fields 1262 // separated by semicolons. Unfortunately, auto-value-formatting 1263 // cannot be used in this case. As an exception, the value passed 1264 // to this property MUST be already escaped. 1265 1266 var $name = 'REQUEST-STATUS'; 1267 var $val_type = RFC2445_TYPE_TEXT; 1268 1269 function __construct() { 1270 parent::__construct(); 1271 $this->valid_parameters = array( 1272 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1273 RFC2445_XNAME => RFC2445_OPTIONAL 1274 ); 1275 } 1276 1277 function is_valid_value($value) { 1278 if(!is_string($value) || empty($value)) { 1279 return false; 1280 } 1281 1282 $len = strlen($value); 1283 $parts = array(); 1284 $from = 0; 1285 $escch = false; 1286 1287 for($i = 0; $i < $len; ++$i) { 1288 if($value[$i] == ';' && !$escch) { 1289 // Token completed 1290 $parts[] = substr($value, $from, $i - $from); 1291 $from = $i + 1; 1292 continue; 1293 } 1294 $escch = ($value[$i] == '\\'); 1295 } 1296 // Add one last token with the remaining text; if the value 1297 // ended with a ';' it was illegal, so check that this token 1298 // is not the empty string. 1299 $parts[] = substr($value, $from); 1300 1301 $count = count($parts); 1302 1303 // May have 2 or 3 tokens (last one is optional) 1304 if($count != 2 && $count != 3) { 1305 return false; 1306 } 1307 1308 // REMEMBER: if ANY part is empty, we have an illegal value 1309 1310 // First token must be hierarchical numeric status (3 levels max) 1311 if(strlen($parts[0]) == 0) { 1312 return false; 1313 } 1314 1315 if($parts[0][0] < '1' || $parts[0][0] > '4') { 1316 return false; 1317 } 1318 1319 $len = strlen($parts[0]); 1320 1321 // Max 3 levels, and can't end with a period 1322 if($len > 5 || $parts[0][$len - 1] == '.') { 1323 return false; 1324 } 1325 1326 for($i = 1; $i < $len; ++$i) { 1327 if(($i & 1) == 1 && $parts[0][$i] != '.') { 1328 // Even-indexed chars must be periods 1329 return false; 1330 } 1331 else if(($i & 1) == 0 && ($parts[0][$i] < '0' || $parts[0][$i] > '9')) { 1332 // Odd-indexed chars must be numbers 1333 return false; 1334 } 1335 } 1336 1337 // Second and third tokens must be TEXT, and already escaped, so 1338 // they are not allowed to have UNESCAPED semicolons, commas, slashes, 1339 // or any newlines at all 1340 1341 for($i = 1; $i < $count; ++$i) { 1342 if(strpos($parts[$i], "\n") !== false) { 1343 return false; 1344 } 1345 1346 $len = strlen($parts[$i]); 1347 if($len == 0) { 1348 // Cannot be empty 1349 return false; 1350 } 1351 1352 $parts[$i] .= '#'; // This guard token saves some conditionals in the loop 1353 1354 for($j = 0; $j < $len; ++$j) { 1355 $thischar = $parts[$i][$j]; 1356 $nextchar = $parts[$i][$j + 1]; 1357 if($thischar == '\\') { 1358 // Next char must now be one of ";,\nN" 1359 if($nextchar != ';' && $nextchar != ',' && $nextchar != '\\' && 1360 $nextchar != 'n' && $nextchar != 'N') { 1361 return false; 1362 } 1363 1364 // OK, this escaped sequence is correct, bypass next char 1365 ++$j; 1366 continue; 1367 } 1368 if($thischar == ';' || $thischar == ',' || $thischar == '\\') { 1369 // This wasn't escaped as it should 1370 return false; 1371 } 1372 } 1373 } 1374 1375 return true; 1376 } 1377 1378 function set_value($value) { 1379 // Must override this, otherwise the value would be quoted again 1380 if($this->is_valid_value($value)) { 1381 $this->value = $value; 1382 return true; 1383 } 1384 1385 return false; 1386 } 1387 1388 } 1389 1390 class iCalendar_property_tzid extends iCalendar_property { 1391 1392 var $name = 'TZID'; 1393 var $val_type = RFC2445_TYPE_TEXT; 1394 1395 function __construct() { 1396 parent::__construct(); 1397 $this->valid_parameters = array( 1398 RFC2445_XNAME => RFC2445_OPTIONAL 1399 ); 1400 } 1401 1402 function is_valid_value($value) { 1403 if(!parent::is_valid_value($value)) { 1404 return false; 1405 } else { 1406 return true; 1407 } 1408 } 1409 } 1410 1411 class iCalendar_property_tzname extends iCalendar_property { 1412 1413 var $name = 'TZNAME'; 1414 var $val_type = RFC2445_TYPE_TEXT; 1415 1416 function __construct() { 1417 parent::__construct(); 1418 $this->valid_parameters = array( 1419 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE, 1420 RFC2445_XNAME => RFC2445_OPTIONAL 1421 ); 1422 } 1423 1424 function is_valid_value($value) { 1425 if(!parent::is_valid_value($value)) { 1426 return false; 1427 } else { 1428 return true; 1429 } 1430 } 1431 } 1432 1433 class iCalendar_property_tzoffsetfrom extends iCalendar_property { 1434 1435 var $name = 'TZOFFSETFROM'; 1436 var $val_type = RFC2445_TYPE_UTC_OFFSET; 1437 1438 function __construct() { 1439 parent::__construct(); 1440 $this->valid_parameters = array( 1441 RFC2445_XNAME => RFC2445_OPTIONAL 1442 ); 1443 } 1444 1445 function is_valid_value($value) { 1446 if(!parent::is_valid_value($value)) { 1447 return false; 1448 } else { 1449 return true; 1450 } 1451 } 1452 } 1453 1454 class iCalendar_property_tzoffsetto extends iCalendar_property { 1455 1456 var $name = 'TZOFFSETTO'; 1457 var $val_type = RFC2445_TYPE_UTC_OFFSET; 1458 1459 function __construct() { 1460 parent::__construct(); 1461 $this->valid_parameters = array( 1462 RFC2445_XNAME => RFC2445_OPTIONAL 1463 ); 1464 } 1465 1466 function is_valid_value($value) { 1467 if(!parent::is_valid_value($value)) { 1468 return false; 1469 } else { 1470 return true; 1471 } 1472 } 1473 } 1474 1475 class iCalendar_property_tzurl extends iCalendar_property { 1476 1477 var $name = 'TZURL'; 1478 var $val_type = RFC2445_TYPE_URI; 1479 1480 function __construct() { 1481 parent::__construct(); 1482 $this->valid_parameters = array( 1483 RFC2445_XNAME => RFC2445_OPTIONAL 1484 ); 1485 } 1486 } 1487 1488 ####################### 1489 /* 1490 class iCalendar_property_class extends iCalendar_property { 1491 1492 var $name = 'CLASS'; 1493 var $val_type = RFC2445_TYPE_TEXT; 1494 1495 function __construct() { 1496 parent::__construct(); 1497 $this->valid_parameters = array( 1498 RFC2445_XNAME => RFC2445_OPTIONAL 1499 ); 1500 } 1501 } 1502 */ 1503
title
Description
Body
title
Description
Body
title
Description
Body
title
Body