/**
  * serialize
  *
  * @param DAV\Server $server
  * @param \DOMElement $dom
  * @return void
  */
 public function serialize(DAV\Server $server, \DOMElement $dom)
 {
     $document = $dom->ownerDocument;
     $properties = $this->responseProperties;
     $xresponse = $document->createElement('d:response');
     $dom->appendChild($xresponse);
     $uri = DAV\URLUtil::encodePath($this->href);
     // Adding the baseurl to the beginning of the url
     $uri = $server->getBaseUri() . $uri;
     $xresponse->appendChild($document->createElement('d:href', $uri));
     // The properties variable is an array containing properties, grouped by
     // HTTP status
     foreach ($properties as $httpStatus => $propertyGroup) {
         // The 'href' is also in this array, and it's special cased.
         // We will ignore it
         if ($httpStatus == 'href') {
             continue;
         }
         // If there are no properties in this group, we can also just carry on
         if (!count($propertyGroup)) {
             continue;
         }
         $xpropstat = $document->createElement('d:propstat');
         $xresponse->appendChild($xpropstat);
         $xprop = $document->createElement('d:prop');
         $xpropstat->appendChild($xprop);
         $nsList = $server->xmlNamespaces;
         foreach ($propertyGroup as $propertyName => $propertyValue) {
             $propName = null;
             preg_match('/^{([^}]*)}(.*)$/', $propertyName, $propName);
             // special case for empty namespaces
             if ($propName[1] == '') {
                 $currentProperty = $document->createElement($propName[2]);
                 $xprop->appendChild($currentProperty);
                 $currentProperty->setAttribute('xmlns', '');
             } else {
                 if (!isset($nsList[$propName[1]])) {
                     $nsList[$propName[1]] = 'x' . count($nsList);
                 }
                 // If the namespace was defined in the top-level xml namespaces, it means
                 // there was already a namespace declaration, and we don't have to worry about it.
                 if (isset($server->xmlNamespaces[$propName[1]])) {
                     $currentProperty = $document->createElement($nsList[$propName[1]] . ':' . $propName[2]);
                 } else {
                     $currentProperty = $document->createElementNS($propName[1], $nsList[$propName[1]] . ':' . $propName[2]);
                 }
                 $xprop->appendChild($currentProperty);
             }
             if (is_scalar($propertyValue)) {
                 $text = $document->createTextNode($propertyValue);
                 $currentProperty->appendChild($text);
             } elseif ($propertyValue instanceof DAV\PropertyInterface) {
                 $propertyValue->serialize($server, $currentProperty);
             } elseif (!is_null($propertyValue)) {
                 throw new DAV\Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName);
             }
         }
         $xpropstat->appendChild($document->createElement('d:status', $server->httpResponse->getStatusMessage($httpStatus)));
     }
 }
Exemple #2
0
 /**
  * Renames the node
  *
  * @param string $name The new name
  * @return void
  */
 public function setName($name)
 {
     list($parentPath, ) = DAV\URLUtil::splitPath($this->path);
     list(, $newName) = DAV\URLUtil::splitPath($name);
     $newPath = $parentPath . '/' . $newName;
     rename($this->path, $newPath);
     $this->path = $newPath;
 }
 /**
  * Handler for teh afterGetProperties event
  *
  * @param string $path
  * @param array $properties
  * @return void
  */
 public function afterGetProperties($path, &$properties)
 {
     if (array_key_exists('{DAV:}getcontenttype', $properties[404])) {
         list(, $fileName) = DAV\URLUtil::splitPath($path);
         $contentType = $this->getContentType($fileName);
         if ($contentType) {
             $properties[200]['{DAV:}getcontenttype'] = $contentType;
             unset($properties[404]['{DAV:}getcontenttype']);
         }
     }
 }
Exemple #4
0
 /**
  * Serializes this property.
  *
  * It will additionally prepend the href property with the server's base uri.
  *
  * @param DAV\Server $server
  * @param \DOMElement $dom
  * @return void
  */
 public function serialize(DAV\Server $server, \DOMElement $dom)
 {
     $prefix = $server->xmlNamespaces['DAV:'];
     $elem = $dom->ownerDocument->createElement($prefix . ':href');
     if ($this->autoPrefix) {
         $value = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href);
     } else {
         $value = $this->href;
     }
     $elem->appendChild($dom->ownerDocument->createTextNode($value));
     $dom->appendChild($elem);
 }
Exemple #5
0
 /**
  * Checks if the submitted iCalendar data is in fact, valid.
  *
  * An exception is thrown if it's not.
  *
  * @param resource|string $data
  * @param string $path
  * @return void
  */
 protected function validateICalendar(&$data, $path)
 {
     // If it's a stream, we convert it to a string first.
     if (is_resource($data)) {
         $data = stream_get_contents($data);
     }
     // Converting the data to unicode, if needed.
     $data = DAV\StringUtil::ensureUTF8($data);
     try {
         $vobj = VObject\Reader::read($data);
     } catch (VObject\ParseException $e) {
         throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage());
     }
     if ($vobj->name !== 'VCALENDAR') {
         throw new DAV\Exception\UnsupportedMediaType('This collection can only support iCalendar objects.');
     }
     // Get the Supported Components for the target calendar
     list($parentPath, $object) = DAV\URLUtil::splitPath($path);
     $calendarProperties = $this->server->getProperties($parentPath, array('{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'));
     $supportedComponents = $calendarProperties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue();
     $foundType = null;
     $foundUID = null;
     foreach ($vobj->getComponents() as $component) {
         switch ($component->name) {
             case 'VTIMEZONE':
                 continue 2;
             case 'VEVENT':
             case 'VTODO':
             case 'VJOURNAL':
                 if (is_null($foundType)) {
                     $foundType = $component->name;
                     if (!in_array($foundType, $supportedComponents)) {
                         throw new Exception\InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType);
                     }
                     if (!isset($component->UID)) {
                         throw new DAV\Exception\BadRequest('Every ' . $component->name . ' component must have an UID');
                     }
                     $foundUID = (string) $component->UID;
                 } else {
                     if ($foundType !== $component->name) {
                         throw new DAV\Exception\BadRequest('A calendar object must only contain 1 component. We found a ' . $component->name . ' as well as a ' . $foundType);
                     }
                     if ($foundUID !== (string) $component->UID) {
                         throw new DAV\Exception\BadRequest('Every ' . $component->name . ' in this object must have identical UIDs');
                     }
                 }
                 break;
             default:
                 throw new DAV\Exception\BadRequest('You are not allowed to create components of type: ' . $component->name . ' here');
         }
     }
     if (!$foundType) {
         throw new DAV\Exception\BadRequest('iCalendar object must contain at least 1 of VEVENT, VTODO or VJOURNAL');
     }
 }
 /**
  * Returns the name of this object
  *
  * @return string
  */
 public function getName()
 {
     list(, $name) = DAV\URLUtil::splitPath($this->principalInfo['uri']);
     return $name;
 }
 /**
  * This method is used to search for principals matching a set of
  * properties.
  *
  * This search is specifically used by RFC3744's principal-property-search
  * REPORT. You should at least allow searching on
  * http://sabredav.org/ns}email-address.
  *
  * The actual search should be a unicode-non-case-sensitive search. The
  * keys in searchProperties are the WebDAV property names, while the values
  * are the property values to search on.
  *
  * If multiple properties are being searched on, the search should be
  * AND'ed.
  *
  * This method should simply return an array with full principal uri's.
  *
  * If somebody attempted to search on a property the backend does not
  * support, you should simply return 0 results.
  *
  * You can also just return 0 results if you choose to not support
  * searching at all, but keep in mind that this may stop certain features
  * from working.
  *
  * @param string $prefixPath
  * @param array $searchProperties
  * @return array
  */
 public function searchPrincipals($prefixPath, array $searchProperties)
 {
     $query = 'SELECT uri FROM ' . $this->tableName . ' WHERE 1=1 ';
     $values = array();
     foreach ($searchProperties as $property => $value) {
         switch ($property) {
             case '{DAV:}displayname':
                 $query .= ' AND displayname LIKE ?';
                 $values[] = '%' . $value . '%';
                 break;
             case '{http://sabredav.org/ns}email-address':
                 $query .= ' AND email LIKE ?';
                 $values[] = '%' . $value . '%';
                 break;
             default:
                 // Unsupported property
                 return array();
         }
     }
     $stmt = $this->pdo->prepare($query);
     $stmt->execute($values);
     $principals = array();
     while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
         // Checking if the principal is in the prefix
         list($rowPrefix) = DAV\URLUtil::splitPath($row['uri']);
         if ($rowPrefix !== $prefixPath) {
             continue;
         }
         $principals[] = $row['uri'];
     }
     return $principals;
 }
Exemple #8
0
 /**
  * Triggered before a node is deleted
  *
  * This allows us to check permissions for any operation that will delete
  * an existing node.
  *
  * @param string $uri
  * @return void
  */
 public function beforeUnbind($uri)
 {
     list($parentUri, $nodeName) = DAV\URLUtil::splitPath($uri);
     $this->checkPrivileges($parentUri, '{DAV:}unbind', self::R_RECURSIVEPARENTS);
 }
 /**
  * Serializes the property into a DOMElement.
  *
  * @param DAV\Server $server
  * @param \DOMElement $node
  * @return void
  */
 public function serialize(DAV\Server $server, \DOMElement $node)
 {
     $prefix = $server->xmlNamespaces['DAV:'];
     switch ($this->type) {
         case self::UNAUTHENTICATED:
             $node->appendChild($node->ownerDocument->createElement($prefix . ':unauthenticated'));
             break;
         case self::AUTHENTICATED:
             $node->appendChild($node->ownerDocument->createElement($prefix . ':authenticated'));
             break;
         case self::HREF:
             $href = $node->ownerDocument->createElement($prefix . ':href');
             $href->nodeValue = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href);
             $node->appendChild($href);
             break;
     }
 }
 /**
  * Returns this principals name.
  *
  * @return string
  */
 public function getName()
 {
     $uri = $this->principalProperties['uri'];
     list(, $name) = DAV\URLUtil::splitPath($uri);
     return $name;
 }
Exemple #11
0
 /**
  * Generates the html directory index for a given url
  *
  * @param string $path
  * @return string
  */
 public function generateDirectoryIndex($path)
 {
     $version = '';
     if (DAV\Server::$exposeVersion) {
         $version = DAV\Version::VERSION . "-" . DAV\Version::STABILITY;
     }
     $html = "<html>\n<head>\n  <title>Index for " . $this->escapeHTML($path) . "/ - SabreDAV " . $version . "</title>\n  <style type=\"text/css\">\n  body { Font-family: arial}\n  h1 { font-size: 150% }\n  </style>\n        ";
     if ($this->enableAssets) {
         $html .= '<link rel="shortcut icon" href="' . $this->getAssetUrl('favicon.ico') . '" type="image/vnd.microsoft.icon" />';
     }
     $html .= "</head>\n<body>\n  <h1>Index for " . $this->escapeHTML($path) . "/</h1>\n  <table>\n    <tr><th width=\"24\"></th><th>Name</th><th>Type</th><th>Size</th><th>Last modified</th></tr>\n    <tr><td colspan=\"5\"><hr /></td></tr>";
     $files = $this->server->getPropertiesForPath($path, array('{DAV:}displayname', '{DAV:}resourcetype', '{DAV:}getcontenttype', '{DAV:}getcontentlength', '{DAV:}getlastmodified'), 1);
     $parent = $this->server->tree->getNodeForPath($path);
     if ($path) {
         list($parentUri) = DAV\URLUtil::splitPath($path);
         $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
         $icon = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="Parent" /></a>' : '';
         $html .= "<tr>\n    <td>{$icon}</td>\n    <td><a href=\"{$fullPath}\">..</a></td>\n    <td>[parent]</td>\n    <td></td>\n    <td></td>\n    </tr>";
     }
     foreach ($files as $file) {
         // This is the current directory, we can skip it
         if (rtrim($file['href'], '/') == $path) {
             continue;
         }
         list(, $name) = DAV\URLUtil::splitPath($file['href']);
         $type = null;
         if (isset($file[200]['{DAV:}resourcetype'])) {
             $type = $file[200]['{DAV:}resourcetype']->getValue();
             // resourcetype can have multiple values
             if (!is_array($type)) {
                 $type = array($type);
             }
             foreach ($type as $k => $v) {
                 // Some name mapping is preferred
                 switch ($v) {
                     case '{DAV:}collection':
                         $type[$k] = 'Collection';
                         break;
                     case '{DAV:}principal':
                         $type[$k] = 'Principal';
                         break;
                     case '{urn:ietf:params:xml:ns:carddav}addressbook':
                         $type[$k] = 'Addressbook';
                         break;
                     case '{urn:ietf:params:xml:ns:caldav}calendar':
                         $type[$k] = 'Calendar';
                         break;
                     case '{urn:ietf:params:xml:ns:caldav}schedule-inbox':
                         $type[$k] = 'Schedule Inbox';
                         break;
                     case '{urn:ietf:params:xml:ns:caldav}schedule-outbox':
                         $type[$k] = 'Schedule Outbox';
                         break;
                     case '{http://calendarserver.org/ns/}calendar-proxy-read':
                         $type[$k] = 'Proxy-Read';
                         break;
                     case '{http://calendarserver.org/ns/}calendar-proxy-write':
                         $type[$k] = 'Proxy-Write';
                         break;
                 }
             }
             $type = implode(', ', $type);
         }
         // If no resourcetype was found, we attempt to use
         // the contenttype property
         if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
             $type = $file[200]['{DAV:}getcontenttype'];
         }
         if (!$type) {
             $type = 'Unknown';
         }
         $size = isset($file[200]['{DAV:}getcontentlength']) ? (int) $file[200]['{DAV:}getcontentlength'] : '';
         $lastmodified = isset($file[200]['{DAV:}getlastmodified']) ? $file[200]['{DAV:}getlastmodified']->getTime()->format(\DateTime::ATOM) : '';
         $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
         $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
         $displayName = $this->escapeHTML($displayName);
         $type = $this->escapeHTML($type);
         $icon = '';
         if ($this->enableAssets) {
             $node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name);
             foreach (array_reverse($this->iconMap) as $class => $iconName) {
                 if ($node instanceof $class) {
                     $icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24" /></a>';
                     break;
                 }
             }
         }
         $html .= "<tr>\n    <td>{$icon}</td>\n    <td><a href=\"{$fullPath}\">{$displayName}</a></td>\n    <td>{$type}</td>\n    <td>{$size}</td>\n    <td>{$lastmodified}</td>\n    </tr>";
     }
     $html .= "<tr><td colspan=\"5\"><hr /></td></tr>";
     $output = '';
     if ($this->enablePost) {
         $this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output));
     }
     $html .= $output;
     $html .= "</table>\n        <address>Generated by SabreDAV " . $version . " (c)2007-2013 <a href=\"http://code.google.com/p/sabredav/\">http://code.google.com/p/sabredav/</a></address>\n        </body>\n        </html>";
     return $html;
 }
Exemple #12
0
 /**
  * Use this method to create a new collection
  *
  * The {DAV:}resourcetype is specified using the resourceType array.
  * At the very least it must contain {DAV:}collection.
  *
  * The properties array can contain a list of additional properties.
  *
  * @param string $uri The new uri
  * @param array $resourceType The resourceType(s)
  * @param array $properties A list of properties
  * @return array|null
  */
 public function createCollection($uri, array $resourceType, array $properties)
 {
     list($parentUri, $newName) = URLUtil::splitPath($uri);
     // Making sure {DAV:}collection was specified as resourceType
     if (!in_array('{DAV:}collection', $resourceType)) {
         throw new Exception\InvalidResourceType('The resourceType for this collection must at least include {DAV:}collection');
     }
     // Making sure the parent exists
     try {
         $parent = $this->tree->getNodeForPath($parentUri);
     } catch (Exception\NotFound $e) {
         throw new Exception\Conflict('Parent node does not exist');
     }
     // Making sure the parent is a collection
     if (!$parent instanceof ICollection) {
         throw new Exception\Conflict('Parent node is not a collection');
     }
     // Making sure the child does not already exist
     try {
         $parent->getChild($newName);
         // If we got here.. it means there's already a node on that url, and we need to throw a 405
         throw new Exception\MethodNotAllowed('The resource you tried to create already exists');
     } catch (Exception\NotFound $e) {
         // This is correct
     }
     if (!$this->broadcastEvent('beforeBind', array($uri))) {
         return;
     }
     // There are 2 modes of operation. The standard collection
     // creates the directory, and then updates properties
     // the extended collection can create it directly.
     if ($parent instanceof IExtendedCollection) {
         $parent->createExtendedCollection($newName, $resourceType, $properties);
     } else {
         // No special resourcetypes are supported
         if (count($resourceType) > 1) {
             throw new Exception\InvalidResourceType('The {DAV:}resourcetype you specified is not supported here.');
         }
         $parent->createDirectory($newName);
         $rollBack = false;
         $exception = null;
         $errorResult = null;
         if (count($properties) > 0) {
             try {
                 $errorResult = $this->updateProperties($uri, $properties);
                 if (!isset($errorResult[200])) {
                     $rollBack = true;
                 }
             } catch (Exception $e) {
                 $rollBack = true;
                 $exception = $e;
             }
         }
         if ($rollBack) {
             if (!$this->broadcastEvent('beforeUnbind', array($uri))) {
                 return;
             }
             $this->tree->delete($uri);
             // Re-throwing exception
             if ($exception) {
                 throw $exception;
             }
             return $errorResult;
         }
     }
     $this->tree->markDirty($parentUri);
     $this->broadcastEvent('afterBind', array($uri));
 }
 /**
  * This method is used to search for principals matching a set of
  * properties.
  *
  * This search is specifically used by RFC3744's principal-property-search
  * REPORT. You should at least allow searching on
  * http://sabredav.org/ns}email-address.
  *
  * The actual search should be a unicode-non-case-sensitive search. The
  * keys in searchProperties are the WebDAV property names, while the values
  * are the property values to search on.
  *
  * If multiple properties are being searched on, the search should be
  * AND'ed.
  *
  * This method should simply return a list of 'child names', which may be
  * used to call $this->getChild in the future.
  *
  * @param array $searchProperties
  * @return array
  */
 public function searchPrincipals(array $searchProperties)
 {
     $result = $this->principalBackend->searchPrincipals($this->principalPrefix, $searchProperties);
     $r = array();
     foreach ($result as $row) {
         list(, $r[]) = DAV\URLUtil::splitPath($row);
     }
     return $r;
 }
Exemple #14
0
 /**
  * Renames the node
  *
  * @param string $name The new name
  * @return void
  */
 public function setName($name)
 {
     list($parentPath, ) = DAV\URLUtil::splitPath($this->path);
     list(, $newName) = DAV\URLUtil::splitPath($name);
     $newPath = $parentPath . '/' . $newName;
     // We're deleting the existing resourcedata, and recreating it
     // for the new path.
     $resourceData = $this->getResourceData();
     $this->deleteResourceData();
     rename($this->path, $newPath);
     $this->path = $newPath;
     $this->putResourceData($resourceData);
 }