dataDir = $dataDir; } /** * Initialize the plugin * * This is called automatically be the Server class after this plugin is * added with Sabre\DAV\Server::addPlugin() * * @param Server $server * @return void */ function initialize(Server $server) { $this->server = $server; $server->on('beforeMethod', [$this, 'beforeMethod']); $server->on('beforeCreateFile', [$this, 'beforeCreateFile']); } /** * This method is called before any HTTP method handler * * This method intercepts any GET, DELETE, PUT and PROPFIND calls to * filenames that are known to match the 'temporary file' regex. * * @param RequestInterface $request * @param ResponseInterface $response * @return bool */ function beforeMethod(RequestInterface $request, ResponseInterface $response) { if (!$tempLocation = $this->isTempFile($request->getPath())) return; switch ($request->getMethod()) { case 'GET' : return $this->httpGet($request, $response, $tempLocation); case 'PUT' : return $this->httpPut($request, $response, $tempLocation); case 'PROPFIND' : return $this->httpPropfind($request, $response, $tempLocation); case 'DELETE' : return $this->httpDelete($request, $response, $tempLocation); } return; } /** * This method is invoked if some subsystem creates a new file. * * This is used to deal with HTTP LOCK requests which create a new * file. * * @param string $uri * @param resource $data * @return bool */ function beforeCreateFile($uri, $data) { if ($tempPath = $this->isTempFile($uri)) { $hR = $this->server->httpResponse; $hR->setHeader('X-Sabre-Temp', 'true'); file_put_contents($tempPath, $data); return false; } return; } /** * This method will check if the url matches the temporary file pattern * if it does, it will return an path based on $this->dataDir for the * temporary file storage. * * @param string $path * @return bool|string */ protected function isTempFile($path) { // We're only interested in the basename. list(, $tempPath) = URLUtil::splitPath($path); foreach ($this->temporaryFilePatterns as $tempFile) { if (preg_match($tempFile, $tempPath)) { return $this->getDataDir() . '/sabredav_' . md5($path) . '.tempfile'; } } return false; } /** * This method handles the GET method for temporary files. * If the file doesn't exist, it will return false which will kick in * the regular system for the GET method. * * @param RequestInterface $request * @param ResponseInterface $hR * @param string $tempLocation * @return bool */ function httpGet(RequestInterface $request, ResponseInterface $hR, $tempLocation) { if (!file_exists($tempLocation)) return; $hR->setHeader('Content-Type', 'application/octet-stream'); $hR->setHeader('Content-Length', filesize($tempLocation)); $hR->setHeader('X-Sabre-Temp', 'true'); $hR->setStatus(200); $hR->setBody(fopen($tempLocation, 'r')); return false; } /** * This method handles the PUT method. * * @param RequestInterface $request * @param ResponseInterface $hR * @param string $tempLocation * @return bool */ function httpPut(RequestInterface $request, ResponseInterface $hR, $tempLocation) { $hR->setHeader('X-Sabre-Temp', 'true'); $newFile = !file_exists($tempLocation); if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) { throw new Exception\PreconditionFailed('The resource already exists, and an If-None-Match header was supplied'); } file_put_contents($tempLocation, $this->server->httpRequest->getBody()); $hR->setStatus($newFile ? 201 : 200); return false; } /** * This method handles the DELETE method. * * If the file didn't exist, it will return false, which will make the * standard HTTP DELETE handler kick in. * * @param RequestInterface $request * @param ResponseInterface $hR * @param string $tempLocation * @return bool */ function httpDelete(RequestInterface $request, ResponseInterface $hR, $tempLocation) { if (!file_exists($tempLocation)) return; unlink($tempLocation); $hR->setHeader('X-Sabre-Temp', 'true'); $hR->setStatus(204); return false; } /** * 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 RequestInterface $request * @param ResponseInterface $hR * @param string $tempLocation * @return bool */ function httpPropfind(RequestInterface $request, ResponseInterface $hR, $tempLocation) { if (!file_exists($tempLocation)) return; $hR->setHeader('X-Sabre-Temp', 'true'); $hR->setStatus(207); $hR->setHeader('Content-Type', 'application/xml; charset=utf-8'); $properties = [ 'href' => $request->getPath(), 200 => [ '{DAV:}getlastmodified' => new Xml\Property\GetLastModified(filemtime($tempLocation)), '{DAV:}getcontentlength' => filesize($tempLocation), '{DAV:}resourcetype' => new Xml\Property\ResourceType(null), '{' . Server::NS_SABREDAV . '}tempFile' => true, ], ]; $data = $this->server->generateMultiStatus([$properties]); $hR->setBody($data); return false; } /** * This method returns the directory where the temporary files should be stored. * * @return string */ protected function getDataDir() { return $this->dataDir; } }