26 protected $parameters;
61 function __construct( $name =
null, &$master =
null, &$refData =
null, $seek =
null ) {
62 parent::__construct($master);
65 if(isset($name) && strlen($name) > 0){
71 unset($this->content);
72 unset($this->parameters);
74 if ( isset($refData)){
76 if(gettype($refData) ==
'object') {
77 $this->iterator = &$refData;
81 $this->line = $refData;
83 unset($this->iterator);
87 unset($this->iterator);
106 if (isset($this->iterator)) {
107 $this->iterator->seek($this->seek);
108 $unescaped = $this->iterator->current();
109 }
else if (isset($this->line)) {
110 $unescaped = $this->line;
115 $this->ParseFrom($unescaped);
119 function ParseFrom( &$unescaped ) {
121 $unescaped = preg_replace( array(
'{\\\\[nN]}',
'{\\\\[rR]}'), array(
"\n",
"\r"), $unescaped);
126 $splitpos = strpos($unescaped,
':',$offset);
127 $start = substr($unescaped,0,$splitpos);
128 if ( substr($start,-1) ==
'\\' ) {
129 $offset = $splitpos + 1;
132 $quotecount = strlen(preg_replace(
'{[^"]}',
'', $start ));
133 if ( ($quotecount % 2) != 0 ) {
134 $offset = $splitpos + 1;
140 $values = substr($unescaped, $splitpos+1);
142 $possiblecontent = preg_replace(
"/\\\\([,;:\"\\\\])/",
'$1', $values);
145 if(!isset($this->content)){
147 $len = strlen($possiblecontent);
148 if($len > 0 &&
"\r" == $possiblecontent[$len-1]){
150 $possiblecontent = substr($possiblecontent, 0, $len-1);
152 $this->content = $possiblecontent;
160 $possiblename = strtoupper(array_shift( $parameters ));
163 if(!isset($this->name)){
164 $this->name = $possiblename;
169 if(!isset($this->parameters)){
170 $this->parameters = array();
171 foreach( $parameters AS $k => $v ) {
172 $pos = strpos($v,
'=');
174 $name = strtoupper(substr( $v, 0, $pos));
175 $value = substr( $v, $pos + 1);
178 $name = strtoupper($v);
181 if ( isset($value) && preg_match(
'{^"(.*)"$}', $value, $matches) ) {
182 $value = $matches[1];
184 if ( isset($this->parameters[$name]) && is_array($this->parameters[$name]) ) {
185 $this->parameters[$name][] = $value;
187 elseif ( isset($this->parameters[$name]) ) {
188 $this->parameters[$name] = array( $this->parameters[$name], $value);
191 $this->parameters[$name] = $value;
205 function Name( $newname =
null ) {
206 if ( $newname !=
null ) {
207 $this->name = strtoupper($newname);
208 if ( $this->isValid() ) $this->invalidate();
210 }
else if(!isset($this->name)){
224 function Value( $newvalue =
null ) {
225 if ( $newvalue !=
null ) {
226 $this->content = $newvalue;
227 if ( $this->isValid() ) $this->invalidate();
228 }
else if(!isset($this->content)){
231 return $this->content;
243 if ( $newparams !=
null ) {
244 $this->parameters = array();
245 foreach( $newparams AS $k => $v ) {
246 $this->parameters[strtoupper($k)] = $v;
248 if ( $this->isValid() ) $this->invalidate();
249 }
else if(!isset($this->parameters)){
252 return $this->parameters;
264 if ( isset($this->content) )
return strstr( $this->content, $search );
277 $name = strtoupper($name);
279 if(!isset($this->parameters)){
283 if ( isset($this->parameters[$name]) ){
284 return $this->parameters[$name];
297 if(!isset($this->parameters)){
301 if ( $this->isValid() ) {
306 $this->parameters[strtoupper($name)] = $value;
316 if(!isset($this->parameters)){
320 if ( $this->isValid() ) {
324 if ( $type !=
null ) {
325 $testtypes = (gettype($type) ==
'string' ? array( $type =>
true ) : $type );
327 foreach( $this->parameters AS $k => $v ) {
328 if ( isset($testtypes[$k]) && $testtypes[$k] ) {
329 unset($this->parameters[$k]);
335 private static function escapeParameter($p) {
336 if ( strpos($p,
';') ===
false && strpos($p,
':') ===
false )
return $p;
337 return '"'.str_replace(
'"',
'\\"',$p).
'"';
346 if(isset($this->parameters)){
347 foreach( $this->parameters AS $k => $v ) {
348 if ( is_array($v) ) {
349 foreach( $v AS $vv ) {
350 $rendered .= sprintf(
';%s=%s', $k, vProperty::escapeParameter($vv) );
355 $rendered .= sprintf(
';%s=%s', $k, vProperty::escapeParameter($v) );
358 $rendered .= sprintf(
';%s', $k);
379 if(!isset($this->name) || !isset($this->content) || !isset($this->parameters)) {
383 $property = preg_replace(
'/[;].*$/',
'', $this->name );
384 $escaped = $this->content;
385 $property = preg_replace(
'/^.*[.]/',
'', $property );
386 switch( $property ) {
388 case 'ATTACH':
case 'GEO':
case 'PERCENT-COMPLETE':
case 'PRIORITY':
389 case 'DURATION':
case 'FREEBUSY':
case 'TZOFFSETFROM':
case 'TZOFFSETTO':
390 case 'TZURL':
case 'ATTENDEE':
case 'ORGANIZER':
case 'RECURRENCE-ID':
391 case 'URL':
case 'EXRULE':
case 'SEQUENCE':
case 'CREATED':
392 case 'RRULE':
case 'REPEAT':
case 'TRIGGER':
case 'RDATE':
393 case 'COMPLETED':
case 'DTEND':
case 'DUE':
case 'DTSTART':
394 case 'DTSTAMP':
case 'LAST-MODIFIED':
case 'CREATED':
case 'EXDATE':
399 case 'ADR':
case 'N':
case 'ORG':
401 $escaped = str_replace(
'\\',
'\\\\', $escaped);
402 $escaped = preg_replace(
'/\r?\n/',
'\\n', $escaped);
403 $escaped = str_replace(
',',
'\\,', $escaped);
407 $escaped = str_replace(
'\\',
'\\\\', $escaped);
408 $escaped = preg_replace(
'/\r?\n/',
'\\n', $escaped);
409 $escaped = preg_replace(
"/([,;])/",
'\\\\$1', $escaped);
414 if ( (strlen($property) + strlen($escaped)) <= 72 ) {
415 $rendered = $property . $escaped;
417 else if ( (strlen($property) <= 72) && (strlen($escaped) <= 72) ) {
418 $rendered = $property .
"\r\n " . $escaped;
421 $rendered = preg_replace(
'/(.{72})/u',
'$1'.
"\r\n ", $property.$escaped );
428 public function __toString() {
444 foreach( $filters AS $k => $v ) {
445 $tag = $v->GetNSTag();
448 case 'urn:ietf:params:xml:ns:caldav:is-defined':
449 case 'urn:ietf:params:xml:ns:carddav:is-defined':
450 if ( empty($this->content) )
return false;
453 case 'urn:ietf:params:xml:ns:caldav:is-not-defined':
454 case 'urn:ietf:params:xml:ns:carddav:is-not-defined':
455 if ( ! empty($this->content) )
return false;
458 case 'urn:ietf:params:xml:ns:caldav:time-range':
462 case 'urn:ietf:params:xml:ns:carddav:text-match':
463 case 'urn:ietf:params:xml:ns:caldav:text-match':
465 $haystack = $this->
Value();
466 $match = $this->TestTextMatch($v, $haystack);
468 if ( $match != $matchAll )
return $match;
471 case 'urn:ietf:params:xml:ns:carddav:param-filter':
472 case 'urn:ietf:params:xml:ns:caldav:param-filter':
473 $subfilter = $v->GetContent();
476 if (empty($subfilter)) {
478 $match = isset($parameter);
480 if (!isset($parameter)) {
481 $parameter = [ null ];
482 } elseif (!is_array($parameter)) {
483 $parameter = explode(
',', $parameter);
487 foreach ($parameter as $param) {
494 if ( $match != $matchAll )
return $match;
498 dbg_error_log(
'myComponent',
' vProperty::TestFilter: unhandled tag "%s"', $tag );
507 function fill($sp, $en, $pe){
511 function TestTextMatch( $filter, $haystack ) {
513 if (!isset($haystack)) {
517 $search = $filter->GetContent();
518 $collation = $filter->GetAttribute(
"collation");
519 if (! isset($collation)) {
522 switch( strtolower($collation) ) {
526 case 'i;ascii-casemap':
527 case 'i;unicode-casemap':
531 $search = strtolower( $search );
532 $haystack = strtolower( $haystack );
536 $matchType = $filter->GetAttribute(
"match-type");
537 if (! isset($matchType)) {
540 switch( strtolower($matchType) ) {
542 $match = ( $haystack === $search );
545 $length = strlen($search);
549 $match = !strncmp($haystack, $search, $length);
553 $length = strlen($search);
557 $match = ( substr($haystack, -$length) === $search );
561 $length = strlen($search);
565 $match = strstr( $haystack, $search );
570 $negate = $filter->GetAttribute(
"negate-condition");
571 if ( isset($negate) && strtolower($negate) ==
"yes" ) {
579 foreach( $filters AS $k => $v ) {
580 $subtag = $v->GetNSTag();
583 case 'urn:ietf:params:xml:ns:caldav:is-not-defined':
584 case 'urn:ietf:params:xml:ns:carddav:is-not-defined':
585 if ( ! empty($parameter_value) )
return false;
588 case 'urn:ietf:params:xml:ns:caldav:time-range':
592 case 'urn:ietf:params:xml:ns:carddav:text-match':
593 case 'urn:ietf:params:xml:ns:caldav:text-match':
594 $match = $this->TestTextMatch($v, $parameter_value);
595 if ( ! $match )
return false;
599 dbg_error_log(
'myComponent',
' vProperty::TestParamFilter: unhandled tag "%s"', $tag );