Page MenuHomePhabricator

TemporaryFileFilterPlugin.php
No OneTemporary

TemporaryFileFilterPlugin.php

<?php
namespace Sabre\DAV;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Sabre\HTTP\URLUtil;
/**
* Temporary File Filter Plugin
*
* The purpose of this filter is to intercept some of the garbage files
* operation systems and applications tend to generate when mounting
* a WebDAV share as a disk.
*
* It will intercept these files and place them in a separate directory.
* these files are not deleted automatically, so it is adviceable to
* delete these after they are not accessed for 24 hours.
*
* Currently it supports:
* * OS/X style resource forks and .DS_Store
* * desktop.ini and Thumbs.db (windows)
* * .*.swp (vim temporary files)
* * .dat.* (smultron temporary files)
*
* Additional patterns can be added, by adding on to the
* temporaryFilePatterns property.
*
* @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
* @author Evert Pot (http://evertpot.com/)
* @license http://sabre.io/license/ Modified BSD License
*/
class TemporaryFileFilterPlugin extends ServerPlugin {
/**
* This is the list of patterns we intercept.
* If new patterns are added, they must be valid patterns for preg_match.
*
* @var array
*/
public $temporaryFilePatterns = [
'/^\._(.*)$/', // OS/X resource forks
'/^.DS_Store$/', // OS/X custom folder settings
'/^desktop.ini$/', // Windows custom folder settings
'/^Thumbs.db$/', // Windows thumbnail cache
'/^.(.*).swp$/', // ViM temporary files
'/^\.dat(.*)$/', // Smultron seems to create these
'/^~lock.(.*)#$/', // Windows 7 lockfiles
];
/**
* A reference to the main Server class
*
* @var Sabre\DAV\Server
*/
protected $server;
/**
* This is the directory where this plugin
* will store it's files.
*
* @var string
*/
private $dataDir;
/**
* Creates the plugin.
*
* Make sure you specify a directory for your files. If you don't, we
* will use PHP's directory for session-storage instead, and you might
* not want that.
*
* @param string|null $dataDir
*/
function __construct($dataDir = null) {
if (!$dataDir) $dataDir = ini_get('session.save_path') . '/sabredav/';
if (!is_dir($dataDir)) mkdir($dataDir);
$this->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;
}
}

File Metadata

Mime Type
text/x-php
Expires
Mon, Dec 23, 10:35 PM (23 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
906808
Default Alt Text
TemporaryFileFilterPlugin.php (8 KB)

Event Timeline