Completed
Push — developer ( e65ba3...d7bfd9 )
by Błażej
478:46 queued 446:35
created
libraries/SabreDAV/composer/ClassLoader.php 2 patches
Doc Comments   +4 added lines patch added patch discarded remove patch
@@ -341,6 +341,10 @@
 block discarded – undo
341 341
         return $file;
342 342
     }
343 343
 
344
+    /**
345
+     * @param string $class
346
+     * @param string $ext
347
+     */
344 348
     private function findFileWithExtension($class, $ext)
345 349
     {
346 350
         // PSR-4 lookup
Please login to merge, or discard this patch.
Indentation   +359 added lines, -359 removed lines patch added patch discarded remove patch
@@ -42,364 +42,364 @@  discard block
 block discarded – undo
42 42
  */
43 43
 class ClassLoader
44 44
 {
45
-    // PSR-4
46
-    private $prefixLengthsPsr4 = array();
47
-    private $prefixDirsPsr4 = array();
48
-    private $fallbackDirsPsr4 = array();
49
-
50
-    // PSR-0
51
-    private $prefixesPsr0 = array();
52
-    private $fallbackDirsPsr0 = array();
53
-
54
-    private $useIncludePath = false;
55
-    private $classMap = array();
56
-
57
-    private $classMapAuthoritative = false;
58
-
59
-    public function getPrefixes()
60
-    {
61
-        if (!empty($this->prefixesPsr0)) {
62
-            return call_user_func_array('array_merge', $this->prefixesPsr0);
63
-        }
64
-
65
-        return array();
66
-    }
67
-
68
-    public function getPrefixesPsr4()
69
-    {
70
-        return $this->prefixDirsPsr4;
71
-    }
72
-
73
-    public function getFallbackDirs()
74
-    {
75
-        return $this->fallbackDirsPsr0;
76
-    }
77
-
78
-    public function getFallbackDirsPsr4()
79
-    {
80
-        return $this->fallbackDirsPsr4;
81
-    }
82
-
83
-    public function getClassMap()
84
-    {
85
-        return $this->classMap;
86
-    }
87
-
88
-    /**
89
-     * @param array $classMap Class to filename map
90
-     */
91
-    public function addClassMap(array $classMap)
92
-    {
93
-        if ($this->classMap) {
94
-            $this->classMap = array_merge($this->classMap, $classMap);
95
-        } else {
96
-            $this->classMap = $classMap;
97
-        }
98
-    }
99
-
100
-    /**
101
-     * Registers a set of PSR-0 directories for a given prefix, either
102
-     * appending or prepending to the ones previously set for this prefix.
103
-     *
104
-     * @param string       $prefix  The prefix
105
-     * @param array|string $paths   The PSR-0 root directories
106
-     * @param bool         $prepend Whether to prepend the directories
107
-     */
108
-    public function add($prefix, $paths, $prepend = false)
109
-    {
110
-        if (!$prefix) {
111
-            if ($prepend) {
112
-                $this->fallbackDirsPsr0 = array_merge(
113
-                    (array) $paths,
114
-                    $this->fallbackDirsPsr0
115
-                );
116
-            } else {
117
-                $this->fallbackDirsPsr0 = array_merge(
118
-                    $this->fallbackDirsPsr0,
119
-                    (array) $paths
120
-                );
121
-            }
122
-
123
-            return;
124
-        }
125
-
126
-        $first = $prefix[0];
127
-        if (!isset($this->prefixesPsr0[$first][$prefix])) {
128
-            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
129
-
130
-            return;
131
-        }
132
-        if ($prepend) {
133
-            $this->prefixesPsr0[$first][$prefix] = array_merge(
134
-                (array) $paths,
135
-                $this->prefixesPsr0[$first][$prefix]
136
-            );
137
-        } else {
138
-            $this->prefixesPsr0[$first][$prefix] = array_merge(
139
-                $this->prefixesPsr0[$first][$prefix],
140
-                (array) $paths
141
-            );
142
-        }
143
-    }
144
-
145
-    /**
146
-     * Registers a set of PSR-4 directories for a given namespace, either
147
-     * appending or prepending to the ones previously set for this namespace.
148
-     *
149
-     * @param string       $prefix  The prefix/namespace, with trailing '\\'
150
-     * @param array|string $paths   The PSR-4 base directories
151
-     * @param bool         $prepend Whether to prepend the directories
152
-     *
153
-     * @throws \InvalidArgumentException
154
-     */
155
-    public function addPsr4($prefix, $paths, $prepend = false)
156
-    {
157
-        if (!$prefix) {
158
-            // Register directories for the root namespace.
159
-            if ($prepend) {
160
-                $this->fallbackDirsPsr4 = array_merge(
161
-                    (array) $paths,
162
-                    $this->fallbackDirsPsr4
163
-                );
164
-            } else {
165
-                $this->fallbackDirsPsr4 = array_merge(
166
-                    $this->fallbackDirsPsr4,
167
-                    (array) $paths
168
-                );
169
-            }
170
-        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
171
-            // Register directories for a new namespace.
172
-            $length = strlen($prefix);
173
-            if ('\\' !== $prefix[$length - 1]) {
174
-                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
175
-            }
176
-            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
177
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
178
-        } elseif ($prepend) {
179
-            // Prepend directories for an already registered namespace.
180
-            $this->prefixDirsPsr4[$prefix] = array_merge(
181
-                (array) $paths,
182
-                $this->prefixDirsPsr4[$prefix]
183
-            );
184
-        } else {
185
-            // Append directories for an already registered namespace.
186
-            $this->prefixDirsPsr4[$prefix] = array_merge(
187
-                $this->prefixDirsPsr4[$prefix],
188
-                (array) $paths
189
-            );
190
-        }
191
-    }
192
-
193
-    /**
194
-     * Registers a set of PSR-0 directories for a given prefix,
195
-     * replacing any others previously set for this prefix.
196
-     *
197
-     * @param string       $prefix The prefix
198
-     * @param array|string $paths  The PSR-0 base directories
199
-     */
200
-    public function set($prefix, $paths)
201
-    {
202
-        if (!$prefix) {
203
-            $this->fallbackDirsPsr0 = (array) $paths;
204
-        } else {
205
-            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
206
-        }
207
-    }
208
-
209
-    /**
210
-     * Registers a set of PSR-4 directories for a given namespace,
211
-     * replacing any others previously set for this namespace.
212
-     *
213
-     * @param string       $prefix The prefix/namespace, with trailing '\\'
214
-     * @param array|string $paths  The PSR-4 base directories
215
-     *
216
-     * @throws \InvalidArgumentException
217
-     */
218
-    public function setPsr4($prefix, $paths)
219
-    {
220
-        if (!$prefix) {
221
-            $this->fallbackDirsPsr4 = (array) $paths;
222
-        } else {
223
-            $length = strlen($prefix);
224
-            if ('\\' !== $prefix[$length - 1]) {
225
-                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
226
-            }
227
-            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
228
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
229
-        }
230
-    }
231
-
232
-    /**
233
-     * Turns on searching the include path for class files.
234
-     *
235
-     * @param bool $useIncludePath
236
-     */
237
-    public function setUseIncludePath($useIncludePath)
238
-    {
239
-        $this->useIncludePath = $useIncludePath;
240
-    }
241
-
242
-    /**
243
-     * Can be used to check if the autoloader uses the include path to check
244
-     * for classes.
245
-     *
246
-     * @return bool
247
-     */
248
-    public function getUseIncludePath()
249
-    {
250
-        return $this->useIncludePath;
251
-    }
252
-
253
-    /**
254
-     * Turns off searching the prefix and fallback directories for classes
255
-     * that have not been registered with the class map.
256
-     *
257
-     * @param bool $classMapAuthoritative
258
-     */
259
-    public function setClassMapAuthoritative($classMapAuthoritative)
260
-    {
261
-        $this->classMapAuthoritative = $classMapAuthoritative;
262
-    }
263
-
264
-    /**
265
-     * Should class lookup fail if not found in the current class map?
266
-     *
267
-     * @return bool
268
-     */
269
-    public function isClassMapAuthoritative()
270
-    {
271
-        return $this->classMapAuthoritative;
272
-    }
273
-
274
-    /**
275
-     * Registers this instance as an autoloader.
276
-     *
277
-     * @param bool $prepend Whether to prepend the autoloader or not
278
-     */
279
-    public function register($prepend = false)
280
-    {
281
-        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
282
-    }
283
-
284
-    /**
285
-     * Unregisters this instance as an autoloader.
286
-     */
287
-    public function unregister()
288
-    {
289
-        spl_autoload_unregister(array($this, 'loadClass'));
290
-    }
291
-
292
-    /**
293
-     * Loads the given class or interface.
294
-     *
295
-     * @param  string    $class The name of the class
296
-     * @return bool|null True if loaded, null otherwise
297
-     */
298
-    public function loadClass($class)
299
-    {
300
-        if ($file = $this->findFile($class)) {
301
-            includeFile($file);
302
-
303
-            return true;
304
-        }
305
-    }
306
-
307
-    /**
308
-     * Finds the path to the file where the class is defined.
309
-     *
310
-     * @param string $class The name of the class
311
-     *
312
-     * @return string|false The path if found, false otherwise
313
-     */
314
-    public function findFile($class)
315
-    {
316
-        // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
-        if ('\\' == $class[0]) {
318
-            $class = substr($class, 1);
319
-        }
320
-
321
-        // class map lookup
322
-        if (isset($this->classMap[$class])) {
323
-            return $this->classMap[$class];
324
-        }
325
-        if ($this->classMapAuthoritative) {
326
-            return false;
327
-        }
328
-
329
-        $file = $this->findFileWithExtension($class, '.php');
330
-
331
-        // Search for Hack files if we are running on HHVM
332
-        if ($file === null && defined('HHVM_VERSION')) {
333
-            $file = $this->findFileWithExtension($class, '.hh');
334
-        }
335
-
336
-        if ($file === null) {
337
-            // Remember that this class does not exist.
338
-            return $this->classMap[$class] = false;
339
-        }
340
-
341
-        return $file;
342
-    }
343
-
344
-    private function findFileWithExtension($class, $ext)
345
-    {
346
-        // PSR-4 lookup
347
-        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
348
-
349
-        $first = $class[0];
350
-        if (isset($this->prefixLengthsPsr4[$first])) {
351
-            foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352
-                if (0 === strpos($class, $prefix)) {
353
-                    foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
354
-                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355
-                            return $file;
356
-                        }
357
-                    }
358
-                }
359
-            }
360
-        }
361
-
362
-        // PSR-4 fallback dirs
363
-        foreach ($this->fallbackDirsPsr4 as $dir) {
364
-            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
365
-                return $file;
366
-            }
367
-        }
368
-
369
-        // PSR-0 lookup
370
-        if (false !== $pos = strrpos($class, '\\')) {
371
-            // namespaced class name
372
-            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
373
-                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
374
-        } else {
375
-            // PEAR-like class name
376
-            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
377
-        }
378
-
379
-        if (isset($this->prefixesPsr0[$first])) {
380
-            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
381
-                if (0 === strpos($class, $prefix)) {
382
-                    foreach ($dirs as $dir) {
383
-                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
384
-                            return $file;
385
-                        }
386
-                    }
387
-                }
388
-            }
389
-        }
390
-
391
-        // PSR-0 fallback dirs
392
-        foreach ($this->fallbackDirsPsr0 as $dir) {
393
-            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
394
-                return $file;
395
-            }
396
-        }
397
-
398
-        // PSR-0 include paths.
399
-        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400
-            return $file;
401
-        }
402
-    }
45
+	// PSR-4
46
+	private $prefixLengthsPsr4 = array();
47
+	private $prefixDirsPsr4 = array();
48
+	private $fallbackDirsPsr4 = array();
49
+
50
+	// PSR-0
51
+	private $prefixesPsr0 = array();
52
+	private $fallbackDirsPsr0 = array();
53
+
54
+	private $useIncludePath = false;
55
+	private $classMap = array();
56
+
57
+	private $classMapAuthoritative = false;
58
+
59
+	public function getPrefixes()
60
+	{
61
+		if (!empty($this->prefixesPsr0)) {
62
+			return call_user_func_array('array_merge', $this->prefixesPsr0);
63
+		}
64
+
65
+		return array();
66
+	}
67
+
68
+	public function getPrefixesPsr4()
69
+	{
70
+		return $this->prefixDirsPsr4;
71
+	}
72
+
73
+	public function getFallbackDirs()
74
+	{
75
+		return $this->fallbackDirsPsr0;
76
+	}
77
+
78
+	public function getFallbackDirsPsr4()
79
+	{
80
+		return $this->fallbackDirsPsr4;
81
+	}
82
+
83
+	public function getClassMap()
84
+	{
85
+		return $this->classMap;
86
+	}
87
+
88
+	/**
89
+	 * @param array $classMap Class to filename map
90
+	 */
91
+	public function addClassMap(array $classMap)
92
+	{
93
+		if ($this->classMap) {
94
+			$this->classMap = array_merge($this->classMap, $classMap);
95
+		} else {
96
+			$this->classMap = $classMap;
97
+		}
98
+	}
99
+
100
+	/**
101
+	 * Registers a set of PSR-0 directories for a given prefix, either
102
+	 * appending or prepending to the ones previously set for this prefix.
103
+	 *
104
+	 * @param string       $prefix  The prefix
105
+	 * @param array|string $paths   The PSR-0 root directories
106
+	 * @param bool         $prepend Whether to prepend the directories
107
+	 */
108
+	public function add($prefix, $paths, $prepend = false)
109
+	{
110
+		if (!$prefix) {
111
+			if ($prepend) {
112
+				$this->fallbackDirsPsr0 = array_merge(
113
+					(array) $paths,
114
+					$this->fallbackDirsPsr0
115
+				);
116
+			} else {
117
+				$this->fallbackDirsPsr0 = array_merge(
118
+					$this->fallbackDirsPsr0,
119
+					(array) $paths
120
+				);
121
+			}
122
+
123
+			return;
124
+		}
125
+
126
+		$first = $prefix[0];
127
+		if (!isset($this->prefixesPsr0[$first][$prefix])) {
128
+			$this->prefixesPsr0[$first][$prefix] = (array) $paths;
129
+
130
+			return;
131
+		}
132
+		if ($prepend) {
133
+			$this->prefixesPsr0[$first][$prefix] = array_merge(
134
+				(array) $paths,
135
+				$this->prefixesPsr0[$first][$prefix]
136
+			);
137
+		} else {
138
+			$this->prefixesPsr0[$first][$prefix] = array_merge(
139
+				$this->prefixesPsr0[$first][$prefix],
140
+				(array) $paths
141
+			);
142
+		}
143
+	}
144
+
145
+	/**
146
+	 * Registers a set of PSR-4 directories for a given namespace, either
147
+	 * appending or prepending to the ones previously set for this namespace.
148
+	 *
149
+	 * @param string       $prefix  The prefix/namespace, with trailing '\\'
150
+	 * @param array|string $paths   The PSR-4 base directories
151
+	 * @param bool         $prepend Whether to prepend the directories
152
+	 *
153
+	 * @throws \InvalidArgumentException
154
+	 */
155
+	public function addPsr4($prefix, $paths, $prepend = false)
156
+	{
157
+		if (!$prefix) {
158
+			// Register directories for the root namespace.
159
+			if ($prepend) {
160
+				$this->fallbackDirsPsr4 = array_merge(
161
+					(array) $paths,
162
+					$this->fallbackDirsPsr4
163
+				);
164
+			} else {
165
+				$this->fallbackDirsPsr4 = array_merge(
166
+					$this->fallbackDirsPsr4,
167
+					(array) $paths
168
+				);
169
+			}
170
+		} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
171
+			// Register directories for a new namespace.
172
+			$length = strlen($prefix);
173
+			if ('\\' !== $prefix[$length - 1]) {
174
+				throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
175
+			}
176
+			$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
177
+			$this->prefixDirsPsr4[$prefix] = (array) $paths;
178
+		} elseif ($prepend) {
179
+			// Prepend directories for an already registered namespace.
180
+			$this->prefixDirsPsr4[$prefix] = array_merge(
181
+				(array) $paths,
182
+				$this->prefixDirsPsr4[$prefix]
183
+			);
184
+		} else {
185
+			// Append directories for an already registered namespace.
186
+			$this->prefixDirsPsr4[$prefix] = array_merge(
187
+				$this->prefixDirsPsr4[$prefix],
188
+				(array) $paths
189
+			);
190
+		}
191
+	}
192
+
193
+	/**
194
+	 * Registers a set of PSR-0 directories for a given prefix,
195
+	 * replacing any others previously set for this prefix.
196
+	 *
197
+	 * @param string       $prefix The prefix
198
+	 * @param array|string $paths  The PSR-0 base directories
199
+	 */
200
+	public function set($prefix, $paths)
201
+	{
202
+		if (!$prefix) {
203
+			$this->fallbackDirsPsr0 = (array) $paths;
204
+		} else {
205
+			$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
206
+		}
207
+	}
208
+
209
+	/**
210
+	 * Registers a set of PSR-4 directories for a given namespace,
211
+	 * replacing any others previously set for this namespace.
212
+	 *
213
+	 * @param string       $prefix The prefix/namespace, with trailing '\\'
214
+	 * @param array|string $paths  The PSR-4 base directories
215
+	 *
216
+	 * @throws \InvalidArgumentException
217
+	 */
218
+	public function setPsr4($prefix, $paths)
219
+	{
220
+		if (!$prefix) {
221
+			$this->fallbackDirsPsr4 = (array) $paths;
222
+		} else {
223
+			$length = strlen($prefix);
224
+			if ('\\' !== $prefix[$length - 1]) {
225
+				throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
226
+			}
227
+			$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
228
+			$this->prefixDirsPsr4[$prefix] = (array) $paths;
229
+		}
230
+	}
231
+
232
+	/**
233
+	 * Turns on searching the include path for class files.
234
+	 *
235
+	 * @param bool $useIncludePath
236
+	 */
237
+	public function setUseIncludePath($useIncludePath)
238
+	{
239
+		$this->useIncludePath = $useIncludePath;
240
+	}
241
+
242
+	/**
243
+	 * Can be used to check if the autoloader uses the include path to check
244
+	 * for classes.
245
+	 *
246
+	 * @return bool
247
+	 */
248
+	public function getUseIncludePath()
249
+	{
250
+		return $this->useIncludePath;
251
+	}
252
+
253
+	/**
254
+	 * Turns off searching the prefix and fallback directories for classes
255
+	 * that have not been registered with the class map.
256
+	 *
257
+	 * @param bool $classMapAuthoritative
258
+	 */
259
+	public function setClassMapAuthoritative($classMapAuthoritative)
260
+	{
261
+		$this->classMapAuthoritative = $classMapAuthoritative;
262
+	}
263
+
264
+	/**
265
+	 * Should class lookup fail if not found in the current class map?
266
+	 *
267
+	 * @return bool
268
+	 */
269
+	public function isClassMapAuthoritative()
270
+	{
271
+		return $this->classMapAuthoritative;
272
+	}
273
+
274
+	/**
275
+	 * Registers this instance as an autoloader.
276
+	 *
277
+	 * @param bool $prepend Whether to prepend the autoloader or not
278
+	 */
279
+	public function register($prepend = false)
280
+	{
281
+		spl_autoload_register(array($this, 'loadClass'), true, $prepend);
282
+	}
283
+
284
+	/**
285
+	 * Unregisters this instance as an autoloader.
286
+	 */
287
+	public function unregister()
288
+	{
289
+		spl_autoload_unregister(array($this, 'loadClass'));
290
+	}
291
+
292
+	/**
293
+	 * Loads the given class or interface.
294
+	 *
295
+	 * @param  string    $class The name of the class
296
+	 * @return bool|null True if loaded, null otherwise
297
+	 */
298
+	public function loadClass($class)
299
+	{
300
+		if ($file = $this->findFile($class)) {
301
+			includeFile($file);
302
+
303
+			return true;
304
+		}
305
+	}
306
+
307
+	/**
308
+	 * Finds the path to the file where the class is defined.
309
+	 *
310
+	 * @param string $class The name of the class
311
+	 *
312
+	 * @return string|false The path if found, false otherwise
313
+	 */
314
+	public function findFile($class)
315
+	{
316
+		// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
+		if ('\\' == $class[0]) {
318
+			$class = substr($class, 1);
319
+		}
320
+
321
+		// class map lookup
322
+		if (isset($this->classMap[$class])) {
323
+			return $this->classMap[$class];
324
+		}
325
+		if ($this->classMapAuthoritative) {
326
+			return false;
327
+		}
328
+
329
+		$file = $this->findFileWithExtension($class, '.php');
330
+
331
+		// Search for Hack files if we are running on HHVM
332
+		if ($file === null && defined('HHVM_VERSION')) {
333
+			$file = $this->findFileWithExtension($class, '.hh');
334
+		}
335
+
336
+		if ($file === null) {
337
+			// Remember that this class does not exist.
338
+			return $this->classMap[$class] = false;
339
+		}
340
+
341
+		return $file;
342
+	}
343
+
344
+	private function findFileWithExtension($class, $ext)
345
+	{
346
+		// PSR-4 lookup
347
+		$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
348
+
349
+		$first = $class[0];
350
+		if (isset($this->prefixLengthsPsr4[$first])) {
351
+			foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352
+				if (0 === strpos($class, $prefix)) {
353
+					foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
354
+						if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355
+							return $file;
356
+						}
357
+					}
358
+				}
359
+			}
360
+		}
361
+
362
+		// PSR-4 fallback dirs
363
+		foreach ($this->fallbackDirsPsr4 as $dir) {
364
+			if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
365
+				return $file;
366
+			}
367
+		}
368
+
369
+		// PSR-0 lookup
370
+		if (false !== $pos = strrpos($class, '\\')) {
371
+			// namespaced class name
372
+			$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
373
+				. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
374
+		} else {
375
+			// PEAR-like class name
376
+			$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
377
+		}
378
+
379
+		if (isset($this->prefixesPsr0[$first])) {
380
+			foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
381
+				if (0 === strpos($class, $prefix)) {
382
+					foreach ($dirs as $dir) {
383
+						if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
384
+							return $file;
385
+						}
386
+					}
387
+				}
388
+			}
389
+		}
390
+
391
+		// PSR-0 fallback dirs
392
+		foreach ($this->fallbackDirsPsr0 as $dir) {
393
+			if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
394
+				return $file;
395
+			}
396
+		}
397
+
398
+		// PSR-0 include paths.
399
+		if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400
+			return $file;
401
+		}
402
+	}
403 403
 }
404 404
 
405 405
 /**
@@ -409,5 +409,5 @@  discard block
 block discarded – undo
409 409
  */
410 410
 function includeFile($file)
411 411
 {
412
-    include $file;
412
+	include $file;
413 413
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/Auth/Backend/AbstractDigest.php 2 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -2,8 +2,8 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\DAV\Auth\Backend;
4 4
 
5
-use Sabre\HTTP;
6 5
 use Sabre\DAV;
6
+use Sabre\HTTP;
7 7
 use Sabre\HTTP\RequestInterface;
8 8
 use Sabre\HTTP\ResponseInterface;
9 9
 
Please login to merge, or discard this patch.
Indentation   +138 added lines, -138 removed lines patch added patch discarded remove patch
@@ -20,143 +20,143 @@
 block discarded – undo
20 20
  */
21 21
 abstract class AbstractDigest implements BackendInterface {
22 22
 
23
-    /**
24
-     * Authentication Realm.
25
-     *
26
-     * The realm is often displayed by browser clients when showing the
27
-     * authentication dialog.
28
-     *
29
-     * @var string
30
-     */
31
-    protected $realm = 'SabreDAV';
32
-
33
-    /**
34
-     * This is the prefix that will be used to generate principal urls.
35
-     *
36
-     * @var string
37
-     */
38
-    protected $principalPrefix = 'principals/';
39
-
40
-    /**
41
-     * Sets the authentication realm for this backend.
42
-     *
43
-     * Be aware that for Digest authentication, the realm influences the digest
44
-     * hash. Choose the realm wisely, because if you change it later, all the
45
-     * existing hashes will break and nobody can authenticate.
46
-     *
47
-     * @param string $realm
48
-     * @return void
49
-     */
50
-    public function setRealm($realm) {
51
-
52
-        $this->realm = $realm;
53
-
54
-    }
55
-
56
-    /**
57
-     * Returns a users digest hash based on the username and realm.
58
-     *
59
-     * If the user was not known, null must be returned.
60
-     *
61
-     * @param string $realm
62
-     * @param string $username
63
-     * @return string|null
64
-     */
65
-    abstract function getDigestHash($realm, $username);
66
-
67
-    /**
68
-     * When this method is called, the backend must check if authentication was
69
-     * successful.
70
-     *
71
-     * The returned value must be one of the following
72
-     *
73
-     * [true, "principals/username"]
74
-     * [false, "reason for failure"]
75
-     *
76
-     * If authentication was successful, it's expected that the authentication
77
-     * backend returns a so-called principal url.
78
-     *
79
-     * Examples of a principal url:
80
-     *
81
-     * principals/admin
82
-     * principals/user1
83
-     * principals/users/joe
84
-     * principals/uid/123457
85
-     *
86
-     * If you don't use WebDAV ACL (RFC3744) we recommend that you simply
87
-     * return a string such as:
88
-     *
89
-     * principals/users/[username]
90
-     *
91
-     * @param RequestInterface $request
92
-     * @param ResponseInterface $response
93
-     * @return array
94
-     */
95
-    public function check(RequestInterface $request, ResponseInterface $response) {
96
-
97
-        $digest = new HTTP\Auth\Digest(
98
-            $this->realm,
99
-            $request,
100
-            $response
101
-        );
102
-        $digest->init();
103
-
104
-        $username = $digest->getUsername();
105
-
106
-        // No username was given
107
-        if (!$username) {
108
-            return [false, "No 'Authorization: Digest' header found. Either the client didn't send one, or the server is misconfigured"];
109
-        }
110
-
111
-        $hash = $this->getDigestHash($this->realm, $username);
112
-        // If this was false, the user account didn't exist
113
-        if ($hash === false || is_null($hash)) {
114
-            return [false, "Username or password was incorrect"];
115
-        }
116
-        if (!is_string($hash)) {
117
-            throw new DAV\Exception('The returned value from getDigestHash must be a string or null');
118
-        }
119
-
120
-        // If this was false, the password or part of the hash was incorrect.
121
-        if (!$digest->validateA1($hash)) {
122
-            return [false, "Username or password was incorrect"];
123
-        }
124
-
125
-        return [true, $this->principalPrefix . $username];
126
-
127
-    }
128
-
129
-    /**
130
-     * This method is called when a user could not be authenticated, and
131
-     * authentication was required for the current request.
132
-     *
133
-     * This gives you the opportunity to set authentication headers. The 401
134
-     * status code will already be set.
135
-     *
136
-     * In this case of Basic Auth, this would for example mean that the
137
-     * following header needs to be set:
138
-     *
139
-     * $response->addHeader('WWW-Authenticate', 'Basic realm=SabreDAV');
140
-     *
141
-     * Keep in mind that in the case of multiple authentication backends, other
142
-     * WWW-Authenticate headers may already have been set, and you'll want to
143
-     * append your own WWW-Authenticate header instead of overwriting the
144
-     * existing one.
145
-     *
146
-     * @param RequestInterface $request
147
-     * @param ResponseInterface $response
148
-     * @return void
149
-     */
150
-    public function challenge(RequestInterface $request, ResponseInterface $response) {
151
-
152
-        $auth = new HTTP\Auth\Digest(
153
-            $this->realm,
154
-            $request,
155
-            $response
156
-        );
157
-        $auth->init();
158
-        $auth->requireLogin();
159
-
160
-    }
23
+	/**
24
+	 * Authentication Realm.
25
+	 *
26
+	 * The realm is often displayed by browser clients when showing the
27
+	 * authentication dialog.
28
+	 *
29
+	 * @var string
30
+	 */
31
+	protected $realm = 'SabreDAV';
32
+
33
+	/**
34
+	 * This is the prefix that will be used to generate principal urls.
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $principalPrefix = 'principals/';
39
+
40
+	/**
41
+	 * Sets the authentication realm for this backend.
42
+	 *
43
+	 * Be aware that for Digest authentication, the realm influences the digest
44
+	 * hash. Choose the realm wisely, because if you change it later, all the
45
+	 * existing hashes will break and nobody can authenticate.
46
+	 *
47
+	 * @param string $realm
48
+	 * @return void
49
+	 */
50
+	public function setRealm($realm) {
51
+
52
+		$this->realm = $realm;
53
+
54
+	}
55
+
56
+	/**
57
+	 * Returns a users digest hash based on the username and realm.
58
+	 *
59
+	 * If the user was not known, null must be returned.
60
+	 *
61
+	 * @param string $realm
62
+	 * @param string $username
63
+	 * @return string|null
64
+	 */
65
+	abstract function getDigestHash($realm, $username);
66
+
67
+	/**
68
+	 * When this method is called, the backend must check if authentication was
69
+	 * successful.
70
+	 *
71
+	 * The returned value must be one of the following
72
+	 *
73
+	 * [true, "principals/username"]
74
+	 * [false, "reason for failure"]
75
+	 *
76
+	 * If authentication was successful, it's expected that the authentication
77
+	 * backend returns a so-called principal url.
78
+	 *
79
+	 * Examples of a principal url:
80
+	 *
81
+	 * principals/admin
82
+	 * principals/user1
83
+	 * principals/users/joe
84
+	 * principals/uid/123457
85
+	 *
86
+	 * If you don't use WebDAV ACL (RFC3744) we recommend that you simply
87
+	 * return a string such as:
88
+	 *
89
+	 * principals/users/[username]
90
+	 *
91
+	 * @param RequestInterface $request
92
+	 * @param ResponseInterface $response
93
+	 * @return array
94
+	 */
95
+	public function check(RequestInterface $request, ResponseInterface $response) {
96
+
97
+		$digest = new HTTP\Auth\Digest(
98
+			$this->realm,
99
+			$request,
100
+			$response
101
+		);
102
+		$digest->init();
103
+
104
+		$username = $digest->getUsername();
105
+
106
+		// No username was given
107
+		if (!$username) {
108
+			return [false, "No 'Authorization: Digest' header found. Either the client didn't send one, or the server is misconfigured"];
109
+		}
110
+
111
+		$hash = $this->getDigestHash($this->realm, $username);
112
+		// If this was false, the user account didn't exist
113
+		if ($hash === false || is_null($hash)) {
114
+			return [false, "Username or password was incorrect"];
115
+		}
116
+		if (!is_string($hash)) {
117
+			throw new DAV\Exception('The returned value from getDigestHash must be a string or null');
118
+		}
119
+
120
+		// If this was false, the password or part of the hash was incorrect.
121
+		if (!$digest->validateA1($hash)) {
122
+			return [false, "Username or password was incorrect"];
123
+		}
124
+
125
+		return [true, $this->principalPrefix . $username];
126
+
127
+	}
128
+
129
+	/**
130
+	 * This method is called when a user could not be authenticated, and
131
+	 * authentication was required for the current request.
132
+	 *
133
+	 * This gives you the opportunity to set authentication headers. The 401
134
+	 * status code will already be set.
135
+	 *
136
+	 * In this case of Basic Auth, this would for example mean that the
137
+	 * following header needs to be set:
138
+	 *
139
+	 * $response->addHeader('WWW-Authenticate', 'Basic realm=SabreDAV');
140
+	 *
141
+	 * Keep in mind that in the case of multiple authentication backends, other
142
+	 * WWW-Authenticate headers may already have been set, and you'll want to
143
+	 * append your own WWW-Authenticate header instead of overwriting the
144
+	 * existing one.
145
+	 *
146
+	 * @param RequestInterface $request
147
+	 * @param ResponseInterface $response
148
+	 * @return void
149
+	 */
150
+	public function challenge(RequestInterface $request, ResponseInterface $response) {
151
+
152
+		$auth = new HTTP\Auth\Digest(
153
+			$this->realm,
154
+			$request,
155
+			$response
156
+		);
157
+		$auth->init();
158
+		$auth->requireLogin();
159
+
160
+	}
161 161
 
162 162
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/Auth/Plugin.php 3 patches
Unused Use Statements   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -2,12 +2,12 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\DAV\Auth;
4 4
 
5
-use Sabre\HTTP\RequestInterface;
6
-use Sabre\HTTP\ResponseInterface;
7
-use Sabre\HTTP\URLUtil;
8 5
 use Sabre\DAV\Exception\NotAuthenticated;
9 6
 use Sabre\DAV\Server;
10 7
 use Sabre\DAV\ServerPlugin;
8
+use Sabre\HTTP\RequestInterface;
9
+use Sabre\HTTP\ResponseInterface;
10
+use Sabre\HTTP\URLUtil;
11 11
 
12 12
 /**
13 13
  * This plugin provides Authentication for a WebDAV server.
Please login to merge, or discard this patch.
Indentation   +184 added lines, -184 removed lines patch added patch discarded remove patch
@@ -25,189 +25,189 @@
 block discarded – undo
25 25
  */
26 26
 class Plugin extends ServerPlugin {
27 27
 
28
-    /**
29
-     * authentication backends
30
-     */
31
-    protected $backends;
32
-
33
-    /**
34
-     * The currently logged in principal. Will be `null` if nobody is currently
35
-     * logged in.
36
-     *
37
-     * @var string|null
38
-     */
39
-    protected $currentPrincipal;
40
-
41
-    /**
42
-     * Creates the authentication plugin
43
-     *
44
-     * @param Backend\BackendInterface $authBackend
45
-     */
46
-    public function __construct(Backend\BackendInterface $authBackend = null) {
47
-
48
-        if (!is_null($authBackend)) {
49
-            $this->addBackend($authBackend);
50
-        }
51
-
52
-    }
53
-
54
-    /**
55
-     * Adds an authentication backend to the plugin.
56
-     *
57
-     * @param Backend\BackendInterface $authBackend
58
-     * @return void
59
-     */
60
-    public function addBackend(Backend\BackendInterface $authBackend) {
61
-
62
-        $this->backends[] = $authBackend;
63
-
64
-    }
65
-
66
-    /**
67
-     * Initializes the plugin. This function is automatically called by the server
68
-     *
69
-     * @param Server $server
70
-     * @return void
71
-     */
72
-    public function initialize(Server $server) {
73
-
74
-        $server->on('beforeMethod', [$this, 'beforeMethod'], 10);
75
-
76
-    }
77
-
78
-    /**
79
-     * Returns a plugin name.
80
-     *
81
-     * Using this name other plugins will be able to access other plugins
82
-     * using DAV\Server::getPlugin
83
-     *
84
-     * @return string
85
-     */
86
-    public function getPluginName() {
87
-
88
-        return 'auth';
89
-
90
-    }
91
-
92
-    /**
93
-     * Returns the currently logged-in principal.
94
-     *
95
-     * This will return a string such as:
96
-     *
97
-     * principals/username
98
-     * principals/users/username
99
-     *
100
-     * This method will return null if nobody is logged in.
101
-     *
102
-     * @return string|null
103
-     */
104
-    public function getCurrentPrincipal() {
105
-
106
-        return $this->currentPrincipal;
107
-
108
-    }
109
-
110
-    /**
111
-     * Returns the current username.
112
-     *
113
-     * This method is deprecated and is only kept for backwards compatibility
114
-     * purposes. Please switch to getCurrentPrincipal().
115
-     *
116
-     * @deprecated Will be removed in a future version!
117
-     * @return string|null
118
-     */
119
-    public function getCurrentUser() {
120
-
121
-        // We just do a 'basename' on the principal to give back a sane value
122
-        // here.
123
-        list(, $userName) = URLUtil::splitPath(
124
-            $this->getCurrentPrincipal()
125
-        );
126
-
127
-        return $userName;
128
-
129
-    }
130
-
131
-    /**
132
-     * This method is called before any HTTP method and forces users to be authenticated
133
-     *
134
-     * @param RequestInterface $request
135
-     * @param ResponseInterface $response
136
-     * @return bool
137
-     */
138
-    public function beforeMethod(RequestInterface $request, ResponseInterface $response) {
139
-
140
-        if ($this->currentPrincipal) {
141
-
142
-            // We already have authentication information. This means that the
143
-            // event has already fired earlier, and is now likely fired for a
144
-            // sub-request.
145
-            //
146
-            // We don't want to authenticate users twice, so we simply don't do
147
-            // anything here. See Issue #700 for additional reasoning.
148
-            //
149
-            // This is not a perfect solution, but will be fixed once the
150
-            // "currently authenticated principal" is information that's not
151
-            // not associated with the plugin, but rather per-request.
152
-            //
153
-            // See issue #580 for more information about that.
154
-            return;
155
-
156
-        }
157
-        if (!$this->backends) {
158
-            throw new \Sabre\DAV\Exception('No authentication backends were configured on this server.');
159
-        }
160
-        $reasons = [];
161
-        foreach ($this->backends as $backend) {
162
-
163
-            $result = $backend->check(
164
-                $request,
165
-                $response
166
-            );
167
-
168
-            if (!is_array($result) || count($result) !== 2 || !is_bool($result[0]) || !is_string($result[1])) {
169
-                throw new \Sabre\DAV\Exception('The authentication backend did not return a correct value from the check() method.');
170
-            }
171
-
172
-            if ($result[0]) {
173
-                $this->currentPrincipal = $result[1];
174
-                // Exit early
175
-                return;
176
-            }
177
-            $reasons[] = $result[1];
178
-
179
-        }
180
-
181
-        // If we got here, it means that no authentication backend was
182
-        // successful in authenticating the user.
183
-        $this->currentPrincipal = null;
184
-
185
-        foreach ($this->backends as $backend) {
186
-            $backend->challenge($request, $response);
187
-        }
188
-        throw new NotAuthenticated(implode(', ', $reasons));
189
-
190
-    }
191
-
192
-    /**
193
-     * Returns a bunch of meta-data about the plugin.
194
-     *
195
-     * Providing this information is optional, and is mainly displayed by the
196
-     * Browser plugin.
197
-     *
198
-     * The description key in the returned array may contain html and will not
199
-     * be sanitized.
200
-     *
201
-     * @return array
202
-     */
203
-    public function getPluginInfo() {
204
-
205
-        return [
206
-            'name'        => $this->getPluginName(),
207
-            'description' => 'Generic authentication plugin',
208
-            'link'        => 'http://sabre.io/dav/authentication/',
209
-        ];
210
-
211
-    }
28
+	/**
29
+	 * authentication backends
30
+	 */
31
+	protected $backends;
32
+
33
+	/**
34
+	 * The currently logged in principal. Will be `null` if nobody is currently
35
+	 * logged in.
36
+	 *
37
+	 * @var string|null
38
+	 */
39
+	protected $currentPrincipal;
40
+
41
+	/**
42
+	 * Creates the authentication plugin
43
+	 *
44
+	 * @param Backend\BackendInterface $authBackend
45
+	 */
46
+	public function __construct(Backend\BackendInterface $authBackend = null) {
47
+
48
+		if (!is_null($authBackend)) {
49
+			$this->addBackend($authBackend);
50
+		}
51
+
52
+	}
53
+
54
+	/**
55
+	 * Adds an authentication backend to the plugin.
56
+	 *
57
+	 * @param Backend\BackendInterface $authBackend
58
+	 * @return void
59
+	 */
60
+	public function addBackend(Backend\BackendInterface $authBackend) {
61
+
62
+		$this->backends[] = $authBackend;
63
+
64
+	}
65
+
66
+	/**
67
+	 * Initializes the plugin. This function is automatically called by the server
68
+	 *
69
+	 * @param Server $server
70
+	 * @return void
71
+	 */
72
+	public function initialize(Server $server) {
73
+
74
+		$server->on('beforeMethod', [$this, 'beforeMethod'], 10);
75
+
76
+	}
77
+
78
+	/**
79
+	 * Returns a plugin name.
80
+	 *
81
+	 * Using this name other plugins will be able to access other plugins
82
+	 * using DAV\Server::getPlugin
83
+	 *
84
+	 * @return string
85
+	 */
86
+	public function getPluginName() {
87
+
88
+		return 'auth';
89
+
90
+	}
91
+
92
+	/**
93
+	 * Returns the currently logged-in principal.
94
+	 *
95
+	 * This will return a string such as:
96
+	 *
97
+	 * principals/username
98
+	 * principals/users/username
99
+	 *
100
+	 * This method will return null if nobody is logged in.
101
+	 *
102
+	 * @return string|null
103
+	 */
104
+	public function getCurrentPrincipal() {
105
+
106
+		return $this->currentPrincipal;
107
+
108
+	}
109
+
110
+	/**
111
+	 * Returns the current username.
112
+	 *
113
+	 * This method is deprecated and is only kept for backwards compatibility
114
+	 * purposes. Please switch to getCurrentPrincipal().
115
+	 *
116
+	 * @deprecated Will be removed in a future version!
117
+	 * @return string|null
118
+	 */
119
+	public function getCurrentUser() {
120
+
121
+		// We just do a 'basename' on the principal to give back a sane value
122
+		// here.
123
+		list(, $userName) = URLUtil::splitPath(
124
+			$this->getCurrentPrincipal()
125
+		);
126
+
127
+		return $userName;
128
+
129
+	}
130
+
131
+	/**
132
+	 * This method is called before any HTTP method and forces users to be authenticated
133
+	 *
134
+	 * @param RequestInterface $request
135
+	 * @param ResponseInterface $response
136
+	 * @return bool
137
+	 */
138
+	public function beforeMethod(RequestInterface $request, ResponseInterface $response) {
139
+
140
+		if ($this->currentPrincipal) {
141
+
142
+			// We already have authentication information. This means that the
143
+			// event has already fired earlier, and is now likely fired for a
144
+			// sub-request.
145
+			//
146
+			// We don't want to authenticate users twice, so we simply don't do
147
+			// anything here. See Issue #700 for additional reasoning.
148
+			//
149
+			// This is not a perfect solution, but will be fixed once the
150
+			// "currently authenticated principal" is information that's not
151
+			// not associated with the plugin, but rather per-request.
152
+			//
153
+			// See issue #580 for more information about that.
154
+			return;
155
+
156
+		}
157
+		if (!$this->backends) {
158
+			throw new \Sabre\DAV\Exception('No authentication backends were configured on this server.');
159
+		}
160
+		$reasons = [];
161
+		foreach ($this->backends as $backend) {
162
+
163
+			$result = $backend->check(
164
+				$request,
165
+				$response
166
+			);
167
+
168
+			if (!is_array($result) || count($result) !== 2 || !is_bool($result[0]) || !is_string($result[1])) {
169
+				throw new \Sabre\DAV\Exception('The authentication backend did not return a correct value from the check() method.');
170
+			}
171
+
172
+			if ($result[0]) {
173
+				$this->currentPrincipal = $result[1];
174
+				// Exit early
175
+				return;
176
+			}
177
+			$reasons[] = $result[1];
178
+
179
+		}
180
+
181
+		// If we got here, it means that no authentication backend was
182
+		// successful in authenticating the user.
183
+		$this->currentPrincipal = null;
184
+
185
+		foreach ($this->backends as $backend) {
186
+			$backend->challenge($request, $response);
187
+		}
188
+		throw new NotAuthenticated(implode(', ', $reasons));
189
+
190
+	}
191
+
192
+	/**
193
+	 * Returns a bunch of meta-data about the plugin.
194
+	 *
195
+	 * Providing this information is optional, and is mainly displayed by the
196
+	 * Browser plugin.
197
+	 *
198
+	 * The description key in the returned array may contain html and will not
199
+	 * be sanitized.
200
+	 *
201
+	 * @return array
202
+	 */
203
+	public function getPluginInfo() {
204
+
205
+		return [
206
+			'name'        => $this->getPluginName(),
207
+			'description' => 'Generic authentication plugin',
208
+			'link'        => 'http://sabre.io/dav/authentication/',
209
+		];
210
+
211
+	}
212 212
 
213 213
 }
Please login to merge, or discard this patch.
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -133,7 +133,7 @@
 block discarded – undo
133 133
      *
134 134
      * @param RequestInterface $request
135 135
      * @param ResponseInterface $response
136
-     * @return bool
136
+     * @return boolean|null
137 137
      */
138 138
     public function beforeMethod(RequestInterface $request, ResponseInterface $response) {
139 139
 
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/Browser/GuessContentType.php 3 patches
Unused Use Statements   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -2,10 +2,9 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\DAV\Browser;
4 4
 
5
-use Sabre\HTTP\URLUtil;
6 5
 use Sabre\DAV;
7 6
 use Sabre\DAV\PropFind;
8
-use Sabre\DAV\Inode;
7
+use Sabre\HTTP\URLUtil;
9 8
 
10 9
 /**
11 10
  * GuessContentType plugin
Please login to merge, or discard this patch.
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -24,78 +24,78 @@
 block discarded – undo
24 24
  */
25 25
 class GuessContentType extends DAV\ServerPlugin {
26 26
 
27
-    /**
28
-     * List of recognized file extensions
29
-     *
30
-     * Feel free to add more
31
-     *
32
-     * @var array
33
-     */
34
-    public $extensionMap = [
35
-
36
-        // images
37
-        'jpg' => 'image/jpeg',
38
-        'gif' => 'image/gif',
39
-        'png' => 'image/png',
40
-
41
-        // groupware
42
-        'ics' => 'text/calendar',
43
-        'vcf' => 'text/vcard',
44
-
45
-        // text
46
-        'txt' => 'text/plain',
47
-
48
-    ];
49
-
50
-    /**
51
-     * Initializes the plugin
52
-     *
53
-     * @param DAV\Server $server
54
-     * @return void
55
-     */
56
-    public function initialize(DAV\Server $server) {
57
-
58
-        // Using a relatively low priority (200) to allow other extensions
59
-        // to set the content-type first.
60
-        $server->on('propFind', [$this, 'propFind'], 200);
61
-
62
-    }
63
-
64
-    /**
65
-     * Our PROPFIND handler
66
-     *
67
-     * Here we set a contenttype, if the node didn't already have one.
68
-     *
69
-     * @param PropFind $propFind
70
-     * @param INode $node
71
-     * @return void
72
-     */
73
-    public function propFind(PropFind $propFind, INode $node) {
74
-
75
-        $propFind->handle('{DAV:}getcontenttype', function() use ($propFind) {
76
-
77
-            list(, $fileName) = URLUtil::splitPath($propFind->getPath());
78
-            return $this->getContentType($fileName);
79
-
80
-        });
81
-
82
-    }
83
-
84
-    /**
85
-     * Simple method to return the contenttype
86
-     *
87
-     * @param string $fileName
88
-     * @return string
89
-     */
90
-    protected function getContentType($fileName) {
91
-
92
-        // Just grabbing the extension
93
-        $extension = strtolower(substr($fileName, strrpos($fileName, '.') + 1));
94
-        if (isset($this->extensionMap[$extension])) {
95
-            return $this->extensionMap[$extension];
96
-        }
97
-        return 'application/octet-stream';
98
-
99
-    }
27
+	/**
28
+	 * List of recognized file extensions
29
+	 *
30
+	 * Feel free to add more
31
+	 *
32
+	 * @var array
33
+	 */
34
+	public $extensionMap = [
35
+
36
+		// images
37
+		'jpg' => 'image/jpeg',
38
+		'gif' => 'image/gif',
39
+		'png' => 'image/png',
40
+
41
+		// groupware
42
+		'ics' => 'text/calendar',
43
+		'vcf' => 'text/vcard',
44
+
45
+		// text
46
+		'txt' => 'text/plain',
47
+
48
+	];
49
+
50
+	/**
51
+	 * Initializes the plugin
52
+	 *
53
+	 * @param DAV\Server $server
54
+	 * @return void
55
+	 */
56
+	public function initialize(DAV\Server $server) {
57
+
58
+		// Using a relatively low priority (200) to allow other extensions
59
+		// to set the content-type first.
60
+		$server->on('propFind', [$this, 'propFind'], 200);
61
+
62
+	}
63
+
64
+	/**
65
+	 * Our PROPFIND handler
66
+	 *
67
+	 * Here we set a contenttype, if the node didn't already have one.
68
+	 *
69
+	 * @param PropFind $propFind
70
+	 * @param INode $node
71
+	 * @return void
72
+	 */
73
+	public function propFind(PropFind $propFind, INode $node) {
74
+
75
+		$propFind->handle('{DAV:}getcontenttype', function() use ($propFind) {
76
+
77
+			list(, $fileName) = URLUtil::splitPath($propFind->getPath());
78
+			return $this->getContentType($fileName);
79
+
80
+		});
81
+
82
+	}
83
+
84
+	/**
85
+	 * Simple method to return the contenttype
86
+	 *
87
+	 * @param string $fileName
88
+	 * @return string
89
+	 */
90
+	protected function getContentType($fileName) {
91
+
92
+		// Just grabbing the extension
93
+		$extension = strtolower(substr($fileName, strrpos($fileName, '.') + 1));
94
+		if (isset($this->extensionMap[$extension])) {
95
+			return $this->extensionMap[$extension];
96
+		}
97
+		return 'application/octet-stream';
98
+
99
+	}
100 100
 
101 101
 }
Please login to merge, or discard this patch.
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -67,7 +67,7 @@
 block discarded – undo
67 67
      * Here we set a contenttype, if the node didn't already have one.
68 68
      *
69 69
      * @param PropFind $propFind
70
-     * @param INode $node
70
+     * @param DAV\INode $node
71 71
      * @return void
72 72
      */
73 73
     public function propFind(PropFind $propFind, INode $node) {
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/Browser/Plugin.php 5 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -4,9 +4,9 @@
 block discarded – undo
4 4
 
5 5
 use Sabre\DAV;
6 6
 use Sabre\DAV\MkCol;
7
-use Sabre\HTTP\URLUtil;
8 7
 use Sabre\HTTP\RequestInterface;
9 8
 use Sabre\HTTP\ResponseInterface;
9
+use Sabre\HTTP\URLUtil;
10 10
 
11 11
 /**
12 12
  * Browser Plugin
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -317,7 +317,7 @@  discard block
 block discarded – undo
317 317
 
318 318
                 $buttonActions = '';
319 319
                 if ($subProps['subNode'] instanceof DAV\IFile) {
320
-                    $buttonActions =  '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>';
320
+                    $buttonActions = '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>';
321 321
                 }
322 322
                 $this->server->emit('browserButtonActions', [$subProps['fullPath'], $subProps['subNode'], &$buttonActions]);
323 323
 
@@ -450,7 +450,7 @@  discard block
 block discarded – undo
450 450
 HTML;
451 451
 
452 452
         // If the path is empty, there's no parent.
453
-        if ($path)  {
453
+        if ($path) {
454 454
             list($parentUri) = URLUtil::splitPath($path);
455 455
             $fullPath = $this->server->getBaseUri() . URLUtil::encodePath($parentUri);
456 456
             $html .= '<a href="' . $fullPath . '" class="btn">⇤ Go to parent</a>';
Please login to merge, or discard this patch.
Indentation   +723 added lines, -723 removed lines patch added patch discarded remove patch
@@ -23,413 +23,413 @@  discard block
 block discarded – undo
23 23
  */
24 24
 class Plugin extends DAV\ServerPlugin {
25 25
 
26
-    /**
27
-     * reference to server class
28
-     *
29
-     * @var Sabre\DAV\Server
30
-     */
31
-    protected $server;
32
-
33
-    /**
34
-     * enablePost turns on the 'actions' panel, which allows people to create
35
-     * folders and upload files straight from a browser.
36
-     *
37
-     * @var bool
38
-     */
39
-    protected $enablePost = true;
40
-
41
-    /**
42
-     * A list of properties that are usually not interesting. This can cut down
43
-     * the browser output a bit by removing the properties that most people
44
-     * will likely not want to see.
45
-     *
46
-     * @var array
47
-     */
48
-    public $uninterestingProperties = [
49
-        '{DAV:}supportedlock',
50
-        '{DAV:}acl-restrictions',
51
-        '{DAV:}supported-privilege-set',
52
-        '{DAV:}supported-method-set',
53
-    ];
54
-
55
-    /**
56
-     * Creates the object.
57
-     *
58
-     * By default it will allow file creation and uploads.
59
-     * Specify the first argument as false to disable this
60
-     *
61
-     * @param bool $enablePost
62
-     */
63
-    public function __construct($enablePost = true) {
64
-
65
-        $this->enablePost = $enablePost;
66
-
67
-    }
68
-
69
-    /**
70
-     * Initializes the plugin and subscribes to events
71
-     *
72
-     * @param DAV\Server $server
73
-     * @return void
74
-     */
75
-    public function initialize(DAV\Server $server) {
76
-
77
-        $this->server = $server;
78
-        $this->server->on('method:GET', [$this, 'httpGetEarly'], 90);
79
-        $this->server->on('method:GET', [$this, 'httpGet'], 200);
80
-        $this->server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel'], 200);
81
-        if ($this->enablePost) $this->server->on('method:POST', [$this, 'httpPOST']);
82
-    }
83
-
84
-    /**
85
-     * This method intercepts GET requests that have ?sabreAction=info
86
-     * appended to the URL
87
-     *
88
-     * @param RequestInterface $request
89
-     * @param ResponseInterface $response
90
-     * @return bool
91
-     */
92
-    public function httpGetEarly(RequestInterface $request, ResponseInterface $response) {
93
-
94
-        $params = $request->getQueryParameters();
95
-        if (isset($params['sabreAction']) && $params['sabreAction'] === 'info') {
96
-            return $this->httpGet($request, $response);
97
-        }
98
-
99
-    }
100
-
101
-    /**
102
-     * This method intercepts GET requests to collections and returns the html
103
-     *
104
-     * @param RequestInterface $request
105
-     * @param ResponseInterface $response
106
-     * @return bool
107
-     */
108
-    public function httpGet(RequestInterface $request, ResponseInterface $response) {
109
-
110
-        // We're not using straight-up $_GET, because we want everything to be
111
-        // unit testable.
112
-        $getVars = $request->getQueryParameters();
113
-
114
-        // CSP headers
115
-        $this->server->httpResponse->setHeader('Content-Security-Policy', "img-src 'self'; style-src 'self';");
116
-
117
-        $sabreAction = isset($getVars['sabreAction']) ? $getVars['sabreAction'] : null;
118
-
119
-        switch ($sabreAction) {
120
-
121
-            case 'asset' :
122
-                // Asset handling, such as images
123
-                $this->serveAsset(isset($getVars['assetName']) ? $getVars['assetName'] : null);
124
-                return false;
125
-            default :
126
-            case 'info' :
127
-                try {
128
-                    $this->server->tree->getNodeForPath($request->getPath());
129
-                } catch (DAV\Exception\NotFound $e) {
130
-                    // We're simply stopping when the file isn't found to not interfere
131
-                    // with other plugins.
132
-                    return;
133
-                }
134
-
135
-                $response->setStatus(200);
136
-                $response->setHeader('Content-Type', 'text/html; charset=utf-8');
137
-
138
-                $response->setBody(
139
-                    $this->generateDirectoryIndex($request->getPath())
140
-                );
141
-
142
-                return false;
143
-
144
-            case 'plugins' :
145
-                $response->setStatus(200);
146
-                $response->setHeader('Content-Type', 'text/html; charset=utf-8');
147
-
148
-                $response->setBody(
149
-                    $this->generatePluginListing()
150
-                );
151
-
152
-                return false;
153
-
154
-        }
155
-
156
-    }
157
-
158
-    /**
159
-     * Handles POST requests for tree operations.
160
-     *
161
-     * @param RequestInterface $request
162
-     * @param ResponseInterface $response
163
-     * @return bool
164
-     */
165
-    public function httpPOST(RequestInterface $request, ResponseInterface $response) {
166
-
167
-        $contentType = $request->getHeader('Content-Type');
168
-        list($contentType) = explode(';', $contentType);
169
-        if ($contentType !== 'application/x-www-form-urlencoded' &&
170
-            $contentType !== 'multipart/form-data') {
171
-                return;
172
-        }
173
-        $postVars = $request->getPostData();
174
-
175
-        if (!isset($postVars['sabreAction']))
176
-            return;
177
-
178
-        $uri = $request->getPath();
179
-
180
-        if ($this->server->emit('onBrowserPostAction', [$uri, $postVars['sabreAction'], $postVars])) {
181
-
182
-            switch ($postVars['sabreAction']) {
183
-
184
-                case 'mkcol' :
185
-                    if (isset($postVars['name']) && trim($postVars['name'])) {
186
-                        // Using basename() because we won't allow slashes
187
-                        list(, $folderName) = URLUtil::splitPath(trim($postVars['name']));
188
-
189
-                        if (isset($postVars['resourceType'])) {
190
-                            $resourceType = explode(',', $postVars['resourceType']);
191
-                        } else {
192
-                            $resourceType = ['{DAV:}collection'];
193
-                        }
194
-
195
-                        $properties = [];
196
-                        foreach ($postVars as $varName => $varValue) {
197
-                            // Any _POST variable in clark notation is treated
198
-                            // like a property.
199
-                            if ($varName[0] === '{') {
200
-                                // PHP will convert any dots to underscores.
201
-                                // This leaves us with no way to differentiate
202
-                                // the two.
203
-                                // Therefore we replace the string *DOT* with a
204
-                                // real dot. * is not allowed in uris so we
205
-                                // should be good.
206
-                                $varName = str_replace('*DOT*', '.', $varName);
207
-                                $properties[$varName] = $varValue;
208
-                            }
209
-                        }
210
-
211
-                        $mkCol = new MkCol(
212
-                            $resourceType,
213
-                            $properties
214
-                        );
215
-                        $this->server->createCollection($uri . '/' . $folderName, $mkCol);
216
-                    }
217
-                    break;
218
-
219
-                // @codeCoverageIgnoreStart
220
-                case 'put' :
221
-
222
-                    if ($_FILES) $file = current($_FILES);
223
-                    else break;
224
-
225
-                    list(, $newName) = URLUtil::splitPath(trim($file['name']));
226
-                    if (isset($postVars['name']) && trim($postVars['name']))
227
-                        $newName = trim($postVars['name']);
228
-
229
-                    // Making sure we only have a 'basename' component
230
-                    list(, $newName) = URLUtil::splitPath($newName);
231
-
232
-                    if (is_uploaded_file($file['tmp_name'])) {
233
-                        $this->server->createFile($uri . '/' . $newName, fopen($file['tmp_name'], 'r'));
234
-                    }
235
-                    break;
236
-                // @codeCoverageIgnoreEnd
237
-
238
-            }
239
-
240
-        }
241
-        $response->setHeader('Location', $request->getUrl());
242
-        $response->setStatus(302);
243
-        return false;
244
-
245
-    }
246
-
247
-    /**
248
-     * Escapes a string for html.
249
-     *
250
-     * @param string $value
251
-     * @return string
252
-     */
253
-    public function escapeHTML($value) {
254
-
255
-        return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
256
-
257
-    }
258
-
259
-    /**
260
-     * Generates the html directory index for a given url
261
-     *
262
-     * @param string $path
263
-     * @return string
264
-     */
265
-    public function generateDirectoryIndex($path) {
266
-
267
-        $html = $this->generateHeader($path ? $path : '/', $path);
268
-
269
-        $node = $this->server->tree->getNodeForPath($path);
270
-        if ($node instanceof DAV\ICollection) {
271
-
272
-            $html .= "<section><h1>Nodes</h1>\n";
273
-            $html .= "<table class=\"nodeTable\">";
274
-
275
-            $subNodes = $this->server->getPropertiesForChildren($path, [
276
-                '{DAV:}displayname',
277
-                '{DAV:}resourcetype',
278
-                '{DAV:}getcontenttype',
279
-                '{DAV:}getcontentlength',
280
-                '{DAV:}getlastmodified',
281
-            ]);
282
-
283
-            foreach ($subNodes as $subPath => $subProps) {
284
-
285
-                $subNode = $this->server->tree->getNodeForPath($subPath);
286
-                $fullPath = $this->server->getBaseUri() . URLUtil::encodePath($subPath);
287
-                list(, $displayPath) = URLUtil::splitPath($subPath);
288
-
289
-                $subNodes[$subPath]['subNode'] = $subNode;
290
-                $subNodes[$subPath]['fullPath'] = $fullPath;
291
-                $subNodes[$subPath]['displayPath'] = $displayPath;
292
-            }
293
-            uasort($subNodes, [$this, 'compareNodes']);
294
-
295
-            foreach ($subNodes as $subProps) {
296
-                $type = [
297
-                    'string' => 'Unknown',
298
-                    'icon'   => 'cog',
299
-                ];
300
-                if (isset($subProps['{DAV:}resourcetype'])) {
301
-                    $type = $this->mapResourceType($subProps['{DAV:}resourcetype']->getValue(), $subProps['subNode']);
302
-                }
303
-
304
-                $html .= '<tr>';
305
-                $html .= '<td class="nameColumn"><a href="' . $this->escapeHTML($subProps['fullPath']) . '"><span class="oi" data-glyph="' . $this->escapeHTML($type['icon']) . '"></span> ' . $this->escapeHTML($subProps['displayPath']) . '</a></td>';
306
-                $html .= '<td class="typeColumn">' . $this->escapeHTML($type['string']) . '</td>';
307
-                $html .= '<td>';
308
-                if (isset($subProps['{DAV:}getcontentlength'])) {
309
-                    $html .= $this->escapeHTML($subProps['{DAV:}getcontentlength'] . ' bytes');
310
-                }
311
-                $html .= '</td><td>';
312
-                if (isset($subProps['{DAV:}getlastmodified'])) {
313
-                    $lastMod = $subProps['{DAV:}getlastmodified']->getTime();
314
-                    $html .= $this->escapeHTML($lastMod->format('F j, Y, g:i a'));
315
-                }
316
-                $html .= '</td>';
317
-
318
-                $buttonActions = '';
319
-                if ($subProps['subNode'] instanceof DAV\IFile) {
320
-                    $buttonActions =  '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>';
321
-                }
322
-                $this->server->emit('browserButtonActions', [$subProps['fullPath'], $subProps['subNode'], &$buttonActions]);
323
-
324
-                $html .= '<td>' . $buttonActions . '</td>';
325
-                $html .= '</tr>';
326
-            }
327
-
328
-            $html .= '</table>';
329
-
330
-        }
331
-
332
-        $html .= "</section>";
333
-        $html .= "<section><h1>Properties</h1>";
334
-        $html .= "<table class=\"propTable\">";
335
-
336
-        // Allprops request
337
-        $propFind = new PropFindAll($path);
338
-        $properties = $this->server->getPropertiesByNode($propFind, $node);
339
-
340
-        $properties = $propFind->getResultForMultiStatus()[200];
341
-
342
-        foreach ($properties as $propName => $propValue) {
343
-            if (!in_array($propName, $this->uninterestingProperties)) {
344
-                $html .= $this->drawPropertyRow($propName, $propValue);
345
-            }
346
-
347
-        }
348
-
349
-
350
-        $html .= "</table>";
351
-        $html .= "</section>";
352
-
353
-        /* Start of generating actions */
354
-
355
-        $output = '';
356
-        if ($this->enablePost) {
357
-            $this->server->emit('onHTMLActionsPanel', [$node, &$output]);
358
-        }
359
-
360
-        if ($output) {
361
-
362
-            $html .= "<section><h1>Actions</h1>";
363
-            $html .= "<div class=\"actions\">\n";
364
-            $html .= $output;
365
-            $html .= "</div>\n";
366
-            $html .= "</section>\n";
367
-        }
368
-
369
-        $html .= $this->generateFooter();
370
-
371
-        $this->server->httpResponse->setHeader('Content-Security-Policy', "img-src 'self'; style-src 'self';");
372
-
373
-        return $html;
374
-
375
-    }
376
-
377
-    /**
378
-     * Generates the 'plugins' page.
379
-     *
380
-     * @return string
381
-     */
382
-    public function generatePluginListing() {
383
-
384
-        $html = $this->generateHeader('Plugins');
385
-
386
-        $html .= "<section><h1>Plugins</h1>";
387
-        $html .= "<table class=\"propTable\">";
388
-        foreach ($this->server->getPlugins() as $plugin) {
389
-            $info = $plugin->getPluginInfo();
390
-            $html .= '<tr><th>' . $info['name'] . '</th>';
391
-            $html .= '<td>' . $info['description'] . '</td>';
392
-            $html .= '<td>';
393
-            if (isset($info['link']) && $info['link']) {
394
-                $html .= '<a href="' . $this->escapeHTML($info['link']) . '"><span class="oi" data-glyph="book"></span></a>';
395
-            }
396
-            $html .= '</td></tr>';
397
-        }
398
-        $html .= "</table>";
399
-        $html .= "</section>";
400
-
401
-        /* Start of generating actions */
402
-
403
-        $html .= $this->generateFooter();
404
-
405
-        return $html;
406
-
407
-    }
408
-
409
-    /**
410
-     * Generates the first block of HTML, including the <head> tag and page
411
-     * header.
412
-     *
413
-     * Returns footer.
414
-     *
415
-     * @param string $title
416
-     * @param string $path
417
-     * @return void
418
-     */
419
-    public function generateHeader($title, $path = null) {
26
+	/**
27
+	 * reference to server class
28
+	 *
29
+	 * @var Sabre\DAV\Server
30
+	 */
31
+	protected $server;
32
+
33
+	/**
34
+	 * enablePost turns on the 'actions' panel, which allows people to create
35
+	 * folders and upload files straight from a browser.
36
+	 *
37
+	 * @var bool
38
+	 */
39
+	protected $enablePost = true;
40
+
41
+	/**
42
+	 * A list of properties that are usually not interesting. This can cut down
43
+	 * the browser output a bit by removing the properties that most people
44
+	 * will likely not want to see.
45
+	 *
46
+	 * @var array
47
+	 */
48
+	public $uninterestingProperties = [
49
+		'{DAV:}supportedlock',
50
+		'{DAV:}acl-restrictions',
51
+		'{DAV:}supported-privilege-set',
52
+		'{DAV:}supported-method-set',
53
+	];
54
+
55
+	/**
56
+	 * Creates the object.
57
+	 *
58
+	 * By default it will allow file creation and uploads.
59
+	 * Specify the first argument as false to disable this
60
+	 *
61
+	 * @param bool $enablePost
62
+	 */
63
+	public function __construct($enablePost = true) {
64
+
65
+		$this->enablePost = $enablePost;
66
+
67
+	}
68
+
69
+	/**
70
+	 * Initializes the plugin and subscribes to events
71
+	 *
72
+	 * @param DAV\Server $server
73
+	 * @return void
74
+	 */
75
+	public function initialize(DAV\Server $server) {
76
+
77
+		$this->server = $server;
78
+		$this->server->on('method:GET', [$this, 'httpGetEarly'], 90);
79
+		$this->server->on('method:GET', [$this, 'httpGet'], 200);
80
+		$this->server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel'], 200);
81
+		if ($this->enablePost) $this->server->on('method:POST', [$this, 'httpPOST']);
82
+	}
83
+
84
+	/**
85
+	 * This method intercepts GET requests that have ?sabreAction=info
86
+	 * appended to the URL
87
+	 *
88
+	 * @param RequestInterface $request
89
+	 * @param ResponseInterface $response
90
+	 * @return bool
91
+	 */
92
+	public function httpGetEarly(RequestInterface $request, ResponseInterface $response) {
93
+
94
+		$params = $request->getQueryParameters();
95
+		if (isset($params['sabreAction']) && $params['sabreAction'] === 'info') {
96
+			return $this->httpGet($request, $response);
97
+		}
98
+
99
+	}
100
+
101
+	/**
102
+	 * This method intercepts GET requests to collections and returns the html
103
+	 *
104
+	 * @param RequestInterface $request
105
+	 * @param ResponseInterface $response
106
+	 * @return bool
107
+	 */
108
+	public function httpGet(RequestInterface $request, ResponseInterface $response) {
109
+
110
+		// We're not using straight-up $_GET, because we want everything to be
111
+		// unit testable.
112
+		$getVars = $request->getQueryParameters();
113
+
114
+		// CSP headers
115
+		$this->server->httpResponse->setHeader('Content-Security-Policy', "img-src 'self'; style-src 'self';");
116
+
117
+		$sabreAction = isset($getVars['sabreAction']) ? $getVars['sabreAction'] : null;
118
+
119
+		switch ($sabreAction) {
120
+
121
+			case 'asset' :
122
+				// Asset handling, such as images
123
+				$this->serveAsset(isset($getVars['assetName']) ? $getVars['assetName'] : null);
124
+				return false;
125
+			default :
126
+			case 'info' :
127
+				try {
128
+					$this->server->tree->getNodeForPath($request->getPath());
129
+				} catch (DAV\Exception\NotFound $e) {
130
+					// We're simply stopping when the file isn't found to not interfere
131
+					// with other plugins.
132
+					return;
133
+				}
134
+
135
+				$response->setStatus(200);
136
+				$response->setHeader('Content-Type', 'text/html; charset=utf-8');
137
+
138
+				$response->setBody(
139
+					$this->generateDirectoryIndex($request->getPath())
140
+				);
141
+
142
+				return false;
143
+
144
+			case 'plugins' :
145
+				$response->setStatus(200);
146
+				$response->setHeader('Content-Type', 'text/html; charset=utf-8');
147
+
148
+				$response->setBody(
149
+					$this->generatePluginListing()
150
+				);
151
+
152
+				return false;
153
+
154
+		}
155
+
156
+	}
157
+
158
+	/**
159
+	 * Handles POST requests for tree operations.
160
+	 *
161
+	 * @param RequestInterface $request
162
+	 * @param ResponseInterface $response
163
+	 * @return bool
164
+	 */
165
+	public function httpPOST(RequestInterface $request, ResponseInterface $response) {
166
+
167
+		$contentType = $request->getHeader('Content-Type');
168
+		list($contentType) = explode(';', $contentType);
169
+		if ($contentType !== 'application/x-www-form-urlencoded' &&
170
+			$contentType !== 'multipart/form-data') {
171
+				return;
172
+		}
173
+		$postVars = $request->getPostData();
174
+
175
+		if (!isset($postVars['sabreAction']))
176
+			return;
177
+
178
+		$uri = $request->getPath();
179
+
180
+		if ($this->server->emit('onBrowserPostAction', [$uri, $postVars['sabreAction'], $postVars])) {
181
+
182
+			switch ($postVars['sabreAction']) {
183
+
184
+				case 'mkcol' :
185
+					if (isset($postVars['name']) && trim($postVars['name'])) {
186
+						// Using basename() because we won't allow slashes
187
+						list(, $folderName) = URLUtil::splitPath(trim($postVars['name']));
188
+
189
+						if (isset($postVars['resourceType'])) {
190
+							$resourceType = explode(',', $postVars['resourceType']);
191
+						} else {
192
+							$resourceType = ['{DAV:}collection'];
193
+						}
194
+
195
+						$properties = [];
196
+						foreach ($postVars as $varName => $varValue) {
197
+							// Any _POST variable in clark notation is treated
198
+							// like a property.
199
+							if ($varName[0] === '{') {
200
+								// PHP will convert any dots to underscores.
201
+								// This leaves us with no way to differentiate
202
+								// the two.
203
+								// Therefore we replace the string *DOT* with a
204
+								// real dot. * is not allowed in uris so we
205
+								// should be good.
206
+								$varName = str_replace('*DOT*', '.', $varName);
207
+								$properties[$varName] = $varValue;
208
+							}
209
+						}
210
+
211
+						$mkCol = new MkCol(
212
+							$resourceType,
213
+							$properties
214
+						);
215
+						$this->server->createCollection($uri . '/' . $folderName, $mkCol);
216
+					}
217
+					break;
218
+
219
+				// @codeCoverageIgnoreStart
220
+				case 'put' :
221
+
222
+					if ($_FILES) $file = current($_FILES);
223
+					else break;
224
+
225
+					list(, $newName) = URLUtil::splitPath(trim($file['name']));
226
+					if (isset($postVars['name']) && trim($postVars['name']))
227
+						$newName = trim($postVars['name']);
228
+
229
+					// Making sure we only have a 'basename' component
230
+					list(, $newName) = URLUtil::splitPath($newName);
231
+
232
+					if (is_uploaded_file($file['tmp_name'])) {
233
+						$this->server->createFile($uri . '/' . $newName, fopen($file['tmp_name'], 'r'));
234
+					}
235
+					break;
236
+				// @codeCoverageIgnoreEnd
237
+
238
+			}
239
+
240
+		}
241
+		$response->setHeader('Location', $request->getUrl());
242
+		$response->setStatus(302);
243
+		return false;
244
+
245
+	}
246
+
247
+	/**
248
+	 * Escapes a string for html.
249
+	 *
250
+	 * @param string $value
251
+	 * @return string
252
+	 */
253
+	public function escapeHTML($value) {
254
+
255
+		return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
256
+
257
+	}
258
+
259
+	/**
260
+	 * Generates the html directory index for a given url
261
+	 *
262
+	 * @param string $path
263
+	 * @return string
264
+	 */
265
+	public function generateDirectoryIndex($path) {
266
+
267
+		$html = $this->generateHeader($path ? $path : '/', $path);
268
+
269
+		$node = $this->server->tree->getNodeForPath($path);
270
+		if ($node instanceof DAV\ICollection) {
271
+
272
+			$html .= "<section><h1>Nodes</h1>\n";
273
+			$html .= "<table class=\"nodeTable\">";
274
+
275
+			$subNodes = $this->server->getPropertiesForChildren($path, [
276
+				'{DAV:}displayname',
277
+				'{DAV:}resourcetype',
278
+				'{DAV:}getcontenttype',
279
+				'{DAV:}getcontentlength',
280
+				'{DAV:}getlastmodified',
281
+			]);
282
+
283
+			foreach ($subNodes as $subPath => $subProps) {
284
+
285
+				$subNode = $this->server->tree->getNodeForPath($subPath);
286
+				$fullPath = $this->server->getBaseUri() . URLUtil::encodePath($subPath);
287
+				list(, $displayPath) = URLUtil::splitPath($subPath);
288
+
289
+				$subNodes[$subPath]['subNode'] = $subNode;
290
+				$subNodes[$subPath]['fullPath'] = $fullPath;
291
+				$subNodes[$subPath]['displayPath'] = $displayPath;
292
+			}
293
+			uasort($subNodes, [$this, 'compareNodes']);
294
+
295
+			foreach ($subNodes as $subProps) {
296
+				$type = [
297
+					'string' => 'Unknown',
298
+					'icon'   => 'cog',
299
+				];
300
+				if (isset($subProps['{DAV:}resourcetype'])) {
301
+					$type = $this->mapResourceType($subProps['{DAV:}resourcetype']->getValue(), $subProps['subNode']);
302
+				}
303
+
304
+				$html .= '<tr>';
305
+				$html .= '<td class="nameColumn"><a href="' . $this->escapeHTML($subProps['fullPath']) . '"><span class="oi" data-glyph="' . $this->escapeHTML($type['icon']) . '"></span> ' . $this->escapeHTML($subProps['displayPath']) . '</a></td>';
306
+				$html .= '<td class="typeColumn">' . $this->escapeHTML($type['string']) . '</td>';
307
+				$html .= '<td>';
308
+				if (isset($subProps['{DAV:}getcontentlength'])) {
309
+					$html .= $this->escapeHTML($subProps['{DAV:}getcontentlength'] . ' bytes');
310
+				}
311
+				$html .= '</td><td>';
312
+				if (isset($subProps['{DAV:}getlastmodified'])) {
313
+					$lastMod = $subProps['{DAV:}getlastmodified']->getTime();
314
+					$html .= $this->escapeHTML($lastMod->format('F j, Y, g:i a'));
315
+				}
316
+				$html .= '</td>';
317
+
318
+				$buttonActions = '';
319
+				if ($subProps['subNode'] instanceof DAV\IFile) {
320
+					$buttonActions =  '<a href="' . $this->escapeHTML($subProps['fullPath']) . '?sabreAction=info"><span class="oi" data-glyph="info"></span></a>';
321
+				}
322
+				$this->server->emit('browserButtonActions', [$subProps['fullPath'], $subProps['subNode'], &$buttonActions]);
323
+
324
+				$html .= '<td>' . $buttonActions . '</td>';
325
+				$html .= '</tr>';
326
+			}
327
+
328
+			$html .= '</table>';
329
+
330
+		}
331
+
332
+		$html .= "</section>";
333
+		$html .= "<section><h1>Properties</h1>";
334
+		$html .= "<table class=\"propTable\">";
335
+
336
+		// Allprops request
337
+		$propFind = new PropFindAll($path);
338
+		$properties = $this->server->getPropertiesByNode($propFind, $node);
339
+
340
+		$properties = $propFind->getResultForMultiStatus()[200];
341
+
342
+		foreach ($properties as $propName => $propValue) {
343
+			if (!in_array($propName, $this->uninterestingProperties)) {
344
+				$html .= $this->drawPropertyRow($propName, $propValue);
345
+			}
346
+
347
+		}
348
+
349
+
350
+		$html .= "</table>";
351
+		$html .= "</section>";
352
+
353
+		/* Start of generating actions */
354
+
355
+		$output = '';
356
+		if ($this->enablePost) {
357
+			$this->server->emit('onHTMLActionsPanel', [$node, &$output]);
358
+		}
359
+
360
+		if ($output) {
361
+
362
+			$html .= "<section><h1>Actions</h1>";
363
+			$html .= "<div class=\"actions\">\n";
364
+			$html .= $output;
365
+			$html .= "</div>\n";
366
+			$html .= "</section>\n";
367
+		}
368
+
369
+		$html .= $this->generateFooter();
370
+
371
+		$this->server->httpResponse->setHeader('Content-Security-Policy', "img-src 'self'; style-src 'self';");
372
+
373
+		return $html;
374
+
375
+	}
376
+
377
+	/**
378
+	 * Generates the 'plugins' page.
379
+	 *
380
+	 * @return string
381
+	 */
382
+	public function generatePluginListing() {
383
+
384
+		$html = $this->generateHeader('Plugins');
385
+
386
+		$html .= "<section><h1>Plugins</h1>";
387
+		$html .= "<table class=\"propTable\">";
388
+		foreach ($this->server->getPlugins() as $plugin) {
389
+			$info = $plugin->getPluginInfo();
390
+			$html .= '<tr><th>' . $info['name'] . '</th>';
391
+			$html .= '<td>' . $info['description'] . '</td>';
392
+			$html .= '<td>';
393
+			if (isset($info['link']) && $info['link']) {
394
+				$html .= '<a href="' . $this->escapeHTML($info['link']) . '"><span class="oi" data-glyph="book"></span></a>';
395
+			}
396
+			$html .= '</td></tr>';
397
+		}
398
+		$html .= "</table>";
399
+		$html .= "</section>";
400
+
401
+		/* Start of generating actions */
402
+
403
+		$html .= $this->generateFooter();
404
+
405
+		return $html;
406
+
407
+	}
408
+
409
+	/**
410
+	 * Generates the first block of HTML, including the <head> tag and page
411
+	 * header.
412
+	 *
413
+	 * Returns footer.
414
+	 *
415
+	 * @param string $title
416
+	 * @param string $path
417
+	 * @return void
418
+	 */
419
+	public function generateHeader($title, $path = null) {
420 420
 
421
-        $version = DAV\Version::VERSION;
421
+		$version = DAV\Version::VERSION;
422 422
 
423
-        $vars = [
424
-            'title'     => $this->escapeHTML($title),
425
-            'favicon'   => $this->escapeHTML($this->getAssetUrl('favicon.ico')),
426
-            'style'     => $this->escapeHTML($this->getAssetUrl('sabredav.css')),
427
-            'iconstyle' => $this->escapeHTML($this->getAssetUrl('openiconic/open-iconic.css')),
428
-            'logo'      => $this->escapeHTML($this->getAssetUrl('sabredav.png')),
429
-            'baseUrl'   => $this->server->getBaseUri(),
430
-        ];
423
+		$vars = [
424
+			'title'     => $this->escapeHTML($title),
425
+			'favicon'   => $this->escapeHTML($this->getAssetUrl('favicon.ico')),
426
+			'style'     => $this->escapeHTML($this->getAssetUrl('sabredav.css')),
427
+			'iconstyle' => $this->escapeHTML($this->getAssetUrl('openiconic/open-iconic.css')),
428
+			'logo'      => $this->escapeHTML($this->getAssetUrl('sabredav.png')),
429
+			'baseUrl'   => $this->server->getBaseUri(),
430
+		];
431 431
 
432
-        $html = <<<HTML
432
+		$html = <<<HTML
433 433
 <!DOCTYPE html>
434 434
 <html>
435 435
 <head>
@@ -449,64 +449,64 @@  discard block
 block discarded – undo
449 449
     <nav>
450 450
 HTML;
451 451
 
452
-        // If the path is empty, there's no parent.
453
-        if ($path)  {
454
-            list($parentUri) = URLUtil::splitPath($path);
455
-            $fullPath = $this->server->getBaseUri() . URLUtil::encodePath($parentUri);
456
-            $html .= '<a href="' . $fullPath . '" class="btn">⇤ Go to parent</a>';
457
-        } else {
458
-            $html .= '<span class="btn disabled">⇤ Go to parent</span>';
459
-        }
452
+		// If the path is empty, there's no parent.
453
+		if ($path)  {
454
+			list($parentUri) = URLUtil::splitPath($path);
455
+			$fullPath = $this->server->getBaseUri() . URLUtil::encodePath($parentUri);
456
+			$html .= '<a href="' . $fullPath . '" class="btn">⇤ Go to parent</a>';
457
+		} else {
458
+			$html .= '<span class="btn disabled">⇤ Go to parent</span>';
459
+		}
460 460
 
461
-        $html .= ' <a href="?sabreAction=plugins" class="btn"><span class="oi" data-glyph="puzzle-piece"></span> Plugins</a>';
461
+		$html .= ' <a href="?sabreAction=plugins" class="btn"><span class="oi" data-glyph="puzzle-piece"></span> Plugins</a>';
462 462
 
463
-        $html .= "</nav>";
463
+		$html .= "</nav>";
464 464
 
465
-        return $html;
465
+		return $html;
466 466
 
467
-    }
467
+	}
468 468
 
469
-    /**
470
-     * Generates the page footer.
471
-     *
472
-     * Returns html.
473
-     *
474
-     * @return string
475
-     */
476
-    public function generateFooter() {
469
+	/**
470
+	 * Generates the page footer.
471
+	 *
472
+	 * Returns html.
473
+	 *
474
+	 * @return string
475
+	 */
476
+	public function generateFooter() {
477 477
 
478
-        $version = DAV\Version::VERSION;
479
-        return <<<HTML
478
+		$version = DAV\Version::VERSION;
479
+		return <<<HTML
480 480
 <footer>Generated by SabreDAV $version (c)2007-2015 <a href="http://sabre.io/">http://sabre.io/</a></footer>
481 481
 </body>
482 482
 </html>
483 483
 HTML;
484 484
 
485
-    }
486
-
487
-    /**
488
-     * This method is used to generate the 'actions panel' output for
489
-     * collections.
490
-     *
491
-     * This specifically generates the interfaces for creating new files, and
492
-     * creating new directories.
493
-     *
494
-     * @param DAV\INode $node
495
-     * @param mixed $output
496
-     * @return void
497
-     */
498
-    public function htmlActionsPanel(DAV\INode $node, &$output) {
499
-
500
-        if (!$node instanceof DAV\ICollection)
501
-            return;
502
-
503
-        // We also know fairly certain that if an object is a non-extended
504
-        // SimpleCollection, we won't need to show the panel either.
505
-        if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
506
-            return;
507
-
508
-        ob_start();
509
-        echo '<form method="post" action="">
485
+	}
486
+
487
+	/**
488
+	 * This method is used to generate the 'actions panel' output for
489
+	 * collections.
490
+	 *
491
+	 * This specifically generates the interfaces for creating new files, and
492
+	 * creating new directories.
493
+	 *
494
+	 * @param DAV\INode $node
495
+	 * @param mixed $output
496
+	 * @return void
497
+	 */
498
+	public function htmlActionsPanel(DAV\INode $node, &$output) {
499
+
500
+		if (!$node instanceof DAV\ICollection)
501
+			return;
502
+
503
+		// We also know fairly certain that if an object is a non-extended
504
+		// SimpleCollection, we won't need to show the panel either.
505
+		if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
506
+			return;
507
+
508
+		ob_start();
509
+		echo '<form method="post" action="">
510 510
         <h3>Create new folder</h3>
511 511
         <input type="hidden" name="sabreAction" value="mkcol" />
512 512
         <label>Name:</label> <input type="text" name="name" /><br />
@@ -521,277 +521,277 @@  discard block
 block discarded – undo
521 521
         </form>
522 522
         ';
523 523
 
524
-        $output .= ob_get_clean();
525
-
526
-    }
527
-
528
-    /**
529
-     * This method takes a path/name of an asset and turns it into url
530
-     * suiteable for http access.
531
-     *
532
-     * @param string $assetName
533
-     * @return string
534
-     */
535
-    protected function getAssetUrl($assetName) {
536
-
537
-        return $this->server->getBaseUri() . '?sabreAction=asset&assetName=' . urlencode($assetName);
538
-
539
-    }
540
-
541
-    /**
542
-     * This method returns a local pathname to an asset.
543
-     *
544
-     * @param string $assetName
545
-     * @return string
546
-     * @throws DAV\Exception\NotFound
547
-     */
548
-    protected function getLocalAssetPath($assetName) {
549
-
550
-        $assetDir = __DIR__ . '/assets/';
551
-        $path = $assetDir . $assetName;
552
-
553
-        // Making sure people aren't trying to escape from the base path.
554
-        $path = str_replace('\\', '/', $path);
555
-        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
556
-            throw new DAV\Exception\NotFound('Path does not exist, or escaping from the base path was detected');
557
-        }
558
-        if (strpos(realpath($path), realpath($assetDir)) === 0 && file_exists($path)) {
559
-            return $path;
560
-        }
561
-        throw new DAV\Exception\NotFound('Path does not exist, or escaping from the base path was detected');
562
-    }
563
-
564
-    /**
565
-     * This method reads an asset from disk and generates a full http response.
566
-     *
567
-     * @param string $assetName
568
-     * @return void
569
-     */
570
-    protected function serveAsset($assetName) {
571
-
572
-        $assetPath = $this->getLocalAssetPath($assetName);
573
-
574
-        // Rudimentary mime type detection
575
-        $mime = 'application/octet-stream';
576
-        $map = [
577
-            'ico'  => 'image/vnd.microsoft.icon',
578
-            'png'  => 'image/png',
579
-            'css'  => 'text/css',
580
-        ];
581
-
582
-        $ext = substr($assetName, strrpos($assetName, '.') + 1);
583
-        if (isset($map[$ext])) {
584
-            $mime = $map[$ext];
585
-        }
586
-
587
-        $this->server->httpResponse->setHeader('Content-Type', $mime);
588
-        $this->server->httpResponse->setHeader('Content-Length', filesize($assetPath));
589
-        $this->server->httpResponse->setHeader('Cache-Control', 'public, max-age=1209600');
590
-        $this->server->httpResponse->setStatus(200);
591
-        $this->server->httpResponse->setBody(fopen($assetPath, 'r'));
592
-
593
-    }
594
-
595
-    /**
596
-     * Sort helper function: compares two directory entries based on type and
597
-     * display name. Collections sort above other types.
598
-     *
599
-     * @param array $a
600
-     * @param array $b
601
-     * @return int
602
-     */
603
-    protected function compareNodes($a, $b) {
604
-
605
-        $typeA = (isset($a['{DAV:}resourcetype']))
606
-            ? (in_array('{DAV:}collection', $a['{DAV:}resourcetype']->getValue()))
607
-            : false;
608
-
609
-        $typeB = (isset($b['{DAV:}resourcetype']))
610
-            ? (in_array('{DAV:}collection', $b['{DAV:}resourcetype']->getValue()))
611
-            : false;
612
-
613
-        // If same type, sort alphabetically by filename:
614
-        if ($typeA === $typeB) {
615
-            return strnatcasecmp($a['displayPath'], $b['displayPath']);
616
-        }
617
-        return (($typeA < $typeB) ? 1 : -1);
618
-
619
-    }
620
-
621
-    /**
622
-     * Maps a resource type to a human-readable string and icon.
623
-     *
624
-     * @param array $resourceTypes
625
-     * @param INode $node
626
-     * @return array
627
-     */
628
-    private function mapResourceType(array $resourceTypes, $node) {
629
-
630
-        if (!$resourceTypes) {
631
-            if ($node instanceof DAV\IFile) {
632
-                return [
633
-                    'string' => 'File',
634
-                    'icon'   => 'file',
635
-                ];
636
-            } else {
637
-                return [
638
-                    'string' => 'Unknown',
639
-                    'icon'   => 'cog',
640
-                ];
641
-            }
642
-        }
643
-
644
-        $types = [
645
-            '{http://calendarserver.org/ns/}calendar-proxy-write' => [
646
-                'string' => 'Proxy-Write',
647
-                'icon'   => 'people',
648
-            ],
649
-            '{http://calendarserver.org/ns/}calendar-proxy-read' => [
650
-                'string' => 'Proxy-Read',
651
-                'icon'   => 'people',
652
-            ],
653
-            '{urn:ietf:params:xml:ns:caldav}schedule-outbox' => [
654
-                'string' => 'Outbox',
655
-                'icon'   => 'inbox',
656
-            ],
657
-            '{urn:ietf:params:xml:ns:caldav}schedule-inbox' => [
658
-                'string' => 'Inbox',
659
-                'icon'   => 'inbox',
660
-            ],
661
-            '{urn:ietf:params:xml:ns:caldav}calendar' => [
662
-                'string' => 'Calendar',
663
-                'icon'   => 'calendar',
664
-            ],
665
-            '{http://calendarserver.org/ns/}shared-owner' => [
666
-                'string' => 'Shared',
667
-                'icon'   => 'calendar',
668
-            ],
669
-            '{http://calendarserver.org/ns/}subscribed' => [
670
-                'string' => 'Subscription',
671
-                'icon'   => 'calendar',
672
-            ],
673
-            '{urn:ietf:params:xml:ns:carddav}directory' => [
674
-                'string' => 'Directory',
675
-                'icon'   => 'globe',
676
-            ],
677
-            '{urn:ietf:params:xml:ns:carddav}addressbook' => [
678
-                'string' => 'Address book',
679
-                'icon'   => 'book',
680
-            ],
681
-            '{DAV:}principal' => [
682
-                'string' => 'Principal',
683
-                'icon'   => 'person',
684
-            ],
685
-            '{DAV:}collection' => [
686
-                'string' => 'Collection',
687
-                'icon'   => 'folder',
688
-            ],
689
-        ];
690
-
691
-        $info = [
692
-            'string' => [],
693
-            'icon'   => 'cog',
694
-        ];
695
-        foreach ($resourceTypes as $k => $resourceType) {
696
-            if (isset($types[$resourceType])) {
697
-                $info['string'][] = $types[$resourceType]['string'];
698
-            } else {
699
-                $info['string'][] = $resourceType;
700
-            }
701
-        }
702
-        foreach ($types as $key => $resourceInfo) {
703
-            if (in_array($key, $resourceTypes)) {
704
-                $info['icon'] = $resourceInfo['icon'];
705
-                break;
706
-            }
707
-        }
708
-        $info['string'] = implode(', ', $info['string']);
709
-
710
-        return $info;
711
-
712
-    }
713
-
714
-    /**
715
-     * Draws a table row for a property
716
-     *
717
-     * @param string $name
718
-     * @param mixed $value
719
-     * @return string
720
-     */
721
-    private function drawPropertyRow($name, $value) {
722
-
723
-        $html = new HtmlOutputHelper(
724
-            $this->server->getBaseUri(),
725
-            $this->server->xml->namespaceMap
726
-        );
727
-
728
-        return "<tr><th>" . $html->xmlName($name) . "</th><td>" . $this->drawPropertyValue($html, $value) . "</td></tr>";
729
-
730
-    }
731
-
732
-    /**
733
-     * Draws a table row for a property
734
-     *
735
-     * @param HtmlOutputHelper $html
736
-     * @param mixed $value
737
-     * @return string
738
-     */
739
-    private function drawPropertyValue($html, $value) {
740
-
741
-        if (is_scalar($value)) {
742
-            return $html->h($value);
743
-        } elseif ($value instanceof HtmlOutput) {
744
-            return $value->toHtml($html);
745
-        } elseif ($value instanceof \Sabre\Xml\XmlSerializable) {
746
-
747
-            // There's no default html output for this property, we're going
748
-            // to output the actual xml serialization instead.
749
-            $xml = $this->server->xml->write('{DAV:}root', $value, $this->server->getBaseUri());
750
-            // removing first and last line, as they contain our root
751
-            // element.
752
-            $xml = explode("\n", $xml);
753
-            $xml = array_slice($xml, 2, -2);
754
-            return "<pre>" . $html->h(implode("\n", $xml)) . "</pre>";
755
-
756
-        } else {
757
-            return "<em>unknown</em>";
758
-        }
759
-
760
-    }
761
-
762
-    /**
763
-     * Returns a plugin name.
764
-     *
765
-     * Using this name other plugins will be able to access other plugins;
766
-     * using \Sabre\DAV\Server::getPlugin
767
-     *
768
-     * @return string
769
-     */
770
-    public function getPluginName() {
771
-
772
-        return 'browser';
773
-
774
-    }
775
-
776
-    /**
777
-     * Returns a bunch of meta-data about the plugin.
778
-     *
779
-     * Providing this information is optional, and is mainly displayed by the
780
-     * Browser plugin.
781
-     *
782
-     * The description key in the returned array may contain html and will not
783
-     * be sanitized.
784
-     *
785
-     * @return array
786
-     */
787
-    public function getPluginInfo() {
788
-
789
-        return [
790
-            'name'        => $this->getPluginName(),
791
-            'description' => 'Generates HTML indexes and debug information for your sabre/dav server',
792
-            'link'        => 'http://sabre.io/dav/browser-plugin/',
793
-        ];
794
-
795
-    }
524
+		$output .= ob_get_clean();
525
+
526
+	}
527
+
528
+	/**
529
+	 * This method takes a path/name of an asset and turns it into url
530
+	 * suiteable for http access.
531
+	 *
532
+	 * @param string $assetName
533
+	 * @return string
534
+	 */
535
+	protected function getAssetUrl($assetName) {
536
+
537
+		return $this->server->getBaseUri() . '?sabreAction=asset&assetName=' . urlencode($assetName);
538
+
539
+	}
540
+
541
+	/**
542
+	 * This method returns a local pathname to an asset.
543
+	 *
544
+	 * @param string $assetName
545
+	 * @return string
546
+	 * @throws DAV\Exception\NotFound
547
+	 */
548
+	protected function getLocalAssetPath($assetName) {
549
+
550
+		$assetDir = __DIR__ . '/assets/';
551
+		$path = $assetDir . $assetName;
552
+
553
+		// Making sure people aren't trying to escape from the base path.
554
+		$path = str_replace('\\', '/', $path);
555
+		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
556
+			throw new DAV\Exception\NotFound('Path does not exist, or escaping from the base path was detected');
557
+		}
558
+		if (strpos(realpath($path), realpath($assetDir)) === 0 && file_exists($path)) {
559
+			return $path;
560
+		}
561
+		throw new DAV\Exception\NotFound('Path does not exist, or escaping from the base path was detected');
562
+	}
563
+
564
+	/**
565
+	 * This method reads an asset from disk and generates a full http response.
566
+	 *
567
+	 * @param string $assetName
568
+	 * @return void
569
+	 */
570
+	protected function serveAsset($assetName) {
571
+
572
+		$assetPath = $this->getLocalAssetPath($assetName);
573
+
574
+		// Rudimentary mime type detection
575
+		$mime = 'application/octet-stream';
576
+		$map = [
577
+			'ico'  => 'image/vnd.microsoft.icon',
578
+			'png'  => 'image/png',
579
+			'css'  => 'text/css',
580
+		];
581
+
582
+		$ext = substr($assetName, strrpos($assetName, '.') + 1);
583
+		if (isset($map[$ext])) {
584
+			$mime = $map[$ext];
585
+		}
586
+
587
+		$this->server->httpResponse->setHeader('Content-Type', $mime);
588
+		$this->server->httpResponse->setHeader('Content-Length', filesize($assetPath));
589
+		$this->server->httpResponse->setHeader('Cache-Control', 'public, max-age=1209600');
590
+		$this->server->httpResponse->setStatus(200);
591
+		$this->server->httpResponse->setBody(fopen($assetPath, 'r'));
592
+
593
+	}
594
+
595
+	/**
596
+	 * Sort helper function: compares two directory entries based on type and
597
+	 * display name. Collections sort above other types.
598
+	 *
599
+	 * @param array $a
600
+	 * @param array $b
601
+	 * @return int
602
+	 */
603
+	protected function compareNodes($a, $b) {
604
+
605
+		$typeA = (isset($a['{DAV:}resourcetype']))
606
+			? (in_array('{DAV:}collection', $a['{DAV:}resourcetype']->getValue()))
607
+			: false;
608
+
609
+		$typeB = (isset($b['{DAV:}resourcetype']))
610
+			? (in_array('{DAV:}collection', $b['{DAV:}resourcetype']->getValue()))
611
+			: false;
612
+
613
+		// If same type, sort alphabetically by filename:
614
+		if ($typeA === $typeB) {
615
+			return strnatcasecmp($a['displayPath'], $b['displayPath']);
616
+		}
617
+		return (($typeA < $typeB) ? 1 : -1);
618
+
619
+	}
620
+
621
+	/**
622
+	 * Maps a resource type to a human-readable string and icon.
623
+	 *
624
+	 * @param array $resourceTypes
625
+	 * @param INode $node
626
+	 * @return array
627
+	 */
628
+	private function mapResourceType(array $resourceTypes, $node) {
629
+
630
+		if (!$resourceTypes) {
631
+			if ($node instanceof DAV\IFile) {
632
+				return [
633
+					'string' => 'File',
634
+					'icon'   => 'file',
635
+				];
636
+			} else {
637
+				return [
638
+					'string' => 'Unknown',
639
+					'icon'   => 'cog',
640
+				];
641
+			}
642
+		}
643
+
644
+		$types = [
645
+			'{http://calendarserver.org/ns/}calendar-proxy-write' => [
646
+				'string' => 'Proxy-Write',
647
+				'icon'   => 'people',
648
+			],
649
+			'{http://calendarserver.org/ns/}calendar-proxy-read' => [
650
+				'string' => 'Proxy-Read',
651
+				'icon'   => 'people',
652
+			],
653
+			'{urn:ietf:params:xml:ns:caldav}schedule-outbox' => [
654
+				'string' => 'Outbox',
655
+				'icon'   => 'inbox',
656
+			],
657
+			'{urn:ietf:params:xml:ns:caldav}schedule-inbox' => [
658
+				'string' => 'Inbox',
659
+				'icon'   => 'inbox',
660
+			],
661
+			'{urn:ietf:params:xml:ns:caldav}calendar' => [
662
+				'string' => 'Calendar',
663
+				'icon'   => 'calendar',
664
+			],
665
+			'{http://calendarserver.org/ns/}shared-owner' => [
666
+				'string' => 'Shared',
667
+				'icon'   => 'calendar',
668
+			],
669
+			'{http://calendarserver.org/ns/}subscribed' => [
670
+				'string' => 'Subscription',
671
+				'icon'   => 'calendar',
672
+			],
673
+			'{urn:ietf:params:xml:ns:carddav}directory' => [
674
+				'string' => 'Directory',
675
+				'icon'   => 'globe',
676
+			],
677
+			'{urn:ietf:params:xml:ns:carddav}addressbook' => [
678
+				'string' => 'Address book',
679
+				'icon'   => 'book',
680
+			],
681
+			'{DAV:}principal' => [
682
+				'string' => 'Principal',
683
+				'icon'   => 'person',
684
+			],
685
+			'{DAV:}collection' => [
686
+				'string' => 'Collection',
687
+				'icon'   => 'folder',
688
+			],
689
+		];
690
+
691
+		$info = [
692
+			'string' => [],
693
+			'icon'   => 'cog',
694
+		];
695
+		foreach ($resourceTypes as $k => $resourceType) {
696
+			if (isset($types[$resourceType])) {
697
+				$info['string'][] = $types[$resourceType]['string'];
698
+			} else {
699
+				$info['string'][] = $resourceType;
700
+			}
701
+		}
702
+		foreach ($types as $key => $resourceInfo) {
703
+			if (in_array($key, $resourceTypes)) {
704
+				$info['icon'] = $resourceInfo['icon'];
705
+				break;
706
+			}
707
+		}
708
+		$info['string'] = implode(', ', $info['string']);
709
+
710
+		return $info;
711
+
712
+	}
713
+
714
+	/**
715
+	 * Draws a table row for a property
716
+	 *
717
+	 * @param string $name
718
+	 * @param mixed $value
719
+	 * @return string
720
+	 */
721
+	private function drawPropertyRow($name, $value) {
722
+
723
+		$html = new HtmlOutputHelper(
724
+			$this->server->getBaseUri(),
725
+			$this->server->xml->namespaceMap
726
+		);
727
+
728
+		return "<tr><th>" . $html->xmlName($name) . "</th><td>" . $this->drawPropertyValue($html, $value) . "</td></tr>";
729
+
730
+	}
731
+
732
+	/**
733
+	 * Draws a table row for a property
734
+	 *
735
+	 * @param HtmlOutputHelper $html
736
+	 * @param mixed $value
737
+	 * @return string
738
+	 */
739
+	private function drawPropertyValue($html, $value) {
740
+
741
+		if (is_scalar($value)) {
742
+			return $html->h($value);
743
+		} elseif ($value instanceof HtmlOutput) {
744
+			return $value->toHtml($html);
745
+		} elseif ($value instanceof \Sabre\Xml\XmlSerializable) {
746
+
747
+			// There's no default html output for this property, we're going
748
+			// to output the actual xml serialization instead.
749
+			$xml = $this->server->xml->write('{DAV:}root', $value, $this->server->getBaseUri());
750
+			// removing first and last line, as they contain our root
751
+			// element.
752
+			$xml = explode("\n", $xml);
753
+			$xml = array_slice($xml, 2, -2);
754
+			return "<pre>" . $html->h(implode("\n", $xml)) . "</pre>";
755
+
756
+		} else {
757
+			return "<em>unknown</em>";
758
+		}
759
+
760
+	}
761
+
762
+	/**
763
+	 * Returns a plugin name.
764
+	 *
765
+	 * Using this name other plugins will be able to access other plugins;
766
+	 * using \Sabre\DAV\Server::getPlugin
767
+	 *
768
+	 * @return string
769
+	 */
770
+	public function getPluginName() {
771
+
772
+		return 'browser';
773
+
774
+	}
775
+
776
+	/**
777
+	 * Returns a bunch of meta-data about the plugin.
778
+	 *
779
+	 * Providing this information is optional, and is mainly displayed by the
780
+	 * Browser plugin.
781
+	 *
782
+	 * The description key in the returned array may contain html and will not
783
+	 * be sanitized.
784
+	 *
785
+	 * @return array
786
+	 */
787
+	public function getPluginInfo() {
788
+
789
+		return [
790
+			'name'        => $this->getPluginName(),
791
+			'description' => 'Generates HTML indexes and debug information for your sabre/dav server',
792
+			'link'        => 'http://sabre.io/dav/browser-plugin/',
793
+		];
794
+
795
+	}
796 796
 
797 797
 }
Please login to merge, or discard this patch.
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
      *
88 88
      * @param RequestInterface $request
89 89
      * @param ResponseInterface $response
90
-     * @return bool
90
+     * @return boolean|null
91 91
      */
92 92
     public function httpGetEarly(RequestInterface $request, ResponseInterface $response) {
93 93
 
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
      *
161 161
      * @param RequestInterface $request
162 162
      * @param ResponseInterface $response
163
-     * @return bool
163
+     * @return null|false
164 164
      */
165 165
     public function httpPOST(RequestInterface $request, ResponseInterface $response) {
166 166
 
@@ -414,7 +414,7 @@  discard block
 block discarded – undo
414 414
      *
415 415
      * @param string $title
416 416
      * @param string $path
417
-     * @return void
417
+     * @return string
418 418
      */
419 419
     public function generateHeader($title, $path = null) {
420 420
 
Please login to merge, or discard this patch.
Braces   +20 added lines, -11 removed lines patch added patch discarded remove patch
@@ -78,7 +78,9 @@  discard block
 block discarded – undo
78 78
         $this->server->on('method:GET', [$this, 'httpGetEarly'], 90);
79 79
         $this->server->on('method:GET', [$this, 'httpGet'], 200);
80 80
         $this->server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel'], 200);
81
-        if ($this->enablePost) $this->server->on('method:POST', [$this, 'httpPOST']);
81
+        if ($this->enablePost) {
82
+        	$this->server->on('method:POST', [$this, 'httpPOST']);
83
+        }
82 84
     }
83 85
 
84 86
     /**
@@ -172,8 +174,9 @@  discard block
 block discarded – undo
172 174
         }
173 175
         $postVars = $request->getPostData();
174 176
 
175
-        if (!isset($postVars['sabreAction']))
176
-            return;
177
+        if (!isset($postVars['sabreAction'])) {
178
+                    return;
179
+        }
177 180
 
178 181
         $uri = $request->getPath();
179 182
 
@@ -219,12 +222,16 @@  discard block
 block discarded – undo
219 222
                 // @codeCoverageIgnoreStart
220 223
                 case 'put' :
221 224
 
222
-                    if ($_FILES) $file = current($_FILES);
223
-                    else break;
225
+                    if ($_FILES) {
226
+                    	$file = current($_FILES);
227
+                    } else {
228
+                    	break;
229
+                    }
224 230
 
225 231
                     list(, $newName) = URLUtil::splitPath(trim($file['name']));
226
-                    if (isset($postVars['name']) && trim($postVars['name']))
227
-                        $newName = trim($postVars['name']);
232
+                    if (isset($postVars['name']) && trim($postVars['name'])) {
233
+                                            $newName = trim($postVars['name']);
234
+                    }
228 235
 
229 236
                     // Making sure we only have a 'basename' component
230 237
                     list(, $newName) = URLUtil::splitPath($newName);
@@ -497,13 +504,15 @@  discard block
 block discarded – undo
497 504
      */
498 505
     public function htmlActionsPanel(DAV\INode $node, &$output) {
499 506
 
500
-        if (!$node instanceof DAV\ICollection)
501
-            return;
507
+        if (!$node instanceof DAV\ICollection) {
508
+                    return;
509
+        }
502 510
 
503 511
         // We also know fairly certain that if an object is a non-extended
504 512
         // SimpleCollection, we won't need to show the panel either.
505
-        if (get_class($node) === 'Sabre\\DAV\\SimpleCollection')
506
-            return;
513
+        if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') {
514
+                    return;
515
+        }
507 516
 
508 517
         ob_start();
509 518
         echo '<form method="post" action="">
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/Exception/InvalidResourceType.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -19,7 +19,7 @@
 block discarded – undo
19 19
     /**
20 20
      * This method allows the exception to include additional information into the WebDAV error response
21 21
      *
22
-     * @param DAV\Server $server
22
+     * @param \Sabre\DAV\Server $server
23 23
      * @param \DOMElement $errorNode
24 24
      * @return void
25 25
      */
Please login to merge, or discard this patch.
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -16,18 +16,18 @@
 block discarded – undo
16 16
  */
17 17
 class InvalidResourceType extends Forbidden {
18 18
 
19
-    /**
20
-     * This method allows the exception to include additional information into the WebDAV error response
21
-     *
22
-     * @param DAV\Server $server
23
-     * @param \DOMElement $errorNode
24
-     * @return void
25
-     */
26
-    public function serialize(\Sabre\DAV\Server $server, \DOMElement $errorNode) {
19
+	/**
20
+	 * This method allows the exception to include additional information into the WebDAV error response
21
+	 *
22
+	 * @param DAV\Server $server
23
+	 * @param \DOMElement $errorNode
24
+	 * @return void
25
+	 */
26
+	public function serialize(\Sabre\DAV\Server $server, \DOMElement $errorNode) {
27 27
 
28
-        $error = $errorNode->ownerDocument->createElementNS('DAV:', 'd:valid-resourcetype');
29
-        $errorNode->appendChild($error);
28
+		$error = $errorNode->ownerDocument->createElementNS('DAV:', 'd:valid-resourcetype');
29
+		$errorNode->appendChild($error);
30 30
 
31
-    }
31
+	}
32 32
 
33 33
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/PropertyStorage/Plugin.php 4 patches
Unused Use Statements   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -2,11 +2,11 @@
 block discarded – undo
2 2
 
3 3
 namespace Sabre\DAV\PropertyStorage;
4 4
 
5
+use Sabre\DAV\INode;
6
+use Sabre\DAV\PropFind;
7
+use Sabre\DAV\PropPatch;
5 8
 use Sabre\DAV\Server;
6 9
 use Sabre\DAV\ServerPlugin;
7
-use Sabre\DAV\PropPatch;
8
-use Sabre\DAV\PropFind;
9
-use Sabre\DAV\INode;
10 10
 
11 11
 /**
12 12
  * PropertyStorage Plugin.
Please login to merge, or discard this patch.
Indentation   +152 added lines, -152 removed lines patch added patch discarded remove patch
@@ -25,156 +25,156 @@
 block discarded – undo
25 25
  */
26 26
 class Plugin extends ServerPlugin {
27 27
 
28
-    /**
29
-     * If you only want this plugin to store properties for a limited set of
30
-     * paths, you can use a pathFilter to do this.
31
-     *
32
-     * The pathFilter should be a callable. The callable retrieves a path as
33
-     * its argument, and should return true or false wether it allows
34
-     * properties to be stored.
35
-     *
36
-     * @var callable
37
-     */
38
-    public $pathFilter;
39
-
40
-    /**
41
-     * Creates the plugin
42
-     *
43
-     * @param Backend\BackendInterface $backend
44
-     */
45
-    public function __construct(Backend\BackendInterface $backend) {
46
-
47
-        $this->backend = $backend;
48
-
49
-    }
50
-
51
-    /**
52
-     * This initializes the plugin.
53
-     *
54
-     * This function is called by Sabre\DAV\Server, after
55
-     * addPlugin is called.
56
-     *
57
-     * This method should set up the required event subscriptions.
58
-     *
59
-     * @param Server $server
60
-     * @return void
61
-     */
62
-    public function initialize(Server $server) {
63
-
64
-        $server->on('propFind',    [$this, 'propFind'], 130);
65
-        $server->on('propPatch',   [$this, 'propPatch'], 300);
66
-        $server->on('afterMove',   [$this, 'afterMove']);
67
-        $server->on('afterUnbind', [$this, 'afterUnbind']);
68
-
69
-    }
70
-
71
-    /**
72
-     * Called during PROPFIND operations.
73
-     *
74
-     * If there's any requested properties that don't have a value yet, this
75
-     * plugin will look in the property storage backend to find them.
76
-     *
77
-     * @param PropFind $propFind
78
-     * @param INode $node
79
-     * @return void
80
-     */
81
-    public function propFind(PropFind $propFind, INode $node) {
82
-
83
-        $path = $propFind->getPath();
84
-        $pathFilter = $this->pathFilter;
85
-        if ($pathFilter && !$pathFilter($path)) return;
86
-        $this->backend->propFind($propFind->getPath(), $propFind);
87
-
88
-    }
89
-
90
-    /**
91
-     * Called during PROPPATCH operations
92
-     *
93
-     * If there's any updated properties that haven't been stored, the
94
-     * propertystorage backend can handle it.
95
-     *
96
-     * @param string $path
97
-     * @param PropPatch $propPatch
98
-     * @return void
99
-     */
100
-    public function propPatch($path, PropPatch $propPatch) {
101
-
102
-        $pathFilter = $this->pathFilter;
103
-        if ($pathFilter && !$pathFilter($path)) return;
104
-        $this->backend->propPatch($path, $propPatch);
105
-
106
-    }
107
-
108
-    /**
109
-     * Called after a node is deleted.
110
-     *
111
-     * This allows the backend to clean up any properties still in the
112
-     * database.
113
-     *
114
-     * @param string $path
115
-     * @return void
116
-     */
117
-    public function afterUnbind($path) {
118
-
119
-        $pathFilter = $this->pathFilter;
120
-        if ($pathFilter && !$pathFilter($path)) return;
121
-        $this->backend->delete($path);
122
-
123
-    }
124
-
125
-    /**
126
-     * Called after a node is moved.
127
-     *
128
-     * This allows the backend to move all the associated properties.
129
-     *
130
-     * @param string $source
131
-     * @param string $destination
132
-     * @return void
133
-     */
134
-    public function afterMove($source, $destination) {
135
-
136
-        $pathFilter = $this->pathFilter;
137
-        if ($pathFilter && !$pathFilter($source)) return;
138
-        // If the destination is filtered, afterUnbind will handle cleaning up
139
-        // the properties.
140
-        if ($pathFilter && !$pathFilter($destination)) return;
141
-
142
-        $this->backend->move($source, $destination);
143
-
144
-    }
145
-
146
-    /**
147
-     * Returns a plugin name.
148
-     *
149
-     * Using this name other plugins will be able to access other plugins
150
-     * using \Sabre\DAV\Server::getPlugin
151
-     *
152
-     * @return string
153
-     */
154
-    public function getPluginName() {
155
-
156
-        return 'property-storage';
157
-
158
-    }
159
-
160
-    /**
161
-     * Returns a bunch of meta-data about the plugin.
162
-     *
163
-     * Providing this information is optional, and is mainly displayed by the
164
-     * Browser plugin.
165
-     *
166
-     * The description key in the returned array may contain html and will not
167
-     * be sanitized.
168
-     *
169
-     * @return array
170
-     */
171
-    public function getPluginInfo() {
172
-
173
-        return [
174
-            'name'        => $this->getPluginName(),
175
-            'description' => 'This plugin allows any arbitrary WebDAV property to be set on any resource.',
176
-            'link'        => 'http://sabre.io/dav/property-storage/',
177
-        ];
178
-
179
-    }
28
+	/**
29
+	 * If you only want this plugin to store properties for a limited set of
30
+	 * paths, you can use a pathFilter to do this.
31
+	 *
32
+	 * The pathFilter should be a callable. The callable retrieves a path as
33
+	 * its argument, and should return true or false wether it allows
34
+	 * properties to be stored.
35
+	 *
36
+	 * @var callable
37
+	 */
38
+	public $pathFilter;
39
+
40
+	/**
41
+	 * Creates the plugin
42
+	 *
43
+	 * @param Backend\BackendInterface $backend
44
+	 */
45
+	public function __construct(Backend\BackendInterface $backend) {
46
+
47
+		$this->backend = $backend;
48
+
49
+	}
50
+
51
+	/**
52
+	 * This initializes the plugin.
53
+	 *
54
+	 * This function is called by Sabre\DAV\Server, after
55
+	 * addPlugin is called.
56
+	 *
57
+	 * This method should set up the required event subscriptions.
58
+	 *
59
+	 * @param Server $server
60
+	 * @return void
61
+	 */
62
+	public function initialize(Server $server) {
63
+
64
+		$server->on('propFind',    [$this, 'propFind'], 130);
65
+		$server->on('propPatch',   [$this, 'propPatch'], 300);
66
+		$server->on('afterMove',   [$this, 'afterMove']);
67
+		$server->on('afterUnbind', [$this, 'afterUnbind']);
68
+
69
+	}
70
+
71
+	/**
72
+	 * Called during PROPFIND operations.
73
+	 *
74
+	 * If there's any requested properties that don't have a value yet, this
75
+	 * plugin will look in the property storage backend to find them.
76
+	 *
77
+	 * @param PropFind $propFind
78
+	 * @param INode $node
79
+	 * @return void
80
+	 */
81
+	public function propFind(PropFind $propFind, INode $node) {
82
+
83
+		$path = $propFind->getPath();
84
+		$pathFilter = $this->pathFilter;
85
+		if ($pathFilter && !$pathFilter($path)) return;
86
+		$this->backend->propFind($propFind->getPath(), $propFind);
87
+
88
+	}
89
+
90
+	/**
91
+	 * Called during PROPPATCH operations
92
+	 *
93
+	 * If there's any updated properties that haven't been stored, the
94
+	 * propertystorage backend can handle it.
95
+	 *
96
+	 * @param string $path
97
+	 * @param PropPatch $propPatch
98
+	 * @return void
99
+	 */
100
+	public function propPatch($path, PropPatch $propPatch) {
101
+
102
+		$pathFilter = $this->pathFilter;
103
+		if ($pathFilter && !$pathFilter($path)) return;
104
+		$this->backend->propPatch($path, $propPatch);
105
+
106
+	}
107
+
108
+	/**
109
+	 * Called after a node is deleted.
110
+	 *
111
+	 * This allows the backend to clean up any properties still in the
112
+	 * database.
113
+	 *
114
+	 * @param string $path
115
+	 * @return void
116
+	 */
117
+	public function afterUnbind($path) {
118
+
119
+		$pathFilter = $this->pathFilter;
120
+		if ($pathFilter && !$pathFilter($path)) return;
121
+		$this->backend->delete($path);
122
+
123
+	}
124
+
125
+	/**
126
+	 * Called after a node is moved.
127
+	 *
128
+	 * This allows the backend to move all the associated properties.
129
+	 *
130
+	 * @param string $source
131
+	 * @param string $destination
132
+	 * @return void
133
+	 */
134
+	public function afterMove($source, $destination) {
135
+
136
+		$pathFilter = $this->pathFilter;
137
+		if ($pathFilter && !$pathFilter($source)) return;
138
+		// If the destination is filtered, afterUnbind will handle cleaning up
139
+		// the properties.
140
+		if ($pathFilter && !$pathFilter($destination)) return;
141
+
142
+		$this->backend->move($source, $destination);
143
+
144
+	}
145
+
146
+	/**
147
+	 * Returns a plugin name.
148
+	 *
149
+	 * Using this name other plugins will be able to access other plugins
150
+	 * using \Sabre\DAV\Server::getPlugin
151
+	 *
152
+	 * @return string
153
+	 */
154
+	public function getPluginName() {
155
+
156
+		return 'property-storage';
157
+
158
+	}
159
+
160
+	/**
161
+	 * Returns a bunch of meta-data about the plugin.
162
+	 *
163
+	 * Providing this information is optional, and is mainly displayed by the
164
+	 * Browser plugin.
165
+	 *
166
+	 * The description key in the returned array may contain html and will not
167
+	 * be sanitized.
168
+	 *
169
+	 * @return array
170
+	 */
171
+	public function getPluginInfo() {
172
+
173
+		return [
174
+			'name'        => $this->getPluginName(),
175
+			'description' => 'This plugin allows any arbitrary WebDAV property to be set on any resource.',
176
+			'link'        => 'http://sabre.io/dav/property-storage/',
177
+		];
178
+
179
+	}
180 180
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -61,9 +61,9 @@
 block discarded – undo
61 61
      */
62 62
     public function initialize(Server $server) {
63 63
 
64
-        $server->on('propFind',    [$this, 'propFind'], 130);
65
-        $server->on('propPatch',   [$this, 'propPatch'], 300);
66
-        $server->on('afterMove',   [$this, 'afterMove']);
64
+        $server->on('propFind', [$this, 'propFind'], 130);
65
+        $server->on('propPatch', [$this, 'propPatch'], 300);
66
+        $server->on('afterMove', [$this, 'afterMove']);
67 67
         $server->on('afterUnbind', [$this, 'afterUnbind']);
68 68
 
69 69
     }
Please login to merge, or discard this patch.
Braces   +15 added lines, -5 removed lines patch added patch discarded remove patch
@@ -82,7 +82,9 @@  discard block
 block discarded – undo
82 82
 
83 83
         $path = $propFind->getPath();
84 84
         $pathFilter = $this->pathFilter;
85
-        if ($pathFilter && !$pathFilter($path)) return;
85
+        if ($pathFilter && !$pathFilter($path)) {
86
+        	return;
87
+        }
86 88
         $this->backend->propFind($propFind->getPath(), $propFind);
87 89
 
88 90
     }
@@ -100,7 +102,9 @@  discard block
 block discarded – undo
100 102
     public function propPatch($path, PropPatch $propPatch) {
101 103
 
102 104
         $pathFilter = $this->pathFilter;
103
-        if ($pathFilter && !$pathFilter($path)) return;
105
+        if ($pathFilter && !$pathFilter($path)) {
106
+        	return;
107
+        }
104 108
         $this->backend->propPatch($path, $propPatch);
105 109
 
106 110
     }
@@ -117,7 +121,9 @@  discard block
 block discarded – undo
117 121
     public function afterUnbind($path) {
118 122
 
119 123
         $pathFilter = $this->pathFilter;
120
-        if ($pathFilter && !$pathFilter($path)) return;
124
+        if ($pathFilter && !$pathFilter($path)) {
125
+        	return;
126
+        }
121 127
         $this->backend->delete($path);
122 128
 
123 129
     }
@@ -134,10 +140,14 @@  discard block
 block discarded – undo
134 140
     public function afterMove($source, $destination) {
135 141
 
136 142
         $pathFilter = $this->pathFilter;
137
-        if ($pathFilter && !$pathFilter($source)) return;
143
+        if ($pathFilter && !$pathFilter($source)) {
144
+        	return;
145
+        }
138 146
         // If the destination is filtered, afterUnbind will handle cleaning up
139 147
         // the properties.
140
-        if ($pathFilter && !$pathFilter($destination)) return;
148
+        if ($pathFilter && !$pathFilter($destination)) {
149
+        	return;
150
+        }
141 151
 
142 152
         $this->backend->move($source, $destination);
143 153
 
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/PropPatch.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -143,7 +143,7 @@
 block discarded – undo
143 143
     /**
144 144
      * Sets the result code for one or more properties.
145 145
      *
146
-     * @param string|string[] $properties
146
+     * @param string[] $properties
147 147
      * @param int $resultCode
148 148
      * @return void
149 149
      */
Please login to merge, or discard this patch.
Indentation   +350 added lines, -350 removed lines patch added patch discarded remove patch
@@ -19,355 +19,355 @@
 block discarded – undo
19 19
  */
20 20
 class PropPatch {
21 21
 
22
-    /**
23
-     * Properties that are being updated.
24
-     *
25
-     * This is a key-value list. If the value is null, the property is supposed
26
-     * to be deleted.
27
-     *
28
-     * @var array
29
-     */
30
-    protected $mutations;
31
-
32
-    /**
33
-     * A list of properties and the result of the update. The result is in the
34
-     * form of a HTTP status code.
35
-     *
36
-     * @var array
37
-     */
38
-    protected $result = [];
39
-
40
-    /**
41
-     * This is the list of callbacks when we're performing the actual update.
42
-     *
43
-     * @var array
44
-     */
45
-    protected $propertyUpdateCallbacks = [];
46
-
47
-    /**
48
-     * This property will be set to true if the operation failed.
49
-     *
50
-     * @var bool
51
-     */
52
-    protected $failed = false;
53
-
54
-    /**
55
-     * Constructor
56
-     *
57
-     * @param array $mutations A list of updates
58
-     */
59
-    public function __construct(array $mutations) {
60
-
61
-        $this->mutations = $mutations;
62
-
63
-    }
64
-
65
-    /**
66
-     * Call this function if you wish to handle updating certain properties.
67
-     * For instance, your class may be responsible for handling updates for the
68
-     * {DAV:}displayname property.
69
-     *
70
-     * In that case, call this method with the first argument
71
-     * "{DAV:}displayname" and a second argument that's a method that does the
72
-     * actual updating.
73
-     *
74
-     * It's possible to specify more than one property as an array.
75
-     *
76
-     * The callback must return a boolean or an it. If the result is true, the
77
-     * operation was considered successful. If it's false, it's consided
78
-     * failed.
79
-     *
80
-     * If the result is an integer, we'll use that integer as the http status
81
-     * code associated with the operation.
82
-     *
83
-     * @param string|string[] $properties
84
-     * @param callable $callback
85
-     * @return void
86
-     */
87
-    public function handle($properties, callable $callback) {
88
-
89
-        $usedProperties = [];
90
-        foreach ((array)$properties as $propertyName) {
91
-
92
-            if (array_key_exists($propertyName, $this->mutations) && !isset($this->result[$propertyName])) {
93
-
94
-                $usedProperties[] = $propertyName;
95
-                // HTTP Accepted
96
-                $this->result[$propertyName] = 202;
97
-            }
98
-
99
-        }
100
-
101
-        // Only registering if there's any unhandled properties.
102
-        if (!$usedProperties) {
103
-            return;
104
-        }
105
-        $this->propertyUpdateCallbacks[] = [
106
-            // If the original argument to this method was a string, we need
107
-            // to also make sure that it stays that way, so the commit function
108
-            // knows how to format the arguments to the callback.
109
-            is_string($properties) ? $properties : $usedProperties,
110
-            $callback
111
-        ];
112
-
113
-    }
114
-
115
-    /**
116
-     * Call this function if you wish to handle _all_ properties that haven't
117
-     * been handled by anything else yet. Note that you effectively claim with
118
-     * this that you promise to process _all_ properties that are coming in.
119
-     *
120
-     * @param callable $callback
121
-     * @return void
122
-     */
123
-    public function handleRemaining(callable $callback) {
124
-
125
-        $properties = $this->getRemainingMutations();
126
-        if (!$properties) {
127
-            // Nothing to do, don't register callback
128
-            return;
129
-        }
130
-
131
-        foreach ($properties as $propertyName) {
132
-            // HTTP Accepted
133
-            $this->result[$propertyName] = 202;
134
-
135
-            $this->propertyUpdateCallbacks[] = [
136
-                $properties,
137
-                $callback
138
-            ];
139
-        }
140
-
141
-    }
142
-
143
-    /**
144
-     * Sets the result code for one or more properties.
145
-     *
146
-     * @param string|string[] $properties
147
-     * @param int $resultCode
148
-     * @return void
149
-     */
150
-    public function setResultCode($properties, $resultCode) {
151
-
152
-        foreach ((array)$properties as $propertyName) {
153
-            $this->result[$propertyName] = $resultCode;
154
-        }
155
-
156
-        if ($resultCode >= 400) {
157
-            $this->failed = true;
158
-        }
159
-
160
-    }
161
-
162
-    /**
163
-     * Sets the result code for all properties that did not have a result yet.
164
-     *
165
-     * @param int $resultCode
166
-     * @return void
167
-     */
168
-    public function setRemainingResultCode($resultCode) {
169
-
170
-        $this->setResultCode(
171
-            $this->getRemainingMutations(),
172
-            $resultCode
173
-        );
174
-
175
-    }
176
-
177
-    /**
178
-     * Returns the list of properties that don't have a result code yet.
179
-     *
180
-     * This method returns a list of property names, but not its values.
181
-     *
182
-     * @return string[]
183
-     */
184
-    public function getRemainingMutations() {
185
-
186
-        $remaining = [];
187
-        foreach ($this->mutations as $propertyName => $propValue) {
188
-            if (!isset($this->result[$propertyName])) {
189
-                $remaining[] = $propertyName;
190
-            }
191
-        }
192
-
193
-        return $remaining;
194
-
195
-    }
196
-
197
-    /**
198
-     * Returns the list of properties that don't have a result code yet.
199
-     *
200
-     * This method returns list of properties and their values.
201
-     *
202
-     * @return array
203
-     */
204
-    public function getRemainingValues() {
205
-
206
-        $remaining = [];
207
-        foreach ($this->mutations as $propertyName => $propValue) {
208
-            if (!isset($this->result[$propertyName])) {
209
-                $remaining[$propertyName] = $propValue;
210
-            }
211
-        }
212
-
213
-        return $remaining;
214
-
215
-    }
216
-
217
-    /**
218
-     * Performs the actual update, and calls all callbacks.
219
-     *
220
-     * This method returns true or false depending on if the operation was
221
-     * successful.
222
-     *
223
-     * @return bool
224
-     */
225
-    public function commit() {
226
-
227
-        // First we validate if every property has a handler
228
-        foreach ($this->mutations as $propertyName => $value) {
229
-
230
-            if (!isset($this->result[$propertyName])) {
231
-                $this->failed = true;
232
-                $this->result[$propertyName] = 403;
233
-            }
234
-
235
-        }
236
-
237
-        foreach ($this->propertyUpdateCallbacks as $callbackInfo) {
238
-
239
-            if ($this->failed) {
240
-                break;
241
-            }
242
-            if (is_string($callbackInfo[0])) {
243
-                $this->doCallbackSingleProp($callbackInfo[0], $callbackInfo[1]);
244
-            } else {
245
-                $this->doCallbackMultiProp($callbackInfo[0], $callbackInfo[1]);
246
-            }
247
-
248
-        }
249
-
250
-        /**
251
-         * If anywhere in this operation updating a property failed, we must
252
-         * update all other properties accordingly.
253
-         */
254
-        if ($this->failed) {
255
-
256
-            foreach ($this->result as $propertyName => $status) {
257
-                if ($status === 202) {
258
-                    // Failed dependency
259
-                    $this->result[$propertyName] = 424;
260
-                }
261
-            }
262
-
263
-        }
264
-
265
-        return !$this->failed;
266
-
267
-    }
268
-
269
-    /**
270
-     * Executes a property callback with the single-property syntax.
271
-     *
272
-     * @param string $propertyName
273
-     * @param callable $callback
274
-     * @return void
275
-     */
276
-    private function doCallBackSingleProp($propertyName, callable $callback) {
277
-
278
-        $result = $callback($this->mutations[$propertyName]);
279
-        if (is_bool($result)) {
280
-            if ($result) {
281
-                if (is_null($this->mutations[$propertyName])) {
282
-                    // Delete
283
-                    $result = 204;
284
-                } else {
285
-                    // Update
286
-                    $result = 200;
287
-                }
288
-            } else {
289
-                // Fail
290
-                $result = 403;
291
-            }
292
-        }
293
-        if (!is_int($result)) {
294
-            throw new UnexpectedValueException('A callback sent to handle() did not return an int or a bool');
295
-        }
296
-        $this->result[$propertyName] = $result;
297
-        if ($result >= 400) {
298
-            $this->failed = true;
299
-        }
300
-
301
-    }
302
-
303
-    /**
304
-     * Executes a property callback with the multi-property syntax.
305
-     *
306
-     * @param array $propertyList
307
-     * @param callable $callback
308
-     * @return void
309
-     */
310
-    private function doCallBackMultiProp(array $propertyList, callable $callback) {
311
-
312
-        $argument = [];
313
-        foreach ($propertyList as $propertyName) {
314
-            $argument[$propertyName] = $this->mutations[$propertyName];
315
-        }
316
-
317
-        $result = $callback($argument);
318
-
319
-        if (is_array($result)) {
320
-            foreach ($propertyList as $propertyName) {
321
-                if (!isset($result[$propertyName])) {
322
-                    $resultCode = 500;
323
-                } else {
324
-                    $resultCode = $result[$propertyName];
325
-                }
326
-                if ($resultCode >= 400) {
327
-                    $this->failed = true;
328
-                }
329
-                $this->result[$propertyName] = $resultCode;
330
-
331
-            }
332
-        } elseif ($result === true) {
333
-
334
-            // Success
335
-            foreach ($argument as $propertyName => $propertyValue) {
336
-                $this->result[$propertyName] = is_null($propertyValue) ? 204 : 200;
337
-            }
338
-
339
-        } elseif ($result === false) {
340
-            // Fail :(
341
-            $this->failed = true;
342
-            foreach ($propertyList as $propertyName) {
343
-                $this->result[$propertyName] = 403;
344
-            }
345
-        } else {
346
-            throw new UnexpectedValueException('A callback sent to handle() did not return an array or a bool');
347
-        }
348
-
349
-    }
350
-
351
-    /**
352
-     * Returns the result of the operation.
353
-     *
354
-     * @return array
355
-     */
356
-    public function getResult() {
357
-
358
-        return $this->result;
359
-
360
-    }
361
-
362
-    /**
363
-     * Returns the full list of mutations
364
-     *
365
-     * @return array
366
-     */
367
-    public function getMutations() {
368
-
369
-        return $this->mutations;
370
-
371
-    }
22
+	/**
23
+	 * Properties that are being updated.
24
+	 *
25
+	 * This is a key-value list. If the value is null, the property is supposed
26
+	 * to be deleted.
27
+	 *
28
+	 * @var array
29
+	 */
30
+	protected $mutations;
31
+
32
+	/**
33
+	 * A list of properties and the result of the update. The result is in the
34
+	 * form of a HTTP status code.
35
+	 *
36
+	 * @var array
37
+	 */
38
+	protected $result = [];
39
+
40
+	/**
41
+	 * This is the list of callbacks when we're performing the actual update.
42
+	 *
43
+	 * @var array
44
+	 */
45
+	protected $propertyUpdateCallbacks = [];
46
+
47
+	/**
48
+	 * This property will be set to true if the operation failed.
49
+	 *
50
+	 * @var bool
51
+	 */
52
+	protected $failed = false;
53
+
54
+	/**
55
+	 * Constructor
56
+	 *
57
+	 * @param array $mutations A list of updates
58
+	 */
59
+	public function __construct(array $mutations) {
60
+
61
+		$this->mutations = $mutations;
62
+
63
+	}
64
+
65
+	/**
66
+	 * Call this function if you wish to handle updating certain properties.
67
+	 * For instance, your class may be responsible for handling updates for the
68
+	 * {DAV:}displayname property.
69
+	 *
70
+	 * In that case, call this method with the first argument
71
+	 * "{DAV:}displayname" and a second argument that's a method that does the
72
+	 * actual updating.
73
+	 *
74
+	 * It's possible to specify more than one property as an array.
75
+	 *
76
+	 * The callback must return a boolean or an it. If the result is true, the
77
+	 * operation was considered successful. If it's false, it's consided
78
+	 * failed.
79
+	 *
80
+	 * If the result is an integer, we'll use that integer as the http status
81
+	 * code associated with the operation.
82
+	 *
83
+	 * @param string|string[] $properties
84
+	 * @param callable $callback
85
+	 * @return void
86
+	 */
87
+	public function handle($properties, callable $callback) {
88
+
89
+		$usedProperties = [];
90
+		foreach ((array)$properties as $propertyName) {
91
+
92
+			if (array_key_exists($propertyName, $this->mutations) && !isset($this->result[$propertyName])) {
93
+
94
+				$usedProperties[] = $propertyName;
95
+				// HTTP Accepted
96
+				$this->result[$propertyName] = 202;
97
+			}
98
+
99
+		}
100
+
101
+		// Only registering if there's any unhandled properties.
102
+		if (!$usedProperties) {
103
+			return;
104
+		}
105
+		$this->propertyUpdateCallbacks[] = [
106
+			// If the original argument to this method was a string, we need
107
+			// to also make sure that it stays that way, so the commit function
108
+			// knows how to format the arguments to the callback.
109
+			is_string($properties) ? $properties : $usedProperties,
110
+			$callback
111
+		];
112
+
113
+	}
114
+
115
+	/**
116
+	 * Call this function if you wish to handle _all_ properties that haven't
117
+	 * been handled by anything else yet. Note that you effectively claim with
118
+	 * this that you promise to process _all_ properties that are coming in.
119
+	 *
120
+	 * @param callable $callback
121
+	 * @return void
122
+	 */
123
+	public function handleRemaining(callable $callback) {
124
+
125
+		$properties = $this->getRemainingMutations();
126
+		if (!$properties) {
127
+			// Nothing to do, don't register callback
128
+			return;
129
+		}
130
+
131
+		foreach ($properties as $propertyName) {
132
+			// HTTP Accepted
133
+			$this->result[$propertyName] = 202;
134
+
135
+			$this->propertyUpdateCallbacks[] = [
136
+				$properties,
137
+				$callback
138
+			];
139
+		}
140
+
141
+	}
142
+
143
+	/**
144
+	 * Sets the result code for one or more properties.
145
+	 *
146
+	 * @param string|string[] $properties
147
+	 * @param int $resultCode
148
+	 * @return void
149
+	 */
150
+	public function setResultCode($properties, $resultCode) {
151
+
152
+		foreach ((array)$properties as $propertyName) {
153
+			$this->result[$propertyName] = $resultCode;
154
+		}
155
+
156
+		if ($resultCode >= 400) {
157
+			$this->failed = true;
158
+		}
159
+
160
+	}
161
+
162
+	/**
163
+	 * Sets the result code for all properties that did not have a result yet.
164
+	 *
165
+	 * @param int $resultCode
166
+	 * @return void
167
+	 */
168
+	public function setRemainingResultCode($resultCode) {
169
+
170
+		$this->setResultCode(
171
+			$this->getRemainingMutations(),
172
+			$resultCode
173
+		);
174
+
175
+	}
176
+
177
+	/**
178
+	 * Returns the list of properties that don't have a result code yet.
179
+	 *
180
+	 * This method returns a list of property names, but not its values.
181
+	 *
182
+	 * @return string[]
183
+	 */
184
+	public function getRemainingMutations() {
185
+
186
+		$remaining = [];
187
+		foreach ($this->mutations as $propertyName => $propValue) {
188
+			if (!isset($this->result[$propertyName])) {
189
+				$remaining[] = $propertyName;
190
+			}
191
+		}
192
+
193
+		return $remaining;
194
+
195
+	}
196
+
197
+	/**
198
+	 * Returns the list of properties that don't have a result code yet.
199
+	 *
200
+	 * This method returns list of properties and their values.
201
+	 *
202
+	 * @return array
203
+	 */
204
+	public function getRemainingValues() {
205
+
206
+		$remaining = [];
207
+		foreach ($this->mutations as $propertyName => $propValue) {
208
+			if (!isset($this->result[$propertyName])) {
209
+				$remaining[$propertyName] = $propValue;
210
+			}
211
+		}
212
+
213
+		return $remaining;
214
+
215
+	}
216
+
217
+	/**
218
+	 * Performs the actual update, and calls all callbacks.
219
+	 *
220
+	 * This method returns true or false depending on if the operation was
221
+	 * successful.
222
+	 *
223
+	 * @return bool
224
+	 */
225
+	public function commit() {
226
+
227
+		// First we validate if every property has a handler
228
+		foreach ($this->mutations as $propertyName => $value) {
229
+
230
+			if (!isset($this->result[$propertyName])) {
231
+				$this->failed = true;
232
+				$this->result[$propertyName] = 403;
233
+			}
234
+
235
+		}
236
+
237
+		foreach ($this->propertyUpdateCallbacks as $callbackInfo) {
238
+
239
+			if ($this->failed) {
240
+				break;
241
+			}
242
+			if (is_string($callbackInfo[0])) {
243
+				$this->doCallbackSingleProp($callbackInfo[0], $callbackInfo[1]);
244
+			} else {
245
+				$this->doCallbackMultiProp($callbackInfo[0], $callbackInfo[1]);
246
+			}
247
+
248
+		}
249
+
250
+		/**
251
+		 * If anywhere in this operation updating a property failed, we must
252
+		 * update all other properties accordingly.
253
+		 */
254
+		if ($this->failed) {
255
+
256
+			foreach ($this->result as $propertyName => $status) {
257
+				if ($status === 202) {
258
+					// Failed dependency
259
+					$this->result[$propertyName] = 424;
260
+				}
261
+			}
262
+
263
+		}
264
+
265
+		return !$this->failed;
266
+
267
+	}
268
+
269
+	/**
270
+	 * Executes a property callback with the single-property syntax.
271
+	 *
272
+	 * @param string $propertyName
273
+	 * @param callable $callback
274
+	 * @return void
275
+	 */
276
+	private function doCallBackSingleProp($propertyName, callable $callback) {
277
+
278
+		$result = $callback($this->mutations[$propertyName]);
279
+		if (is_bool($result)) {
280
+			if ($result) {
281
+				if (is_null($this->mutations[$propertyName])) {
282
+					// Delete
283
+					$result = 204;
284
+				} else {
285
+					// Update
286
+					$result = 200;
287
+				}
288
+			} else {
289
+				// Fail
290
+				$result = 403;
291
+			}
292
+		}
293
+		if (!is_int($result)) {
294
+			throw new UnexpectedValueException('A callback sent to handle() did not return an int or a bool');
295
+		}
296
+		$this->result[$propertyName] = $result;
297
+		if ($result >= 400) {
298
+			$this->failed = true;
299
+		}
300
+
301
+	}
302
+
303
+	/**
304
+	 * Executes a property callback with the multi-property syntax.
305
+	 *
306
+	 * @param array $propertyList
307
+	 * @param callable $callback
308
+	 * @return void
309
+	 */
310
+	private function doCallBackMultiProp(array $propertyList, callable $callback) {
311
+
312
+		$argument = [];
313
+		foreach ($propertyList as $propertyName) {
314
+			$argument[$propertyName] = $this->mutations[$propertyName];
315
+		}
316
+
317
+		$result = $callback($argument);
318
+
319
+		if (is_array($result)) {
320
+			foreach ($propertyList as $propertyName) {
321
+				if (!isset($result[$propertyName])) {
322
+					$resultCode = 500;
323
+				} else {
324
+					$resultCode = $result[$propertyName];
325
+				}
326
+				if ($resultCode >= 400) {
327
+					$this->failed = true;
328
+				}
329
+				$this->result[$propertyName] = $resultCode;
330
+
331
+			}
332
+		} elseif ($result === true) {
333
+
334
+			// Success
335
+			foreach ($argument as $propertyName => $propertyValue) {
336
+				$this->result[$propertyName] = is_null($propertyValue) ? 204 : 200;
337
+			}
338
+
339
+		} elseif ($result === false) {
340
+			// Fail :(
341
+			$this->failed = true;
342
+			foreach ($propertyList as $propertyName) {
343
+				$this->result[$propertyName] = 403;
344
+			}
345
+		} else {
346
+			throw new UnexpectedValueException('A callback sent to handle() did not return an array or a bool');
347
+		}
348
+
349
+	}
350
+
351
+	/**
352
+	 * Returns the result of the operation.
353
+	 *
354
+	 * @return array
355
+	 */
356
+	public function getResult() {
357
+
358
+		return $this->result;
359
+
360
+	}
361
+
362
+	/**
363
+	 * Returns the full list of mutations
364
+	 *
365
+	 * @return array
366
+	 */
367
+	public function getMutations() {
368
+
369
+		return $this->mutations;
370
+
371
+	}
372 372
 
373 373
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
     public function handle($properties, callable $callback) {
88 88
 
89 89
         $usedProperties = [];
90
-        foreach ((array)$properties as $propertyName) {
90
+        foreach ((array) $properties as $propertyName) {
91 91
 
92 92
             if (array_key_exists($propertyName, $this->mutations) && !isset($this->result[$propertyName])) {
93 93
 
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
      */
150 150
     public function setResultCode($properties, $resultCode) {
151 151
 
152
-        foreach ((array)$properties as $propertyName) {
152
+        foreach ((array) $properties as $propertyName) {
153 153
             $this->result[$propertyName] = $resultCode;
154 154
         }
155 155
 
Please login to merge, or discard this patch.
libraries/SabreDAV/DAV/Sync/Plugin.php 3 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -3,8 +3,8 @@
 block discarded – undo
3 3
 namespace Sabre\DAV\Sync;
4 4
 
5 5
 use Sabre\DAV;
6
-use Sabre\HTTP\RequestInterface;
7 6
 use Sabre\DAV\Xml\Request\SyncCollectionReport;
7
+use Sabre\HTTP\RequestInterface;
8 8
 
9 9
 /**
10 10
  * This plugin all WebDAV-sync capabilities to the Server.
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -68,7 +68,7 @@
 block discarded – undo
68 68
 
69 69
         });
70 70
 
71
-        $server->on('propFind',       [$this, 'propFind']);
71
+        $server->on('propFind', [$this, 'propFind']);
72 72
         $server->on('validateTokens', [$this, 'validateTokens']);
73 73
 
74 74
     }
Please login to merge, or discard this patch.
Indentation   +253 added lines, -253 removed lines patch added patch discarded remove patch
@@ -20,258 +20,258 @@
 block discarded – undo
20 20
  */
21 21
 class Plugin extends DAV\ServerPlugin {
22 22
 
23
-    /**
24
-     * Reference to server object
25
-     *
26
-     * @var DAV\Server
27
-     */
28
-    protected $server;
29
-
30
-    const SYNCTOKEN_PREFIX = 'http://sabre.io/ns/sync/';
31
-
32
-    /**
33
-     * Returns a plugin name.
34
-     *
35
-     * Using this name other plugins will be able to access other plugins
36
-     * using \Sabre\DAV\Server::getPlugin
37
-     *
38
-     * @return string
39
-     */
40
-    public function getPluginName() {
41
-
42
-        return 'sync';
43
-
44
-    }
45
-
46
-    /**
47
-     * Initializes the plugin.
48
-     *
49
-     * This is when the plugin registers it's hooks.
50
-     *
51
-     * @param DAV\Server $server
52
-     * @return void
53
-     */
54
-    public function initialize(DAV\Server $server) {
55
-
56
-        $this->server = $server;
57
-        $server->xml->elementMap['{DAV:}sync-collection'] = 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport';
58
-
59
-        $self = $this;
60
-
61
-        $server->on('report', function($reportName, $dom, $uri) use ($self) {
62
-
63
-            if ($reportName === '{DAV:}sync-collection') {
64
-                $this->server->transactionType = 'report-sync-collection';
65
-                $self->syncCollection($uri, $dom);
66
-                return false;
67
-            }
68
-
69
-        });
70
-
71
-        $server->on('propFind',       [$this, 'propFind']);
72
-        $server->on('validateTokens', [$this, 'validateTokens']);
73
-
74
-    }
75
-
76
-    /**
77
-     * Returns a list of reports this plugin supports.
78
-     *
79
-     * This will be used in the {DAV:}supported-report-set property.
80
-     * Note that you still need to subscribe to the 'report' event to actually
81
-     * implement them
82
-     *
83
-     * @param string $uri
84
-     * @return array
85
-     */
86
-    public function getSupportedReportSet($uri) {
87
-
88
-        $node = $this->server->tree->getNodeForPath($uri);
89
-        if ($node instanceof ISyncCollection && $node->getSyncToken()) {
90
-            return [
91
-                '{DAV:}sync-collection',
92
-            ];
93
-        }
94
-
95
-        return [];
96
-
97
-    }
98
-
99
-
100
-    /**
101
-     * This method handles the {DAV:}sync-collection HTTP REPORT.
102
-     *
103
-     * @param string $uri
104
-     * @param SyncCollectionReport $report
105
-     * @return void
106
-     */
107
-    public function syncCollection($uri, SyncCollectionReport $report) {
108
-
109
-        // Getting the data
110
-        $node = $this->server->tree->getNodeForPath($uri);
111
-        if (!$node instanceof ISyncCollection) {
112
-            throw new DAV\Exception\ReportNotSupported('The {DAV:}sync-collection REPORT is not supported on this url.');
113
-        }
114
-        $token = $node->getSyncToken();
115
-        if (!$token) {
116
-            throw new DAV\Exception\ReportNotSupported('No sync information is available at this node');
117
-        }
118
-
119
-        $syncToken = $report->syncToken;
120
-        if (!is_null($syncToken)) {
121
-            // Sync-token must start with our prefix
122
-            if (substr($syncToken, 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX) {
123
-                throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token');
124
-            }
125
-
126
-            $syncToken = substr($syncToken, strlen(self::SYNCTOKEN_PREFIX));
127
-
128
-        }
129
-        $changeInfo = $node->getChanges($syncToken, $report->syncLevel, $report->limit);
130
-
131
-        if (is_null($changeInfo)) {
132
-
133
-            throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token');
134
-
135
-        }
136
-
137
-        // Encoding the response
138
-        $this->sendSyncCollectionResponse(
139
-            $changeInfo['syncToken'],
140
-            $uri,
141
-            $changeInfo['added'],
142
-            $changeInfo['modified'],
143
-            $changeInfo['deleted'],
144
-            $report->properties
145
-        );
146
-
147
-    }
148
-
149
-    /**
150
-     * Sends the response to a sync-collection request.
151
-     *
152
-     * @param string $syncToken
153
-     * @param string $collectionUrl
154
-     * @param array $added
155
-     * @param array $modified
156
-     * @param array $deleted
157
-     * @param array $properties
158
-     * @return void
159
-     */
160
-    protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties) {
161
-
162
-
163
-        $fullPaths = [];
164
-
165
-        // Pre-fetching children, if this is possible.
166
-        foreach (array_merge($added, $modified) as $item) {
167
-            $fullPath = $collectionUrl . '/' . $item;
168
-            $fullPaths[] = $fullPath;
169
-        }
170
-
171
-        $responses = [];
172
-        foreach ($this->server->getPropertiesForMultiplePaths($fullPaths, $properties) as $fullPath => $props) {
173
-
174
-            // The 'Property_Response' class is responsible for generating a
175
-            // single {DAV:}response xml element.
176
-            $responses[] = new DAV\Xml\Element\Response($fullPath, $props);
177
-
178
-        }
179
-
180
-
181
-
182
-        // Deleted items also show up as 'responses'. They have no properties,
183
-        // and a single {DAV:}status element set as 'HTTP/1.1 404 Not Found'.
184
-        foreach ($deleted as $item) {
185
-
186
-            $fullPath = $collectionUrl . '/' . $item;
187
-            $responses[] = new DAV\Xml\Element\Response($fullPath, [], 404);
188
-
189
-        }
190
-        $multiStatus = new DAV\Xml\Response\MultiStatus($responses, self::SYNCTOKEN_PREFIX . $syncToken);
191
-
192
-        $this->server->httpResponse->setStatus(207);
193
-        $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
194
-        $this->server->httpResponse->setBody(
195
-            $this->server->xml->write('{DAV:}multistatus', $multiStatus, $this->server->getBaseUri())
196
-        );
197
-
198
-    }
199
-
200
-    /**
201
-     * This method is triggered whenever properties are requested for a node.
202
-     * We intercept this to see if we must return a {DAV:}sync-token.
203
-     *
204
-     * @param DAV\PropFind $propFind
205
-     * @param DAV\INode $node
206
-     * @return void
207
-     */
208
-    public function propFind(DAV\PropFind $propFind, DAV\INode $node) {
209
-
210
-        $propFind->handle('{DAV:}sync-token', function() use ($node) {
211
-            if (!$node instanceof ISyncCollection || !$token = $node->getSyncToken()) {
212
-                return;
213
-            }
214
-            return self::SYNCTOKEN_PREFIX . $token;
215
-        });
216
-
217
-    }
218
-
219
-    /**
220
-     * The validateTokens event is triggered before every request.
221
-     *
222
-     * It's a moment where this plugin can check all the supplied lock tokens
223
-     * in the If: header, and check if they are valid.
224
-     *
225
-     * @param RequestInterface $request
226
-     * @param array $conditions
227
-     * @return void
228
-     */
229
-    public function validateTokens(RequestInterface $request, &$conditions) {
230
-
231
-        foreach ($conditions as $kk => $condition) {
232
-
233
-            foreach ($condition['tokens'] as $ii => $token) {
234
-
235
-                // Sync-tokens must always start with our designated prefix.
236
-                if (substr($token['token'], 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX) {
237
-                    continue;
238
-                }
239
-
240
-                // Checking if the token is a match.
241
-                $node = $this->server->tree->getNodeForPath($condition['uri']);
242
-
243
-                if (
244
-                    $node instanceof ISyncCollection &&
245
-                    $node->getSyncToken() == substr($token['token'], strlen(self::SYNCTOKEN_PREFIX))
246
-                ) {
247
-                    $conditions[$kk]['tokens'][$ii]['validToken'] = true;
248
-                }
249
-
250
-            }
251
-
252
-        }
253
-
254
-    }
255
-
256
-    /**
257
-     * Returns a bunch of meta-data about the plugin.
258
-     *
259
-     * Providing this information is optional, and is mainly displayed by the
260
-     * Browser plugin.
261
-     *
262
-     * The description key in the returned array may contain html and will not
263
-     * be sanitized.
264
-     *
265
-     * @return array
266
-     */
267
-    public function getPluginInfo() {
268
-
269
-        return [
270
-            'name'        => $this->getPluginName(),
271
-            'description' => 'Adds support for WebDAV Collection Sync (rfc6578)',
272
-            'link'        => 'http://sabre.io/dav/sync/',
273
-        ];
274
-
275
-    }
23
+	/**
24
+	 * Reference to server object
25
+	 *
26
+	 * @var DAV\Server
27
+	 */
28
+	protected $server;
29
+
30
+	const SYNCTOKEN_PREFIX = 'http://sabre.io/ns/sync/';
31
+
32
+	/**
33
+	 * Returns a plugin name.
34
+	 *
35
+	 * Using this name other plugins will be able to access other plugins
36
+	 * using \Sabre\DAV\Server::getPlugin
37
+	 *
38
+	 * @return string
39
+	 */
40
+	public function getPluginName() {
41
+
42
+		return 'sync';
43
+
44
+	}
45
+
46
+	/**
47
+	 * Initializes the plugin.
48
+	 *
49
+	 * This is when the plugin registers it's hooks.
50
+	 *
51
+	 * @param DAV\Server $server
52
+	 * @return void
53
+	 */
54
+	public function initialize(DAV\Server $server) {
55
+
56
+		$this->server = $server;
57
+		$server->xml->elementMap['{DAV:}sync-collection'] = 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport';
58
+
59
+		$self = $this;
60
+
61
+		$server->on('report', function($reportName, $dom, $uri) use ($self) {
62
+
63
+			if ($reportName === '{DAV:}sync-collection') {
64
+				$this->server->transactionType = 'report-sync-collection';
65
+				$self->syncCollection($uri, $dom);
66
+				return false;
67
+			}
68
+
69
+		});
70
+
71
+		$server->on('propFind',       [$this, 'propFind']);
72
+		$server->on('validateTokens', [$this, 'validateTokens']);
73
+
74
+	}
75
+
76
+	/**
77
+	 * Returns a list of reports this plugin supports.
78
+	 *
79
+	 * This will be used in the {DAV:}supported-report-set property.
80
+	 * Note that you still need to subscribe to the 'report' event to actually
81
+	 * implement them
82
+	 *
83
+	 * @param string $uri
84
+	 * @return array
85
+	 */
86
+	public function getSupportedReportSet($uri) {
87
+
88
+		$node = $this->server->tree->getNodeForPath($uri);
89
+		if ($node instanceof ISyncCollection && $node->getSyncToken()) {
90
+			return [
91
+				'{DAV:}sync-collection',
92
+			];
93
+		}
94
+
95
+		return [];
96
+
97
+	}
98
+
99
+
100
+	/**
101
+	 * This method handles the {DAV:}sync-collection HTTP REPORT.
102
+	 *
103
+	 * @param string $uri
104
+	 * @param SyncCollectionReport $report
105
+	 * @return void
106
+	 */
107
+	public function syncCollection($uri, SyncCollectionReport $report) {
108
+
109
+		// Getting the data
110
+		$node = $this->server->tree->getNodeForPath($uri);
111
+		if (!$node instanceof ISyncCollection) {
112
+			throw new DAV\Exception\ReportNotSupported('The {DAV:}sync-collection REPORT is not supported on this url.');
113
+		}
114
+		$token = $node->getSyncToken();
115
+		if (!$token) {
116
+			throw new DAV\Exception\ReportNotSupported('No sync information is available at this node');
117
+		}
118
+
119
+		$syncToken = $report->syncToken;
120
+		if (!is_null($syncToken)) {
121
+			// Sync-token must start with our prefix
122
+			if (substr($syncToken, 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX) {
123
+				throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token');
124
+			}
125
+
126
+			$syncToken = substr($syncToken, strlen(self::SYNCTOKEN_PREFIX));
127
+
128
+		}
129
+		$changeInfo = $node->getChanges($syncToken, $report->syncLevel, $report->limit);
130
+
131
+		if (is_null($changeInfo)) {
132
+
133
+			throw new DAV\Exception\InvalidSyncToken('Invalid or unknown sync token');
134
+
135
+		}
136
+
137
+		// Encoding the response
138
+		$this->sendSyncCollectionResponse(
139
+			$changeInfo['syncToken'],
140
+			$uri,
141
+			$changeInfo['added'],
142
+			$changeInfo['modified'],
143
+			$changeInfo['deleted'],
144
+			$report->properties
145
+		);
146
+
147
+	}
148
+
149
+	/**
150
+	 * Sends the response to a sync-collection request.
151
+	 *
152
+	 * @param string $syncToken
153
+	 * @param string $collectionUrl
154
+	 * @param array $added
155
+	 * @param array $modified
156
+	 * @param array $deleted
157
+	 * @param array $properties
158
+	 * @return void
159
+	 */
160
+	protected function sendSyncCollectionResponse($syncToken, $collectionUrl, array $added, array $modified, array $deleted, array $properties) {
161
+
162
+
163
+		$fullPaths = [];
164
+
165
+		// Pre-fetching children, if this is possible.
166
+		foreach (array_merge($added, $modified) as $item) {
167
+			$fullPath = $collectionUrl . '/' . $item;
168
+			$fullPaths[] = $fullPath;
169
+		}
170
+
171
+		$responses = [];
172
+		foreach ($this->server->getPropertiesForMultiplePaths($fullPaths, $properties) as $fullPath => $props) {
173
+
174
+			// The 'Property_Response' class is responsible for generating a
175
+			// single {DAV:}response xml element.
176
+			$responses[] = new DAV\Xml\Element\Response($fullPath, $props);
177
+
178
+		}
179
+
180
+
181
+
182
+		// Deleted items also show up as 'responses'. They have no properties,
183
+		// and a single {DAV:}status element set as 'HTTP/1.1 404 Not Found'.
184
+		foreach ($deleted as $item) {
185
+
186
+			$fullPath = $collectionUrl . '/' . $item;
187
+			$responses[] = new DAV\Xml\Element\Response($fullPath, [], 404);
188
+
189
+		}
190
+		$multiStatus = new DAV\Xml\Response\MultiStatus($responses, self::SYNCTOKEN_PREFIX . $syncToken);
191
+
192
+		$this->server->httpResponse->setStatus(207);
193
+		$this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
194
+		$this->server->httpResponse->setBody(
195
+			$this->server->xml->write('{DAV:}multistatus', $multiStatus, $this->server->getBaseUri())
196
+		);
197
+
198
+	}
199
+
200
+	/**
201
+	 * This method is triggered whenever properties are requested for a node.
202
+	 * We intercept this to see if we must return a {DAV:}sync-token.
203
+	 *
204
+	 * @param DAV\PropFind $propFind
205
+	 * @param DAV\INode $node
206
+	 * @return void
207
+	 */
208
+	public function propFind(DAV\PropFind $propFind, DAV\INode $node) {
209
+
210
+		$propFind->handle('{DAV:}sync-token', function() use ($node) {
211
+			if (!$node instanceof ISyncCollection || !$token = $node->getSyncToken()) {
212
+				return;
213
+			}
214
+			return self::SYNCTOKEN_PREFIX . $token;
215
+		});
216
+
217
+	}
218
+
219
+	/**
220
+	 * The validateTokens event is triggered before every request.
221
+	 *
222
+	 * It's a moment where this plugin can check all the supplied lock tokens
223
+	 * in the If: header, and check if they are valid.
224
+	 *
225
+	 * @param RequestInterface $request
226
+	 * @param array $conditions
227
+	 * @return void
228
+	 */
229
+	public function validateTokens(RequestInterface $request, &$conditions) {
230
+
231
+		foreach ($conditions as $kk => $condition) {
232
+
233
+			foreach ($condition['tokens'] as $ii => $token) {
234
+
235
+				// Sync-tokens must always start with our designated prefix.
236
+				if (substr($token['token'], 0, strlen(self::SYNCTOKEN_PREFIX)) !== self::SYNCTOKEN_PREFIX) {
237
+					continue;
238
+				}
239
+
240
+				// Checking if the token is a match.
241
+				$node = $this->server->tree->getNodeForPath($condition['uri']);
242
+
243
+				if (
244
+					$node instanceof ISyncCollection &&
245
+					$node->getSyncToken() == substr($token['token'], strlen(self::SYNCTOKEN_PREFIX))
246
+				) {
247
+					$conditions[$kk]['tokens'][$ii]['validToken'] = true;
248
+				}
249
+
250
+			}
251
+
252
+		}
253
+
254
+	}
255
+
256
+	/**
257
+	 * Returns a bunch of meta-data about the plugin.
258
+	 *
259
+	 * Providing this information is optional, and is mainly displayed by the
260
+	 * Browser plugin.
261
+	 *
262
+	 * The description key in the returned array may contain html and will not
263
+	 * be sanitized.
264
+	 *
265
+	 * @return array
266
+	 */
267
+	public function getPluginInfo() {
268
+
269
+		return [
270
+			'name'        => $this->getPluginName(),
271
+			'description' => 'Adds support for WebDAV Collection Sync (rfc6578)',
272
+			'link'        => 'http://sabre.io/dav/sync/',
273
+		];
274
+
275
+	}
276 276
 
277 277
 }
Please login to merge, or discard this patch.