17 include_once(
'vObject.php');
19 include_once(
'vProperty.php');
29 private $propertyLocation;
31 const KEYBEGIN =
'BEGIN:';
32 const KEYBEGINLENGTH = 6;
33 const KEYEND =
"END:";
34 const KEYENDLENGTH = 4;
37 public static $PREPARSED =
false;
39 function __construct($propstring=null, &$refData=null){
40 parent::__construct($master);
44 if(isset($propstring) && gettype($propstring) ==
'string'){
45 $this->initFromText($propstring);
46 }
else if(isset($refData)){
47 if(gettype($refData) ==
'string'){
48 $this->initFromText($refData);
49 }
else if(gettype($refData) ==
'object') {
50 $this->initFromIterator($refData);
65 function initFromIterator(&$iterator, $begin = -1){
66 $this->iterator = &$iterator;
72 $iterator = $this->iterator;
74 $line = $iterator->current();
75 $seek = $iterator->key();
77 $posStart = strpos(strtoupper($line), vComponent::KEYBEGIN);
78 if($posStart !==
false && $posStart == 0){
79 if(!isset($this->type)){
80 $this->seekBegin = $seek;
82 $this->type = strtoupper(substr($line, vComponent::KEYBEGINLENGTH));
86 $posEnd = strpos(strtoupper($line), vComponent::KEYEND);
87 if($posEnd !==
false && $posEnd == 0){
88 $thisEnd = strtoupper(substr($line, vComponent::KEYENDLENGTH));
89 if($thisEnd == $this->type){
90 $this->seekEnd = $seek;
92 $len = strlen($this->type);
93 $last = $this->type[$len-1];
95 $this->type = strtoupper(substr($this->type, 0, $len-1));
109 }
while($iterator->valid());
114 public function getIterator(){
115 return $this->iterator;
118 function initFromText(&$plainText){
135 $arrayOfLines =
new ArrayObject(preg_split(
'{\r?\n}', $plain2));
136 $this->iterator = $arrayOfLines->getIterator();
142 $this->parseFrom($this->iterator);
147 if(isset($this->iterator) && isset($this->seekBegin)){
148 $this->iterator->seek($this->seekBegin);
164 if(!isset($this->properties) && !isset($this->components) && $this->isValid()){
165 unset($this->properties);
166 unset($this->components);
169 $this->parseFrom($this->iterator);
175 if(isset($this->components)){
176 foreach($this->components as $comp){
181 if($this->isValid()){
182 unset($this->properties);
183 unset($this->components);
190 function parseFrom(&$iterator){
193 $begin = $iterator->key();
198 $line = $iterator->current();
200 $end = $iterator->key();
202 $pos = strpos(strtoupper($line), vComponent::KEYBEGIN);
204 if($pos !==
false && $pos == 0) {
205 $type = strtoupper(substr($line, vComponent::KEYBEGINLENGTH));
207 if($typelen !== 0 && strncmp($this->type, $type, $typelen) !== 0){
208 $this->components[] =
new vComponent(null, $iterator);
214 $typelen = strlen($type);
215 if($type[$typelen-1] ==
"\r"){
217 $this->type = substr($type, 0, $typelen);
229 $pos = strpos(strtoupper($line), vComponent::KEYEND);
231 if($pos !==
false && $pos == 0) {
232 $this->seekBegin = $begin;
233 $this->seekEnd = $end;
250 $parameters = preg_split(
'(:|;)', $line);
251 $possiblename = strtoupper(array_shift( $parameters ));
252 $this->properties[] =
new vProperty($possiblename, $this->master, $iterator, $end);
263 if($iterator->valid())
266 }
while($iterator->valid() && ( !isset($this->seekEnd) || $this->seekEnd > $end ) );
280 return isset($this->components) ? count($this->components) : 0;
289 return isset($this->properties) ? count($this->properties) : 0;
299 return $this->components[$position];
305 function getPropertyAt($position){
308 return $this->properties[$position];
315 function clearPropertyAt($position) {
317 if($this->isValid()){
322 foreach( $this->properties AS $k => $v ) {
323 if ( $i == $position ) {
324 unset($this->properties[$k]);
328 $this->properties = array_values($this->properties);
344 if ( $this->isValid() ) {
347 $this->type = strtoupper($type);
359 if(isset($this->components)){
360 foreach( $this->components AS $k => $v ) {
361 $also = $v->CollectParameterValues($parameter_name);
362 $values = array_merge( $values, $also );
365 if(isset($this->properties)){
366 foreach( $this->properties AS $k => $v ) {
367 $also = $v->GetParameterValue($parameter_name);
368 if ( isset($also) && $also !=
"" ) {
384 foreach( $this->properties AS $k => $v ) {
385 if ( is_object($v) && $v->Name() == $type ) {
388 else if ( !is_object($v) ) {
389 dbg_error_log(
"ERROR",
'vComponent::GetProperty(): Trying to get %s on %s which is not an object!', $type, $v );
402 if ( isset($p) )
return $p->Value();
414 if(!isset($this->properties)){
417 $properties = array();
418 $testtypes = (gettype($type) ==
'string' ? array( $type =>
true ) : $type );
419 foreach( $this->properties AS $k => $v ) {
421 $name = preg_replace(
'/^.*[.]/',
'', $name );
422 if ( $type == null || (isset($testtypes[$name]) && $testtypes[$name])) {
439 $properties = array();
440 dbg_error_log(
'vComponent',
"GetPropertiesByPath: Querying within '%s' for path '%s'", $this->type, $path );
441 if ( !preg_match(
'#(/?)(!?)([^/]+)(/?.*)$#', $path, $matches ) )
return $properties;
443 $anchored = ($matches[1] ==
'/');
444 $inverted = ($matches[2] ==
'!');
445 $ourtest = $matches[3];
446 $therest = $matches[4];
447 dbg_error_log(
'vComponent',
"GetPropertiesByPath: Matches: %s -- %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3], $matches[4] );
448 if ( $ourtest ==
'*' || (($ourtest == $this->type) !== $inverted) && $therest !=
'' ) {
449 if ( preg_match(
'#^/(!?)([^/]+)$#', $therest, $matches ) ) {
450 $normmatch = ($matches[1] ==
'');
451 $proptest = $matches[2];
454 if(isset($thisproperties) && count($thisproperties) > 0){
455 foreach( $thisproperties AS $k => $v ) {
456 if ( $proptest ==
'*' || (($v->Name() == $proptest) === $normmatch ) ) {
468 $properties = array_merge( $properties, $v->GetPropertiesByPath($therest) );
478 $properties = array_merge( $properties, $v->GetPropertiesByPath($path) );
481 dbg_error_log(
'vComponent',
"GetPropertiesByPath: Found %d within '%s' for path '%s'\n", count($properties), $this->type, $path );
492 if($this->isValid()){
496 if ( $type != null ) {
497 $testtypes = (gettype($type) ==
'string' ? array( $type =>
true ) : $type );
499 foreach( $this->properties AS $k => $v ) {
500 if ( isset($testtypes[$v->Name()]) && $testtypes[$v->Name()] ) {
501 unset($this->properties[$k]);
505 $this->properties = array_values($this->properties);
509 $this->properties = array();
519 foreach( $new_properties AS $k => $v ) {
520 $this->properties[] = $v;
531 function AddProperty( $new_property, $value = null, $parameters = null ) {
533 if ( isset($value) && gettype($new_property) ==
'string' ) {
534 $new_prop =
new vProperty(
'', $this->master);
535 $new_prop->Name($new_property);
536 $new_prop->Value($value);
537 if ( $parameters != null ) {
538 $new_prop->Parameters($parameters);
541 $this->properties[] = $new_prop;
543 else if ( $new_property instanceof
vProperty ) {
544 $this->properties[] = $new_property;
545 $new_property->setMaster($this->master);
548 if($this->isValid()){
564 $components = isset($this->components) ? $this->components : array();
566 if ( $type != null ) {
568 $testtypes = (gettype($type) ==
'string' ? array( $type =>
true ) : $type );
569 foreach( $components AS $k => $v ) {
574 if ( !($normal_match && isset($testtypes[$v->GetType()]) && $testtypes[$v->GetType()] )
575 && !( !$normal_match && (!isset($testtypes[$v->GetType()]) || !$testtypes[$v->GetType()])) ) {
576 unset($components[$k]);
579 $components = array_values($components);
591 if($this->isValid()){
596 if ( $type != null && !empty($this->components)) {
597 $testtypes = (gettype($type) ==
'string' ? array( $type =>
true ) : $type );
599 foreach( $this->components AS $k => $v ) {
600 $this->components[$k]->ClearComponents($testtypes);
601 if ( isset($testtypes[$v->GetType()]) && $testtypes[$v->GetType()] ) {
602 unset($this->components[$k]);
603 if ( $this->isValid()) {
611 $this->components = array();
612 if ( $this->isValid()) {
617 return $this->isValid();
628 if ( $this->isValid()) {
631 if ( empty($type) ) {
632 $this->components = $new_component;
637 foreach( $new_component AS $k => $v ) {
638 $this->components[] = $v;
649 if ( is_array($new_component) && count($new_component) == 0 )
return;
651 if ( $this->isValid()) {
656 if ( is_array($new_component) ) {
657 foreach( $new_component AS $k => $v ) {
658 $this->components[] = $v;
659 if ( !method_exists($v,
'setMaster') ) fatal(
'Component to be added must be a vComponent');
660 $v->setMaster($this->master);
664 if ( !method_exists($new_component,
'setMaster') ) fatal(
'Component to be added must be a vComponent');
665 $new_component->setMaster($this->master);
666 $this->components[] = $new_component;
669 catch( Exception $e ) {
682 if(!isset($this->components)){
686 foreach( $this->components AS $k => $v ) {
687 if ( !isset($keep[$v->GetType()]) ) {
688 unset($this->components[$k]);
689 if ( $this->isValid()) {
693 else if ( $recursive ) {
694 $v->MaskComponents($keep);
706 if ( !isset($component_list) || isset($component_list[$this->type]) ) {
707 foreach( $this->properties AS $k => $v ) {
708 if ( !isset($keep[$v->Name()]) || !$keep[$v->Name()] ) {
709 unset($this->properties[$k]);
710 if ( $this->isValid()) {
716 if(isset($this->components)){
717 foreach( $this->components AS $k => $v ) {
718 $v->MaskProperties($keep, $component_list);
733 $strs = preg_split(
"/\r?\n/", $content );
735 foreach ($strs as $str) {
737 $wrapped_bit = (strlen($str) < 76 ? $str : preg_replace(
'/(.{72})/u',
'$1'.
"\r\n ", $str )) .self::VEOL;
739 $wrapped .= $wrapped_bit;
750 return preg_replace(
'/\r?\n[ \t]/',
'', $content );
761 $unrolledComponents = isset($this->components);
762 $rendered = vComponent::KEYBEGIN . $this->type . self::VEOL;
765 if($this->isValid()){
771 if($unrolledComponents){
773 foreach($this->components as $component){
776 $component_render = $component->RenderWithoutWrap( null, $force_rendering );
777 if(strlen($component_render) > 0){
778 $rendered .= $component_render . self::VEOL;
786 return $rendered . vComponent::KEYEND . $this->type;
795 if(isset($this->properties)){
796 foreach( $this->properties AS $k => $v ) {
797 if ( method_exists($v,
'Render') ) {
798 $forebug = $v->Render() . self::VEOL;
799 $rendered .= $forebug;
817 if(isset($this->type)){
818 $lentype = strlen($this->type);
821 $iterator = $this->iterator;
824 $line = $iterator->current() . self::VEOL;
825 $seek = $iterator->key();
827 $posStart = strpos($line, vComponent::KEYBEGIN);
828 if($posStart !==
false && $posStart == 0){
829 $type = substr($line, vComponent::KEYBEGINLENGTH);
830 if(!isset($this->type)){
833 $lentype = strlen($this->type);
834 }
else if(strncmp($type, $this->type, $lentype) != 0){
837 if($unrolledComponents){
845 $posEnd = strpos($line, vComponent::KEYEND);
846 if($posEnd !==
false && $posEnd == 0){
847 $thisEnd = substr($line, vComponent::KEYENDLENGTH);
848 if(strncmp($thisEnd, $this->type, $lentype) == 0){
850 $this->seekEnd = $seek;
853 }
else if($unrolledComponents){
861 }
else if($inInnerObject === 0 || !$unrolledComponents){
866 }
while($iterator->valid() && ( !isset($this->seekEnd) || $this->seekEnd > $seek));
880 function Render($restricted_properties = null, $force_rendering =
false){
887 if(isset($this->components)){
888 foreach($this->components as $comp){
889 if(!$comp->isValid()){
910 foreach( $filters AS $k => $v ) {
911 $tag = $v->GetNSTag();
914 case 'urn:ietf:params:xml:ns:caldav:is-defined':
915 case 'urn:ietf:params:xml:ns:carddav:is-defined':
916 if ( count($this->properties) == 0 && count($this->components) == 0 )
return false;
919 case 'urn:ietf:params:xml:ns:caldav:is-not-defined':
920 case 'urn:ietf:params:xml:ns:carddav:is-not-defined':
921 if ( count($this->properties) > 0 || count($this->components) > 0 )
return false;
924 case 'urn:ietf:params:xml:ns:caldav:comp-filter':
925 case 'urn:ietf:params:xml:ns:carddav:comp-filter':
926 $subcomponents = $this->
GetComponents($v->GetAttribute(
'name'));
927 $subfilter = $v->GetContent();
930 $subtag = $subfilter[0]->GetNSTag();
931 if ( $subtag ==
'urn:ietf:params:xml:ns:caldav:is-not-defined'
932 || $subtag ==
'urn:ietf:params:xml:ns:carddav:is-not-defined' ) {
933 if ( count($properties) > 0 ) {
938 else if ( count($subcomponents) == 0 ) {
939 if ( $subtag ==
'urn:ietf:params:xml:ns:caldav:is-defined'
940 || $subtag ==
'urn:ietf:params:xml:ns:carddav:is-defined' ) {
946 $negate = $subfilter[0]->GetAttribute(
"negate-condition");
947 if ( empty($negate) || strtolower($negate) !=
'yes' )
return false;
951 foreach( $subcomponents AS $kk => $subcomponent ) {
952 if ( ! $subcomponent->TestFilter($subfilter) )
return false;
957 case 'urn:ietf:params:xml:ns:carddav:prop-filter':
958 case 'urn:ietf:params:xml:ns:caldav:prop-filter':
959 $subfilter = $v->GetContent();
960 $properties = $this->
GetProperties($v->GetAttribute(
"name"));
961 dbg_error_log(
'vCalendar',
":TestFilter: Found '%d' props of type '%s'", count($properties), $v->GetAttribute(
'name') );
962 if ( empty($subfilter) ) {
964 $subtag = str_replace(
'prop-filter',
'is-defined', $tag);
966 $subtag = $subfilter[0]->GetNSTag();
968 if ( $subtag ==
'urn:ietf:params:xml:ns:caldav:is-not-defined'
969 || $subtag ==
'urn:ietf:params:xml:ns:carddav:is-not-defined' ) {
970 if ( count($properties) > 0 ) {
975 else if ( count($properties) == 0 ) {
976 if ( $subtag ==
'urn:ietf:params:xml:ns:caldav:is-defined'
977 || $subtag ==
'urn:ietf:params:xml:ns:carddav:is-defined' ) {
983 $negate = $subfilter[0]->GetAttribute(
"negate-condition");
984 if ( empty($negate) || strtolower($negate) !=
'yes' )
return false;
988 foreach( $properties AS $kk => $property ) {
989 if ( !empty($subfilter) && !$property->TestFilter($subfilter) )
return false;
AddComponent($new_component)
getComponentAt($position)
GetComponents($type=null, $normal_match=true)
SetComponents($new_component, $type=null)
MaskProperties($keep, $component_list=null)
ClearComponents($type=null)
GetPropertiesByPath($path)
UnwrapComponent(&$content)
SetProperties($new_properties, $type=null)
Render($restricted_properties=null, $force_rendering=false)
AddProperty($new_property, $value=null, $parameters=null)
ClearProperties($type=null)
RenderWithoutWrap($restricted_properties=null, $force_rendering=false)
RenderWithoutWrapFromIterator($unrolledComponents)
GetProperties($type=null)
MaskComponents($keep, $recursive=true)
RenderWithoutWrapFromObjects()
CollectParameterValues($parameter_name)