/**
  * This method intercepts GET requests to non-files, and changes it into an HTTP PROPFIND request 
  * 
  * @param string $method 
  * @return bool 
  */
 public function httpGetInterceptor($method)
 {
     if ($method != 'GET') {
         return true;
     }
     $node = $this->server->tree->getNodeForPath($this->server->getRequestUri());
     if ($node instanceof Sabre_DAV_IFile) {
         return true;
     }
     $this->server->httpPropFind();
     return false;
 }
예제 #2
0
 /**
  * This function handles the calendar-query REPORT
  *
  * This report is used by clients to request calendar objects based on
  * complex conditions.
  * 
  * @param DOMNode $dom 
  * @return void
  */
 public function calendarQueryReport($dom)
 {
     $requestedProperties = array_keys(Sabre_DAV_XMLUtil::parseProperties($dom->firstChild));
     $filterNode = $dom->getElementsByTagNameNS('urn:ietf:params:xml:ns:caldav', 'filter');
     if ($filterNode->length !== 1) {
         throw new Sabre_DAV_Exception_BadRequest('The calendar-query report must have a filter element');
     }
     $filters = Sabre_CalDAV_XMLUtil::parseCalendarQueryFilters($filterNode->item(0));
     $requestedCalendarData = true;
     if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) {
         // We always retrieve calendar-data, as we need it for filtering.
         $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data';
         // If calendar-data wasn't explicitly requested, we need to remove
         // it after processing.
         $requestedCalendarData = false;
     }
     // These are the list of nodes that potentially match the requirement
     $candidateNodes = $this->server->getPropertiesForPath($this->server->getRequestUri(), $requestedProperties, $this->server->getHTTPDepth(0));
     $verifiedNodes = array();
     foreach ($candidateNodes as $node) {
         // If the node didn't have a calendar-data property, it must not be a calendar object
         if (!isset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
             continue;
         }
         if ($this->validateFilters($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'], $filters)) {
             if (!$requestedCalendarData) {
                 unset($node[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
             }
             $verifiedNodes[] = $node;
         }
     }
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->sendBody($this->server->generateMultiStatus($verifiedNodes));
 }
예제 #3
0
파일: Plugin.php 프로젝트: jtietema/Fizzy
 protected function principalPropertySearchReport($dom)
 {
     $searchableProperties = array('{DAV:}displayname' => 'display name');
     list($searchProperties, $requestedProperties) = $this->parsePrincipalPropertySearchReportRequest($dom);
     $uri = $this->server->getRequestUri();
     $result = array();
     $lookupResults = $this->server->getPropertiesForPath($uri, array_keys($searchProperties), 1);
     // The first item in the results is the parent, so we get rid of it.
     array_shift($lookupResults);
     $matches = array();
     foreach ($lookupResults as $lookupResult) {
         foreach ($searchProperties as $searchProperty => $searchValue) {
             if (!isset($searchableProperties[$searchProperty])) {
                 throw new Sabre_DAV_Exception_BadRequest('Searching for ' . $searchProperty . ' is not supported');
             }
             if (isset($lookupResult[200][$searchProperty]) && mb_stripos($lookupResult[200][$searchProperty], $searchValue, 0, 'UTF-8') !== false) {
                 $matches[] = $lookupResult['href'];
             }
         }
     }
     $matchProperties = array();
     foreach ($matches as $match) {
         list($result) = $this->server->getPropertiesForPath($match, $requestedProperties, 0);
         $matchProperties[] = $result;
     }
     $xml = $this->server->generateMultiStatus($matchProperties);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->sendBody($xml);
 }
예제 #4
0
 /**
  * Handles POST requests for tree operations
  * 
  * This method is not yet used.
  * 
  * @param string $method 
  * @return bool
  */
 public function httpPOSTHandler($method)
 {
     if ($method != 'POST') {
         return true;
     }
     if (isset($_POST['action'])) {
         switch ($_POST['action']) {
             case 'mkcol':
                 if (isset($_POST['name']) && trim($_POST['name'])) {
                     // Using basename() because we won't allow slashes
                     $folderName = trim(basename($_POST['name']));
                     $this->server->createDirectory($this->server->getRequestUri() . '/' . $folderName);
                 }
                 break;
             case 'put':
                 if ($_FILES) {
                     $file = current($_FILES);
                 } else {
                     break;
                 }
                 $newName = basename($file['name']);
                 if (isset($_POST['name']) && trim($_POST['name'])) {
                     $newName = trim(basename($_POST['name']));
                 }
                 if (is_uploaded_file($file['tmp_name'])) {
                     $parent = $this->server->tree->getNodeForPath(trim($this->server->getRequestUri(), '/'));
                     $parent->createFile($newName, fopen($file['tmp_name'], 'r'));
                 }
         }
     }
     $this->server->httpResponse->setHeader('Location', $this->server->httpRequest->getUri());
     return false;
 }
예제 #5
0
 /**
  * principalPropertySearchReport
  *
  * This method is responsible for handing the
  * {DAV:}principal-property-search report. This report can be used for
  * clients to search for groups of principals, based on the value of one
  * or more properties.
  *
  * @param DOMDocument $dom
  * @return void
  */
 protected function principalPropertySearchReport(DOMDocument $dom)
 {
     list($searchProperties, $requestedProperties, $applyToPrincipalCollectionSet) = $this->parsePrincipalPropertySearchReportRequest($dom);
     $uri = null;
     if (!$applyToPrincipalCollectionSet) {
         $uri = $this->server->getRequestUri();
     }
     $result = $this->principalSearch($searchProperties, $requestedProperties, $uri);
     $xml = $this->server->generateMultiStatus($result);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->sendBody($xml);
 }
예제 #6
0
 /**
  * This method handles the PROPFIND method. 
  *
  * It's a very lazy method, it won't bother checking the request body
  * for which properties were requested, and just sends back a default
  * set of properties.
  *
  * @param string $tempLocation 
  * @return void
  */
 public function httpPropfind($tempLocation)
 {
     if (!file_exists($tempLocation)) {
         return true;
     }
     $hR = $this->server->httpResponse;
     $hR->setHeader('X-Sabre-Temp', 'true');
     $hR->sendStatus(207);
     $hR->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $requestedProps = $this->server->parsePropFindRequest($this->server->httpRequest->getBody(true));
     $properties = array('href' => $this->server->getRequestUri(), 200 => array('{DAV:}getlastmodified' => new Sabre_DAV_Property_GetLastModified(filemtime($tempLocation)), '{DAV:}getcontentlength' => filesize($tempLocation), '{DAV:}resourcetype' => new Sabre_DAV_Property_ResourceType(null), '{http://www.rooftopsolutions.nl/NS/sabredav}tempFile' => true));
     $data = $this->server->generateMultiStatus(array($properties));
     $hR->sendBody($data);
     return false;
 }
예제 #7
0
 /**
  * This method is responsible for parsing the request and generating the
  * response for the CALDAV:free-busy-query REPORT.
  *
  * @param DOMNode $dom
  * @return void
  */
 protected function freeBusyQueryReport(DOMNode $dom)
 {
     $start = null;
     $end = null;
     foreach ($dom->firstChild->childNodes as $childNode) {
         $clark = Sabre_DAV_XMLUtil::toClarkNotation($childNode);
         if ($clark == '{' . self::NS_CALDAV . '}time-range') {
             $start = $childNode->getAttribute('start');
             $end = $childNode->getAttribute('end');
             break;
         }
     }
     if ($start) {
         $start = Sabre_VObject_DateTimeParser::parseDateTime($start);
     }
     if ($end) {
         $end = Sabre_VObject_DateTimeParser::parseDateTime($end);
     }
     if (!$start && !$end) {
         throw new Sabre_DAV_Exception_BadRequest('The freebusy report must have a time-range filter');
     }
     $acl = $this->server->getPlugin('acl');
     if (!$acl) {
         throw new Sabre_DAV_Exception('The ACL plugin must be loaded for free-busy queries to work');
     }
     $uri = $this->server->getRequestUri();
     $acl->checkPrivileges($uri, '{' . self::NS_CALDAV . '}read-free-busy');
     $calendar = $this->server->tree->getNodeForPath($uri);
     if (!$calendar instanceof Sabre_CalDAV_ICalendar) {
         throw new Sabre_DAV_Exception_NotImplemented('The free-busy-query REPORT is only implemented on calendars');
     }
     $objects = array_map(function ($child) {
         $obj = $child->get();
         if (is_resource($obj)) {
             $obj = stream_get_contents($obj);
         }
         return $obj;
     }, $calendar->getChildren());
     $generator = new Sabre_VObject_FreeBusyGenerator();
     $generator->setObjects($objects);
     $generator->setTimeRange($start, $end);
     $result = $generator->getResult();
     $result = $result->serialize();
     $this->server->httpResponse->sendStatus(200);
     $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
     $this->server->httpResponse->setHeader('Content-Length', strlen($result));
     $this->server->httpResponse->sendBody($result);
 }
예제 #8
0
 /**
  * This method is responsible for parsing the request and generating the
  * response for the CALDAV:free-busy-query REPORT.
  *
  * @param DOMNode $dom
  * @return void
  */
 protected function freeBusyQueryReport(DOMNode $dom)
 {
     $start = null;
     $end = null;
     foreach ($dom->firstChild->childNodes as $childNode) {
         $clark = Sabre_DAV_XMLUtil::toClarkNotation($childNode);
         if ($clark == '{' . self::NS_CALDAV . '}time-range') {
             $start = $childNode->getAttribute('start');
             $end = $childNode->getAttribute('end');
             break;
         }
     }
     if ($start) {
         $start = VObject\DateTimeParser::parseDateTime($start);
     }
     if ($end) {
         $end = VObject\DateTimeParser::parseDateTime($end);
     }
     if (!$start && !$end) {
         throw new Sabre_DAV_Exception_BadRequest('The freebusy report must have a time-range filter');
     }
     $acl = $this->server->getPlugin('acl');
     if (!$acl) {
         throw new Sabre_DAV_Exception('The ACL plugin must be loaded for free-busy queries to work');
     }
     $uri = $this->server->getRequestUri();
     $acl->checkPrivileges($uri, '{' . self::NS_CALDAV . '}read-free-busy');
     $calendar = $this->server->tree->getNodeForPath($uri);
     if (!$calendar instanceof Sabre_CalDAV_ICalendar) {
         throw new Sabre_DAV_Exception_NotImplemented('The free-busy-query REPORT is only implemented on calendars');
     }
     // Doing a calendar-query first, to make sure we get the most
     // performance.
     $urls = $calendar->calendarQuery(array('name' => 'VCALENDAR', 'comp-filters' => array(array('name' => 'VEVENT', 'comp-filters' => array(), 'prop-filters' => array(), 'is-not-defined' => false, 'time-range' => array('start' => $start, 'end' => $end))), 'prop-filters' => array(), 'is-not-defined' => false, 'time-range' => null));
     $objects = array_map(function ($url) use($calendar) {
         $obj = $calendar->getChild($url)->get();
         return $obj;
     }, $urls);
     $generator = new VObject\FreeBusyGenerator();
     $generator->setObjects($objects);
     $generator->setTimeRange($start, $end);
     $result = $generator->getResult();
     $result = $result->serialize();
     $this->server->httpResponse->sendStatus(200);
     $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
     $this->server->httpResponse->setHeader('Content-Length', strlen($result));
     $this->server->httpResponse->sendBody($result);
 }
예제 #9
0
 /**
  * principalPropertySearchReport
  *
  * This method is reponsible for handing the 
  * {DAV:}principal-property-search report. This report can be used for 
  * clients to search for groups of principals, based on the value of one
  * or more properties.
  * 
  * @param DOMDocument $dom 
  * @return void
  */
 protected function principalPropertySearchReport(DOMDocument $dom)
 {
     $searchableProperties = array('{DAV:}displayname' => 'display name');
     list($searchProperties, $requestedProperties, $applyToPrincipalCollectionSet) = $this->parsePrincipalPropertySearchReportRequest($dom);
     $result = array();
     if ($applyToPrincipalCollectionSet) {
         $uris = array();
     } else {
         $uris = array($this->server->getRequestUri());
     }
     $lookupResults = array();
     foreach ($uris as $uri) {
         $p = array_keys($searchProperties);
         $p[] = '{DAV:}resourcetype';
         $r = $this->server->getPropertiesForPath($uri, $p, 1);
         // The first item in the results is the parent, so we get rid of it.
         array_shift($r);
         $lookupResults = array_merge($lookupResults, $r);
     }
     $matches = array();
     foreach ($lookupResults as $lookupResult) {
         // We're only looking for principals
         if (!isset($lookupResult[200]['{DAV:}resourcetype']) || !$lookupResult[200]['{DAV:}resourcetype'] instanceof Sabre_DAV_Property_ResourceType || !$lookupResult[200]['{DAV:}resourcetype']->is('{DAV:}principal')) {
             continue;
         }
         foreach ($searchProperties as $searchProperty => $searchValue) {
             if (!isset($searchableProperties[$searchProperty])) {
                 // If a property is not 'searchable', the spec dictates
                 // this is not a match.
                 continue;
             }
             if (isset($lookupResult[200][$searchProperty]) && mb_stripos($lookupResult[200][$searchProperty], $searchValue, 0, 'UTF-8') !== false) {
                 $matches[] = $lookupResult['href'];
             }
         }
     }
     $matchProperties = array();
     foreach ($matches as $match) {
         list($result) = $this->server->getPropertiesForPath($match, $requestedProperties, 0);
         $matchProperties[] = $result;
     }
     $xml = $this->server->generateMultiStatus($matchProperties);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->sendBody($xml);
 }
예제 #10
0
 /**
  * This function handles the addressbook-query REPORT
  *
  * This report is used by the client to filter an addressbook based on a
  * complex query.
  *
  * @param DOMNode $dom
  * @return void
  */
 protected function addressbookQueryReport($dom)
 {
     $query = new Sabre_CardDAV_AddressBookQueryParser($dom);
     $query->parse();
     $depth = $this->server->getHTTPDepth(0);
     if ($depth == 0) {
         $candidateNodes = array($this->server->tree->getNodeForPath($this->server->getRequestUri()));
     } else {
         $candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri());
     }
     $validNodes = array();
     foreach ($candidateNodes as $node) {
         if (!$node instanceof Sabre_CardDAV_ICard) {
             continue;
         }
         $blob = $node->get();
         if (is_resource($blob)) {
             $blob = stream_get_contents($blob);
         }
         if (!$this->validateFilters($blob, $query->filters, $query->test)) {
             continue;
         }
         $validNodes[] = $node;
         if ($query->limit && $query->limit <= count($validNodes)) {
             // We hit the maximum number of items, we can stop now.
             break;
         }
     }
     $result = array();
     foreach ($validNodes as $validNode) {
         if ($depth == 0) {
             $href = $this->server->getRequestUri();
         } else {
             $href = $this->server->getRequestUri() . '/' . $validNode->getName();
         }
         list($result[]) = $this->server->getPropertiesForPath($href, $query->requestedProperties, 0);
     }
     $prefer = $this->server->getHTTPPRefer();
     $this->server->httpResponse->sendStatus(207);
     $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
     $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
     $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
 }
 /**
  * This method allows the exception to return any extra HTTP response headers.
  *
  * The headers must be returned as an array.
  * 
  * @return array 
  */
 public function getHTTPHeaders(Sabre_DAV_Server $server)
 {
     $methods = $server->getAllowedMethods($server->getRequestUri());
     return array('Allow' => strtoupper(implode(', ', $methods)));
 }
예제 #12
0
파일: Plugin.php 프로젝트: ngocanh/pimcore
 /**
  * validateLock should be called when a write operation is about to happen
  * It will check if the requested url is locked, and see if the correct lock tokens are passed 
  *
  * @param mixed $urls List of relevant urls. Can be an array, a string or nothing at all for the current request uri
  * @param mixed $lastLock This variable will be populated with the last checked lock object (Sabre_DAV_Locks_LockInfo)
  * @return bool
  */
 protected function validateLock($urls = null, &$lastLock = null)
 {
     if (is_null($urls)) {
         $urls = array($this->server->getRequestUri());
     } elseif (is_string($urls)) {
         $urls = array($urls);
     } elseif (!is_array($urls)) {
         throw new Sabre_DAV_Exception('The urls parameter should either be null, a string or an array');
     }
     $conditions = $this->getIfConditions();
     // We're going to loop through the urls and make sure all lock conditions are satisfied
     foreach ($urls as $url) {
         $locks = $this->getLocks($url);
         // If there were no conditions, but there were locks, we fail
         if (!$conditions && $locks) {
             reset($locks);
             $lastLock = current($locks);
             return false;
         }
         // If there were no locks or conditions, we go to the next url
         if (!$locks && !$conditions) {
             continue;
         }
         foreach ($conditions as $condition) {
             $conditionUri = $condition['uri'] ? $this->server->calculateUri($condition['uri']) : '';
             // If the condition has a url, and it isn't part of the affected url at all, check the next condition
             if ($conditionUri && strpos($url, $conditionUri) !== 0) {
                 continue;
             }
             // The tokens array contians arrays with 2 elements. 0=true/false for normal/not condition, 1=locktoken
             // At least 1 condition has to be satisfied
             foreach ($condition['tokens'] as $conditionToken) {
                 $etagValid = true;
                 $lockValid = true;
                 // key 2 can contain an etag
                 if ($conditionToken[2]) {
                     $uri = $conditionUri ? $conditionUri : $this->server->getRequestUri();
                     $node = $this->server->tree->getNodeForPath($uri);
                     $etagValid = $node->getETag() == $conditionToken[2];
                 }
                 // key 1 can contain a lock token
                 if ($conditionToken[1]) {
                     $lockValid = false;
                     // Match all the locks
                     foreach ($locks as $lockIndex => $lock) {
                         $lockToken = 'opaquelocktoken:' . $lock->token;
                         // Checking NOT
                         if (!$conditionToken[0] && $lockToken != $conditionToken[1]) {
                             // Condition valid, onto the next
                             $lockValid = true;
                             break;
                         }
                         if ($conditionToken[0] && $lockToken == $conditionToken[1]) {
                             $lastLock = $lock;
                             // Condition valid and lock matched
                             unset($locks[$lockIndex]);
                             $lockValid = true;
                             break;
                         }
                     }
                 }
                 // If, after checking both etags and locks they are stil valid,
                 // we can continue with the next condition.
                 if ($etagValid && $lockValid) {
                     continue 2;
                 }
             }
             // No conditions matched, so we fail
             throw new Sabre_DAV_Exception_PreconditionFailed('The tokens provided in the if header did not match', 'If');
         }
         // Conditions were met, we'll also need to check if all the locks are gone
         if (count($locks)) {
             reset($locks);
             // There's still locks, we fail
             $lastLock = current($locks);
             return false;
         }
     }
     // We got here, this means every condition was satisfied
     return true;
 }