35        $server->on(
'method:GET',       [$this, 
'httpGet']);
 
   36        $server->on(
'method:OPTIONS',   [$this, 
'httpOptions']);
 
   37        $server->on(
'method:HEAD',      [$this, 
'httpHead']);
 
   38        $server->on(
'method:DELETE',    [$this, 
'httpDelete']);
 
   39        $server->on(
'method:PROPFIND',  [$this, 
'httpPropFind']);
 
   40        $server->on(
'method:PROPPATCH', [$this, 
'httpPropPatch']);
 
   41        $server->on(
'method:PUT',       [$this, 
'httpPut']);
 
   42        $server->on(
'method:MKCOL',     [$this, 
'httpMkcol']);
 
   43        $server->on(
'method:MOVE',      [$this, 
'httpMove']);
 
   44        $server->on(
'method:COPY',      [$this, 
'httpCopy']);
 
   45        $server->on(
'method:REPORT',    [$this, 
'httpReport']);
 
   47        $server->on(
'propPatch',        [$this, 
'propPatchProtectedPropertyCheck'], 90);
 
   48        $server->on(
'propPatch',        [$this, 
'propPatchNodeUpdate'], 200);
 
   49        $server->on(
'propFind',         [$this, 
'propFind']);
 
   50        $server->on(
'propFind',         [$this, 
'propFindNode'], 120);
 
   51        $server->on(
'propFind',         [$this, 
'propFindLate'], 200);
 
   53        $server->on(
'exception',        [$this, 
'exception']);
 
   81        $node = $this->server->tree->getNodeForPath(
$path);
 
   83        if (!$node instanceof 
IFile) 
return;
 
   88        if (is_string($body)) {
 
   89            $stream = fopen(
'php://temp', 
'r+');
 
   99        $httpHeaders = $this->server->getHTTPHeaders(
$path);
 
  104        if (!isset($httpHeaders[
'Content-Type'])) {
 
  105            $httpHeaders[
'Content-Type'] = 
'application/octet-stream';
 
  109        if (isset($httpHeaders[
'Content-Length'])) {
 
  111            $nodeSize = $httpHeaders[
'Content-Length'];
 
  114            unset($httpHeaders[
'Content-Length']);
 
  122        $range = $this->server->getHTTPRange();
 
  123        $ifRange = 
$request->getHeader(
'If-Range');
 
  124        $ignoreRangeHeader = 
false;
 
  128        if ($nodeSize && $range && $ifRange) {
 
  133                $ifRangeDate = new \DateTime($ifRange);
 
  137                if (!isset($httpHeaders[
'Last-Modified'])) $ignoreRangeHeader = 
true;
 
  139                    $modified = new \DateTime($httpHeaders[
'Last-Modified']);
 
  140                    if ($modified > $ifRangeDate) $ignoreRangeHeader = 
true;
 
  146                if (!isset($httpHeaders[
'ETag'])) $ignoreRangeHeader = 
true;
 
  147                elseif ($httpHeaders[
'ETag'] !== $ifRange) $ignoreRangeHeader = 
true;
 
  152        if (!$ignoreRangeHeader && $nodeSize && $range) {
 
  155            if (!is_null($range[0])) {
 
  158                $end = $range[1] ? $range[1] : $nodeSize - 1;
 
  163                if (
$end >= $nodeSize) 
$end = $nodeSize - 1;
 
  167                $start = $nodeSize - $range[1];
 
  168                $end = $nodeSize - 1;
 
  177            if (!stream_get_meta_data($body)[
'seekable'] || fseek($body, 
$start, SEEK_SET) === -1) {
 
  178                $consumeBlock = 8192;
 
  179                for ($consumed = 0; 
$start - $consumed > 0;){
 
  181                    $consumed += strlen(fread($body, min(
$start - $consumed, $consumeBlock)));
 
  192            if ($nodeSize) 
$response->setHeader(
'Content-Length', $nodeSize);
 
  212        $methods = $this->server->getAllowedMethods(
$request->getPath());
 
  214        $response->setHeader(
'Allow', strtoupper(implode(
', ', $methods)));
 
  215        $features = [
'1', 
'3', 
'extended-mkcol'];
 
  217        foreach ($this->server->getPlugins() as $plugin) {
 
  218            $features = array_merge($features, $plugin->getFeatures());
 
  221        $response->setHeader(
'DAV', implode(
', ', $features));
 
  222        $response->setHeader(
'MS-Author-Via', 
'DAV');
 
  223        $response->setHeader(
'Accept-Ranges', 
'bytes');
 
  224        $response->setHeader(
'Content-Length', 
'0');
 
  263            $response->setHeader(
'Content-Type', 
'text/plain');
 
  264            $response->setHeader(
'X-Sabre-Real-Status', $e->getHTTPCode());
 
  286        if (!$this->server->emit(
'beforeUnbind', [
$path])) 
return false;
 
  287        $this->server->tree->delete(
$path);
 
  288        $this->server->emit(
'afterUnbind', [
$path]);
 
  291        $response->setHeader(
'Content-Length', 
'0');
 
  319        $requestBody = 
$request->getBodyAsString();
 
  320        if (strlen($requestBody)) {
 
  322                $propFindXml = $this->server->xml->expect(
'{DAV:}propfind', $requestBody);
 
  324                throw new BadRequest($e->getMessage(), 
null, $e);
 
  328            $propFindXml->allProp = 
true;
 
  329            $propFindXml->properties = [];
 
  332        $depth = $this->server->getHTTPDepth(1);
 
  334        if (!$this->server->enablePropfindDepthInfinity && $depth != 0) $depth = 1;
 
  336        $newProperties = $this->server->getPropertiesIteratorForPath(
$path, $propFindXml->properties, $depth);
 
  340        $response->setHeader(
'Content-Type', 
'application/xml; charset=utf-8');
 
  341        $response->setHeader(
'Vary', 
'Brief,Prefer');
 
  346        $features = [
'1', 
'3', 
'extended-mkcol'];
 
  347        foreach ($this->server->getPlugins() as $plugin) {
 
  348            $features = array_merge($features, $plugin->getFeatures());
 
  350        $response->setHeader(
'DAV', implode(
', ', $features));
 
  352        $prefer = $this->server->getHTTPPrefer();
 
  353        $minimal = $prefer[
'return'] === 
'minimal';
 
  355        $data = $this->server->generateMultiStatus($newProperties, $minimal);
 
  379            $propPatch = $this->server->xml->expect(
'{DAV:}propertyupdate', 
$request->getBody());
 
  381            throw new BadRequest($e->getMessage(), 
null, $e);
 
  383        $newProperties = $propPatch->properties;
 
  385        $result = $this->server->updateProperties(
$path, $newProperties);
 
  387        $prefer = $this->server->getHTTPPrefer();
 
  388        $response->setHeader(
'Vary', 
'Brief,Prefer');
 
  390        if ($prefer[
'return'] === 
'minimal') {
 
  397                if ((
int)
$code > 299) {
 
  412        $response->setHeader(
'Content-Type', 
'application/xml; charset=utf-8');
 
  418            if (isset($multiStatus[
$code])) {
 
  419                $multiStatus[
$code][$propertyName] = 
null;
 
  421                $multiStatus[
$code] = [$propertyName => 
null];
 
  424        $multiStatus[
'href'] = 
$path;
 
  427            $this->server->generateMultiStatus([$multiStatus])
 
  449        $body = 
$request->getBodyAsStream();
 
  453        if (
$request->getHeader(
'Content-Range')) {
 
  465        if (($expected = 
$request->getHeader(
'X-Expected-Entity-Length')) && $expected > 0) {
 
  489            $firstByte = fread($body, 1);
 
  490            if (strlen($firstByte) !== 1) {
 
  491                throw new Exception\Forbidden(
'This server is not compatible with OS/X finder. Consider using a different WebDAV client or webserver.');
 
  497            $newBody = fopen(
'php://temp', 
'r+');
 
  498            fwrite($newBody, $firstByte);
 
  499            stream_copy_to_stream($body, $newBody);
 
  506        if ($this->server->tree->nodeExists(
$path)) {
 
  508            $node = $this->server->tree->getNodeForPath(
$path);
 
  513            if (!$this->server->updateFile(
$path, $body, $etag)) {
 
  517            $response->setHeader(
'Content-Length', 
'0');
 
  518            if ($etag) 
$response->setHeader(
'ETag', $etag);
 
  525            if (!$this->server->createFile(
$path, $body, $etag)) {
 
  530            $response->setHeader(
'Content-Length', 
'0');
 
  531            if ($etag) 
$response->setHeader(
'ETag', $etag);
 
  554        $requestBody = 
$request->getBodyAsString();
 
  568                $mkcol = $this->server->xml->expect(
'{DAV:}mkcol', $requestBody);
 
  573            $properties = $mkcol->getProperties();
 
  575            if (!isset($properties[
'{DAV:}resourcetype']))
 
  578            $resourceType = $properties[
'{DAV:}resourcetype']->getValue();
 
  579            unset($properties[
'{DAV:}resourcetype']);
 
  584            $resourceType = [
'{DAV:}collection'];
 
  588        $mkcol = 
new MkCol($resourceType, $properties);
 
  590        $result = $this->server->createCollection(
$path, $mkcol);
 
  594            $response->setHeader(
'Content-Type', 
'application/xml; charset=utf-8');
 
  597                $this->server->generateMultiStatus([
$result])
 
  601            $response->setHeader(
'Content-Length', 
'0');
 
  624        $moveInfo = $this->server->getCopyAndMoveInfo(
$request);
 
  626        if ($moveInfo[
'destinationExists']) {
 
  628            if (!$this->server->emit(
'beforeUnbind', [$moveInfo[
'destination']])) 
return false;
 
  631        if (!$this->server->emit(
'beforeUnbind', [
$path])) 
return false;
 
  632        if (!$this->server->emit(
'beforeBind', [$moveInfo[
'destination']])) 
return false;
 
  633        if (!$this->server->emit(
'beforeMove', [
$path, $moveInfo[
'destination']])) 
return false;
 
  635        if ($moveInfo[
'destinationExists']) {
 
  637            $this->server->tree->delete($moveInfo[
'destination']);
 
  638            $this->server->emit(
'afterUnbind', [$moveInfo[
'destination']]);
 
  642        $this->server->tree->move(
$path, $moveInfo[
'destination']);
 
  648        $this->server->emit(
'afterMove', [
$path, $moveInfo[
'destination']]);
 
  649        $this->server->emit(
'afterUnbind', [
$path]);
 
  650        $this->server->emit(
'afterBind', [$moveInfo[
'destination']]);
 
  653        $response->setHeader(
'Content-Length', 
'0');
 
  654        $response->setStatus($moveInfo[
'destinationExists'] ? 204 : 201);
 
  676        $copyInfo = $this->server->getCopyAndMoveInfo(
$request);
 
  678        if (!$this->server->emit(
'beforeBind', [$copyInfo[
'destination']])) 
return false;
 
  679        if ($copyInfo[
'destinationExists']) {
 
  680            if (!$this->server->emit(
'beforeUnbind', [$copyInfo[
'destination']])) 
return false;
 
  681            $this->server->tree->delete($copyInfo[
'destination']);
 
  684        $this->server->tree->copy(
$path, $copyInfo[
'destination']);
 
  685        $this->server->emit(
'afterBind', [$copyInfo[
'destination']]);
 
  688        $response->setHeader(
'Content-Length', 
'0');
 
  689        $response->setStatus($copyInfo[
'destinationExists'] ? 204 : 201);
 
  712        $result = $this->server->xml->parse(
 
  718        if ($this->server->emit(
'report', [$rootElementName, 
$result, 
$path])) {
 
  746        $protected = array_intersect(
 
  747            $this->server->protectedProperties,
 
  748            array_keys($mutations)
 
  770        $node = $this->server->tree->getNodeForPath(
$path);
 
  773            $node->propPatch($propPatch);
 
  789        $propFind->
handle(
'{DAV:}getlastmodified', 
function() use ($node) {
 
  796        if ($node instanceof 
IFile) {
 
  797            $propFind->
handle(
'{DAV:}getcontentlength', [$node, 
'getSize']);
 
  798            $propFind->
handle(
'{DAV:}getetag', [$node, 
'getETag']);
 
  799            $propFind->
handle(
'{DAV:}getcontenttype', [$node, 
'getContentType']);
 
  802        if ($node instanceof 
IQuota) {
 
  804            $propFind->
handle(
'{DAV:}quota-used-bytes', 
function() use (&$quotaInfo, $node) {
 
  805                $quotaInfo = $node->getQuotaInfo();
 
  806                return $quotaInfo[0];
 
  808            $propFind->
handle(
'{DAV:}quota-available-bytes', 
function() use (&$quotaInfo, $node) {
 
  810                    $quotaInfo = $node->getQuotaInfo();
 
  812                return $quotaInfo[1];
 
  816        $propFind->
handle(
'{DAV:}supported-report-set', 
function() use ($propFind) {
 
  818            foreach ($this->server->getPlugins() as $plugin) {
 
  819                $reports = array_merge($reports, $plugin->getSupportedReportSet($propFind->
getPath()));
 
  823        $propFind->
handle(
'{DAV:}resourcetype', 
function() use ($node) {
 
  826        $propFind->
handle(
'{DAV:}supported-method-set', 
function() use ($propFind) {
 
  828                $this->server->getAllowedMethods($propFind->
getPath())
 
  848            $nodeProperties = $node->getProperties($propertyNames);
 
  849            foreach ($nodeProperties as $propertyName => $propertyValue) {
 
  850                $propFind->
set($propertyName, $propertyValue, 200);
 
  869        $propFind->
handle(
'{http://calendarserver.org/ns/}getctag', 
function() use ($propFind) {
 
  873            $val = $propFind->
get(
'{http://sabredav.org/ns}sync-token');
 
  874            if ($val) 
return $val;
 
  876            $val = $propFind->
get(
'{DAV:}sync-token');
 
  877            if ($val && is_scalar($val)) {
 
  880            if ($val && $val instanceof Xml\Property\Href) {
 
  881                return substr($val->getHref(), strlen(Sync\Plugin::SYNCTOKEN_PREFIX));
 
  887                '{http://sabredav.org/ns}sync-token',
 
  891            if (isset(
$result[
'{http://sabredav.org/ns}sync-token'])) {
 
  892                return $result[
'{http://sabredav.org/ns}sync-token'];
 
  894            if (isset(
$result[
'{DAV:}sync-token'])) {
 
  895                $val = 
$result[
'{DAV:}sync-token'];
 
  896                if (is_scalar($val)) {
 
  898                } elseif ($val instanceof Xml\Property\Href) {
 
  899                    return substr($val->getHref(), strlen(Sync\Plugin::SYNCTOKEN_PREFIX));
 
  918            $code = $e->getHTTPCode();
 
  930        $this->server->getLogger()->log(
 
  932            'Uncaught exception',
 
  954            'description' => 
'The Core plugin provides a lot of the basic functionality required by WebDAV, such as a default implementation for all HTTP and WebDAV methods.',
 
foreach($paths as $path) $request
An exception for terminatinating execution or to throw for unit testing.
The core plugin provides all the basic features for a WebDAV server.
propFindLate(PropFind $propFind, INode $node)
This method is called when properties are retrieved.
httpCopy(RequestInterface $request, ResponseInterface $response)
WebDAV HTTP COPY method.
initialize(Server $server)
Sets up the plugin.
propPatchNodeUpdate($path, PropPatch $propPatch)
This method is called during property updates.
httpHead(RequestInterface $request, ResponseInterface $response)
HTTP HEAD.
getPluginInfo()
Returns a bunch of meta-data about the plugin.
httpMove(RequestInterface $request, ResponseInterface $response)
WebDAV HTTP MOVE method.
httpReport(RequestInterface $request, ResponseInterface $response)
HTTP REPORT method implementation.
httpMkcol(RequestInterface $request, ResponseInterface $response)
WebDAV MKCOL.
getPluginName()
Returns a plugin name.
exception($e)
Listens for exception events, and automatically logs them.
httpPropFind(RequestInterface $request, ResponseInterface $response)
WebDAV PROPFIND.
propFind(PropFind $propFind, INode $node)
This method is called when properties are retrieved.
propFindNode(PropFind $propFind, INode $node)
Fetches properties for a node.
propPatchProtectedPropertyCheck($path, PropPatch $propPatch)
This method is called during property updates.
httpDelete(RequestInterface $request, ResponseInterface $response)
HTTP Delete.
httpPut(RequestInterface $request, ResponseInterface $response)
HTTP PUT method.
httpPropPatch(RequestInterface $request, ResponseInterface $response)
WebDAV PROPPATCH.
httpGet(RequestInterface $request, ResponseInterface $response)
This is the default implementation for the GET method.
httpOptions(RequestInterface $request, ResponseInterface $response)
HTTP OPTIONS.
RequestedRangeNotSatisfiable.
This class represents a MKCOL operation.
This class holds all the information about a PROPFIND request.
set($propertyName, $value, $status=null)
Sets the value of the property.
get($propertyName)
Returns the current value for a property.
get404Properties()
Returns all propertynames that have a 404 status, and thus don't have a value yet.
getPath()
Returns the path this PROPFIND request is for.
handle($propertyName, $valueOrCallBack)
Handles a specific property.
This class represents a set of properties that are going to be updated.
setResultCode($properties, $resultCode)
Sets the result code for one or more properties.
getMutations()
Returns the full list of mutations.
The baseclass for all server plugins.
This property represents the {DAV:}getlastmodified property.
{DAV:}resourcetype property
supported-method-set property.
supported-report-set property.
This is a base exception for any exception related to parsing xml files.
This interface represents a file in the directory tree.
The INode interface is the base interface, and the parent class of both ICollection and IFile.
getLastModified()
Returns the last modification time, as a unix timestamp.
The RequestInterface represents a HTTP request.
This interface represents a HTTP response.
if( $path[strlen( $path) - 1]==='/') if(is_dir($path)) if(!file_exists( $path)) if(preg_match('#\.php$#D', mb_strtolower($path, 'UTF-8'))) $contentType
$stream
PHP stream implementation.