Completed
Branch develop (fa72bb)
by
unknown
26:08
created
htdocs/includes/sabre/sabre/dav/lib/DAV/FS/Node.php 1 patch
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -19,78 +19,78 @@
 block discarded – undo
19 19
  */
20 20
 abstract class Node implements INode
21 21
 {
22
-    /**
23
-     * The path to the current node.
24
-     *
25
-     * @var string
26
-     */
27
-    protected $path;
22
+	/**
23
+	 * The path to the current node.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $path;
28 28
 
29
-    /**
30
-     * The overridden name of the node.
31
-     *
32
-     * @var string
33
-     */
34
-    protected $overrideName;
29
+	/**
30
+	 * The overridden name of the node.
31
+	 *
32
+	 * @var string
33
+	 */
34
+	protected $overrideName;
35 35
 
36
-    /**
37
-     * Sets up the node, expects a full path name.
38
-     *
39
-     * If $overrideName is set, this node shows up in the tree under a
40
-     * different name. In this case setName() will be disabled.
41
-     *
42
-     * @param string $path
43
-     * @param string $overrideName
44
-     */
45
-    public function __construct($path, $overrideName = null)
46
-    {
47
-        $this->path = $path;
48
-        $this->overrideName = $overrideName;
49
-    }
36
+	/**
37
+	 * Sets up the node, expects a full path name.
38
+	 *
39
+	 * If $overrideName is set, this node shows up in the tree under a
40
+	 * different name. In this case setName() will be disabled.
41
+	 *
42
+	 * @param string $path
43
+	 * @param string $overrideName
44
+	 */
45
+	public function __construct($path, $overrideName = null)
46
+	{
47
+		$this->path = $path;
48
+		$this->overrideName = $overrideName;
49
+	}
50 50
 
51
-    /**
52
-     * Returns the name of the node.
53
-     *
54
-     * @return string
55
-     */
56
-    public function getName()
57
-    {
58
-        if ($this->overrideName) {
59
-            return $this->overrideName;
60
-        }
51
+	/**
52
+	 * Returns the name of the node.
53
+	 *
54
+	 * @return string
55
+	 */
56
+	public function getName()
57
+	{
58
+		if ($this->overrideName) {
59
+			return $this->overrideName;
60
+		}
61 61
 
62
-        list(, $name) = Uri\split($this->path);
62
+		list(, $name) = Uri\split($this->path);
63 63
 
64
-        return $name;
65
-    }
64
+		return $name;
65
+	}
66 66
 
67
-    /**
68
-     * Renames the node.
69
-     *
70
-     * @param string $name The new name
71
-     */
72
-    public function setName($name)
73
-    {
74
-        if ($this->overrideName) {
75
-            throw new Forbidden('This node cannot be renamed');
76
-        }
67
+	/**
68
+	 * Renames the node.
69
+	 *
70
+	 * @param string $name The new name
71
+	 */
72
+	public function setName($name)
73
+	{
74
+		if ($this->overrideName) {
75
+			throw new Forbidden('This node cannot be renamed');
76
+		}
77 77
 
78
-        list($parentPath) = Uri\split($this->path);
79
-        list(, $newName) = Uri\split($name);
78
+		list($parentPath) = Uri\split($this->path);
79
+		list(, $newName) = Uri\split($name);
80 80
 
81
-        $newPath = $parentPath.'/'.$newName;
82
-        rename($this->path, $newPath);
81
+		$newPath = $parentPath.'/'.$newName;
82
+		rename($this->path, $newPath);
83 83
 
84
-        $this->path = $newPath;
85
-    }
84
+		$this->path = $newPath;
85
+	}
86 86
 
87
-    /**
88
-     * Returns the last modification time, as a unix timestamp.
89
-     *
90
-     * @return int
91
-     */
92
-    public function getLastModified()
93
-    {
94
-        return filemtime($this->path);
95
-    }
87
+	/**
88
+	 * Returns the last modification time, as a unix timestamp.
89
+	 *
90
+	 * @return int
91
+	 */
92
+	public function getLastModified()
93
+	{
94
+		return filemtime($this->path);
95
+	}
96 96
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/PropPatch.php 1 patch
Indentation   +284 added lines, -284 removed lines patch added patch discarded remove patch
@@ -21,317 +21,317 @@
 block discarded – undo
21 21
  */
22 22
 class PropPatch
23 23
 {
24
-    /**
25
-     * Properties that are being updated.
26
-     *
27
-     * This is a key-value list. If the value is null, the property is supposed
28
-     * to be deleted.
29
-     *
30
-     * @var array
31
-     */
32
-    protected $mutations;
24
+	/**
25
+	 * Properties that are being updated.
26
+	 *
27
+	 * This is a key-value list. If the value is null, the property is supposed
28
+	 * to be deleted.
29
+	 *
30
+	 * @var array
31
+	 */
32
+	protected $mutations;
33 33
 
34
-    /**
35
-     * A list of properties and the result of the update. The result is in the
36
-     * form of a HTTP status code.
37
-     *
38
-     * @var array
39
-     */
40
-    protected $result = [];
34
+	/**
35
+	 * A list of properties and the result of the update. The result is in the
36
+	 * form of a HTTP status code.
37
+	 *
38
+	 * @var array
39
+	 */
40
+	protected $result = [];
41 41
 
42
-    /**
43
-     * This is the list of callbacks when we're performing the actual update.
44
-     *
45
-     * @var array
46
-     */
47
-    protected $propertyUpdateCallbacks = [];
42
+	/**
43
+	 * This is the list of callbacks when we're performing the actual update.
44
+	 *
45
+	 * @var array
46
+	 */
47
+	protected $propertyUpdateCallbacks = [];
48 48
 
49
-    /**
50
-     * This property will be set to true if the operation failed.
51
-     *
52
-     * @var bool
53
-     */
54
-    protected $failed = false;
49
+	/**
50
+	 * This property will be set to true if the operation failed.
51
+	 *
52
+	 * @var bool
53
+	 */
54
+	protected $failed = false;
55 55
 
56
-    /**
57
-     * Constructor.
58
-     *
59
-     * @param array $mutations A list of updates
60
-     */
61
-    public function __construct(array $mutations)
62
-    {
63
-        $this->mutations = $mutations;
64
-    }
56
+	/**
57
+	 * Constructor.
58
+	 *
59
+	 * @param array $mutations A list of updates
60
+	 */
61
+	public function __construct(array $mutations)
62
+	{
63
+		$this->mutations = $mutations;
64
+	}
65 65
 
66
-    /**
67
-     * Call this function if you wish to handle updating certain properties.
68
-     * For instance, your class may be responsible for handling updates for the
69
-     * {DAV:}displayname property.
70
-     *
71
-     * In that case, call this method with the first argument
72
-     * "{DAV:}displayname" and a second argument that's a method that does the
73
-     * actual updating.
74
-     *
75
-     * It's possible to specify more than one property as an array.
76
-     *
77
-     * The callback must return a boolean or an it. If the result is true, the
78
-     * operation was considered successful. If it's false, it's consided
79
-     * failed.
80
-     *
81
-     * If the result is an integer, we'll use that integer as the http status
82
-     * code associated with the operation.
83
-     *
84
-     * @param string|string[] $properties
85
-     */
86
-    public function handle($properties, callable $callback)
87
-    {
88
-        $usedProperties = [];
89
-        foreach ((array) $properties as $propertyName) {
90
-            if (array_key_exists($propertyName, $this->mutations) && !isset($this->result[$propertyName])) {
91
-                $usedProperties[] = $propertyName;
92
-                // HTTP Accepted
93
-                $this->result[$propertyName] = 202;
94
-            }
95
-        }
66
+	/**
67
+	 * Call this function if you wish to handle updating certain properties.
68
+	 * For instance, your class may be responsible for handling updates for the
69
+	 * {DAV:}displayname property.
70
+	 *
71
+	 * In that case, call this method with the first argument
72
+	 * "{DAV:}displayname" and a second argument that's a method that does the
73
+	 * actual updating.
74
+	 *
75
+	 * It's possible to specify more than one property as an array.
76
+	 *
77
+	 * The callback must return a boolean or an it. If the result is true, the
78
+	 * operation was considered successful. If it's false, it's consided
79
+	 * failed.
80
+	 *
81
+	 * If the result is an integer, we'll use that integer as the http status
82
+	 * code associated with the operation.
83
+	 *
84
+	 * @param string|string[] $properties
85
+	 */
86
+	public function handle($properties, callable $callback)
87
+	{
88
+		$usedProperties = [];
89
+		foreach ((array) $properties as $propertyName) {
90
+			if (array_key_exists($propertyName, $this->mutations) && !isset($this->result[$propertyName])) {
91
+				$usedProperties[] = $propertyName;
92
+				// HTTP Accepted
93
+				$this->result[$propertyName] = 202;
94
+			}
95
+		}
96 96
 
97
-        // Only registering if there's any unhandled properties.
98
-        if (!$usedProperties) {
99
-            return;
100
-        }
101
-        $this->propertyUpdateCallbacks[] = [
102
-            // If the original argument to this method was a string, we need
103
-            // to also make sure that it stays that way, so the commit function
104
-            // knows how to format the arguments to the callback.
105
-            is_string($properties) ? $properties : $usedProperties,
106
-            $callback,
107
-        ];
108
-    }
97
+		// Only registering if there's any unhandled properties.
98
+		if (!$usedProperties) {
99
+			return;
100
+		}
101
+		$this->propertyUpdateCallbacks[] = [
102
+			// If the original argument to this method was a string, we need
103
+			// to also make sure that it stays that way, so the commit function
104
+			// knows how to format the arguments to the callback.
105
+			is_string($properties) ? $properties : $usedProperties,
106
+			$callback,
107
+		];
108
+	}
109 109
 
110
-    /**
111
-     * Call this function if you wish to handle _all_ properties that haven't
112
-     * been handled by anything else yet. Note that you effectively claim with
113
-     * this that you promise to process _all_ properties that are coming in.
114
-     */
115
-    public function handleRemaining(callable $callback)
116
-    {
117
-        $properties = $this->getRemainingMutations();
118
-        if (!$properties) {
119
-            // Nothing to do, don't register callback
120
-            return;
121
-        }
110
+	/**
111
+	 * Call this function if you wish to handle _all_ properties that haven't
112
+	 * been handled by anything else yet. Note that you effectively claim with
113
+	 * this that you promise to process _all_ properties that are coming in.
114
+	 */
115
+	public function handleRemaining(callable $callback)
116
+	{
117
+		$properties = $this->getRemainingMutations();
118
+		if (!$properties) {
119
+			// Nothing to do, don't register callback
120
+			return;
121
+		}
122 122
 
123
-        foreach ($properties as $propertyName) {
124
-            // HTTP Accepted
125
-            $this->result[$propertyName] = 202;
123
+		foreach ($properties as $propertyName) {
124
+			// HTTP Accepted
125
+			$this->result[$propertyName] = 202;
126 126
 
127
-            $this->propertyUpdateCallbacks[] = [
128
-                $properties,
129
-                $callback,
130
-            ];
131
-        }
132
-    }
127
+			$this->propertyUpdateCallbacks[] = [
128
+				$properties,
129
+				$callback,
130
+			];
131
+		}
132
+	}
133 133
 
134
-    /**
135
-     * Sets the result code for one or more properties.
136
-     *
137
-     * @param string|string[] $properties
138
-     * @param int             $resultCode
139
-     */
140
-    public function setResultCode($properties, $resultCode)
141
-    {
142
-        foreach ((array) $properties as $propertyName) {
143
-            $this->result[$propertyName] = $resultCode;
144
-        }
134
+	/**
135
+	 * Sets the result code for one or more properties.
136
+	 *
137
+	 * @param string|string[] $properties
138
+	 * @param int             $resultCode
139
+	 */
140
+	public function setResultCode($properties, $resultCode)
141
+	{
142
+		foreach ((array) $properties as $propertyName) {
143
+			$this->result[$propertyName] = $resultCode;
144
+		}
145 145
 
146
-        if ($resultCode >= 400) {
147
-            $this->failed = true;
148
-        }
149
-    }
146
+		if ($resultCode >= 400) {
147
+			$this->failed = true;
148
+		}
149
+	}
150 150
 
151
-    /**
152
-     * Sets the result code for all properties that did not have a result yet.
153
-     *
154
-     * @param int $resultCode
155
-     */
156
-    public function setRemainingResultCode($resultCode)
157
-    {
158
-        $this->setResultCode(
159
-            $this->getRemainingMutations(),
160
-            $resultCode
161
-        );
162
-    }
151
+	/**
152
+	 * Sets the result code for all properties that did not have a result yet.
153
+	 *
154
+	 * @param int $resultCode
155
+	 */
156
+	public function setRemainingResultCode($resultCode)
157
+	{
158
+		$this->setResultCode(
159
+			$this->getRemainingMutations(),
160
+			$resultCode
161
+		);
162
+	}
163 163
 
164
-    /**
165
-     * Returns the list of properties that don't have a result code yet.
166
-     *
167
-     * This method returns a list of property names, but not its values.
168
-     *
169
-     * @return string[]
170
-     */
171
-    public function getRemainingMutations()
172
-    {
173
-        $remaining = [];
174
-        foreach ($this->mutations as $propertyName => $propValue) {
175
-            if (!isset($this->result[$propertyName])) {
176
-                $remaining[] = $propertyName;
177
-            }
178
-        }
164
+	/**
165
+	 * Returns the list of properties that don't have a result code yet.
166
+	 *
167
+	 * This method returns a list of property names, but not its values.
168
+	 *
169
+	 * @return string[]
170
+	 */
171
+	public function getRemainingMutations()
172
+	{
173
+		$remaining = [];
174
+		foreach ($this->mutations as $propertyName => $propValue) {
175
+			if (!isset($this->result[$propertyName])) {
176
+				$remaining[] = $propertyName;
177
+			}
178
+		}
179 179
 
180
-        return $remaining;
181
-    }
180
+		return $remaining;
181
+	}
182 182
 
183
-    /**
184
-     * Returns the list of properties that don't have a result code yet.
185
-     *
186
-     * This method returns list of properties and their values.
187
-     *
188
-     * @return array
189
-     */
190
-    public function getRemainingValues()
191
-    {
192
-        $remaining = [];
193
-        foreach ($this->mutations as $propertyName => $propValue) {
194
-            if (!isset($this->result[$propertyName])) {
195
-                $remaining[$propertyName] = $propValue;
196
-            }
197
-        }
183
+	/**
184
+	 * Returns the list of properties that don't have a result code yet.
185
+	 *
186
+	 * This method returns list of properties and their values.
187
+	 *
188
+	 * @return array
189
+	 */
190
+	public function getRemainingValues()
191
+	{
192
+		$remaining = [];
193
+		foreach ($this->mutations as $propertyName => $propValue) {
194
+			if (!isset($this->result[$propertyName])) {
195
+				$remaining[$propertyName] = $propValue;
196
+			}
197
+		}
198 198
 
199
-        return $remaining;
200
-    }
199
+		return $remaining;
200
+	}
201 201
 
202
-    /**
203
-     * Performs the actual update, and calls all callbacks.
204
-     *
205
-     * This method returns true or false depending on if the operation was
206
-     * successful.
207
-     *
208
-     * @return bool
209
-     */
210
-    public function commit()
211
-    {
212
-        // First we validate if every property has a handler
213
-        foreach ($this->mutations as $propertyName => $value) {
214
-            if (!isset($this->result[$propertyName])) {
215
-                $this->failed = true;
216
-                $this->result[$propertyName] = 403;
217
-            }
218
-        }
202
+	/**
203
+	 * Performs the actual update, and calls all callbacks.
204
+	 *
205
+	 * This method returns true or false depending on if the operation was
206
+	 * successful.
207
+	 *
208
+	 * @return bool
209
+	 */
210
+	public function commit()
211
+	{
212
+		// First we validate if every property has a handler
213
+		foreach ($this->mutations as $propertyName => $value) {
214
+			if (!isset($this->result[$propertyName])) {
215
+				$this->failed = true;
216
+				$this->result[$propertyName] = 403;
217
+			}
218
+		}
219 219
 
220
-        foreach ($this->propertyUpdateCallbacks as $callbackInfo) {
221
-            if ($this->failed) {
222
-                break;
223
-            }
224
-            if (is_string($callbackInfo[0])) {
225
-                $this->doCallbackSingleProp($callbackInfo[0], $callbackInfo[1]);
226
-            } else {
227
-                $this->doCallbackMultiProp($callbackInfo[0], $callbackInfo[1]);
228
-            }
229
-        }
220
+		foreach ($this->propertyUpdateCallbacks as $callbackInfo) {
221
+			if ($this->failed) {
222
+				break;
223
+			}
224
+			if (is_string($callbackInfo[0])) {
225
+				$this->doCallbackSingleProp($callbackInfo[0], $callbackInfo[1]);
226
+			} else {
227
+				$this->doCallbackMultiProp($callbackInfo[0], $callbackInfo[1]);
228
+			}
229
+		}
230 230
 
231
-        /*
231
+		/*
232 232
          * If anywhere in this operation updating a property failed, we must
233 233
          * update all other properties accordingly.
234 234
          */
235
-        if ($this->failed) {
236
-            foreach ($this->result as $propertyName => $status) {
237
-                if (202 === $status) {
238
-                    // Failed dependency
239
-                    $this->result[$propertyName] = 424;
240
-                }
241
-            }
242
-        }
235
+		if ($this->failed) {
236
+			foreach ($this->result as $propertyName => $status) {
237
+				if (202 === $status) {
238
+					// Failed dependency
239
+					$this->result[$propertyName] = 424;
240
+				}
241
+			}
242
+		}
243 243
 
244
-        return !$this->failed;
245
-    }
244
+		return !$this->failed;
245
+	}
246 246
 
247
-    /**
248
-     * Executes a property callback with the single-property syntax.
249
-     *
250
-     * @param string $propertyName
251
-     */
252
-    private function doCallBackSingleProp($propertyName, callable $callback)
253
-    {
254
-        $result = $callback($this->mutations[$propertyName]);
255
-        if (is_bool($result)) {
256
-            if ($result) {
257
-                if (is_null($this->mutations[$propertyName])) {
258
-                    // Delete
259
-                    $result = 204;
260
-                } else {
261
-                    // Update
262
-                    $result = 200;
263
-                }
264
-            } else {
265
-                // Fail
266
-                $result = 403;
267
-            }
268
-        }
269
-        if (!is_int($result)) {
270
-            throw new UnexpectedValueException('A callback sent to handle() did not return an int or a bool');
271
-        }
272
-        $this->result[$propertyName] = $result;
273
-        if ($result >= 400) {
274
-            $this->failed = true;
275
-        }
276
-    }
247
+	/**
248
+	 * Executes a property callback with the single-property syntax.
249
+	 *
250
+	 * @param string $propertyName
251
+	 */
252
+	private function doCallBackSingleProp($propertyName, callable $callback)
253
+	{
254
+		$result = $callback($this->mutations[$propertyName]);
255
+		if (is_bool($result)) {
256
+			if ($result) {
257
+				if (is_null($this->mutations[$propertyName])) {
258
+					// Delete
259
+					$result = 204;
260
+				} else {
261
+					// Update
262
+					$result = 200;
263
+				}
264
+			} else {
265
+				// Fail
266
+				$result = 403;
267
+			}
268
+		}
269
+		if (!is_int($result)) {
270
+			throw new UnexpectedValueException('A callback sent to handle() did not return an int or a bool');
271
+		}
272
+		$this->result[$propertyName] = $result;
273
+		if ($result >= 400) {
274
+			$this->failed = true;
275
+		}
276
+	}
277 277
 
278
-    /**
279
-     * Executes a property callback with the multi-property syntax.
280
-     */
281
-    private function doCallBackMultiProp(array $propertyList, callable $callback)
282
-    {
283
-        $argument = [];
284
-        foreach ($propertyList as $propertyName) {
285
-            $argument[$propertyName] = $this->mutations[$propertyName];
286
-        }
278
+	/**
279
+	 * Executes a property callback with the multi-property syntax.
280
+	 */
281
+	private function doCallBackMultiProp(array $propertyList, callable $callback)
282
+	{
283
+		$argument = [];
284
+		foreach ($propertyList as $propertyName) {
285
+			$argument[$propertyName] = $this->mutations[$propertyName];
286
+		}
287 287
 
288
-        $result = $callback($argument);
288
+		$result = $callback($argument);
289 289
 
290
-        if (is_array($result)) {
291
-            foreach ($propertyList as $propertyName) {
292
-                if (!isset($result[$propertyName])) {
293
-                    $resultCode = 500;
294
-                } else {
295
-                    $resultCode = $result[$propertyName];
296
-                }
297
-                if ($resultCode >= 400) {
298
-                    $this->failed = true;
299
-                }
300
-                $this->result[$propertyName] = $resultCode;
301
-            }
302
-        } elseif (true === $result) {
303
-            // Success
304
-            foreach ($argument as $propertyName => $propertyValue) {
305
-                $this->result[$propertyName] = is_null($propertyValue) ? 204 : 200;
306
-            }
307
-        } elseif (false === $result) {
308
-            // Fail :(
309
-            $this->failed = true;
310
-            foreach ($propertyList as $propertyName) {
311
-                $this->result[$propertyName] = 403;
312
-            }
313
-        } else {
314
-            throw new UnexpectedValueException('A callback sent to handle() did not return an array or a bool');
315
-        }
316
-    }
290
+		if (is_array($result)) {
291
+			foreach ($propertyList as $propertyName) {
292
+				if (!isset($result[$propertyName])) {
293
+					$resultCode = 500;
294
+				} else {
295
+					$resultCode = $result[$propertyName];
296
+				}
297
+				if ($resultCode >= 400) {
298
+					$this->failed = true;
299
+				}
300
+				$this->result[$propertyName] = $resultCode;
301
+			}
302
+		} elseif (true === $result) {
303
+			// Success
304
+			foreach ($argument as $propertyName => $propertyValue) {
305
+				$this->result[$propertyName] = is_null($propertyValue) ? 204 : 200;
306
+			}
307
+		} elseif (false === $result) {
308
+			// Fail :(
309
+			$this->failed = true;
310
+			foreach ($propertyList as $propertyName) {
311
+				$this->result[$propertyName] = 403;
312
+			}
313
+		} else {
314
+			throw new UnexpectedValueException('A callback sent to handle() did not return an array or a bool');
315
+		}
316
+	}
317 317
 
318
-    /**
319
-     * Returns the result of the operation.
320
-     *
321
-     * @return array
322
-     */
323
-    public function getResult()
324
-    {
325
-        return $this->result;
326
-    }
318
+	/**
319
+	 * Returns the result of the operation.
320
+	 *
321
+	 * @return array
322
+	 */
323
+	public function getResult()
324
+	{
325
+		return $this->result;
326
+	}
327 327
 
328
-    /**
329
-     * Returns the full list of mutations.
330
-     *
331
-     * @return array
332
-     */
333
-    public function getMutations()
334
-    {
335
-        return $this->mutations;
336
-    }
328
+	/**
329
+	 * Returns the full list of mutations.
330
+	 *
331
+	 * @return array
332
+	 */
333
+	public function getMutations()
334
+	{
335
+		return $this->mutations;
336
+	}
337 337
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/Exception.php 1 patch
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -19,32 +19,32 @@
 block discarded – undo
19 19
  */
20 20
 class Exception extends \Exception
21 21
 {
22
-    /**
23
-     * Returns the HTTP statuscode for this exception.
24
-     *
25
-     * @return int
26
-     */
27
-    public function getHTTPCode()
28
-    {
29
-        return 500;
30
-    }
22
+	/**
23
+	 * Returns the HTTP statuscode for this exception.
24
+	 *
25
+	 * @return int
26
+	 */
27
+	public function getHTTPCode()
28
+	{
29
+		return 500;
30
+	}
31 31
 
32
-    /**
33
-     * This method allows the exception to include additional information into the WebDAV error response.
34
-     */
35
-    public function serialize(Server $server, \DOMElement $errorNode)
36
-    {
37
-    }
32
+	/**
33
+	 * This method allows the exception to include additional information into the WebDAV error response.
34
+	 */
35
+	public function serialize(Server $server, \DOMElement $errorNode)
36
+	{
37
+	}
38 38
 
39
-    /**
40
-     * This method allows the exception to return any extra HTTP response headers.
41
-     *
42
-     * The headers must be returned as an array.
43
-     *
44
-     * @return array
45
-     */
46
-    public function getHTTPHeaders(Server $server)
47
-    {
48
-        return [];
49
-    }
39
+	/**
40
+	 * This method allows the exception to return any extra HTTP response headers.
41
+	 *
42
+	 * The headers must be returned as an array.
43
+	 *
44
+	 * @return array
45
+	 */
46
+	public function getHTTPHeaders(Server $server)
47
+	{
48
+		return [];
49
+	}
50 50
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/MkCol.php 1 patch
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -24,48 +24,48 @@
 block discarded – undo
24 24
  */
25 25
 class MkCol extends PropPatch
26 26
 {
27
-    /**
28
-     * A list of resource-types in clark-notation.
29
-     *
30
-     * @var array
31
-     */
32
-    protected $resourceType;
27
+	/**
28
+	 * A list of resource-types in clark-notation.
29
+	 *
30
+	 * @var array
31
+	 */
32
+	protected $resourceType;
33 33
 
34
-    /**
35
-     * Creates the MKCOL object.
36
-     *
37
-     * @param string[] $resourceType list of resourcetype values
38
-     * @param array    $mutations    list of new properties values
39
-     */
40
-    public function __construct(array $resourceType, array $mutations)
41
-    {
42
-        $this->resourceType = $resourceType;
43
-        parent::__construct($mutations);
44
-    }
34
+	/**
35
+	 * Creates the MKCOL object.
36
+	 *
37
+	 * @param string[] $resourceType list of resourcetype values
38
+	 * @param array    $mutations    list of new properties values
39
+	 */
40
+	public function __construct(array $resourceType, array $mutations)
41
+	{
42
+		$this->resourceType = $resourceType;
43
+		parent::__construct($mutations);
44
+	}
45 45
 
46
-    /**
47
-     * Returns the resourcetype of the new collection.
48
-     *
49
-     * @return string[]
50
-     */
51
-    public function getResourceType()
52
-    {
53
-        return $this->resourceType;
54
-    }
46
+	/**
47
+	 * Returns the resourcetype of the new collection.
48
+	 *
49
+	 * @return string[]
50
+	 */
51
+	public function getResourceType()
52
+	{
53
+		return $this->resourceType;
54
+	}
55 55
 
56
-    /**
57
-     * Returns true or false if the MKCOL operation has at least the specified
58
-     * resource type.
59
-     *
60
-     * If the resourcetype is specified as an array, all resourcetypes are
61
-     * checked.
62
-     *
63
-     * @param string|string[] $resourceType
64
-     *
65
-     * @return bool
66
-     */
67
-    public function hasResourceType($resourceType)
68
-    {
69
-        return 0 === count(array_diff((array) $resourceType, $this->resourceType));
70
-    }
56
+	/**
57
+	 * Returns true or false if the MKCOL operation has at least the specified
58
+	 * resource type.
59
+	 *
60
+	 * If the resourcetype is specified as an array, all resourcetypes are
61
+	 * checked.
62
+	 *
63
+	 * @param string|string[] $resourceType
64
+	 *
65
+	 * @return bool
66
+	 */
67
+	public function hasResourceType($resourceType)
68
+	{
69
+		return 0 === count(array_diff((array) $resourceType, $this->resourceType));
70
+	}
71 71
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/File.php 1 patch
Indentation   +70 added lines, -70 removed lines patch added patch discarded remove patch
@@ -16,78 +16,78 @@
 block discarded – undo
16 16
  */
17 17
 abstract class File extends Node implements IFile
18 18
 {
19
-    /**
20
-     * Replaces the contents of the file.
21
-     *
22
-     * The data argument is a readable stream resource.
23
-     *
24
-     * After a successful put operation, you may choose to return an ETag. The
25
-     * etag must always be surrounded by double-quotes. These quotes must
26
-     * appear in the actual string you're returning.
27
-     *
28
-     * Clients may use the ETag from a PUT request to later on make sure that
29
-     * when they update the file, the contents haven't changed in the mean
30
-     * time.
31
-     *
32
-     * If you don't plan to store the file byte-by-byte, and you return a
33
-     * different object on a subsequent GET you are strongly recommended to not
34
-     * return an ETag, and just return null.
35
-     *
36
-     * @param string|resource $data
37
-     *
38
-     * @return string|null
39
-     */
40
-    public function put($data)
41
-    {
42
-        throw new Exception\Forbidden('Permission denied to change data');
43
-    }
19
+	/**
20
+	 * Replaces the contents of the file.
21
+	 *
22
+	 * The data argument is a readable stream resource.
23
+	 *
24
+	 * After a successful put operation, you may choose to return an ETag. The
25
+	 * etag must always be surrounded by double-quotes. These quotes must
26
+	 * appear in the actual string you're returning.
27
+	 *
28
+	 * Clients may use the ETag from a PUT request to later on make sure that
29
+	 * when they update the file, the contents haven't changed in the mean
30
+	 * time.
31
+	 *
32
+	 * If you don't plan to store the file byte-by-byte, and you return a
33
+	 * different object on a subsequent GET you are strongly recommended to not
34
+	 * return an ETag, and just return null.
35
+	 *
36
+	 * @param string|resource $data
37
+	 *
38
+	 * @return string|null
39
+	 */
40
+	public function put($data)
41
+	{
42
+		throw new Exception\Forbidden('Permission denied to change data');
43
+	}
44 44
 
45
-    /**
46
-     * Returns the data.
47
-     *
48
-     * This method may either return a string or a readable stream resource
49
-     *
50
-     * @return mixed
51
-     */
52
-    public function get()
53
-    {
54
-        throw new Exception\Forbidden('Permission denied to read this file');
55
-    }
45
+	/**
46
+	 * Returns the data.
47
+	 *
48
+	 * This method may either return a string or a readable stream resource
49
+	 *
50
+	 * @return mixed
51
+	 */
52
+	public function get()
53
+	{
54
+		throw new Exception\Forbidden('Permission denied to read this file');
55
+	}
56 56
 
57
-    /**
58
-     * Returns the size of the file, in bytes.
59
-     *
60
-     * @return int
61
-     */
62
-    public function getSize()
63
-    {
64
-        return 0;
65
-    }
57
+	/**
58
+	 * Returns the size of the file, in bytes.
59
+	 *
60
+	 * @return int
61
+	 */
62
+	public function getSize()
63
+	{
64
+		return 0;
65
+	}
66 66
 
67
-    /**
68
-     * Returns the ETag for a file.
69
-     *
70
-     * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
71
-     * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
72
-     *
73
-     * Return null if the ETag can not effectively be determined
74
-     *
75
-     * @return string|null
76
-     */
77
-    public function getETag()
78
-    {
79
-        return null;
80
-    }
67
+	/**
68
+	 * Returns the ETag for a file.
69
+	 *
70
+	 * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
71
+	 * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
72
+	 *
73
+	 * Return null if the ETag can not effectively be determined
74
+	 *
75
+	 * @return string|null
76
+	 */
77
+	public function getETag()
78
+	{
79
+		return null;
80
+	}
81 81
 
82
-    /**
83
-     * Returns the mime-type for a file.
84
-     *
85
-     * If null is returned, we'll assume application/octet-stream
86
-     *
87
-     * @return string|null
88
-     */
89
-    public function getContentType()
90
-    {
91
-        return null;
92
-    }
82
+	/**
83
+	 * Returns the mime-type for a file.
84
+	 *
85
+	 * If null is returned, we'll assume application/octet-stream
86
+	 *
87
+	 * @return string|null
88
+	 */
89
+	public function getContentType()
90
+	{
91
+		return null;
92
+	}
93 93
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/Collection.php 1 patch
Indentation   +83 added lines, -83 removed lines patch added patch discarded remove patch
@@ -16,91 +16,91 @@
 block discarded – undo
16 16
  */
17 17
 abstract class Collection extends Node implements ICollection
18 18
 {
19
-    /**
20
-     * Returns a child object, by its name.
21
-     *
22
-     * This method makes use of the getChildren method to grab all the child
23
-     * nodes, and compares the name.
24
-     * Generally its wise to override this, as this can usually be optimized
25
-     *
26
-     * This method must throw Sabre\DAV\Exception\NotFound if the node does not
27
-     * exist.
28
-     *
29
-     * @param string $name
30
-     *
31
-     * @throws Exception\NotFound
32
-     *
33
-     * @return INode
34
-     */
35
-    public function getChild($name)
36
-    {
37
-        foreach ($this->getChildren() as $child) {
38
-            if ($child->getName() === $name) {
39
-                return $child;
40
-            }
41
-        }
42
-        throw new Exception\NotFound('File not found: '.$name);
43
-    }
19
+	/**
20
+	 * Returns a child object, by its name.
21
+	 *
22
+	 * This method makes use of the getChildren method to grab all the child
23
+	 * nodes, and compares the name.
24
+	 * Generally its wise to override this, as this can usually be optimized
25
+	 *
26
+	 * This method must throw Sabre\DAV\Exception\NotFound if the node does not
27
+	 * exist.
28
+	 *
29
+	 * @param string $name
30
+	 *
31
+	 * @throws Exception\NotFound
32
+	 *
33
+	 * @return INode
34
+	 */
35
+	public function getChild($name)
36
+	{
37
+		foreach ($this->getChildren() as $child) {
38
+			if ($child->getName() === $name) {
39
+				return $child;
40
+			}
41
+		}
42
+		throw new Exception\NotFound('File not found: '.$name);
43
+	}
44 44
 
45
-    /**
46
-     * Checks is a child-node exists.
47
-     *
48
-     * It is generally a good idea to try and override this. Usually it can be optimized.
49
-     *
50
-     * @param string $name
51
-     *
52
-     * @return bool
53
-     */
54
-    public function childExists($name)
55
-    {
56
-        try {
57
-            $this->getChild($name);
45
+	/**
46
+	 * Checks is a child-node exists.
47
+	 *
48
+	 * It is generally a good idea to try and override this. Usually it can be optimized.
49
+	 *
50
+	 * @param string $name
51
+	 *
52
+	 * @return bool
53
+	 */
54
+	public function childExists($name)
55
+	{
56
+		try {
57
+			$this->getChild($name);
58 58
 
59
-            return true;
60
-        } catch (Exception\NotFound $e) {
61
-            return false;
62
-        }
63
-    }
59
+			return true;
60
+		} catch (Exception\NotFound $e) {
61
+			return false;
62
+		}
63
+	}
64 64
 
65
-    /**
66
-     * Creates a new file in the directory.
67
-     *
68
-     * Data will either be supplied as a stream resource, or in certain cases
69
-     * as a string. Keep in mind that you may have to support either.
70
-     *
71
-     * After successful creation of the file, you may choose to return the ETag
72
-     * of the new file here.
73
-     *
74
-     * The returned ETag must be surrounded by double-quotes (The quotes should
75
-     * be part of the actual string).
76
-     *
77
-     * If you cannot accurately determine the ETag, you should not return it.
78
-     * If you don't store the file exactly as-is (you're transforming it
79
-     * somehow) you should also not return an ETag.
80
-     *
81
-     * This means that if a subsequent GET to this new file does not exactly
82
-     * return the same contents of what was submitted here, you are strongly
83
-     * recommended to omit the ETag.
84
-     *
85
-     * @param string          $name Name of the file
86
-     * @param resource|string $data Initial payload
87
-     *
88
-     * @return string|null
89
-     */
90
-    public function createFile($name, $data = null)
91
-    {
92
-        throw new Exception\Forbidden('Permission denied to create file (filename '.$name.')');
93
-    }
65
+	/**
66
+	 * Creates a new file in the directory.
67
+	 *
68
+	 * Data will either be supplied as a stream resource, or in certain cases
69
+	 * as a string. Keep in mind that you may have to support either.
70
+	 *
71
+	 * After successful creation of the file, you may choose to return the ETag
72
+	 * of the new file here.
73
+	 *
74
+	 * The returned ETag must be surrounded by double-quotes (The quotes should
75
+	 * be part of the actual string).
76
+	 *
77
+	 * If you cannot accurately determine the ETag, you should not return it.
78
+	 * If you don't store the file exactly as-is (you're transforming it
79
+	 * somehow) you should also not return an ETag.
80
+	 *
81
+	 * This means that if a subsequent GET to this new file does not exactly
82
+	 * return the same contents of what was submitted here, you are strongly
83
+	 * recommended to omit the ETag.
84
+	 *
85
+	 * @param string          $name Name of the file
86
+	 * @param resource|string $data Initial payload
87
+	 *
88
+	 * @return string|null
89
+	 */
90
+	public function createFile($name, $data = null)
91
+	{
92
+		throw new Exception\Forbidden('Permission denied to create file (filename '.$name.')');
93
+	}
94 94
 
95
-    /**
96
-     * Creates a new subdirectory.
97
-     *
98
-     * @param string $name
99
-     *
100
-     * @throws Exception\Forbidden
101
-     */
102
-    public function createDirectory($name)
103
-    {
104
-        throw new Exception\Forbidden('Permission denied to create directory');
105
-    }
95
+	/**
96
+	 * Creates a new subdirectory.
97
+	 *
98
+	 * @param string $name
99
+	 *
100
+	 * @throws Exception\Forbidden
101
+	 */
102
+	public function createDirectory($name)
103
+	{
104
+		throw new Exception\Forbidden('Permission denied to create directory');
105
+	}
106 106
 }
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/TemporaryFileFilterPlugin.php 2 patches
Indentation   +261 added lines, -261 removed lines patch added patch discarded remove patch
@@ -34,265 +34,265 @@
 block discarded – undo
34 34
  */
35 35
 class TemporaryFileFilterPlugin extends ServerPlugin
36 36
 {
37
-    /**
38
-     * This is the list of patterns we intercept.
39
-     * If new patterns are added, they must be valid patterns for preg_match.
40
-     *
41
-     * @var array
42
-     */
43
-    public $temporaryFilePatterns = [
44
-        '/^\._(.*)$/',     // OS/X resource forks
45
-        '/^.DS_Store$/',   // OS/X custom folder settings
46
-        '/^desktop.ini$/', // Windows custom folder settings
47
-        '/^Thumbs.db$/',   // Windows thumbnail cache
48
-        '/^.(.*).swp$/',   // ViM temporary files
49
-        '/^\.dat(.*)$/',   // Smultron seems to create these
50
-        '/^~lock.(.*)#$/', // Windows 7 lockfiles
51
-    ];
52
-
53
-    /**
54
-     * A reference to the main Server class.
55
-     *
56
-     * @var \Sabre\DAV\Server
57
-     */
58
-    protected $server;
59
-
60
-    /**
61
-     * This is the directory where this plugin
62
-     * will store it's files.
63
-     *
64
-     * @var string
65
-     */
66
-    private $dataDir;
67
-
68
-    /**
69
-     * Creates the plugin.
70
-     *
71
-     * Make sure you specify a directory for your files. If you don't, we
72
-     * will use PHP's directory for session-storage instead, and you might
73
-     * not want that.
74
-     *
75
-     * @param string|null $dataDir
76
-     */
77
-    public function __construct($dataDir = null)
78
-    {
79
-        if (!$dataDir) {
80
-            $dataDir = ini_get('session.save_path').'/sabredav/';
81
-        }
82
-        if (!is_dir($dataDir)) {
83
-            mkdir($dataDir);
84
-        }
85
-        $this->dataDir = $dataDir;
86
-    }
87
-
88
-    /**
89
-     * Initialize the plugin.
90
-     *
91
-     * This is called automatically be the Server class after this plugin is
92
-     * added with Sabre\DAV\Server::addPlugin()
93
-     */
94
-    public function initialize(Server $server)
95
-    {
96
-        $this->server = $server;
97
-        $server->on('beforeMethod:*', [$this, 'beforeMethod']);
98
-        $server->on('beforeCreateFile', [$this, 'beforeCreateFile']);
99
-    }
100
-
101
-    /**
102
-     * This method is called before any HTTP method handler.
103
-     *
104
-     * This method intercepts any GET, DELETE, PUT and PROPFIND calls to
105
-     * filenames that are known to match the 'temporary file' regex.
106
-     *
107
-     * @return bool
108
-     */
109
-    public function beforeMethod(RequestInterface $request, ResponseInterface $response)
110
-    {
111
-        if (!$tempLocation = $this->isTempFile($request->getPath())) {
112
-            return;
113
-        }
114
-
115
-        switch ($request->getMethod()) {
116
-            case 'GET':
117
-                return $this->httpGet($request, $response, $tempLocation);
118
-            case 'PUT':
119
-                return $this->httpPut($request, $response, $tempLocation);
120
-            case 'PROPFIND':
121
-                return $this->httpPropfind($request, $response, $tempLocation);
122
-            case 'DELETE':
123
-                return $this->httpDelete($request, $response, $tempLocation);
124
-        }
125
-
126
-        return;
127
-    }
128
-
129
-    /**
130
-     * This method is invoked if some subsystem creates a new file.
131
-     *
132
-     * This is used to deal with HTTP LOCK requests which create a new
133
-     * file.
134
-     *
135
-     * @param string   $uri
136
-     * @param resource $data
137
-     * @param bool     $modified should be set to true, if this event handler
138
-     *                           changed &$data
139
-     *
140
-     * @return bool
141
-     */
142
-    public function beforeCreateFile($uri, $data, ICollection $parent, $modified)
143
-    {
144
-        if ($tempPath = $this->isTempFile($uri)) {
145
-            $hR = $this->server->httpResponse;
146
-            $hR->setHeader('X-Sabre-Temp', 'true');
147
-            file_put_contents($tempPath, $data);
148
-
149
-            return false;
150
-        }
151
-
152
-        return;
153
-    }
154
-
155
-    /**
156
-     * This method will check if the url matches the temporary file pattern
157
-     * if it does, it will return an path based on $this->dataDir for the
158
-     * temporary file storage.
159
-     *
160
-     * @param string $path
161
-     *
162
-     * @return bool|string
163
-     */
164
-    protected function isTempFile($path)
165
-    {
166
-        // We're only interested in the basename.
167
-        list(, $tempPath) = Uri\split($path);
168
-
169
-        if (null === $tempPath) {
170
-            return false;
171
-        }
172
-
173
-        foreach ($this->temporaryFilePatterns as $tempFile) {
174
-            if (preg_match($tempFile, $tempPath)) {
175
-                return $this->getDataDir().'/sabredav_'.md5($path).'.tempfile';
176
-            }
177
-        }
178
-
179
-        return false;
180
-    }
181
-
182
-    /**
183
-     * This method handles the GET method for temporary files.
184
-     * If the file doesn't exist, it will return false which will kick in
185
-     * the regular system for the GET method.
186
-     *
187
-     * @param string $tempLocation
188
-     *
189
-     * @return bool
190
-     */
191
-    public function httpGet(RequestInterface $request, ResponseInterface $hR, $tempLocation)
192
-    {
193
-        if (!file_exists($tempLocation)) {
194
-            return;
195
-        }
196
-
197
-        $hR->setHeader('Content-Type', 'application/octet-stream');
198
-        $hR->setHeader('Content-Length', filesize($tempLocation));
199
-        $hR->setHeader('X-Sabre-Temp', 'true');
200
-        $hR->setStatus(200);
201
-        $hR->setBody(fopen($tempLocation, 'r'));
202
-
203
-        return false;
204
-    }
205
-
206
-    /**
207
-     * This method handles the PUT method.
208
-     *
209
-     * @param string $tempLocation
210
-     *
211
-     * @return bool
212
-     */
213
-    public function httpPut(RequestInterface $request, ResponseInterface $hR, $tempLocation)
214
-    {
215
-        $hR->setHeader('X-Sabre-Temp', 'true');
216
-
217
-        $newFile = !file_exists($tempLocation);
218
-
219
-        if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) {
220
-            throw new Exception\PreconditionFailed('The resource already exists, and an If-None-Match header was supplied');
221
-        }
222
-
223
-        file_put_contents($tempLocation, $this->server->httpRequest->getBody());
224
-        $hR->setStatus($newFile ? 201 : 200);
225
-
226
-        return false;
227
-    }
228
-
229
-    /**
230
-     * This method handles the DELETE method.
231
-     *
232
-     * If the file didn't exist, it will return false, which will make the
233
-     * standard HTTP DELETE handler kick in.
234
-     *
235
-     * @param string $tempLocation
236
-     *
237
-     * @return bool
238
-     */
239
-    public function httpDelete(RequestInterface $request, ResponseInterface $hR, $tempLocation)
240
-    {
241
-        if (!file_exists($tempLocation)) {
242
-            return;
243
-        }
244
-
245
-        unlink($tempLocation);
246
-        $hR->setHeader('X-Sabre-Temp', 'true');
247
-        $hR->setStatus(204);
248
-
249
-        return false;
250
-    }
251
-
252
-    /**
253
-     * This method handles the PROPFIND method.
254
-     *
255
-     * It's a very lazy method, it won't bother checking the request body
256
-     * for which properties were requested, and just sends back a default
257
-     * set of properties.
258
-     *
259
-     * @param string $tempLocation
260
-     *
261
-     * @return bool
262
-     */
263
-    public function httpPropfind(RequestInterface $request, ResponseInterface $hR, $tempLocation)
264
-    {
265
-        if (!file_exists($tempLocation)) {
266
-            return;
267
-        }
268
-
269
-        $hR->setHeader('X-Sabre-Temp', 'true');
270
-        $hR->setStatus(207);
271
-        $hR->setHeader('Content-Type', 'application/xml; charset=utf-8');
272
-
273
-        $properties = [
274
-            'href' => $request->getPath(),
275
-            200 => [
276
-                '{DAV:}getlastmodified' => new Xml\Property\GetLastModified(filemtime($tempLocation)),
277
-                '{DAV:}getcontentlength' => filesize($tempLocation),
278
-                '{DAV:}resourcetype' => new Xml\Property\ResourceType(null),
279
-                '{'.Server::NS_SABREDAV.'}tempFile' => true,
280
-            ],
281
-        ];
282
-
283
-        $data = $this->server->generateMultiStatus([$properties]);
284
-        $hR->setBody($data);
285
-
286
-        return false;
287
-    }
288
-
289
-    /**
290
-     * This method returns the directory where the temporary files should be stored.
291
-     *
292
-     * @return string
293
-     */
294
-    protected function getDataDir()
295
-    {
296
-        return $this->dataDir;
297
-    }
37
+	/**
38
+	 * This is the list of patterns we intercept.
39
+	 * If new patterns are added, they must be valid patterns for preg_match.
40
+	 *
41
+	 * @var array
42
+	 */
43
+	public $temporaryFilePatterns = [
44
+		'/^\._(.*)$/',     // OS/X resource forks
45
+		'/^.DS_Store$/',   // OS/X custom folder settings
46
+		'/^desktop.ini$/', // Windows custom folder settings
47
+		'/^Thumbs.db$/',   // Windows thumbnail cache
48
+		'/^.(.*).swp$/',   // ViM temporary files
49
+		'/^\.dat(.*)$/',   // Smultron seems to create these
50
+		'/^~lock.(.*)#$/', // Windows 7 lockfiles
51
+	];
52
+
53
+	/**
54
+	 * A reference to the main Server class.
55
+	 *
56
+	 * @var \Sabre\DAV\Server
57
+	 */
58
+	protected $server;
59
+
60
+	/**
61
+	 * This is the directory where this plugin
62
+	 * will store it's files.
63
+	 *
64
+	 * @var string
65
+	 */
66
+	private $dataDir;
67
+
68
+	/**
69
+	 * Creates the plugin.
70
+	 *
71
+	 * Make sure you specify a directory for your files. If you don't, we
72
+	 * will use PHP's directory for session-storage instead, and you might
73
+	 * not want that.
74
+	 *
75
+	 * @param string|null $dataDir
76
+	 */
77
+	public function __construct($dataDir = null)
78
+	{
79
+		if (!$dataDir) {
80
+			$dataDir = ini_get('session.save_path').'/sabredav/';
81
+		}
82
+		if (!is_dir($dataDir)) {
83
+			mkdir($dataDir);
84
+		}
85
+		$this->dataDir = $dataDir;
86
+	}
87
+
88
+	/**
89
+	 * Initialize the plugin.
90
+	 *
91
+	 * This is called automatically be the Server class after this plugin is
92
+	 * added with Sabre\DAV\Server::addPlugin()
93
+	 */
94
+	public function initialize(Server $server)
95
+	{
96
+		$this->server = $server;
97
+		$server->on('beforeMethod:*', [$this, 'beforeMethod']);
98
+		$server->on('beforeCreateFile', [$this, 'beforeCreateFile']);
99
+	}
100
+
101
+	/**
102
+	 * This method is called before any HTTP method handler.
103
+	 *
104
+	 * This method intercepts any GET, DELETE, PUT and PROPFIND calls to
105
+	 * filenames that are known to match the 'temporary file' regex.
106
+	 *
107
+	 * @return bool
108
+	 */
109
+	public function beforeMethod(RequestInterface $request, ResponseInterface $response)
110
+	{
111
+		if (!$tempLocation = $this->isTempFile($request->getPath())) {
112
+			return;
113
+		}
114
+
115
+		switch ($request->getMethod()) {
116
+			case 'GET':
117
+				return $this->httpGet($request, $response, $tempLocation);
118
+			case 'PUT':
119
+				return $this->httpPut($request, $response, $tempLocation);
120
+			case 'PROPFIND':
121
+				return $this->httpPropfind($request, $response, $tempLocation);
122
+			case 'DELETE':
123
+				return $this->httpDelete($request, $response, $tempLocation);
124
+		}
125
+
126
+		return;
127
+	}
128
+
129
+	/**
130
+	 * This method is invoked if some subsystem creates a new file.
131
+	 *
132
+	 * This is used to deal with HTTP LOCK requests which create a new
133
+	 * file.
134
+	 *
135
+	 * @param string   $uri
136
+	 * @param resource $data
137
+	 * @param bool     $modified should be set to true, if this event handler
138
+	 *                           changed &$data
139
+	 *
140
+	 * @return bool
141
+	 */
142
+	public function beforeCreateFile($uri, $data, ICollection $parent, $modified)
143
+	{
144
+		if ($tempPath = $this->isTempFile($uri)) {
145
+			$hR = $this->server->httpResponse;
146
+			$hR->setHeader('X-Sabre-Temp', 'true');
147
+			file_put_contents($tempPath, $data);
148
+
149
+			return false;
150
+		}
151
+
152
+		return;
153
+	}
154
+
155
+	/**
156
+	 * This method will check if the url matches the temporary file pattern
157
+	 * if it does, it will return an path based on $this->dataDir for the
158
+	 * temporary file storage.
159
+	 *
160
+	 * @param string $path
161
+	 *
162
+	 * @return bool|string
163
+	 */
164
+	protected function isTempFile($path)
165
+	{
166
+		// We're only interested in the basename.
167
+		list(, $tempPath) = Uri\split($path);
168
+
169
+		if (null === $tempPath) {
170
+			return false;
171
+		}
172
+
173
+		foreach ($this->temporaryFilePatterns as $tempFile) {
174
+			if (preg_match($tempFile, $tempPath)) {
175
+				return $this->getDataDir().'/sabredav_'.md5($path).'.tempfile';
176
+			}
177
+		}
178
+
179
+		return false;
180
+	}
181
+
182
+	/**
183
+	 * This method handles the GET method for temporary files.
184
+	 * If the file doesn't exist, it will return false which will kick in
185
+	 * the regular system for the GET method.
186
+	 *
187
+	 * @param string $tempLocation
188
+	 *
189
+	 * @return bool
190
+	 */
191
+	public function httpGet(RequestInterface $request, ResponseInterface $hR, $tempLocation)
192
+	{
193
+		if (!file_exists($tempLocation)) {
194
+			return;
195
+		}
196
+
197
+		$hR->setHeader('Content-Type', 'application/octet-stream');
198
+		$hR->setHeader('Content-Length', filesize($tempLocation));
199
+		$hR->setHeader('X-Sabre-Temp', 'true');
200
+		$hR->setStatus(200);
201
+		$hR->setBody(fopen($tempLocation, 'r'));
202
+
203
+		return false;
204
+	}
205
+
206
+	/**
207
+	 * This method handles the PUT method.
208
+	 *
209
+	 * @param string $tempLocation
210
+	 *
211
+	 * @return bool
212
+	 */
213
+	public function httpPut(RequestInterface $request, ResponseInterface $hR, $tempLocation)
214
+	{
215
+		$hR->setHeader('X-Sabre-Temp', 'true');
216
+
217
+		$newFile = !file_exists($tempLocation);
218
+
219
+		if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) {
220
+			throw new Exception\PreconditionFailed('The resource already exists, and an If-None-Match header was supplied');
221
+		}
222
+
223
+		file_put_contents($tempLocation, $this->server->httpRequest->getBody());
224
+		$hR->setStatus($newFile ? 201 : 200);
225
+
226
+		return false;
227
+	}
228
+
229
+	/**
230
+	 * This method handles the DELETE method.
231
+	 *
232
+	 * If the file didn't exist, it will return false, which will make the
233
+	 * standard HTTP DELETE handler kick in.
234
+	 *
235
+	 * @param string $tempLocation
236
+	 *
237
+	 * @return bool
238
+	 */
239
+	public function httpDelete(RequestInterface $request, ResponseInterface $hR, $tempLocation)
240
+	{
241
+		if (!file_exists($tempLocation)) {
242
+			return;
243
+		}
244
+
245
+		unlink($tempLocation);
246
+		$hR->setHeader('X-Sabre-Temp', 'true');
247
+		$hR->setStatus(204);
248
+
249
+		return false;
250
+	}
251
+
252
+	/**
253
+	 * This method handles the PROPFIND method.
254
+	 *
255
+	 * It's a very lazy method, it won't bother checking the request body
256
+	 * for which properties were requested, and just sends back a default
257
+	 * set of properties.
258
+	 *
259
+	 * @param string $tempLocation
260
+	 *
261
+	 * @return bool
262
+	 */
263
+	public function httpPropfind(RequestInterface $request, ResponseInterface $hR, $tempLocation)
264
+	{
265
+		if (!file_exists($tempLocation)) {
266
+			return;
267
+		}
268
+
269
+		$hR->setHeader('X-Sabre-Temp', 'true');
270
+		$hR->setStatus(207);
271
+		$hR->setHeader('Content-Type', 'application/xml; charset=utf-8');
272
+
273
+		$properties = [
274
+			'href' => $request->getPath(),
275
+			200 => [
276
+				'{DAV:}getlastmodified' => new Xml\Property\GetLastModified(filemtime($tempLocation)),
277
+				'{DAV:}getcontentlength' => filesize($tempLocation),
278
+				'{DAV:}resourcetype' => new Xml\Property\ResourceType(null),
279
+				'{'.Server::NS_SABREDAV.'}tempFile' => true,
280
+			],
281
+		];
282
+
283
+		$data = $this->server->generateMultiStatus([$properties]);
284
+		$hR->setBody($data);
285
+
286
+		return false;
287
+	}
288
+
289
+	/**
290
+	 * This method returns the directory where the temporary files should be stored.
291
+	 *
292
+	 * @return string
293
+	 */
294
+	protected function getDataDir()
295
+	{
296
+		return $this->dataDir;
297
+	}
298 298
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -41,12 +41,12 @@
 block discarded – undo
41 41
      * @var array
42 42
      */
43 43
     public $temporaryFilePatterns = [
44
-        '/^\._(.*)$/',     // OS/X resource forks
45
-        '/^.DS_Store$/',   // OS/X custom folder settings
44
+        '/^\._(.*)$/', // OS/X resource forks
45
+        '/^.DS_Store$/', // OS/X custom folder settings
46 46
         '/^desktop.ini$/', // Windows custom folder settings
47
-        '/^Thumbs.db$/',   // Windows thumbnail cache
48
-        '/^.(.*).swp$/',   // ViM temporary files
49
-        '/^\.dat(.*)$/',   // Smultron seems to create these
47
+        '/^Thumbs.db$/', // Windows thumbnail cache
48
+        '/^.(.*).swp$/', // ViM temporary files
49
+        '/^\.dat(.*)$/', // Smultron seems to create these
50 50
         '/^~lock.(.*)#$/', // Windows 7 lockfiles
51 51
     ];
52 52
 
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/Locks/Plugin.php 2 patches
Indentation   +523 added lines, -523 removed lines patch added patch discarded remove patch
@@ -24,527 +24,527 @@
 block discarded – undo
24 24
  */
25 25
 class Plugin extends DAV\ServerPlugin
26 26
 {
27
-    /**
28
-     * locksBackend.
29
-     *
30
-     * @var Backend\BackendInterface
31
-     */
32
-    protected $locksBackend;
33
-
34
-    /**
35
-     * server.
36
-     *
37
-     * @var DAV\Server
38
-     */
39
-    protected $server;
40
-
41
-    /**
42
-     * __construct.
43
-     */
44
-    public function __construct(Backend\BackendInterface $locksBackend)
45
-    {
46
-        $this->locksBackend = $locksBackend;
47
-    }
48
-
49
-    /**
50
-     * Initializes the plugin.
51
-     *
52
-     * This method is automatically called by the Server class after addPlugin.
53
-     */
54
-    public function initialize(DAV\Server $server)
55
-    {
56
-        $this->server = $server;
57
-
58
-        $this->server->xml->elementMap['{DAV:}lockinfo'] = 'Sabre\\DAV\\Xml\\Request\\Lock';
59
-
60
-        $server->on('method:LOCK', [$this, 'httpLock']);
61
-        $server->on('method:UNLOCK', [$this, 'httpUnlock']);
62
-        $server->on('validateTokens', [$this, 'validateTokens']);
63
-        $server->on('propFind', [$this, 'propFind']);
64
-        $server->on('afterUnbind', [$this, 'afterUnbind']);
65
-    }
66
-
67
-    /**
68
-     * Returns a plugin name.
69
-     *
70
-     * Using this name other plugins will be able to access other plugins
71
-     * using Sabre\DAV\Server::getPlugin
72
-     *
73
-     * @return string
74
-     */
75
-    public function getPluginName()
76
-    {
77
-        return 'locks';
78
-    }
79
-
80
-    /**
81
-     * This method is called after most properties have been found
82
-     * it allows us to add in any Lock-related properties.
83
-     */
84
-    public function propFind(DAV\PropFind $propFind, DAV\INode $node)
85
-    {
86
-        $propFind->handle('{DAV:}supportedlock', function () {
87
-            return new DAV\Xml\Property\SupportedLock();
88
-        });
89
-        $propFind->handle('{DAV:}lockdiscovery', function () use ($propFind) {
90
-            return new DAV\Xml\Property\LockDiscovery(
91
-                $this->getLocks($propFind->getPath())
92
-            );
93
-        });
94
-    }
95
-
96
-    /**
97
-     * Use this method to tell the server this plugin defines additional
98
-     * HTTP methods.
99
-     *
100
-     * This method is passed a uri. It should only return HTTP methods that are
101
-     * available for the specified uri.
102
-     *
103
-     * @param string $uri
104
-     *
105
-     * @return array
106
-     */
107
-    public function getHTTPMethods($uri)
108
-    {
109
-        return ['LOCK', 'UNLOCK'];
110
-    }
111
-
112
-    /**
113
-     * Returns a list of features for the HTTP OPTIONS Dav: header.
114
-     *
115
-     * In this case this is only the number 2. The 2 in the Dav: header
116
-     * indicates the server supports locks.
117
-     *
118
-     * @return array
119
-     */
120
-    public function getFeatures()
121
-    {
122
-        return [2];
123
-    }
124
-
125
-    /**
126
-     * Returns all lock information on a particular uri.
127
-     *
128
-     * This function should return an array with Sabre\DAV\Locks\LockInfo objects. If there are no locks on a file, return an empty array.
129
-     *
130
-     * Additionally there is also the possibility of locks on parent nodes, so we'll need to traverse every part of the tree
131
-     * If the $returnChildLocks argument is set to true, we'll also traverse all the children of the object
132
-     * for any possible locks and return those as well.
133
-     *
134
-     * @param string $uri
135
-     * @param bool   $returnChildLocks
136
-     *
137
-     * @return array
138
-     */
139
-    public function getLocks($uri, $returnChildLocks = false)
140
-    {
141
-        return $this->locksBackend->getLocks($uri, $returnChildLocks);
142
-    }
143
-
144
-    /**
145
-     * Locks an uri.
146
-     *
147
-     * The WebDAV lock request can be operated to either create a new lock on a file, or to refresh an existing lock
148
-     * If a new lock is created, a full XML body should be supplied, containing information about the lock such as the type
149
-     * of lock (shared or exclusive) and the owner of the lock
150
-     *
151
-     * If a lock is to be refreshed, no body should be supplied and there should be a valid If header containing the lock
152
-     *
153
-     * Additionally, a lock can be requested for a non-existent file. In these case we're obligated to create an empty file as per RFC4918:S7.3
154
-     *
155
-     * @return bool
156
-     */
157
-    public function httpLock(RequestInterface $request, ResponseInterface $response)
158
-    {
159
-        $uri = $request->getPath();
160
-
161
-        $existingLocks = $this->getLocks($uri);
162
-
163
-        if ($body = $request->getBodyAsString()) {
164
-            // This is a new lock request
165
-
166
-            $existingLock = null;
167
-            // Checking if there's already non-shared locks on the uri.
168
-            foreach ($existingLocks as $existingLock) {
169
-                if (LockInfo::EXCLUSIVE === $existingLock->scope) {
170
-                    throw new DAV\Exception\ConflictingLock($existingLock);
171
-                }
172
-            }
173
-
174
-            $lockInfo = $this->parseLockRequest($body);
175
-            $lockInfo->depth = $this->server->getHTTPDepth();
176
-            $lockInfo->uri = $uri;
177
-            if ($existingLock && LockInfo::SHARED != $lockInfo->scope) {
178
-                throw new DAV\Exception\ConflictingLock($existingLock);
179
-            }
180
-        } else {
181
-            // Gonna check if this was a lock refresh.
182
-            $existingLocks = $this->getLocks($uri);
183
-            $conditions = $this->server->getIfConditions($request);
184
-            $found = null;
185
-
186
-            foreach ($existingLocks as $existingLock) {
187
-                foreach ($conditions as $condition) {
188
-                    foreach ($condition['tokens'] as $token) {
189
-                        if ($token['token'] === 'opaquelocktoken:'.$existingLock->token) {
190
-                            $found = $existingLock;
191
-                            break 3;
192
-                        }
193
-                    }
194
-                }
195
-            }
196
-
197
-            // If none were found, this request is in error.
198
-            if (is_null($found)) {
199
-                if ($existingLocks) {
200
-                    throw new DAV\Exception\Locked(reset($existingLocks));
201
-                } else {
202
-                    throw new DAV\Exception\BadRequest('An xml body is required for lock requests');
203
-                }
204
-            }
205
-
206
-            // This must have been a lock refresh
207
-            $lockInfo = $found;
208
-
209
-            // The resource could have been locked through another uri.
210
-            if ($uri != $lockInfo->uri) {
211
-                $uri = $lockInfo->uri;
212
-            }
213
-        }
214
-
215
-        if ($timeout = $this->getTimeoutHeader()) {
216
-            $lockInfo->timeout = $timeout;
217
-        }
218
-
219
-        $newFile = false;
220
-
221
-        // If we got this far.. we should go check if this node actually exists. If this is not the case, we need to create it first
222
-        try {
223
-            $this->server->tree->getNodeForPath($uri);
224
-
225
-            // We need to call the beforeWriteContent event for RFC3744
226
-            // Edit: looks like this is not used, and causing problems now.
227
-            //
228
-            // See Issue 222
229
-            // $this->server->emit('beforeWriteContent',array($uri));
230
-        } catch (DAV\Exception\NotFound $e) {
231
-            // It didn't, lets create it
232
-            $this->server->createFile($uri, fopen('php://memory', 'r'));
233
-            $newFile = true;
234
-        }
235
-
236
-        $this->lockNode($uri, $lockInfo);
237
-
238
-        $response->setHeader('Content-Type', 'application/xml; charset=utf-8');
239
-        $response->setHeader('Lock-Token', '<opaquelocktoken:'.$lockInfo->token.'>');
240
-        $response->setStatus($newFile ? 201 : 200);
241
-        $response->setBody($this->generateLockResponse($lockInfo));
242
-
243
-        // Returning false will interrupt the event chain and mark this method
244
-        // as 'handled'.
245
-        return false;
246
-    }
247
-
248
-    /**
249
-     * Unlocks a uri.
250
-     *
251
-     * This WebDAV method allows you to remove a lock from a node. The client should provide a valid locktoken through the Lock-token http header
252
-     * The server should return 204 (No content) on success
253
-     */
254
-    public function httpUnlock(RequestInterface $request, ResponseInterface $response)
255
-    {
256
-        $lockToken = $request->getHeader('Lock-Token');
257
-
258
-        // If the locktoken header is not supplied, we need to throw a bad request exception
259
-        if (!$lockToken) {
260
-            throw new DAV\Exception\BadRequest('No lock token was supplied');
261
-        }
262
-        $path = $request->getPath();
263
-        $locks = $this->getLocks($path);
264
-
265
-        // Windows sometimes forgets to include < and > in the Lock-Token
266
-        // header
267
-        if ('<' !== $lockToken[0]) {
268
-            $lockToken = '<'.$lockToken.'>';
269
-        }
270
-
271
-        foreach ($locks as $lock) {
272
-            if ('<opaquelocktoken:'.$lock->token.'>' == $lockToken) {
273
-                $this->unlockNode($path, $lock);
274
-                $response->setHeader('Content-Length', '0');
275
-                $response->setStatus(204);
276
-
277
-                // Returning false will break the method chain, and mark the
278
-                // method as 'handled'.
279
-                return false;
280
-            }
281
-        }
282
-
283
-        // If we got here, it means the locktoken was invalid
284
-        throw new DAV\Exception\LockTokenMatchesRequestUri();
285
-    }
286
-
287
-    /**
288
-     * This method is called after a node is deleted.
289
-     *
290
-     * We use this event to clean up any locks that still exist on the node.
291
-     *
292
-     * @param string $path
293
-     */
294
-    public function afterUnbind($path)
295
-    {
296
-        $locks = $this->getLocks($path, $includeChildren = true);
297
-        foreach ($locks as $lock) {
298
-            // don't delete a lock on a parent dir
299
-            if (0 !== strpos($lock->uri, $path)) {
300
-                continue;
301
-            }
302
-            $this->unlockNode($path, $lock);
303
-        }
304
-    }
305
-
306
-    /**
307
-     * Locks a uri.
308
-     *
309
-     * All the locking information is supplied in the lockInfo object. The object has a suggested timeout, but this can be safely ignored
310
-     * It is important that if the existing timeout is ignored, the property is overwritten, as this needs to be sent back to the client
311
-     *
312
-     * @param string $uri
313
-     *
314
-     * @return bool
315
-     */
316
-    public function lockNode($uri, LockInfo $lockInfo)
317
-    {
318
-        if (!$this->server->emit('beforeLock', [$uri, $lockInfo])) {
319
-            return;
320
-        }
321
-
322
-        return $this->locksBackend->lock($uri, $lockInfo);
323
-    }
324
-
325
-    /**
326
-     * Unlocks a uri.
327
-     *
328
-     * This method removes a lock from a uri. It is assumed all the supplied information is correct and verified
329
-     *
330
-     * @param string $uri
331
-     *
332
-     * @return bool
333
-     */
334
-    public function unlockNode($uri, LockInfo $lockInfo)
335
-    {
336
-        if (!$this->server->emit('beforeUnlock', [$uri, $lockInfo])) {
337
-            return;
338
-        }
339
-
340
-        return $this->locksBackend->unlock($uri, $lockInfo);
341
-    }
342
-
343
-    /**
344
-     * Returns the contents of the HTTP Timeout header.
345
-     *
346
-     * The method formats the header into an integer.
347
-     *
348
-     * @return int
349
-     */
350
-    public function getTimeoutHeader()
351
-    {
352
-        $header = $this->server->httpRequest->getHeader('Timeout');
353
-
354
-        if ($header) {
355
-            if (0 === stripos($header, 'second-')) {
356
-                $header = (int) (substr($header, 7));
357
-            } elseif (0 === stripos($header, 'infinite')) {
358
-                $header = LockInfo::TIMEOUT_INFINITE;
359
-            } else {
360
-                throw new DAV\Exception\BadRequest('Invalid HTTP timeout header');
361
-            }
362
-        } else {
363
-            $header = 0;
364
-        }
365
-
366
-        return $header;
367
-    }
368
-
369
-    /**
370
-     * Generates the response for successful LOCK requests.
371
-     *
372
-     * @return string
373
-     */
374
-    protected function generateLockResponse(LockInfo $lockInfo)
375
-    {
376
-        return $this->server->xml->write('{DAV:}prop', [
377
-            '{DAV:}lockdiscovery' => new DAV\Xml\Property\LockDiscovery([$lockInfo]),
378
-        ], $this->server->getBaseUri());
379
-    }
380
-
381
-    /**
382
-     * The validateTokens event is triggered before every request.
383
-     *
384
-     * It's a moment where this plugin can check all the supplied lock tokens
385
-     * in the If: header, and check if they are valid.
386
-     *
387
-     * In addition, it will also ensure that it checks any missing lokens that
388
-     * must be present in the request, and reject requests without the proper
389
-     * tokens.
390
-     *
391
-     * @param mixed $conditions
392
-     */
393
-    public function validateTokens(RequestInterface $request, &$conditions)
394
-    {
395
-        // First we need to gather a list of locks that must be satisfied.
396
-        $mustLocks = [];
397
-        $method = $request->getMethod();
398
-
399
-        // Methods not in that list are operations that doesn't alter any
400
-        // resources, and we don't need to check the lock-states for.
401
-        switch ($method) {
402
-            case 'DELETE':
403
-                $mustLocks = array_merge($mustLocks, $this->getLocks(
404
-                    $request->getPath(),
405
-                    true
406
-                ));
407
-                break;
408
-            case 'MKCOL':
409
-            case 'MKCALENDAR':
410
-            case 'PROPPATCH':
411
-            case 'PUT':
412
-            case 'PATCH':
413
-                $mustLocks = array_merge($mustLocks, $this->getLocks(
414
-                    $request->getPath(),
415
-                    false
416
-                ));
417
-                break;
418
-            case 'MOVE':
419
-                $mustLocks = array_merge($mustLocks, $this->getLocks(
420
-                    $request->getPath(),
421
-                    true
422
-                ));
423
-                $mustLocks = array_merge($mustLocks, $this->getLocks(
424
-                    $this->server->calculateUri($request->getHeader('Destination')),
425
-                    false
426
-                ));
427
-                break;
428
-            case 'COPY':
429
-                $mustLocks = array_merge($mustLocks, $this->getLocks(
430
-                    $this->server->calculateUri($request->getHeader('Destination')),
431
-                    false
432
-                ));
433
-                break;
434
-            case 'LOCK':
435
-                //Temporary measure.. figure out later why this is needed
436
-                // Here we basically ignore all incoming tokens...
437
-                foreach ($conditions as $ii => $condition) {
438
-                    foreach ($condition['tokens'] as $jj => $token) {
439
-                        $conditions[$ii]['tokens'][$jj]['validToken'] = true;
440
-                    }
441
-                }
442
-
443
-                return;
444
-        }
445
-
446
-        // It's possible that there's identical locks, because of shared
447
-        // parents. We're removing the duplicates here.
448
-        $tmp = [];
449
-        foreach ($mustLocks as $lock) {
450
-            $tmp[$lock->token] = $lock;
451
-        }
452
-        $mustLocks = array_values($tmp);
453
-
454
-        foreach ($conditions as $kk => $condition) {
455
-            foreach ($condition['tokens'] as $ii => $token) {
456
-                // Lock tokens always start with opaquelocktoken:
457
-                if ('opaquelocktoken:' !== substr($token['token'], 0, 16)) {
458
-                    continue;
459
-                }
460
-
461
-                $checkToken = substr($token['token'], 16);
462
-                // Looping through our list with locks.
463
-                foreach ($mustLocks as $jj => $mustLock) {
464
-                    if ($mustLock->token == $checkToken) {
465
-                        // We have a match!
466
-                        // Removing this one from mustlocks
467
-                        unset($mustLocks[$jj]);
468
-
469
-                        // Marking the condition as valid.
470
-                        $conditions[$kk]['tokens'][$ii]['validToken'] = true;
471
-
472
-                        // Advancing to the next token
473
-                        continue 2;
474
-                    }
475
-                }
476
-
477
-                // If we got here, it means that there was a
478
-                // lock-token, but it was not in 'mustLocks'.
479
-                //
480
-                // This is an edge-case, as it could mean that token
481
-                // was specified with a url that was not 'required' to
482
-                // check. So we're doing one extra lookup to make sure
483
-                // we really don't know this token.
484
-                //
485
-                // This also gets triggered when the user specified a
486
-                // lock-token that was expired.
487
-                $oddLocks = $this->getLocks($condition['uri']);
488
-                foreach ($oddLocks as $oddLock) {
489
-                    if ($oddLock->token === $checkToken) {
490
-                        // We have a hit!
491
-                        $conditions[$kk]['tokens'][$ii]['validToken'] = true;
492
-                        continue 2;
493
-                    }
494
-                }
495
-
496
-                // If we get all the way here, the lock-token was
497
-                // really unknown.
498
-            }
499
-        }
500
-
501
-        // If there's any locks left in the 'mustLocks' array, it means that
502
-        // the resource was locked and we must block it.
503
-        if ($mustLocks) {
504
-            throw new DAV\Exception\Locked(reset($mustLocks));
505
-        }
506
-    }
507
-
508
-    /**
509
-     * Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object.
510
-     *
511
-     * @param string $body
512
-     *
513
-     * @return LockInfo
514
-     */
515
-    protected function parseLockRequest($body)
516
-    {
517
-        $result = $this->server->xml->expect(
518
-            '{DAV:}lockinfo',
519
-            $body
520
-        );
521
-
522
-        $lockInfo = new LockInfo();
523
-
524
-        $lockInfo->owner = $result->owner;
525
-        $lockInfo->token = DAV\UUIDUtil::getUUID();
526
-        $lockInfo->scope = $result->scope;
527
-
528
-        return $lockInfo;
529
-    }
530
-
531
-    /**
532
-     * Returns a bunch of meta-data about the plugin.
533
-     *
534
-     * Providing this information is optional, and is mainly displayed by the
535
-     * Browser plugin.
536
-     *
537
-     * The description key in the returned array may contain html and will not
538
-     * be sanitized.
539
-     *
540
-     * @return array
541
-     */
542
-    public function getPluginInfo()
543
-    {
544
-        return [
545
-            'name' => $this->getPluginName(),
546
-            'description' => 'The locks plugin turns this server into a class-2 WebDAV server and adds support for LOCK and UNLOCK',
547
-            'link' => 'http://sabre.io/dav/locks/',
548
-        ];
549
-    }
27
+	/**
28
+	 * locksBackend.
29
+	 *
30
+	 * @var Backend\BackendInterface
31
+	 */
32
+	protected $locksBackend;
33
+
34
+	/**
35
+	 * server.
36
+	 *
37
+	 * @var DAV\Server
38
+	 */
39
+	protected $server;
40
+
41
+	/**
42
+	 * __construct.
43
+	 */
44
+	public function __construct(Backend\BackendInterface $locksBackend)
45
+	{
46
+		$this->locksBackend = $locksBackend;
47
+	}
48
+
49
+	/**
50
+	 * Initializes the plugin.
51
+	 *
52
+	 * This method is automatically called by the Server class after addPlugin.
53
+	 */
54
+	public function initialize(DAV\Server $server)
55
+	{
56
+		$this->server = $server;
57
+
58
+		$this->server->xml->elementMap['{DAV:}lockinfo'] = 'Sabre\\DAV\\Xml\\Request\\Lock';
59
+
60
+		$server->on('method:LOCK', [$this, 'httpLock']);
61
+		$server->on('method:UNLOCK', [$this, 'httpUnlock']);
62
+		$server->on('validateTokens', [$this, 'validateTokens']);
63
+		$server->on('propFind', [$this, 'propFind']);
64
+		$server->on('afterUnbind', [$this, 'afterUnbind']);
65
+	}
66
+
67
+	/**
68
+	 * Returns a plugin name.
69
+	 *
70
+	 * Using this name other plugins will be able to access other plugins
71
+	 * using Sabre\DAV\Server::getPlugin
72
+	 *
73
+	 * @return string
74
+	 */
75
+	public function getPluginName()
76
+	{
77
+		return 'locks';
78
+	}
79
+
80
+	/**
81
+	 * This method is called after most properties have been found
82
+	 * it allows us to add in any Lock-related properties.
83
+	 */
84
+	public function propFind(DAV\PropFind $propFind, DAV\INode $node)
85
+	{
86
+		$propFind->handle('{DAV:}supportedlock', function () {
87
+			return new DAV\Xml\Property\SupportedLock();
88
+		});
89
+		$propFind->handle('{DAV:}lockdiscovery', function () use ($propFind) {
90
+			return new DAV\Xml\Property\LockDiscovery(
91
+				$this->getLocks($propFind->getPath())
92
+			);
93
+		});
94
+	}
95
+
96
+	/**
97
+	 * Use this method to tell the server this plugin defines additional
98
+	 * HTTP methods.
99
+	 *
100
+	 * This method is passed a uri. It should only return HTTP methods that are
101
+	 * available for the specified uri.
102
+	 *
103
+	 * @param string $uri
104
+	 *
105
+	 * @return array
106
+	 */
107
+	public function getHTTPMethods($uri)
108
+	{
109
+		return ['LOCK', 'UNLOCK'];
110
+	}
111
+
112
+	/**
113
+	 * Returns a list of features for the HTTP OPTIONS Dav: header.
114
+	 *
115
+	 * In this case this is only the number 2. The 2 in the Dav: header
116
+	 * indicates the server supports locks.
117
+	 *
118
+	 * @return array
119
+	 */
120
+	public function getFeatures()
121
+	{
122
+		return [2];
123
+	}
124
+
125
+	/**
126
+	 * Returns all lock information on a particular uri.
127
+	 *
128
+	 * This function should return an array with Sabre\DAV\Locks\LockInfo objects. If there are no locks on a file, return an empty array.
129
+	 *
130
+	 * Additionally there is also the possibility of locks on parent nodes, so we'll need to traverse every part of the tree
131
+	 * If the $returnChildLocks argument is set to true, we'll also traverse all the children of the object
132
+	 * for any possible locks and return those as well.
133
+	 *
134
+	 * @param string $uri
135
+	 * @param bool   $returnChildLocks
136
+	 *
137
+	 * @return array
138
+	 */
139
+	public function getLocks($uri, $returnChildLocks = false)
140
+	{
141
+		return $this->locksBackend->getLocks($uri, $returnChildLocks);
142
+	}
143
+
144
+	/**
145
+	 * Locks an uri.
146
+	 *
147
+	 * The WebDAV lock request can be operated to either create a new lock on a file, or to refresh an existing lock
148
+	 * If a new lock is created, a full XML body should be supplied, containing information about the lock such as the type
149
+	 * of lock (shared or exclusive) and the owner of the lock
150
+	 *
151
+	 * If a lock is to be refreshed, no body should be supplied and there should be a valid If header containing the lock
152
+	 *
153
+	 * Additionally, a lock can be requested for a non-existent file. In these case we're obligated to create an empty file as per RFC4918:S7.3
154
+	 *
155
+	 * @return bool
156
+	 */
157
+	public function httpLock(RequestInterface $request, ResponseInterface $response)
158
+	{
159
+		$uri = $request->getPath();
160
+
161
+		$existingLocks = $this->getLocks($uri);
162
+
163
+		if ($body = $request->getBodyAsString()) {
164
+			// This is a new lock request
165
+
166
+			$existingLock = null;
167
+			// Checking if there's already non-shared locks on the uri.
168
+			foreach ($existingLocks as $existingLock) {
169
+				if (LockInfo::EXCLUSIVE === $existingLock->scope) {
170
+					throw new DAV\Exception\ConflictingLock($existingLock);
171
+				}
172
+			}
173
+
174
+			$lockInfo = $this->parseLockRequest($body);
175
+			$lockInfo->depth = $this->server->getHTTPDepth();
176
+			$lockInfo->uri = $uri;
177
+			if ($existingLock && LockInfo::SHARED != $lockInfo->scope) {
178
+				throw new DAV\Exception\ConflictingLock($existingLock);
179
+			}
180
+		} else {
181
+			// Gonna check if this was a lock refresh.
182
+			$existingLocks = $this->getLocks($uri);
183
+			$conditions = $this->server->getIfConditions($request);
184
+			$found = null;
185
+
186
+			foreach ($existingLocks as $existingLock) {
187
+				foreach ($conditions as $condition) {
188
+					foreach ($condition['tokens'] as $token) {
189
+						if ($token['token'] === 'opaquelocktoken:'.$existingLock->token) {
190
+							$found = $existingLock;
191
+							break 3;
192
+						}
193
+					}
194
+				}
195
+			}
196
+
197
+			// If none were found, this request is in error.
198
+			if (is_null($found)) {
199
+				if ($existingLocks) {
200
+					throw new DAV\Exception\Locked(reset($existingLocks));
201
+				} else {
202
+					throw new DAV\Exception\BadRequest('An xml body is required for lock requests');
203
+				}
204
+			}
205
+
206
+			// This must have been a lock refresh
207
+			$lockInfo = $found;
208
+
209
+			// The resource could have been locked through another uri.
210
+			if ($uri != $lockInfo->uri) {
211
+				$uri = $lockInfo->uri;
212
+			}
213
+		}
214
+
215
+		if ($timeout = $this->getTimeoutHeader()) {
216
+			$lockInfo->timeout = $timeout;
217
+		}
218
+
219
+		$newFile = false;
220
+
221
+		// If we got this far.. we should go check if this node actually exists. If this is not the case, we need to create it first
222
+		try {
223
+			$this->server->tree->getNodeForPath($uri);
224
+
225
+			// We need to call the beforeWriteContent event for RFC3744
226
+			// Edit: looks like this is not used, and causing problems now.
227
+			//
228
+			// See Issue 222
229
+			// $this->server->emit('beforeWriteContent',array($uri));
230
+		} catch (DAV\Exception\NotFound $e) {
231
+			// It didn't, lets create it
232
+			$this->server->createFile($uri, fopen('php://memory', 'r'));
233
+			$newFile = true;
234
+		}
235
+
236
+		$this->lockNode($uri, $lockInfo);
237
+
238
+		$response->setHeader('Content-Type', 'application/xml; charset=utf-8');
239
+		$response->setHeader('Lock-Token', '<opaquelocktoken:'.$lockInfo->token.'>');
240
+		$response->setStatus($newFile ? 201 : 200);
241
+		$response->setBody($this->generateLockResponse($lockInfo));
242
+
243
+		// Returning false will interrupt the event chain and mark this method
244
+		// as 'handled'.
245
+		return false;
246
+	}
247
+
248
+	/**
249
+	 * Unlocks a uri.
250
+	 *
251
+	 * This WebDAV method allows you to remove a lock from a node. The client should provide a valid locktoken through the Lock-token http header
252
+	 * The server should return 204 (No content) on success
253
+	 */
254
+	public function httpUnlock(RequestInterface $request, ResponseInterface $response)
255
+	{
256
+		$lockToken = $request->getHeader('Lock-Token');
257
+
258
+		// If the locktoken header is not supplied, we need to throw a bad request exception
259
+		if (!$lockToken) {
260
+			throw new DAV\Exception\BadRequest('No lock token was supplied');
261
+		}
262
+		$path = $request->getPath();
263
+		$locks = $this->getLocks($path);
264
+
265
+		// Windows sometimes forgets to include < and > in the Lock-Token
266
+		// header
267
+		if ('<' !== $lockToken[0]) {
268
+			$lockToken = '<'.$lockToken.'>';
269
+		}
270
+
271
+		foreach ($locks as $lock) {
272
+			if ('<opaquelocktoken:'.$lock->token.'>' == $lockToken) {
273
+				$this->unlockNode($path, $lock);
274
+				$response->setHeader('Content-Length', '0');
275
+				$response->setStatus(204);
276
+
277
+				// Returning false will break the method chain, and mark the
278
+				// method as 'handled'.
279
+				return false;
280
+			}
281
+		}
282
+
283
+		// If we got here, it means the locktoken was invalid
284
+		throw new DAV\Exception\LockTokenMatchesRequestUri();
285
+	}
286
+
287
+	/**
288
+	 * This method is called after a node is deleted.
289
+	 *
290
+	 * We use this event to clean up any locks that still exist on the node.
291
+	 *
292
+	 * @param string $path
293
+	 */
294
+	public function afterUnbind($path)
295
+	{
296
+		$locks = $this->getLocks($path, $includeChildren = true);
297
+		foreach ($locks as $lock) {
298
+			// don't delete a lock on a parent dir
299
+			if (0 !== strpos($lock->uri, $path)) {
300
+				continue;
301
+			}
302
+			$this->unlockNode($path, $lock);
303
+		}
304
+	}
305
+
306
+	/**
307
+	 * Locks a uri.
308
+	 *
309
+	 * All the locking information is supplied in the lockInfo object. The object has a suggested timeout, but this can be safely ignored
310
+	 * It is important that if the existing timeout is ignored, the property is overwritten, as this needs to be sent back to the client
311
+	 *
312
+	 * @param string $uri
313
+	 *
314
+	 * @return bool
315
+	 */
316
+	public function lockNode($uri, LockInfo $lockInfo)
317
+	{
318
+		if (!$this->server->emit('beforeLock', [$uri, $lockInfo])) {
319
+			return;
320
+		}
321
+
322
+		return $this->locksBackend->lock($uri, $lockInfo);
323
+	}
324
+
325
+	/**
326
+	 * Unlocks a uri.
327
+	 *
328
+	 * This method removes a lock from a uri. It is assumed all the supplied information is correct and verified
329
+	 *
330
+	 * @param string $uri
331
+	 *
332
+	 * @return bool
333
+	 */
334
+	public function unlockNode($uri, LockInfo $lockInfo)
335
+	{
336
+		if (!$this->server->emit('beforeUnlock', [$uri, $lockInfo])) {
337
+			return;
338
+		}
339
+
340
+		return $this->locksBackend->unlock($uri, $lockInfo);
341
+	}
342
+
343
+	/**
344
+	 * Returns the contents of the HTTP Timeout header.
345
+	 *
346
+	 * The method formats the header into an integer.
347
+	 *
348
+	 * @return int
349
+	 */
350
+	public function getTimeoutHeader()
351
+	{
352
+		$header = $this->server->httpRequest->getHeader('Timeout');
353
+
354
+		if ($header) {
355
+			if (0 === stripos($header, 'second-')) {
356
+				$header = (int) (substr($header, 7));
357
+			} elseif (0 === stripos($header, 'infinite')) {
358
+				$header = LockInfo::TIMEOUT_INFINITE;
359
+			} else {
360
+				throw new DAV\Exception\BadRequest('Invalid HTTP timeout header');
361
+			}
362
+		} else {
363
+			$header = 0;
364
+		}
365
+
366
+		return $header;
367
+	}
368
+
369
+	/**
370
+	 * Generates the response for successful LOCK requests.
371
+	 *
372
+	 * @return string
373
+	 */
374
+	protected function generateLockResponse(LockInfo $lockInfo)
375
+	{
376
+		return $this->server->xml->write('{DAV:}prop', [
377
+			'{DAV:}lockdiscovery' => new DAV\Xml\Property\LockDiscovery([$lockInfo]),
378
+		], $this->server->getBaseUri());
379
+	}
380
+
381
+	/**
382
+	 * The validateTokens event is triggered before every request.
383
+	 *
384
+	 * It's a moment where this plugin can check all the supplied lock tokens
385
+	 * in the If: header, and check if they are valid.
386
+	 *
387
+	 * In addition, it will also ensure that it checks any missing lokens that
388
+	 * must be present in the request, and reject requests without the proper
389
+	 * tokens.
390
+	 *
391
+	 * @param mixed $conditions
392
+	 */
393
+	public function validateTokens(RequestInterface $request, &$conditions)
394
+	{
395
+		// First we need to gather a list of locks that must be satisfied.
396
+		$mustLocks = [];
397
+		$method = $request->getMethod();
398
+
399
+		// Methods not in that list are operations that doesn't alter any
400
+		// resources, and we don't need to check the lock-states for.
401
+		switch ($method) {
402
+			case 'DELETE':
403
+				$mustLocks = array_merge($mustLocks, $this->getLocks(
404
+					$request->getPath(),
405
+					true
406
+				));
407
+				break;
408
+			case 'MKCOL':
409
+			case 'MKCALENDAR':
410
+			case 'PROPPATCH':
411
+			case 'PUT':
412
+			case 'PATCH':
413
+				$mustLocks = array_merge($mustLocks, $this->getLocks(
414
+					$request->getPath(),
415
+					false
416
+				));
417
+				break;
418
+			case 'MOVE':
419
+				$mustLocks = array_merge($mustLocks, $this->getLocks(
420
+					$request->getPath(),
421
+					true
422
+				));
423
+				$mustLocks = array_merge($mustLocks, $this->getLocks(
424
+					$this->server->calculateUri($request->getHeader('Destination')),
425
+					false
426
+				));
427
+				break;
428
+			case 'COPY':
429
+				$mustLocks = array_merge($mustLocks, $this->getLocks(
430
+					$this->server->calculateUri($request->getHeader('Destination')),
431
+					false
432
+				));
433
+				break;
434
+			case 'LOCK':
435
+				//Temporary measure.. figure out later why this is needed
436
+				// Here we basically ignore all incoming tokens...
437
+				foreach ($conditions as $ii => $condition) {
438
+					foreach ($condition['tokens'] as $jj => $token) {
439
+						$conditions[$ii]['tokens'][$jj]['validToken'] = true;
440
+					}
441
+				}
442
+
443
+				return;
444
+		}
445
+
446
+		// It's possible that there's identical locks, because of shared
447
+		// parents. We're removing the duplicates here.
448
+		$tmp = [];
449
+		foreach ($mustLocks as $lock) {
450
+			$tmp[$lock->token] = $lock;
451
+		}
452
+		$mustLocks = array_values($tmp);
453
+
454
+		foreach ($conditions as $kk => $condition) {
455
+			foreach ($condition['tokens'] as $ii => $token) {
456
+				// Lock tokens always start with opaquelocktoken:
457
+				if ('opaquelocktoken:' !== substr($token['token'], 0, 16)) {
458
+					continue;
459
+				}
460
+
461
+				$checkToken = substr($token['token'], 16);
462
+				// Looping through our list with locks.
463
+				foreach ($mustLocks as $jj => $mustLock) {
464
+					if ($mustLock->token == $checkToken) {
465
+						// We have a match!
466
+						// Removing this one from mustlocks
467
+						unset($mustLocks[$jj]);
468
+
469
+						// Marking the condition as valid.
470
+						$conditions[$kk]['tokens'][$ii]['validToken'] = true;
471
+
472
+						// Advancing to the next token
473
+						continue 2;
474
+					}
475
+				}
476
+
477
+				// If we got here, it means that there was a
478
+				// lock-token, but it was not in 'mustLocks'.
479
+				//
480
+				// This is an edge-case, as it could mean that token
481
+				// was specified with a url that was not 'required' to
482
+				// check. So we're doing one extra lookup to make sure
483
+				// we really don't know this token.
484
+				//
485
+				// This also gets triggered when the user specified a
486
+				// lock-token that was expired.
487
+				$oddLocks = $this->getLocks($condition['uri']);
488
+				foreach ($oddLocks as $oddLock) {
489
+					if ($oddLock->token === $checkToken) {
490
+						// We have a hit!
491
+						$conditions[$kk]['tokens'][$ii]['validToken'] = true;
492
+						continue 2;
493
+					}
494
+				}
495
+
496
+				// If we get all the way here, the lock-token was
497
+				// really unknown.
498
+			}
499
+		}
500
+
501
+		// If there's any locks left in the 'mustLocks' array, it means that
502
+		// the resource was locked and we must block it.
503
+		if ($mustLocks) {
504
+			throw new DAV\Exception\Locked(reset($mustLocks));
505
+		}
506
+	}
507
+
508
+	/**
509
+	 * Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object.
510
+	 *
511
+	 * @param string $body
512
+	 *
513
+	 * @return LockInfo
514
+	 */
515
+	protected function parseLockRequest($body)
516
+	{
517
+		$result = $this->server->xml->expect(
518
+			'{DAV:}lockinfo',
519
+			$body
520
+		);
521
+
522
+		$lockInfo = new LockInfo();
523
+
524
+		$lockInfo->owner = $result->owner;
525
+		$lockInfo->token = DAV\UUIDUtil::getUUID();
526
+		$lockInfo->scope = $result->scope;
527
+
528
+		return $lockInfo;
529
+	}
530
+
531
+	/**
532
+	 * Returns a bunch of meta-data about the plugin.
533
+	 *
534
+	 * Providing this information is optional, and is mainly displayed by the
535
+	 * Browser plugin.
536
+	 *
537
+	 * The description key in the returned array may contain html and will not
538
+	 * be sanitized.
539
+	 *
540
+	 * @return array
541
+	 */
542
+	public function getPluginInfo()
543
+	{
544
+		return [
545
+			'name' => $this->getPluginName(),
546
+			'description' => 'The locks plugin turns this server into a class-2 WebDAV server and adds support for LOCK and UNLOCK',
547
+			'link' => 'http://sabre.io/dav/locks/',
548
+		];
549
+	}
550 550
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -83,10 +83,10 @@
 block discarded – undo
83 83
      */
84 84
     public function propFind(DAV\PropFind $propFind, DAV\INode $node)
85 85
     {
86
-        $propFind->handle('{DAV:}supportedlock', function () {
86
+        $propFind->handle('{DAV:}supportedlock', function() {
87 87
             return new DAV\Xml\Property\SupportedLock();
88 88
         });
89
-        $propFind->handle('{DAV:}lockdiscovery', function () use ($propFind) {
89
+        $propFind->handle('{DAV:}lockdiscovery', function() use ($propFind) {
90 90
             return new DAV\Xml\Property\LockDiscovery(
91 91
                 $this->getLocks($propFind->getPath())
92 92
             );
Please login to merge, or discard this patch.
htdocs/includes/sabre/sabre/dav/lib/DAV/Locks/Backend/BackendInterface.php 1 patch
Indentation   +31 added lines, -31 removed lines patch added patch discarded remove patch
@@ -16,37 +16,37 @@
 block discarded – undo
16 16
  */
17 17
 interface BackendInterface
18 18
 {
19
-    /**
20
-     * Returns a list of Sabre\DAV\Locks\LockInfo objects.
21
-     *
22
-     * This method should return all the locks for a particular uri, including
23
-     * locks that might be set on a parent uri.
24
-     *
25
-     * If returnChildLocks is set to true, this method should also look for
26
-     * any locks in the subtree of the uri for locks.
27
-     *
28
-     * @param string $uri
29
-     * @param bool   $returnChildLocks
30
-     *
31
-     * @return array
32
-     */
33
-    public function getLocks($uri, $returnChildLocks);
19
+	/**
20
+	 * Returns a list of Sabre\DAV\Locks\LockInfo objects.
21
+	 *
22
+	 * This method should return all the locks for a particular uri, including
23
+	 * locks that might be set on a parent uri.
24
+	 *
25
+	 * If returnChildLocks is set to true, this method should also look for
26
+	 * any locks in the subtree of the uri for locks.
27
+	 *
28
+	 * @param string $uri
29
+	 * @param bool   $returnChildLocks
30
+	 *
31
+	 * @return array
32
+	 */
33
+	public function getLocks($uri, $returnChildLocks);
34 34
 
35
-    /**
36
-     * Locks a uri.
37
-     *
38
-     * @param string $uri
39
-     *
40
-     * @return bool
41
-     */
42
-    public function lock($uri, Locks\LockInfo $lockInfo);
35
+	/**
36
+	 * Locks a uri.
37
+	 *
38
+	 * @param string $uri
39
+	 *
40
+	 * @return bool
41
+	 */
42
+	public function lock($uri, Locks\LockInfo $lockInfo);
43 43
 
44
-    /**
45
-     * Removes a lock from a uri.
46
-     *
47
-     * @param string $uri
48
-     *
49
-     * @return bool
50
-     */
51
-    public function unlock($uri, Locks\LockInfo $lockInfo);
44
+	/**
45
+	 * Removes a lock from a uri.
46
+	 *
47
+	 * @param string $uri
48
+	 *
49
+	 * @return bool
50
+	 */
51
+	public function unlock($uri, Locks\LockInfo $lockInfo);
52 52
 }
Please login to merge, or discard this patch.