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