4 * BENNU - PHP iCalendar library
5 * (c) 2005-2006 Ioannis Papaioannou (pj@moodle.org). All rights reserved.
7 * Released under the LGPL.
9 * See http://bennu.sourceforge.net/ for more information and downloads.
11 * @author Ioannis Papaioannou
13 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
16 class iCalendar_property
{
17 // Properties can have parameters, but cannot have other properties or components
19 var $parent_component = NULL;
21 var $parameters = NULL;
22 var $valid_parameters = NULL;
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;
28 function iCalendar_property() {
32 function construct() {
33 $this->parameters
= array();
36 // If some property needs extra care with its parameters, override this
37 // IMPORTANT: the parameter name MUST BE CAPITALIZED!
38 function is_valid_parameter($parameter, $value) {
40 if(is_array($value)) {
41 if(!iCalendar_parameter
::multiple_values_allowed($parameter)) {
44 foreach($value as $item) {
45 if(!iCalendar_parameter
::is_valid_value($this, $parameter, $item)) {
52 return iCalendar_parameter
::is_valid_value($this, $parameter, $value);
55 function invariant_holds() {
59 // If some property is very picky about its values, it should do the work itself
60 // Only data type validation is done here
61 function is_valid_value($value) {
62 if(is_array($value)) {
63 if(!$this->val_multi
) {
67 foreach($value as $oneval) {
68 if(!rfc2445_is_valid_value($oneval, $this->val_type
)) {
75 return rfc2445_is_valid_value($value, $this->val_type
);
78 function default_value() {
79 return $this->val_default
;
82 function set_parent_component($componentname) {
83 if(class_exists('iCalendar_'.strtolower(substr($componentname, 1)))) {
84 $this->parent_component
= strtoupper($componentname);
91 function set_value($value) {
92 if($this->is_valid_value($value)) {
93 // This transparently formats any value type according to the iCalendar specs
94 if(is_array($value)) {
95 foreach($value as $key => $item) {
96 $value[$key] = rfc2445_do_value_formatting($item, $this->val_type
);
98 $this->value
= implode(',', $value);
101 $this->value
= rfc2445_do_value_formatting($value, $this->val_type
);
109 function get_value() {
110 // First of all, assume that we have multiple values
111 $valarray = explode('\\,', $this->value
);
113 // Undo transparent formatting
114 $replace_function = create_function('$a', 'return rfc2445_undo_value_formatting($a, '.$this->val_type
.');');
115 $valarray = array_map($replace_function, $valarray);
117 // Now, if this property cannot have multiple values, don't return as an array
118 if(!$this->val_multi
) {
122 // Otherwise return an array even if it has one element, for uniformity
127 function set_parameter($name, $value) {
130 $name = strtoupper($name);
132 // Are we trying to add a valid parameter?
134 if(!isset($this->valid_parameters
[$name])) {
135 // If not, is it an x-name as per RFC 2445?
136 if(!rfc2445_is_xname($name)) {
139 // No more checks -- all components are supposed to allow x-name parameters
143 if(!$this->is_valid_parameter($name, $value)) {
147 if(is_array($value)) {
148 foreach($value as $key => $element) {
149 $value[$key] = iCalendar_parameter
::do_value_formatting($name, $element);
153 $value = iCalendar_parameter
::do_value_formatting($name, $value);
156 $this->parameters
[$name] = $value;
158 // Special case: if we just changed the VALUE parameter, reflect this
159 // in the object's status so that it only accepts correct type values
160 if($name == 'VALUE') {
161 // TODO: what if this invalidates an already-set value?
162 $this->val_type
= constant('RFC2445_TYPE_'.str_replace('-', '_', $value));
169 function get_parameter($name) {
172 $name = strtoupper($name);
174 if(isset($this->parameters
[$name])) {
175 // If there are any double quotes in the value, invisibly strip them
176 if(is_array($this->parameters
[$name])) {
177 foreach($this->parameters
[$name] as $key => $value) {
178 if(substr($value, 0, 1) == '"') {
179 $this->parameters
[$name][$key] = substr($value, 1, strlen($value) - 2);
182 return $this->parameters
[$name];
186 if(substr($this->parameters
[$name], 0, 1) == '"') {
187 return substr($this->parameters
[$name], 1, strlen($this->parameters
[$name]) - 2);
195 function serialize() {
196 $string = $this->name
;
198 if(!empty($this->parameters
)) {
199 foreach($this->parameters
as $name => $value) {
200 $string .= ';'.$name.'=';
201 if(is_array($value)) {
202 $string .= implode(',', $value);
210 $string .= ':'.$this->value
;
212 return rfc2445_fold($string) . RFC2445_CRLF
;
216 // 4.7 Calendar Properties
217 // -----------------------
219 class iCalendar_property_calscale
extends iCalendar_property
{
221 var $name = 'CALSCALE';
222 var $val_type = RFC2445_TYPE_TEXT
;
224 function construct() {
225 $this->valid_parameters
= array(
226 RFC2445_XNAME
=> RFC2445_OPTIONAL
230 function is_valid_value($value) {
231 // This is case-sensitive
232 return ($value === 'GREGORIAN');
236 class iCalendar_property_method
extends iCalendar_property
{
238 var $name = 'METHOD';
239 var $val_type = RFC2445_TYPE_TEXT
;
241 function construct() {
242 $this->valid_parameters
= array(
243 RFC2445_XNAME
=> RFC2445_OPTIONAL
247 function is_valid_value($value) {
248 // This is case-sensitive
249 // Methods from RFC 2446
250 $methods = array('PUBLISH', 'REQUEST', 'REPLY', 'ADD', 'CANCEL', 'REFRESH', 'COUNTER', 'DECLINECOUNTER');
251 return in_array($value, $methods);
255 class iCalendar_property_prodid
extends iCalendar_property
{
257 var $name = 'PRODID';
258 var $val_type = RFC2445_TYPE_TEXT
;
259 var $val_default = NULL;
261 function construct() {
262 $this->val_default
= '-//John Papaioannou/NONSGML Bennu '._BENNU_VERSION
.'//EN';
264 $this->valid_parameters
= array(
265 RFC2445_XNAME
=> RFC2445_OPTIONAL
270 class iCalendar_property_version
extends iCalendar_property
{
272 var $name = 'VERSION';
273 var $val_type = RFC2445_TYPE_TEXT
;
274 var $val_default = '2.0';
276 function construct() {
277 $this->valid_parameters
= array(
278 RFC2445_XNAME
=> RFC2445_OPTIONAL
282 function is_valid_value($value) {
283 return($value === '2.0' ||
$value === 2.0);
288 // 4.8.1 Descriptive Component Properties
289 // --------------------------------------
291 class iCalendar_property_attach
extends iCalendar_property
{
293 var $name = 'ATTACH';
294 var $val_type = RFC2445_TYPE_URI
;
296 function construct() {
297 $this->valid_parameters
= array(
298 'FMTTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
299 'ENCODING' => RFC2445_OPTIONAL | RFC2445_ONCE
,
300 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
301 RFC2445_XNAME
=> RFC2445_OPTIONAL
305 function invariant_holds() {
306 if(isset($this->parameters
['ENCODING']) && !isset($this->parameters
['VALUE'])) {
309 if(isset($this->parameters
['VALUE']) && !isset($this->parameters
['ENCODING'])) {
316 function is_valid_parameter($parameter, $value) {
318 $parameter = strtoupper($parameter);
320 if(!parent
::is_valid_parameter($parameter, $value)) {
324 if($parameter === 'ENCODING' && strtoupper($value) != 'BASE64') {
328 if($parameter === 'VALUE' && strtoupper($value) != 'BINARY') {
336 class iCalendar_property_categories
extends iCalendar_property
{
338 var $name = 'CATEGORIES';
339 var $val_type = RFC2445_TYPE_TEXT
;
340 var $val_multi = true;
342 function construct() {
343 $this->valid_parameters
= array(
344 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
345 RFC2445_XNAME
=> RFC2445_OPTIONAL
350 class iCalendar_property_class
extends iCalendar_property
{
353 var $val_type = RFC2445_TYPE_TEXT
;
354 var $val_default = 'PUBLIC';
356 function construct() {
357 $this->valid_parameters
= array(
358 RFC2445_XNAME
=> RFC2445_OPTIONAL
362 function is_valid_value($value) {
363 // If this is not an xname, it is case-sensitive
364 return ($value === 'PUBLIC' ||
$value === 'PRIVATE' ||
$value === 'CONFIDENTIAL' ||
rfc2445_is_xname(strtoupper($value)));
368 class iCalendar_property_comment
extends iCalendar_property
{
370 var $name = 'COMMENT';
371 var $val_type = RFC2445_TYPE_TEXT
;
373 function construct() {
374 $this->valid_parameters
= array(
375 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
376 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
377 RFC2445_XNAME
=> RFC2445_OPTIONAL
382 class iCalendar_property_description
extends iCalendar_property
{
384 var $name = 'DESCRIPTION';
385 var $val_type = RFC2445_TYPE_TEXT
;
387 function construct() {
388 $this->valid_parameters
= array(
389 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
390 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
391 RFC2445_XNAME
=> RFC2445_OPTIONAL
396 class iCalendar_property_geo
extends iCalendar_property
{
399 var $val_type = RFC2445_TYPE_TEXT
;
401 function construct() {
402 $this->valid_parameters
= array(
403 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
404 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
405 RFC2445_XNAME
=> RFC2445_OPTIONAL
409 function is_valid_value($value) {
410 // This MUST be two floats separated by a semicolon
411 if(!is_string($value)) {
415 $floats = explode(';', $value);
416 if(count($floats) != 2) {
420 return rfc2445_is_valid_value($floats[0], RFC2445_TYPE_FLOAT
) && rfc2445_is_valid_value($floats[1], RFC2445_TYPE_FLOAT
);
423 function set_value($value) {
424 // Must override this, otherwise the semicolon separating
425 // the two floats would get auto-quoted, which is illegal
426 if($this->is_valid_value($value)) {
427 $this->value
= $value;
436 class iCalendar_property_location
extends iCalendar_property
{
438 var $name = 'LOCATION';
439 var $val_type = RFC2445_TYPE_TEXT
;
441 function construct() {
442 $this->valid_parameters
= array(
443 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
444 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
445 RFC2445_XNAME
=> RFC2445_OPTIONAL
450 class iCalendar_property_percent_complete
extends iCalendar_property
{
452 var $name = 'PERCENT-COMPLETE';
453 var $val_type = RFC2445_TYPE_INTEGER
;
455 function construct() {
456 $this->valid_parameters
= array(
457 RFC2445_XNAME
=> RFC2445_OPTIONAL
461 function is_valid_value($value) {
462 // Only integers between 0 and 100 inclusive allowed
463 if(!parent
::is_valid_value($value)) {
466 $value = intval($value);
467 return ($value >= 0 && $value <= 100);
472 class iCalendar_property_priority
extends iCalendar_property
{
474 var $name = 'PRIORITY';
475 var $val_type = RFC2445_TYPE_INTEGER
;
477 function construct() {
478 $this->valid_parameters
= array(
479 RFC2445_XNAME
=> RFC2445_OPTIONAL
483 function is_valid_value($value) {
484 // Only integers between 0 and 9 inclusive allowed
485 if(!parent
::is_valid_value($value)) {
489 $value = intval($value);
490 return ($value >= 0 && $value <= 9);
494 class iCalendar_property_resources
extends iCalendar_property
{
496 var $name = 'RESOURCES';
497 var $val_type = RFC2445_TYPE_TEXT
;
498 var $val_multi = true;
500 function construct() {
501 $this->valid_parameters
= array(
502 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
503 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
504 RFC2445_XNAME
=> RFC2445_OPTIONAL
509 class iCalendar_property_status
extends iCalendar_property
{
511 var $name = 'STATUS';
512 var $val_type = RFC2445_TYPE_TEXT
;
514 function construct() {
515 $this->valid_parameters
= array(
516 RFC2445_XNAME
=> RFC2445_OPTIONAL
520 function is_valid_value($value) {
521 // This is case-sensitive
522 switch ($this->parent_component
) {
524 $allowed = array('TENTATIVE', 'CONFIRMED', 'CANCELLED');
527 $allowed = array('NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED');
530 $allowed = array('DRAFT', 'FINAL', 'CANCELLED');
533 return in_array($value, $allowed);
539 class iCalendar_property_summary
extends iCalendar_property
{
541 var $name = 'SUMMARY';
542 var $val_type = RFC2445_TYPE_TEXT
;
544 function construct() {
545 $this->valid_parameters
= array(
546 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
547 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
548 RFC2445_XNAME
=> RFC2445_OPTIONAL
553 // 4.8.2 Date and Time Component Properties
554 // ----------------------------------------
556 class iCalendar_property_completed
extends iCalendar_property
{
558 var $name = 'COMPLETED';
559 var $val_type = RFC2445_TYPE_DATE_TIME
;
561 function construct() {
562 $this->valid_parameters
= array(
563 RFC2445_XNAME
=> RFC2445_OPTIONAL
567 function is_valid_value($value) {
568 if(!parent
::is_valid_value($value)) {
571 // Time MUST be in UTC format
572 return(substr($value, -1) == 'Z');
576 class iCalendar_property_dtend
extends iCalendar_property
{
579 var $val_type = RFC2445_TYPE_DATE_TIME
;
581 function construct() {
582 $this->valid_parameters
= array(
583 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
584 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE
,
585 RFC2445_XNAME
=> RFC2445_OPTIONAL
589 function is_valid_value($value) {
590 if(!parent
::is_valid_value($value)) {
594 // If present in a FREEBUSY component, must be in UTC format
595 if($this->parent_component
== 'VFREEBUSY' && substr($value, -1) != 'Z') {
603 function is_valid_parameter($parameter, $value) {
605 $parameter = strtoupper($parameter);
607 if(!parent
::is_valid_parameter($parameter, $value)) {
610 if($parameter == 'VALUE' && !($value == 'DATE' ||
$value == 'DATE-TIME')) {
618 class iCalendar_property_due
extends iCalendar_property
{
621 var $val_type = RFC2445_TYPE_DATE_TIME
;
623 function construct() {
624 $this->valid_parameters
= array(
625 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
626 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE
,
627 RFC2445_XNAME
=> RFC2445_OPTIONAL
631 function is_valid_value($value) {
632 if(!parent
::is_valid_value($value)) {
636 // If present in a FREEBUSY component, must be in UTC format
637 if($this->parent_component
== 'VFREEBUSY' && substr($value, -1) != 'Z') {
645 function is_valid_parameter($parameter, $value) {
647 $parameter = strtoupper($parameter);
649 if(!parent
::is_valid_parameter($parameter, $value)) {
652 if($parameter == 'VALUE' && !($value == 'DATE' ||
$value == 'DATE-TIME')) {
660 class iCalendar_property_dtstart
extends iCalendar_property
{
662 var $name = 'DTSTART';
663 var $val_type = RFC2445_TYPE_DATE_TIME
;
665 function construct() {
666 $this->valid_parameters
= array(
667 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
668 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE
,
669 RFC2445_XNAME
=> RFC2445_OPTIONAL
673 // TODO: unimplemented stuff when parent is a VTIMEZONE component
675 function is_valid_value($value) {
676 if(!parent
::is_valid_value($value)) {
680 // If present in a FREEBUSY component, must be in UTC format
681 if($this->parent_component
== 'VFREEBUSY' && substr($value, -1) != 'Z') {
688 function is_valid_parameter($parameter, $value) {
690 $parameter = strtoupper($parameter);
692 if(!parent
::is_valid_parameter($parameter, $value)) {
695 if($parameter == 'VALUE' && !($value == 'DATE' ||
$value == 'DATE-TIME')) {
703 class iCalendar_property_duration
extends iCalendar_property
{
705 var $name = 'DURATION';
706 var $val_type = RFC2445_TYPE_DURATION
;
708 function construct() {
709 $this->valid_parameters
= array(
710 RFC2445_XNAME
=> RFC2445_OPTIONAL
714 function is_valid_value($value) {
715 if(!parent
::is_valid_value($value)) {
719 // Value must be positive
720 return ($value{0} != '-');
724 class iCalendar_property_freebusy
extends iCalendar_property
{
726 var $name = 'FREEBUSY';
727 var $val_type = RFC2445_TYPE_PERIOD
;
728 var $val_multi = true;
730 function construct() {
731 $this->valid_parameters
= array(
732 'FBTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
733 RFC2445_XNAME
=> RFC2445_OPTIONAL
737 function is_valid_value($value) {
738 if(!parent
::is_valid_value($value)) {
742 $pos = strpos($value, '/'); // We know there's only one / in there
743 if($value{$pos - 1} != 'Z') {
744 // Start time MUST be in UTC
747 if($value{$pos +
1} != 'P' && $substr($value, -1) != 'Z') {
748 // If the second part is not a period, it MUST be in UTC
755 // TODO: these properties SHOULD be shorted in ascending order (by start time and end time as tiebreak)
758 class iCalendar_property_transp
extends iCalendar_property
{
760 var $name = 'TRANSP';
761 var $val_type = RFC2445_TYPE_TEXT
;
762 var $val_default = 'OPAQUE';
764 function construct() {
765 $this->valid_parameters
= array(
766 RFC2445_XNAME
=> RFC2445_OPTIONAL
770 function is_valid_value($value) {
771 return ($value === 'TRANSPARENT' ||
$value === 'OPAQUE');
775 // TODO: 4.8.3 timezone component properties
778 // 4.8.4 Relationship Component Properties
779 // ---------------------------------------
781 class iCalendar_property_attendee
extends iCalendar_property
{
783 var $name = 'ATTENDEE';
784 var $val_type = RFC2445_TYPE_CAL_ADDRESS
;
786 // TODO: MUST NOT be specified when the calendar object has METHOD=PUBLISH
787 // TODO: standard has lots of detail here, make triple sure that we eventually conform
789 function construct() {
790 $this->valid_parameters
= array(
791 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
792 'CN' => RFC2445_OPTIONAL | RFC2445_ONCE
,
793 'ROLE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
794 'PARTSTAT' => RFC2445_OPTIONAL | RFC2445_ONCE
,
795 'RSVP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
796 'CUTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
797 'MEMBER' => RFC2445_OPTIONAL | RFC2445_ONCE
,
798 'DELEGATED-TO' => RFC2445_OPTIONAL | RFC2445_ONCE
,
799 'DELEGATED-FROM' => RFC2445_OPTIONAL | RFC2445_ONCE
,
800 'SENT-BY' => RFC2445_OPTIONAL | RFC2445_ONCE
,
801 'DIR' => RFC2445_OPTIONAL | RFC2445_ONCE
,
802 RFC2445_XNAME
=> RFC2445_OPTIONAL
806 function set_parent_component($componentname) {
807 if(!parent
::set_parent_component($componentname)) {
811 if($this->parent_component
== 'VFREEBUSY' ||
$this->parent_component
== 'VALARM') {
812 // Most parameters become invalid in this case, the full allowed set is now:
813 $this->valid_parameters
= array(
814 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
815 RFC2445_XNAME
=> RFC2445_OPTIONAL
824 class iCalendar_property_contact
extends iCalendar_property
{
826 var $name = 'CONTACT';
827 var $val_type = RFC2445_TYPE_TEXT
;
829 function construct() {
830 $this->valid_parameters
= array(
831 'ALTREP' => RFC2445_OPTIONAL | RFC2445_ONCE
,
832 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
833 RFC2445_XNAME
=> RFC2445_OPTIONAL
838 class iCalendar_property_organizer
extends iCalendar_property
{
840 var $name = 'ORGANIZER';
841 var $val_type = RFC2445_TYPE_CAL_ADDRESS
;
843 function construct() {
844 $this->valid_parameters
= array(
845 'CN' => RFC2445_OPTIONAL | RFC2445_ONCE
,
846 'DIR' => RFC2445_OPTIONAL | RFC2445_ONCE
,
847 'SENT-BY' => RFC2445_OPTIONAL | RFC2445_ONCE
,
848 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
849 RFC2445_XNAME
=> RFC2445_OPTIONAL
855 Conformance: This property MUST be specified in an iCalendar object
856 that specifies a group scheduled calendar entity. This property MUST
857 be specified in an iCalendar object that specifies the publication of
858 a calendar user's busy time. This property MUST NOT be specified in
859 an iCalendar object that specifies only a time zone definition or
860 that defines calendar entities that are not group scheduled entities,
861 but are entities only on a single user's calendar.
866 class iCalendar_property_recurrence_id
extends iCalendar_property
{
868 // TODO: can only be specified when defining recurring components in the calendar
870 Conformance: This property can be specified in an iCalendar object
871 containing a recurring calendar component.
873 Description: The full range of calendar components specified by a
874 recurrence set is referenced by referring to just the "UID" property
875 value corresponding to the calendar component. The "RECURRENCE-ID"
876 property allows the reference to an individual instance within the
880 var $name = 'RECURRENCE-ID';
881 var $val_type = RFC2445_TYPE_DATE_TIME
;
883 function construct() {
884 $this->valid_parameters
= array(
885 'RANGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
886 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE
,
887 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
888 RFC2445_XNAME
=> RFC2445_OPTIONAL
892 function is_valid_parameter($parameter, $value) {
894 $parameter = strtoupper($parameter);
896 if(!parent
::is_valid_parameter($parameter, $value)) {
899 if($parameter == 'VALUE' && !($value == 'DATE' ||
$value == 'DATE-TIME')) {
908 class iCalendar_property_related_to
extends iCalendar_property
{
910 var $name = 'RELATED-TO';
911 var $val_type = RFC2445_TYPE_TEXT
;
913 // TODO: the value of this property must reference another component's UID
915 function construct() {
916 $this->valid_parameters
= array(
917 'RELTYPE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
918 RFC2445_XNAME
=> RFC2445_OPTIONAL
923 class iCalendar_property_url
extends iCalendar_property
{
926 var $val_type = RFC2445_TYPE_URI
;
928 function construct() {
929 $this->valid_parameters
= array(
930 RFC2445_XNAME
=> RFC2445_OPTIONAL
935 class iCalendar_property_uid
extends iCalendar_property
{
938 var $val_type = RFC2445_TYPE_TEXT
;
940 function construct() {
941 $this->valid_parameters
= array(
942 RFC2445_XNAME
=> RFC2445_OPTIONAL
945 // The exception to the rule: this is not a static value, so we
946 // generate it on-the-fly here. Guaranteed to be different for
947 // each instance of this property, too. Nice.
948 $this->val_default
= Bennu
::generate_guid();
952 // 4.8.5 Recurrence Component Properties
953 // -------------------------------------
955 class iCalendar_property_exdate
extends iCalendar_property
{
957 var $name = 'EXDATE';
958 var $val_type = RFC2445_TYPE_DATE_TIME
;
959 var $val_multi = true;
961 function construct() {
962 $this->valid_parameters
= array(
963 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE
,
964 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
965 RFC2445_XNAME
=> RFC2445_OPTIONAL
969 function is_valid_parameter($parameter, $value) {
971 $parameter = strtoupper($parameter);
973 if(!parent
::is_valid_parameter($parameter, $value)) {
976 if($parameter == 'VALUE' && !($value == 'DATE' ||
$value == 'DATE-TIME')) {
985 class iCalendar_property_exrule
extends iCalendar_property
{
987 var $name = 'EXRULE';
988 var $val_type = RFC2445_TYPE_RECUR
;
990 function construct() {
991 $this->valid_parameters
= array(
992 RFC2445_XNAME
=> RFC2445_OPTIONAL
997 class iCalendar_property_rdate
extends iCalendar_property
{
1000 var $val_type = RFC2445_TYPE_DATE_TIME
;
1001 var $val_multi = true;
1003 function construct() {
1004 $this->valid_parameters
= array(
1005 'TZID' => RFC2445_OPTIONAL | RFC2445_ONCE
,
1006 'VALUE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
1007 RFC2445_XNAME
=> RFC2445_OPTIONAL
1011 function is_valid_parameter($parameter, $value) {
1013 $parameter = strtoupper($parameter);
1015 if(!parent
::is_valid_parameter($parameter, $value)) {
1018 if($parameter == 'VALUE' && !($value == 'DATE' ||
$value == 'DATE-TIME' ||
$value == 'PERIOD')) {
1027 class iCalendar_property_rrule
extends iCalendar_property
{
1029 var $name = 'RRULE';
1030 var $val_type = RFC2445_TYPE_RECUR
;
1032 function construct() {
1033 $this->valid_parameters
= array(
1034 RFC2445_XNAME
=> RFC2445_OPTIONAL
1039 // TODO: 4.8.6 Alarm Component Properties
1041 // 4.8.7 Change Management Component Properties
1042 // --------------------------------------------
1044 class iCalendar_property_created
extends iCalendar_property
{
1046 var $name = 'CREATED';
1047 var $val_type = RFC2445_TYPE_DATE_TIME
;
1049 function construct() {
1050 $this->valid_parameters
= array(
1051 RFC2445_XNAME
=> RFC2445_OPTIONAL
1055 function is_valid_value($value) {
1056 if(!parent
::is_valid_value($value)) {
1059 // Time MUST be in UTC format
1060 return(substr($value, -1) == 'Z');
1064 class iCalendar_property_dtstamp
extends iCalendar_property
{
1066 var $name = 'DTSTAMP';
1067 var $val_type = RFC2445_TYPE_DATE_TIME
;
1069 function construct() {
1070 $this->valid_parameters
= array(
1071 RFC2445_XNAME
=> RFC2445_OPTIONAL
1075 function is_valid_value($value) {
1076 if(!parent
::is_valid_value($value)) {
1079 // Time MUST be in UTC format
1080 return(substr($value, -1) == 'Z');
1084 class iCalendar_property_last_modified
extends iCalendar_property
{
1086 var $name = 'LAST-MODIFIED';
1087 var $val_type = RFC2445_TYPE_DATE_TIME
;
1089 function construct() {
1090 $this->valid_parameters
= array(
1091 RFC2445_XNAME
=> RFC2445_OPTIONAL
1095 function is_valid_value($value) {
1096 if(!parent
::is_valid_value($value)) {
1099 // Time MUST be in UTC format
1100 return(substr($value, -1) == 'Z');
1104 class iCalendar_property_sequence
extends iCalendar_property
{
1106 var $name = 'SEQUENCE';
1107 var $val_type = RFC2445_TYPE_INTEGER
;
1108 var $val_default = 0;
1110 function construct() {
1111 $this->valid_parameters
= array(
1112 RFC2445_XNAME
=> RFC2445_OPTIONAL
1116 function is_valid_value($value) {
1117 if(!parent
::is_valid_value($value)) {
1120 $value = intval($value);
1121 return ($value >= 0);
1125 // 4.8.8 Miscellaneous Component Properties
1126 // ----------------------------------------
1128 class iCalendar_property_x
extends iCalendar_property
{
1130 var $name = RFC2445_XNAME
;
1131 var $val_type = NULL;
1133 function construct() {
1134 $this->valid_parameters
= array(
1135 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
1136 RFC2445_XNAME
=> RFC2445_OPTIONAL
1140 function set_name($name) {
1142 $name = strtoupper($name);
1144 if(rfc2445_is_xname($name)) {
1145 $this->name
= $name;
1153 class iCalendar_property_request_status
extends iCalendar_property
{
1155 // IMPORTANT NOTE: This property value includes TEXT fields
1156 // separated by semicolons. Unfortunately, auto-value-formatting
1157 // cannot be used in this case. As an exception, the value passed
1158 // to this property MUST be already escaped.
1160 var $name = 'REQUEST-STATUS';
1161 var $val_type = RFC2445_TYPE_TEXT
;
1163 function construct() {
1164 $this->valid_parameters
= array(
1165 'LANGUAGE' => RFC2445_OPTIONAL | RFC2445_ONCE
,
1166 RFC2445_XNAME
=> RFC2445_OPTIONAL
1170 function is_valid_value($value) {
1171 if(!is_string($value) ||
empty($value)) {
1175 $len = strlen($value);
1180 for($i = 0; $i < $len; ++
$i) {
1181 if($value{$i} == ';' && !$escch) {
1183 $parts[] = substr($value, $from, $i - $from);
1187 $escch = ($value{$i} == '\\');
1189 // Add one last token with the remaining text; if the value
1190 // ended with a ';' it was illegal, so check that this token
1191 // is not the empty string.
1192 $parts[] = substr($value, $from);
1194 $count = count($parts);
1196 // May have 2 or 3 tokens (last one is optional)
1197 if($count != 2 && $count != 3) {
1201 // REMEMBER: if ANY part is empty, we have an illegal value
1203 // First token must be hierarchical numeric status (3 levels max)
1204 if(strlen($parts[0]) == 0) {
1208 if($parts[0]{0} < '1' ||
$parts[0]{0} > '4') {
1212 $len = strlen($parts[0]);
1214 // Max 3 levels, and can't end with a period
1215 if($len > 5 ||
$parts[0]{$len - 1} == '.') {
1219 for($i = 1; $i < $len; ++
$i) {
1220 if(($i & 1) == 1 && $parts[0]{$i} != '.') {
1221 // Even-indexed chars must be periods
1224 else if(($i & 1) == 0 && ($parts[0]{$i} < '0' ||
$parts[0]{$i} > '9')) {
1225 // Odd-indexed chars must be numbers
1230 // Second and third tokens must be TEXT, and already escaped, so
1231 // they are not allowed to have UNESCAPED semicolons, commas, slashes,
1232 // or any newlines at all
1234 for($i = 1; $i < $count; ++
$i) {
1235 if(strpos($parts[$i], "\n") !== false) {
1239 $len = strlen($parts[$i]);
1245 $parts[$i] .= '#'; // This guard token saves some conditionals in the loop
1247 for($j = 0; $j < $len; ++
$j) {
1248 $thischar = $parts[$i]{$j};
1249 $nextchar = $parts[$i]{$j +
1};
1250 if($thischar == '\\') {
1251 // Next char must now be one of ";,\nN"
1252 if($nextchar != ';' && $nextchar != ',' && $nextchar != '\\' &&
1253 $nextchar != 'n' && $nextchar != 'N') {
1257 // OK, this escaped sequence is correct, bypass next char
1261 if($thischar == ';' ||
$thischar == ',' ||
$thischar == '\\') {
1262 // This wasn't escaped as it should
1271 function set_value($value) {
1272 // Must override this, otherwise the value would be quoted again
1273 if($this->is_valid_value($value)) {
1274 $this->value
= $value;
1284 #######################
1286 class iCalendar_property_class extends iCalendar_property {
1288 var $name = 'CLASS';
1289 var $val_type = RFC2445_TYPE_TEXT;
1291 function construct() {
1292 $this->valid_parameters = array(
1293 RFC2445_XNAME => RFC2445_OPTIONAL