ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Sabre\CardDAV\Plugin Class Reference

CardDAV plugin. More...

+ Inheritance diagram for Sabre\CardDAV\Plugin:
+ Collaboration diagram for Sabre\CardDAV\Plugin:

Public Member Functions

 initialize (DAV\Server $server)
 Initializes the plugin. More...
 
 getFeatures ()
 Returns a list of supported features. More...
 
 getSupportedReportSet ($uri)
 Returns a list of reports this plugin supports. More...
 
 propFindEarly (DAV\PropFind $propFind, DAV\INode $node)
 Adds all CardDAV-specific properties. More...
 
 report ($reportName, $dom, $path)
 This functions handles REPORT requests specific to CardDAV. More...
 
 addressbookMultiGetReport ($report)
 This function handles the addressbook-multiget REPORT. More...
 
 beforeWriteContent ($path, DAV\IFile $node, &$data, &$modified)
 This method is triggered before a file gets updated with new content. More...
 
 beforeCreateFile ($path, &$data, DAV\ICollection $parentNode, &$modified)
 This method is triggered before a new file is created. More...
 
 validateFilters ($vcardData, array $filters, $test)
 Validates if a vcard makes it throught a list of filters. More...
 
 propFindLate (DAV\PropFind $propFind, DAV\INode $node)
 This event is triggered when fetching properties. More...
 
 htmlActionsPanel (DAV\INode $node, &$output)
 This method is used to generate HTML output for the Sabre. More...
 
 httpAfterGet (RequestInterface $request, ResponseInterface $response)
 This event is triggered after GET requests. More...
 
 getPluginName ()
 Returns a plugin name. More...
 
 getPluginInfo ()
 Returns a bunch of meta-data about the plugin. More...
 
- Public Member Functions inherited from Sabre\DAV\ServerPlugin
 initialize (Server $server)
 This initializes the plugin. More...
 
 getFeatures ()
 This method should return a list of server-features. More...
 
 getHTTPMethods ($path)
 Use this method to tell the server this plugin defines additional HTTP methods. More...
 
 getPluginName ()
 Returns a plugin name. More...
 
 getSupportedReportSet ($uri)
 Returns a list of reports this plugin supports. More...
 
 getPluginInfo ()
 Returns a bunch of meta-data about the plugin. More...
 

Data Fields

const ADDRESSBOOK_ROOT = 'addressbooks'
 Url to the addressbooks. More...
 
const NS_CARDDAV = 'urn:ietf:params:xml:ns:carddav'
 xml namespace for CardDAV elements More...
 
 $directories = []
 

Protected Member Functions

 getAddressbookHomeForPrincipal ($principal)
 Returns the addressbook home for a given principal. More...
 
 validateVCard (&$data, &$modified)
 Checks if the submitted iCalendar data is in fact, valid. More...
 
 addressbookQueryReport ($report)
 This function handles the addressbook-query REPORT. More...
 
 validateParamFilters (array $vProperties, array $filters, $test)
 Validates if a param-filter can be applied to a specific property. More...
 
 validateTextMatches (array $texts, array $filters, $test)
 Validates if a text-filter can be applied to a specific property. More...
 
 negotiateVCard ($input, &$mimeType=null)
 This helper function performs the content-type negotiation for vcards. More...
 
 convertVCard ($data, $target, array $propertiesFilter=null)
 Converts a vcard blob to a different version, or jcard. More...
 

Protected Attributes

 $server
 
 $maxResourceSize = 10000000
 The default PDO storage uses a MySQL MEDIUMBLOB for iCalendar data, which can hold up to 2^24 = 16777216 bytes. More...
 

Detailed Description

CardDAV plugin.

The CardDAV plugin adds CardDAV functionality to the WebDAV server

Author
Evert Pot (http://evertpot.com/) http://sabre.io/license/ Modified BSD License

Definition at line 23 of file Plugin.php.

Member Function Documentation

◆ addressbookMultiGetReport()

Sabre\CardDAV\Plugin::addressbookMultiGetReport (   $report)

This function handles the addressbook-multiget REPORT.

This report is used by the client to fetch the content of a series of urls. Effectively avoiding a lot of redundant requests.

Parameters
Xml\Request\AddressBookMultiGetReport$report
Returns
void

Definition at line 236 of file Plugin.php.

References $contentType, $paths, $version, Sabre\CardDAV\Plugin\convertVCard(), and Sabre\CardDAV\Plugin\negotiateVCard().

Referenced by Sabre\CardDAV\Plugin\report().

236  {
237 
238  $contentType = $report->contentType;
239  $version = $report->version;
240  if ($version) {
241  $contentType .= '; version=' . $version;
242  }
243 
244  $vcardType = $this->negotiateVCard(
246  );
247 
248  $propertyList = [];
249  $paths = array_map(
250  [$this->server, 'calculateUri'],
251  $report->hrefs
252  );
253  foreach ($this->server->getPropertiesForMultiplePaths($paths, $report->properties) as $props) {
254 
255  if (isset($props['200']['{' . self::NS_CARDDAV . '}address-data'])) {
256 
257  $props['200']['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard(
258  $props[200]['{' . self::NS_CARDDAV . '}address-data'],
259  $vcardType
260  );
261 
262  }
263  $propertyList[] = $props;
264 
265  }
266 
267  $prefer = $this->server->getHTTPPrefer();
268 
269  $this->server->httpResponse->setStatus(207);
270  $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
271  $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
272  $this->server->httpResponse->setBody($this->server->generateMultiStatus($propertyList, $prefer['return'] === 'minimal'));
273 
274  }
if($argc< 2) $paths
Definition: migrateto20.php:44
negotiateVCard($input, &$mimeType=null)
This helper function performs the content-type negotiation for vcards.
Definition: Plugin.php:805
$version
Definition: build.php:27
if($path[strlen($path) - 1]==='/') if(is_dir($path)) if(!file_exists($path)) if(preg_match('#\.php$#D', mb_strtolower($path, 'UTF-8'))) $contentType
Definition: module.php:144
convertVCard($data, $target, array $propertiesFilter=null)
Converts a vcard blob to a different version, or jcard.
Definition: Plugin.php:852
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addressbookQueryReport()

Sabre\CardDAV\Plugin::addressbookQueryReport (   $report)
protected

This function handles the addressbook-query REPORT.

This report is used by the client to filter an addressbook based on a complex query.

Parameters
Xml\Request\AddressBookQueryReport$report
Returns
void

Definition at line 430 of file Plugin.php.

References $contentType, $result, Sabre\CardDAV\Plugin\convertVCard(), Sabre\CardDAV\Plugin\negotiateVCard(), and Sabre\CardDAV\Plugin\validateFilters().

430  {
431 
432  $depth = $this->server->getHTTPDepth(0);
433 
434  if ($depth == 0) {
435  $candidateNodes = [
436  $this->server->tree->getNodeForPath($this->server->getRequestUri())
437  ];
438  if (!$candidateNodes[0] instanceof ICard) {
439  throw new ReportNotSupported('The addressbook-query report is not supported on this url with Depth: 0');
440  }
441  } else {
442  $candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri());
443  }
444 
445  $contentType = $report->contentType;
446  if ($report->version) {
447  $contentType .= '; version=' . $report->version;
448  }
449 
450  $vcardType = $this->negotiateVCard(
452  );
453 
454  $validNodes = [];
455  foreach ($candidateNodes as $node) {
456 
457  if (!$node instanceof ICard)
458  continue;
459 
460  $blob = $node->get();
461  if (is_resource($blob)) {
462  $blob = stream_get_contents($blob);
463  }
464 
465  if (!$this->validateFilters($blob, $report->filters, $report->test)) {
466  continue;
467  }
468 
469  $validNodes[] = $node;
470 
471  if ($report->limit && $report->limit <= count($validNodes)) {
472  // We hit the maximum number of items, we can stop now.
473  break;
474  }
475 
476  }
477 
478  $result = [];
479  foreach ($validNodes as $validNode) {
480 
481  if ($depth == 0) {
482  $href = $this->server->getRequestUri();
483  } else {
484  $href = $this->server->getRequestUri() . '/' . $validNode->getName();
485  }
486 
487  list($props) = $this->server->getPropertiesForPath($href, $report->properties, 0);
488 
489  if (isset($props[200]['{' . self::NS_CARDDAV . '}address-data'])) {
490 
491  $props[200]['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard(
492  $props[200]['{' . self::NS_CARDDAV . '}address-data'],
493  $vcardType,
494  $report->addressDataProperties
495  );
496 
497  }
498  $result[] = $props;
499 
500  }
501 
502  $prefer = $this->server->getHTTPPrefer();
503 
504  $this->server->httpResponse->setStatus(207);
505  $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
506  $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
507  $this->server->httpResponse->setBody($this->server->generateMultiStatus($result, $prefer['return'] === 'minimal'));
508 
509  }
$result
negotiateVCard($input, &$mimeType=null)
This helper function performs the content-type negotiation for vcards.
Definition: Plugin.php:805
validateFilters($vcardData, array $filters, $test)
Validates if a vcard makes it throught a list of filters.
Definition: Plugin.php:519
if($path[strlen($path) - 1]==='/') if(is_dir($path)) if(!file_exists($path)) if(preg_match('#\.php$#D', mb_strtolower($path, 'UTF-8'))) $contentType
Definition: module.php:144
convertVCard($data, $target, array $propertiesFilter=null)
Converts a vcard blob to a different version, or jcard.
Definition: Plugin.php:852
+ Here is the call graph for this function:

◆ beforeCreateFile()

Sabre\CardDAV\Plugin::beforeCreateFile (   $path,
$data,
DAV\ICollection  $parentNode,
$modified 
)

This method is triggered before a new file is created.

This plugin uses this method to ensure that Card nodes receive valid vcard data.

Parameters
string$path
resource$data
DAV\ICollection$parentNode
bool$modifiedShould be set to true, if this event handler changed &$data.
Returns
void

Definition at line 311 of file Plugin.php.

References $data, and Sabre\CardDAV\Plugin\validateVCard().

311  {
312 
313  if (!$parentNode instanceof IAddressBook)
314  return;
315 
316  $this->validateVCard($data, $modified);
317 
318  }
validateVCard(&$data, &$modified)
Checks if the submitted iCalendar data is in fact, valid.
Definition: Plugin.php:330
$data
Definition: bench.php:6
+ Here is the call graph for this function:

◆ beforeWriteContent()

Sabre\CardDAV\Plugin::beforeWriteContent (   $path,
DAV\IFile  $node,
$data,
$modified 
)

This method is triggered before a file gets updated with new content.

This plugin uses this method to ensure that Card nodes receive valid vcard data.

Parameters
string$path
DAV\IFile$node
resource$data
bool$modifiedShould be set to true, if this event handler changed &$data.
Returns
void

Definition at line 289 of file Plugin.php.

References $data, and Sabre\CardDAV\Plugin\validateVCard().

289  {
290 
291  if (!$node instanceof ICard)
292  return;
293 
294  $this->validateVCard($data, $modified);
295 
296  }
validateVCard(&$data, &$modified)
Checks if the submitted iCalendar data is in fact, valid.
Definition: Plugin.php:330
$data
Definition: bench.php:6
+ Here is the call graph for this function:

◆ convertVCard()

Sabre\CardDAV\Plugin::convertVCard (   $data,
  $target,
array  $propertiesFilter = null 
)
protected

Converts a vcard blob to a different version, or jcard.

Parameters
string | resource$data
string$target
array$propertiesFilter
Returns
string

Definition at line 852 of file Plugin.php.

References $data, $input, $key, $keys, Sabre\VObject\$output, $target, Sabre\VObject\Reader\read(), Sabre\VObject\Document\VCARD30, and Sabre\VObject\Document\VCARD40.

Referenced by Sabre\CardDAV\Plugin\addressbookMultiGetReport(), Sabre\CardDAV\Plugin\addressbookQueryReport(), and Sabre\CardDAV\Plugin\httpAfterGet().

852  {
853 
854  if (is_resource($data)) {
855  $data = stream_get_contents($data);
856  }
858  if (!empty($propertiesFilter)) {
859  $propertiesFilter = array_merge(['UID', 'VERSION', 'FN'], $propertiesFilter);
860  $keys = array_unique(array_map(function($child) {
861  return $child->name;
862  }, $input->children()));
863  $keys = array_diff($keys, $propertiesFilter);
864  foreach ($keys as $key) {
865  unset($input->$key);
866  }
867  $data = $input->serialize();
868  }
869  $output = null;
870  try {
871 
872  switch ($target) {
873  default :
874  case 'vcard3' :
875  if ($input->getDocumentType() === VObject\Document::VCARD30) {
876  // Do nothing
877  return $data;
878  }
879  $output = $input->convert(VObject\Document::VCARD30);
880  return $output->serialize();
881  case 'vcard4' :
882  if ($input->getDocumentType() === VObject\Document::VCARD40) {
883  // Do nothing
884  return $data;
885  }
886  $output = $input->convert(VObject\Document::VCARD40);
887  return $output->serialize();
888  case 'jcard' :
889  $output = $input->convert(VObject\Document::VCARD40);
890  return json_encode($output);
891 
892  }
893 
894  } finally {
895 
896  // Destroy circular references to PHP will GC the object.
897  $input->destroy();
898  if (!is_null($output)) {
899  $output->destroy();
900  }
901  }
902 
903  }
$keys
const VCARD30
vCard 3.0.
Definition: Document.php:44
static read($data, $options=0, $charset='UTF-8')
Parses a vCard or iCalendar object, and returns the top component.
Definition: Reader.php:42
const VCARD40
vCard 4.0.
Definition: Document.php:49
$target
Definition: test.php:19
$key
Definition: croninfo.php:18
$data
Definition: bench.php:6
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getAddressbookHomeForPrincipal()

Sabre\CardDAV\Plugin::getAddressbookHomeForPrincipal (   $principal)
protected

Returns the addressbook home for a given principal.

Parameters
string$principal
Returns
string

Definition at line 219 of file Plugin.php.

References Sabre\HTTP\URLUtil\splitPath().

219  {
220 
221  list(, $principalId) = \Sabre\HTTP\URLUtil::splitPath($principal);
222  return self::ADDRESSBOOK_ROOT . '/' . $principalId;
223 
224  }
static splitPath($path)
Returns the &#39;dirname&#39; and &#39;basename&#39; for a path.
Definition: URLUtil.php:83
+ Here is the call graph for this function:

◆ getFeatures()

Sabre\CardDAV\Plugin::getFeatures ( )

Returns a list of supported features.

This is used in the DAV: header in the OPTIONS and PROPFIND requests.

Returns
array

Definition at line 102 of file Plugin.php.

102  {
103 
104  return ['addressbook'];
105 
106  }

◆ getPluginInfo()

Sabre\CardDAV\Plugin::getPluginInfo ( )

Returns a bunch of meta-data about the plugin.

Providing this information is optional, and is mainly displayed by the Browser plugin.

The description key in the returned array may contain html and will not be sanitized.

Returns
array

Definition at line 930 of file Plugin.php.

References Sabre\CardDAV\Plugin\getPluginName().

930  {
931 
932  return [
933  'name' => $this->getPluginName(),
934  'description' => 'Adds support for CardDAV (rfc6352)',
935  'link' => 'http://sabre.io/dav/carddav/',
936  ];
937 
938  }
getPluginName()
Returns a plugin name.
Definition: Plugin.php:913
+ Here is the call graph for this function:

◆ getPluginName()

Sabre\CardDAV\Plugin::getPluginName ( )

Returns a plugin name.

Using this name other plugins will be able to access other plugins using DAV::getPlugin

Returns
string

Definition at line 913 of file Plugin.php.

Referenced by Sabre\CardDAV\Plugin\getPluginInfo().

913  {
914 
915  return 'carddav';
916 
917  }
+ Here is the caller graph for this function:

◆ getSupportedReportSet()

Sabre\CardDAV\Plugin::getSupportedReportSet (   $uri)

Returns a list of reports this plugin supports.

This will be used in the {DAV:}supported-report-set property. Note that you still need to subscribe to the 'report' event to actually implement them

Parameters
string$uri
Returns
array

Definition at line 118 of file Plugin.php.

118  {
119 
120  $node = $this->server->tree->getNodeForPath($uri);
121  if ($node instanceof IAddressBook || $node instanceof ICard) {
122  return [
123  '{' . self::NS_CARDDAV . '}addressbook-multiget',
124  '{' . self::NS_CARDDAV . '}addressbook-query',
125  ];
126  }
127  return [];
128 
129  }

◆ htmlActionsPanel()

Sabre\CardDAV\Plugin::htmlActionsPanel ( DAV\INode  $node,
$output 
)

This method is used to generate HTML output for the Sabre.

This allows us to generate an interface users can use to create new addressbooks.

Parameters
DAV\INode$node
string$output
Returns
bool

Definition at line 744 of file Plugin.php.

References Sabre\VObject\$output.

744  {
745 
746  if (!$node instanceof AddressBookHome)
747  return;
748 
749  $output .= '<tr><td colspan="2"><form method="post" action="">
750  <h3>Create new address book</h3>
751  <input type="hidden" name="sabreAction" value="mkcol" />
752  <input type="hidden" name="resourceType" value="{DAV:}collection,{' . self::NS_CARDDAV . '}addressbook" />
753  <label>Name (uri):</label> <input type="text" name="name" /><br />
754  <label>Display name:</label> <input type="text" name="{DAV:}displayname" /><br />
755  <input type="submit" value="create" />
756  </form>
757  </td></tr>';
758 
759  return false;
760 
761  }

◆ httpAfterGet()

Sabre\CardDAV\Plugin::httpAfterGet ( RequestInterface  $request,
ResponseInterface  $response 
)

This event is triggered after GET requests.

This is used to transform data into jCal, if this was requested.

Parameters
RequestInterface$request
ResponseInterface$response
Returns
void

Definition at line 772 of file Plugin.php.

References $target, Sabre\CardDAV\Plugin\convertVCard(), Sabre\HTTP\MessageInterface\getBody(), Sabre\HTTP\MessageInterface\getHeader(), Sabre\CardDAV\Plugin\negotiateVCard(), Sabre\HTTP\MessageInterface\setBody(), and Sabre\HTTP\MessageInterface\setHeader().

772  {
773 
774  if (strpos($response->getHeader('Content-Type'), 'text/vcard') === false) {
775  return;
776  }
777 
778  $target = $this->negotiateVCard($request->getHeader('Accept'), $mimeType);
779 
780  $newBody = $this->convertVCard(
781  $response->getBody(),
782  $target
783  );
784 
785  $response->setBody($newBody);
786  $response->setHeader('Content-Type', $mimeType . '; charset=utf-8');
787  $response->setHeader('Content-Length', strlen($newBody));
788 
789  }
foreach($paths as $path) $request
Definition: asyncclient.php:32
negotiateVCard($input, &$mimeType=null)
This helper function performs the content-type negotiation for vcards.
Definition: Plugin.php:805
convertVCard($data, $target, array $propertiesFilter=null)
Converts a vcard blob to a different version, or jcard.
Definition: Plugin.php:852
$response
$target
Definition: test.php:19
+ Here is the call graph for this function:

◆ initialize()

Sabre\CardDAV\Plugin::initialize ( DAV\Server  $server)

Initializes the plugin.

Parameters
DAV\Server$server
Returns
void

Definition at line 63 of file Plugin.php.

References Sabre\CardDAV\Plugin\$server.

63  {
64 
65  /* Events */
66  $server->on('propFind', [$this, 'propFindEarly']);
67  $server->on('propFind', [$this, 'propFindLate'], 150);
68  $server->on('report', [$this, 'report']);
69  $server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel']);
70  $server->on('beforeWriteContent', [$this, 'beforeWriteContent']);
71  $server->on('beforeCreateFile', [$this, 'beforeCreateFile']);
72  $server->on('afterMethod:GET', [$this, 'httpAfterGet']);
73 
74  $server->xml->namespaceMap[self::NS_CARDDAV] = 'card';
75 
76  $server->xml->elementMap['{' . self::NS_CARDDAV . '}addressbook-query'] = 'Sabre\\CardDAV\\Xml\\Request\\AddressBookQueryReport';
77  $server->xml->elementMap['{' . self::NS_CARDDAV . '}addressbook-multiget'] = 'Sabre\\CardDAV\\Xml\\Request\\AddressBookMultiGetReport';
78 
79  /* Mapping Interfaces to {DAV:}resourcetype values */
80  $server->resourceTypeMapping['Sabre\\CardDAV\\IAddressBook'] = '{' . self::NS_CARDDAV . '}addressbook';
81  $server->resourceTypeMapping['Sabre\\CardDAV\\IDirectory'] = '{' . self::NS_CARDDAV . '}directory';
82 
83  /* Adding properties that may never be changed */
84  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-address-data';
85  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}max-resource-size';
86  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}addressbook-home-set';
87  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-collation-set';
88 
89  $server->xml->elementMap['{http://calendarserver.org/ns/}me-card'] = 'Sabre\\DAV\\Xml\\Property\\Href';
90 
91  $this->server = $server;
92 
93  }

◆ negotiateVCard()

Sabre\CardDAV\Plugin::negotiateVCard (   $input,
$mimeType = null 
)
protected

This helper function performs the content-type negotiation for vcards.

It will return one of the following strings:

  1. vcard3
  2. vcard4
  3. jcard

It defaults to vcard3.

Parameters
string$input
string$mimeType
Returns
string

Definition at line 805 of file Plugin.php.

References $input, $result, and Sabre\HTTP\Util\negotiate().

Referenced by Sabre\CardDAV\Plugin\addressbookMultiGetReport(), Sabre\CardDAV\Plugin\addressbookQueryReport(), and Sabre\CardDAV\Plugin\httpAfterGet().

805  {
806 
808  $input,
809  [
810  // Most often used mime-type. Version 3
811  'text/x-vcard',
812  // The correct standard mime-type. Defaults to version 3 as
813  // well.
814  'text/vcard',
815  // vCard 4
816  'text/vcard; version=4.0',
817  // vCard 3
818  'text/vcard; version=3.0',
819  // jCard
820  'application/vcard+json',
821  ]
822  );
823 
824  $mimeType = $result;
825  switch ($result) {
826 
827  default :
828  case 'text/x-vcard' :
829  case 'text/vcard' :
830  case 'text/vcard; version=3.0' :
831  $mimeType = 'text/vcard';
832  return 'vcard3';
833  case 'text/vcard; version=4.0' :
834  return 'vcard4';
835  case 'application/vcard+json' :
836  return 'jcard';
837 
838  // @codeCoverageIgnoreStart
839  }
840  // @codeCoverageIgnoreEnd
841 
842  }
$result
static negotiate($acceptHeaderValue, array $availableOptions)
Deprecated! Use negotiateContentType.
Definition: Util.php:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ propFindEarly()

Sabre\CardDAV\Plugin::propFindEarly ( DAV\PropFind  $propFind,
DAV\INode  $node 
)

Adds all CardDAV-specific properties.

Parameters
DAV\PropFind$propFind
DAV\INode$node
Returns
void

Definition at line 139 of file Plugin.php.

References $path.

139  {
140 
141  $ns = '{' . self::NS_CARDDAV . '}';
142 
143  if ($node instanceof IAddressBook) {
144 
145  $propFind->handle($ns . 'max-resource-size', $this->maxResourceSize);
146  $propFind->handle($ns . 'supported-address-data', function() {
147  return new Xml\Property\SupportedAddressData();
148  });
149  $propFind->handle($ns . 'supported-collation-set', function() {
150  return new Xml\Property\SupportedCollationSet();
151  });
152 
153  }
154  if ($node instanceof DAVACL\IPrincipal) {
155 
156  $path = $propFind->getPath();
157 
158  $propFind->handle('{' . self::NS_CARDDAV . '}addressbook-home-set', function() use ($path) {
159  return new LocalHref($this->getAddressBookHomeForPrincipal($path) . '/');
160  });
161 
162  if ($this->directories) $propFind->handle('{' . self::NS_CARDDAV . '}directory-gateway', function() {
163  return new LocalHref($this->directories);
164  });
165 
166  }
167 
168  if ($node instanceof ICard) {
169 
170  // The address-data property is not supposed to be a 'real'
171  // property, but in large chunks of the spec it does act as such.
172  // Therefore we simply expose it as a property.
173  $propFind->handle('{' . self::NS_CARDDAV . '}address-data', function() use ($node) {
174  $val = $node->get();
175  if (is_resource($val))
176  $val = stream_get_contents($val);
177 
178  return $val;
179 
180  });
181 
182  }
183 
184  }
$path
Definition: aliased.php:25

◆ propFindLate()

Sabre\CardDAV\Plugin::propFindLate ( DAV\PropFind  $propFind,
DAV\INode  $node 
)

This event is triggered when fetching properties.

This event is scheduled late in the process, after most work for propfind has been done.

Parameters
DAV\PropFind$propFind
DAV\INode$node
Returns
void

Definition at line 718 of file Plugin.php.

References $contentType.

718  {
719 
720  // If the request was made using the SOGO connector, we must rewrite
721  // the content-type property. By default SabreDAV will send back
722  // text/x-vcard; charset=utf-8, but for SOGO we must strip that last
723  // part.
724  if (strpos($this->server->httpRequest->getHeader('User-Agent'), 'Thunderbird') === false) {
725  return;
726  }
727  $contentType = $propFind->get('{DAV:}getcontenttype');
728  list($part) = explode(';', $contentType);
729  if ($part === 'text/x-vcard' || $part === 'text/vcard') {
730  $propFind->set('{DAV:}getcontenttype', 'text/x-vcard');
731  }
732 
733  }
if($path[strlen($path) - 1]==='/') if(is_dir($path)) if(!file_exists($path)) if(preg_match('#\.php$#D', mb_strtolower($path, 'UTF-8'))) $contentType
Definition: module.php:144

◆ report()

Sabre\CardDAV\Plugin::report (   $reportName,
  $dom,
  $path 
)

This functions handles REPORT requests specific to CardDAV.

Parameters
string$reportName
\DOMNode$dom
mixed$path
Returns
bool

Definition at line 194 of file Plugin.php.

References Sabre\CardDAV\Plugin\addressbookMultiGetReport().

194  {
195 
196  switch ($reportName) {
197  case '{' . self::NS_CARDDAV . '}addressbook-multiget' :
198  $this->server->transactionType = 'report-addressbook-multiget';
199  $this->addressbookMultiGetReport($dom);
200  return false;
201  case '{' . self::NS_CARDDAV . '}addressbook-query' :
202  $this->server->transactionType = 'report-addressbook-query';
203  $this->addressBookQueryReport($dom);
204  return false;
205  default :
206  return;
207 
208  }
209 
210 
211  }
addressbookMultiGetReport($report)
This function handles the addressbook-multiget REPORT.
Definition: Plugin.php:236
+ Here is the call graph for this function:

◆ validateFilters()

Sabre\CardDAV\Plugin::validateFilters (   $vcardData,
array  $filters,
  $test 
)

Validates if a vcard makes it throught a list of filters.

Parameters
string$vcardData
array$filters
string$testanyof or allof (which means OR or AND)
Returns
bool

Definition at line 519 of file Plugin.php.

References $results, $success, $test, Sabre\VObject\Reader\read(), Sabre\CardDAV\Plugin\validateParamFilters(), and Sabre\CardDAV\Plugin\validateTextMatches().

Referenced by Sabre\CardDAV\Plugin\addressbookQueryReport().

519  {
520 
521 
522  if (!$filters) return true;
523  $vcard = VObject\Reader::read($vcardData);
524 
525  foreach ($filters as $filter) {
526 
527  $isDefined = isset($vcard->{$filter['name']});
528  if ($filter['is-not-defined']) {
529  if ($isDefined) {
530  $success = false;
531  } else {
532  $success = true;
533  }
534  } elseif ((!$filter['param-filters'] && !$filter['text-matches']) || !$isDefined) {
535 
536  // We only need to check for existence
537  $success = $isDefined;
538 
539  } else {
540 
541  $vProperties = $vcard->select($filter['name']);
542 
543  $results = [];
544  if ($filter['param-filters']) {
545  $results[] = $this->validateParamFilters($vProperties, $filter['param-filters'], $filter['test']);
546  }
547  if ($filter['text-matches']) {
548  $texts = [];
549  foreach ($vProperties as $vProperty)
550  $texts[] = $vProperty->getValue();
551 
552  $results[] = $this->validateTextMatches($texts, $filter['text-matches'], $filter['test']);
553  }
554 
555  if (count($results) === 1) {
556  $success = $results[0];
557  } else {
558  if ($filter['test'] === 'anyof') {
559  $success = $results[0] || $results[1];
560  } else {
561  $success = $results[0] && $results[1];
562  }
563  }
564 
565  } // else
566 
567  // There are two conditions where we can already determine whether
568  // or not this filter succeeds.
569  if ($test === 'anyof' && $success) {
570 
571  // Destroy circular references to PHP will GC the object.
572  $vcard->destroy();
573 
574  return true;
575  }
576  if ($test === 'allof' && !$success) {
577 
578  // Destroy circular references to PHP will GC the object.
579  $vcard->destroy();
580 
581  return false;
582  }
583 
584  } // foreach
585 
586 
587  // Destroy circular references to PHP will GC the object.
588  $vcard->destroy();
589 
590  // If we got all the way here, it means we haven't been able to
591  // determine early if the test failed or not.
592  //
593  // This implies for 'anyof' that the test failed, and for 'allof' that
594  // we succeeded. Sounds weird, but makes sense.
595  return $test === 'allof';
596 
597  }
validateParamFilters(array $vProperties, array $filters, $test)
Validates if a param-filter can be applied to a specific property.
Definition: Plugin.php:610
validateTextMatches(array $texts, array $filters, $test)
Validates if a text-filter can be applied to a specific property.
Definition: Plugin.php:675
$success
Definition: Utf8Test.php:86
static read($data, $options=0, $charset='UTF-8')
Parses a vCard or iCalendar object, and returns the top component.
Definition: Reader.php:42
$results
Definition: svg-scanner.php:47
$test
Definition: Utf8Test.php:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ validateParamFilters()

Sabre\CardDAV\Plugin::validateParamFilters ( array  $vProperties,
array  $filters,
  $test 
)
protected

Validates if a param-filter can be applied to a specific property.

Todo:
currently we're only validating the first parameter of the passed property. Any subsequence parameters with the same name are ignored.
Parameters
array$vProperties
array$filters
string$test
Returns
bool

Definition at line 610 of file Plugin.php.

References $success, $test, and Sabre\DAV\StringUtil\textMatch().

Referenced by Sabre\CardDAV\Plugin\validateFilters().

610  {
611 
612  foreach ($filters as $filter) {
613 
614  $isDefined = false;
615  foreach ($vProperties as $vProperty) {
616  $isDefined = isset($vProperty[$filter['name']]);
617  if ($isDefined) break;
618  }
619 
620  if ($filter['is-not-defined']) {
621  if ($isDefined) {
622  $success = false;
623  } else {
624  $success = true;
625  }
626 
627  // If there's no text-match, we can just check for existence
628  } elseif (!$filter['text-match'] || !$isDefined) {
629 
630  $success = $isDefined;
631 
632  } else {
633 
634  $success = false;
635  foreach ($vProperties as $vProperty) {
636  // If we got all the way here, we'll need to validate the
637  // text-match filter.
638  $success = DAV\StringUtil::textMatch($vProperty[$filter['name']]->getValue(), $filter['text-match']['value'], $filter['text-match']['collation'], $filter['text-match']['match-type']);
639  if ($success) break;
640  }
641  if ($filter['text-match']['negate-condition']) {
642  $success = !$success;
643  }
644 
645  } // else
646 
647  // There are two conditions where we can already determine whether
648  // or not this filter succeeds.
649  if ($test === 'anyof' && $success) {
650  return true;
651  }
652  if ($test === 'allof' && !$success) {
653  return false;
654  }
655 
656  }
657 
658  // If we got all the way here, it means we haven't been able to
659  // determine early if the test failed or not.
660  //
661  // This implies for 'anyof' that the test failed, and for 'allof' that
662  // we succeeded. Sounds weird, but makes sense.
663  return $test === 'allof';
664 
665  }
$success
Definition: Utf8Test.php:86
static textMatch($haystack, $needle, $collation, $matchType='contains')
Checks if a needle occurs in a haystack ;)
Definition: StringUtil.php:27
$test
Definition: Utf8Test.php:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ validateTextMatches()

Sabre\CardDAV\Plugin::validateTextMatches ( array  $texts,
array  $filters,
  $test 
)
protected

Validates if a text-filter can be applied to a specific property.

Parameters
array$texts
array$filters
string$test
Returns
bool

Definition at line 675 of file Plugin.php.

References $success, $test, and Sabre\DAV\StringUtil\textMatch().

Referenced by Sabre\CardDAV\Plugin\validateFilters().

675  {
676 
677  foreach ($filters as $filter) {
678 
679  $success = false;
680  foreach ($texts as $haystack) {
681  $success = DAV\StringUtil::textMatch($haystack, $filter['value'], $filter['collation'], $filter['match-type']);
682 
683  // Breaking on the first match
684  if ($success) break;
685  }
686  if ($filter['negate-condition']) {
687  $success = !$success;
688  }
689 
690  if ($success && $test === 'anyof')
691  return true;
692 
693  if (!$success && $test == 'allof')
694  return false;
695 
696 
697  }
698 
699  // If we got all the way here, it means we haven't been able to
700  // determine early if the test failed or not.
701  //
702  // This implies for 'anyof' that the test failed, and for 'allof' that
703  // we succeeded. Sounds weird, but makes sense.
704  return $test === 'allof';
705 
706  }
$success
Definition: Utf8Test.php:86
static textMatch($haystack, $needle, $collation, $matchType='contains')
Checks if a needle occurs in a haystack ;)
Definition: StringUtil.php:27
$test
Definition: Utf8Test.php:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ validateVCard()

Sabre\CardDAV\Plugin::validateVCard ( $data,
$modified 
)
protected

Checks if the submitted iCalendar data is in fact, valid.

An exception is thrown if it's not.

Parameters
resource | string$data
bool$modifiedShould be set to true, if this event handler changed &$data.
Returns
void

Definition at line 330 of file Plugin.php.

References $data, $message, $messages, PHPMailer\PHPMailer\$options, $vobj, Sabre\VObject\Node\PROFILE_CARDDAV, Sabre\VObject\Reader\read(), Sabre\VObject\Reader\readJson(), and Sabre\VObject\Node\REPAIR.

Referenced by Sabre\CardDAV\Plugin\beforeCreateFile(), and Sabre\CardDAV\Plugin\beforeWriteContent().

330  {
331 
332  // If it's a stream, we convert it to a string first.
333  if (is_resource($data)) {
334  $data = stream_get_contents($data);
335  }
336 
337  $before = $data;
338 
339  try {
340 
341  // If the data starts with a [, we can reasonably assume we're dealing
342  // with a jCal object.
343  if (substr($data, 0, 1) === '[') {
345 
346  // Converting $data back to iCalendar, as that's what we
347  // technically support everywhere.
348  $data = $vobj->serialize();
349  $modified = true;
350  } else {
352  }
353 
354  } catch (VObject\ParseException $e) {
355 
356  throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid vCard or jCard data. Parse error: ' . $e->getMessage());
357 
358  }
359 
360  if ($vobj->name !== 'VCARD') {
361  throw new DAV\Exception\UnsupportedMediaType('This collection can only support vcard objects.');
362  }
363 
365  $prefer = $this->server->getHTTPPrefer();
366 
367  if ($prefer['handling'] !== 'strict') {
369  }
370 
371  $messages = $vobj->validate($options);
372 
373  $highestLevel = 0;
374  $warningMessage = null;
375 
376  // $messages contains a list of problems with the vcard, along with
377  // their severity.
378  foreach ($messages as $message) {
379 
380  if ($message['level'] > $highestLevel) {
381  // Recording the highest reported error level.
382  $highestLevel = $message['level'];
383  $warningMessage = $message['message'];
384  }
385 
386  switch ($message['level']) {
387 
388  case 1 :
389  // Level 1 means that there was a problem, but it was repaired.
390  $modified = true;
391  break;
392  case 2 :
393  // Level 2 means a warning, but not critical
394  break;
395  case 3 :
396  // Level 3 means a critical error
397  throw new DAV\Exception\UnsupportedMediaType('Validation error in vCard: ' . $message['message']);
398 
399  }
400 
401  }
402  if ($warningMessage) {
403  $this->server->httpResponse->setHeader(
404  'X-Sabre-Ew-Gross',
405  'vCard validation warning: ' . $warningMessage
406  );
407 
408  // Re-serializing object.
409  $data = $vobj->serialize();
410  if (!$modified && strcmp($data, $before) !== 0) {
411  // This ensures that the system does not send an ETag back.
412  $modified = true;
413  }
414  }
415 
416  // Destroy circular references to PHP will GC the object.
417  $vobj->destroy();
418  }
$messages
Definition: en.php:5
catch(Exception $e) $message
$vobj
Definition: rrulebench.php:21
static readJson($data, $options=0)
Parses a jCard or jCal object, and returns the top component.
Definition: Reader.php:67
const REPAIR
The following constants are used by the validate() method.
Definition: Node.php:27
static read($data, $options=0, $charset='UTF-8')
Parses a vCard or iCalendar object, and returns the top component.
Definition: Reader.php:42
const PROFILE_CARDDAV
If this option is set, the validator will operate on the vcards on the assumption that the vcards nee...
Definition: Node.php:36
$data
Definition: bench.php:6
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Field Documentation

◆ $directories

Sabre\CardDAV\Plugin::$directories = []

Definition at line 41 of file Plugin.php.

◆ $maxResourceSize

Sabre\CardDAV\Plugin::$maxResourceSize = 10000000
protected

The default PDO storage uses a MySQL MEDIUMBLOB for iCalendar data, which can hold up to 2^24 = 16777216 bytes.

This is plenty. We're capping it to 10M here.

Definition at line 55 of file Plugin.php.

◆ $server

Sabre\CardDAV\Plugin::$server
protected

Definition at line 48 of file Plugin.php.

Referenced by Sabre\CardDAV\Plugin\initialize().

◆ ADDRESSBOOK_ROOT

const Sabre\CardDAV\Plugin::ADDRESSBOOK_ROOT = 'addressbooks'

Url to the addressbooks.

Definition at line 28 of file Plugin.php.

Referenced by Sabre\CardDAV\AddressBookRoot\getName().

◆ NS_CARDDAV

const Sabre\CardDAV\Plugin::NS_CARDDAV = 'urn:ietf:params:xml:ns:carddav'

The documentation for this class was generated from the following file: