4 * Temporary File Filter Plugin
6 * The purpose of this filter is to intercept some of the garbage files
7 * operation systems and applications tend to generate when mounting
8 * a WebDAV share as a disk.
10 * It will intercept these files and place them in a separate directory.
11 * these files are not deleted automatically, so it is adviceable to
12 * delete these after they are not accessed for 24 hours.
14 * Currently it supports:
15 * * OS/X style resource forks and .DS_Store
16 * * desktop.ini and Thumbs.db (windows)
17 * * .*.swp (vim temporary files)
18 * * .dat.* (smultron temporary files)
20 * Additional patterns can be added, by adding on to the
21 * temporaryFilePatterns property.
25 * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
26 * @author Evert Pot (http://www.rooftopsolutions.nl/)
27 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
29 class Sabre_DAV_TemporaryFileFilterPlugin extends Sabre_DAV_ServerPlugin {
32 * This is the list of patterns we intercept.
33 * If new patterns are added, they must be valid patterns for preg_match.
37 public $temporaryFilePatterns = array(
38 '/^\._(.*)$/', // OS/X resource forks
39 '/^.DS_Store$/', // OS/X custom folder settings
40 '/^desktop.ini$/', // Windows custom folder settings
41 '/^Thumbs.db$/', // Windows thumbnail cache
42 '/^.(.*).swp$/', // ViM temporary files
43 '/^\.dat(.*)$/', // Smultron seems to create these
44 '/^~lock.(.*)#$/', // Windows 7 lockfiles
48 * This is the directory where this plugin
49 * will store it's files.
56 * A reference to the main Server class
58 * @var Sabre_DAV_Server
65 * Make sure you specify a directory for your files. If you don't, we
66 * will use PHP's directory for session-storage instead, and you might
69 * @param string|null $dataDir
71 public function __construct($dataDir = null) {
73 if (!$dataDir) $dataDir = ini_get('session.save_path').'/sabredav/';
74 if (!is_dir($dataDir)) mkdir($dataDir);
75 $this->dataDir = $dataDir;
80 * Initialize the plugin
82 * This is called automatically be the Server class after this plugin is
83 * added with Sabre_DAV_Server::addPlugin()
85 * @param Sabre_DAV_Server $server
88 public function initialize(Sabre_DAV_Server $server) {
90 $this->server = $server;
91 $server->subscribeEvent('beforeMethod',array($this,'beforeMethod'));
92 $server->subscribeEvent('beforeCreateFile',array($this,'beforeCreateFile'));
97 * This method is called before any HTTP method handler
99 * This method intercepts any GET, DELETE, PUT and PROPFIND calls to
100 * filenames that are known to match the 'temporary file' regex.
102 * @param string $method
106 public function beforeMethod($method, $uri) {
108 if (!$tempLocation = $this->isTempFile($uri))
113 return $this->httpGet($tempLocation);
115 return $this->httpPut($tempLocation);
117 return $this->httpPropfind($tempLocation, $uri);
119 return $this->httpDelete($tempLocation);
126 * This method is invoked if some subsystem creates a new file.
128 * This is used to deal with HTTP LOCK requests which create a new
132 * @param resource $data
135 public function beforeCreateFile($uri,$data) {
137 if ($tempPath = $this->isTempFile($uri)) {
139 $hR = $this->server->httpResponse;
140 $hR->setHeader('X-Sabre-Temp','true');
141 file_put_contents($tempPath,$data);
149 * This method will check if the url matches the temporary file pattern
150 * if it does, it will return an path based on $this->dataDir for the
151 * temporary file storage.
153 * @param string $path
154 * @return boolean|string
156 protected function isTempFile($path) {
158 // We're only interested in the basename.
159 list(, $tempPath) = Sabre_DAV_URLUtil::splitPath($path);
161 foreach($this->temporaryFilePatterns as $tempFile) {
163 if (preg_match($tempFile,$tempPath)) {
164 return $this->getDataDir() . '/sabredav_' . md5($path) . '.tempfile';
175 * This method handles the GET method for temporary files.
176 * If the file doesn't exist, it will return false which will kick in
177 * the regular system for the GET method.
179 * @param string $tempLocation
182 public function httpGet($tempLocation) {
184 if (!file_exists($tempLocation)) return true;
186 $hR = $this->server->httpResponse;
187 $hR->setHeader('Content-Type','application/octet-stream');
188 $hR->setHeader('Content-Length',filesize($tempLocation));
189 $hR->setHeader('X-Sabre-Temp','true');
190 $hR->sendStatus(200);
191 $hR->sendBody(fopen($tempLocation,'r'));
197 * This method handles the PUT method.
199 * @param string $tempLocation
202 public function httpPut($tempLocation) {
204 $hR = $this->server->httpResponse;
205 $hR->setHeader('X-Sabre-Temp','true');
207 $newFile = !file_exists($tempLocation);
209 if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) {
210 throw new Sabre_DAV_Exception_PreconditionFailed('The resource already exists, and an If-None-Match header was supplied');
213 file_put_contents($tempLocation,$this->server->httpRequest->getBody());
214 $hR->sendStatus($newFile?201:200);
220 * This method handles the DELETE method.
222 * If the file didn't exist, it will return false, which will make the
223 * standard HTTP DELETE handler kick in.
225 * @param string $tempLocation
228 public function httpDelete($tempLocation) {
230 if (!file_exists($tempLocation)) return true;
232 unlink($tempLocation);
233 $hR = $this->server->httpResponse;
234 $hR->setHeader('X-Sabre-Temp','true');
235 $hR->sendStatus(204);
241 * This method handles the PROPFIND method.
243 * It's a very lazy method, it won't bother checking the request body
244 * for which properties were requested, and just sends back a default
247 * @param string $tempLocation
251 public function httpPropfind($tempLocation, $uri) {
253 if (!file_exists($tempLocation)) return true;
255 $hR = $this->server->httpResponse;
256 $hR->setHeader('X-Sabre-Temp','true');
257 $hR->sendStatus(207);
258 $hR->setHeader('Content-Type','application/xml; charset=utf-8');
260 $this->server->parsePropFindRequest($this->server->httpRequest->getBody(true));
265 '{DAV:}getlastmodified' => new Sabre_DAV_Property_GetLastModified(filemtime($tempLocation)),
266 '{DAV:}getcontentlength' => filesize($tempLocation),
267 '{DAV:}resourcetype' => new Sabre_DAV_Property_ResourceType(null),
268 '{'.Sabre_DAV_Server::NS_SABREDAV.'}tempFile' => true,
273 $data = $this->server->generateMultiStatus(array($properties));
274 $hR->sendBody($data);
281 * This method returns the directory where the temporary files should be stored.
285 protected function getDataDir()
287 return $this->dataDir;