Completed
Pull Request — master (#7075)
by Morris
35:13 queued 21:00
created
lib/private/legacy/files.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -338,7 +338,7 @@
 block discarded – undo
338 338
 	 *
339 339
 	 * @param int $size file size in bytes
340 340
 	 * @param array $files override '.htaccess' and '.user.ini' locations
341
-	 * @return bool|int false on failure, size on success
341
+	 * @return integer false on failure, size on success
342 342
 	 */
343 343
 	public static function setUploadLimit($size, $files = []) {
344 344
 		//don't allow user to break his config
Please login to merge, or discard this patch.
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -46,396 +46,396 @@
 block discarded – undo
46 46
  *
47 47
  */
48 48
 class OC_Files {
49
-	const FILE = 1;
50
-	const ZIP_FILES = 2;
51
-	const ZIP_DIR = 3;
52
-
53
-	const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
54
-
55
-
56
-	private static $multipartBoundary = '';
57
-
58
-	/**
59
-	 * @return string
60
-	 */
61
-	private static function getBoundary() {
62
-		if (empty(self::$multipartBoundary)) {
63
-			self::$multipartBoundary = md5(mt_rand());
64
-		}
65
-		return self::$multipartBoundary;
66
-	}
67
-
68
-	/**
69
-	 * @param string $filename
70
-	 * @param string $name
71
-	 * @param array $rangeArray ('from'=>int,'to'=>int), ...
72
-	 */
73
-	private static function sendHeaders($filename, $name, array $rangeArray) {
74
-		OC_Response::setContentDispositionHeader($name, 'attachment');
75
-		header('Content-Transfer-Encoding: binary', true);
76
-		OC_Response::disableCaching();
77
-		$fileSize = \OC\Files\Filesystem::filesize($filename);
78
-		$type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
79
-		if ($fileSize > -1) {
80
-			if (!empty($rangeArray)) {
81
-			    header('HTTP/1.1 206 Partial Content', true);
82
-			    header('Accept-Ranges: bytes', true);
83
-			    if (count($rangeArray) > 1) {
84
-				$type = 'multipart/byteranges; boundary='.self::getBoundary();
85
-				// no Content-Length header here
86
-			    }
87
-			    else {
88
-				header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
89
-				OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
90
-			    }
91
-			}
92
-			else {
93
-			    OC_Response::setContentLengthHeader($fileSize);
94
-			}
95
-		}
96
-		header('Content-Type: '.$type, true);
97
-	}
98
-
99
-	/**
100
-	 * return the content of a file or return a zip file containing multiple files
101
-	 *
102
-	 * @param string $dir
103
-	 * @param string $files ; separated list of files to download
104
-	 * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
105
-	 */
106
-	public static function get($dir, $files, $params = null) {
107
-
108
-		$view = \OC\Files\Filesystem::getView();
109
-		$getType = self::FILE;
110
-		$filename = $dir;
111
-		try {
112
-
113
-			if (is_array($files) && count($files) === 1) {
114
-				$files = $files[0];
115
-			}
116
-
117
-			if (!is_array($files)) {
118
-				$filename = $dir . '/' . $files;
119
-				if (!$view->is_dir($filename)) {
120
-					self::getSingleFile($view, $dir, $files, is_null($params) ? array() : $params);
121
-					return;
122
-				}
123
-			}
124
-
125
-			$name = 'download';
126
-			if (is_array($files)) {
127
-				$getType = self::ZIP_FILES;
128
-				$basename = basename($dir);
129
-				if ($basename) {
130
-					$name = $basename;
131
-				}
132
-
133
-				$filename = $dir . '/' . $name;
134
-			} else {
135
-				$filename = $dir . '/' . $files;
136
-				$getType = self::ZIP_DIR;
137
-				// downloading root ?
138
-				if ($files !== '') {
139
-					$name = $files;
140
-				}
141
-			}
142
-
143
-			$streamer = new Streamer();
144
-			OC_Util::obEnd();
145
-
146
-			self::lockFiles($view, $dir, $files);
147
-
148
-			$streamer->sendHeaders($name);
149
-			$executionTime = intval(OC::$server->getIniWrapper()->getNumeric('max_execution_time'));
150
-			if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
151
-				@set_time_limit(0);
152
-			}
153
-			ignore_user_abort(true);
154
-			if ($getType === self::ZIP_FILES) {
155
-				foreach ($files as $file) {
156
-					$file = $dir . '/' . $file;
157
-					if (\OC\Files\Filesystem::is_file($file)) {
158
-						$fileSize = \OC\Files\Filesystem::filesize($file);
159
-						$fileTime = \OC\Files\Filesystem::filemtime($file);
160
-						$fh = \OC\Files\Filesystem::fopen($file, 'r');
161
-						$streamer->addFileFromStream($fh, basename($file), $fileSize, $fileTime);
162
-						fclose($fh);
163
-					} elseif (\OC\Files\Filesystem::is_dir($file)) {
164
-						$streamer->addDirRecursive($file);
165
-					}
166
-				}
167
-			} elseif ($getType === self::ZIP_DIR) {
168
-				$file = $dir . '/' . $files;
169
-				$streamer->addDirRecursive($file);
170
-			}
171
-			$streamer->finalize();
172
-			set_time_limit($executionTime);
173
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
174
-		} catch (\OCP\Lock\LockedException $ex) {
175
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
176
-			OC::$server->getLogger()->logException($ex);
177
-			$l = \OC::$server->getL10N('core');
178
-			$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
179
-			\OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint);
180
-		} catch (\OCP\Files\ForbiddenException $ex) {
181
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
182
-			OC::$server->getLogger()->logException($ex);
183
-			$l = \OC::$server->getL10N('core');
184
-			\OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage());
185
-		} catch (\Exception $ex) {
186
-			self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
187
-			OC::$server->getLogger()->logException($ex);
188
-			$l = \OC::$server->getL10N('core');
189
-			$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
190
-			\OC_Template::printErrorPage($l->t('Can\'t read file'), $hint);
191
-		}
192
-	}
193
-
194
-	/**
195
-	 * @param string $rangeHeaderPos
196
-	 * @param int $fileSize
197
-	 * @return array $rangeArray ('from'=>int,'to'=>int), ...
198
-	 */
199
-	private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
200
-		$rArray=explode(',', $rangeHeaderPos);
201
-		$minOffset = 0;
202
-		$ind = 0;
203
-
204
-		$rangeArray = array();
205
-
206
-		foreach ($rArray as $value) {
207
-			$ranges = explode('-', $value);
208
-			if (is_numeric($ranges[0])) {
209
-				if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
210
-					$ranges[0] = $minOffset;
211
-				}
212
-				if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999
213
-					$ind--;
214
-					$ranges[0] = $rangeArray[$ind]['from'];
215
-				}
216
-			}
217
-
218
-			if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
219
-				// case: x-x
220
-				if ($ranges[1] >= $fileSize) {
221
-					$ranges[1] = $fileSize-1;
222
-				}
223
-				$rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize );
224
-				$minOffset = $ranges[1] + 1;
225
-				if ($minOffset >= $fileSize) {
226
-					break;
227
-				}
228
-			}
229
-			elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
230
-				// case: x-
231
-				$rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize );
232
-				break;
233
-			}
234
-			elseif (is_numeric($ranges[1])) {
235
-				// case: -x
236
-				if ($ranges[1] > $fileSize) {
237
-					$ranges[1] = $fileSize;
238
-				}
239
-				$rangeArray[$ind++] = array( 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize );
240
-				break;
241
-			}
242
-		}
243
-		return $rangeArray;
244
-	}
245
-
246
-	/**
247
-	 * @param View $view
248
-	 * @param string $name
249
-	 * @param string $dir
250
-	 * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
251
-	 */
252
-	private static function getSingleFile($view, $dir, $name, $params) {
253
-		$filename = $dir . '/' . $name;
254
-		OC_Util::obEnd();
255
-		$view->lockFile($filename, ILockingProvider::LOCK_SHARED);
49
+    const FILE = 1;
50
+    const ZIP_FILES = 2;
51
+    const ZIP_DIR = 3;
52
+
53
+    const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
54
+
55
+
56
+    private static $multipartBoundary = '';
57
+
58
+    /**
59
+     * @return string
60
+     */
61
+    private static function getBoundary() {
62
+        if (empty(self::$multipartBoundary)) {
63
+            self::$multipartBoundary = md5(mt_rand());
64
+        }
65
+        return self::$multipartBoundary;
66
+    }
67
+
68
+    /**
69
+     * @param string $filename
70
+     * @param string $name
71
+     * @param array $rangeArray ('from'=>int,'to'=>int), ...
72
+     */
73
+    private static function sendHeaders($filename, $name, array $rangeArray) {
74
+        OC_Response::setContentDispositionHeader($name, 'attachment');
75
+        header('Content-Transfer-Encoding: binary', true);
76
+        OC_Response::disableCaching();
77
+        $fileSize = \OC\Files\Filesystem::filesize($filename);
78
+        $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
79
+        if ($fileSize > -1) {
80
+            if (!empty($rangeArray)) {
81
+                header('HTTP/1.1 206 Partial Content', true);
82
+                header('Accept-Ranges: bytes', true);
83
+                if (count($rangeArray) > 1) {
84
+                $type = 'multipart/byteranges; boundary='.self::getBoundary();
85
+                // no Content-Length header here
86
+                }
87
+                else {
88
+                header(sprintf('Content-Range: bytes %d-%d/%d', $rangeArray[0]['from'], $rangeArray[0]['to'], $fileSize), true);
89
+                OC_Response::setContentLengthHeader($rangeArray[0]['to'] - $rangeArray[0]['from'] + 1);
90
+                }
91
+            }
92
+            else {
93
+                OC_Response::setContentLengthHeader($fileSize);
94
+            }
95
+        }
96
+        header('Content-Type: '.$type, true);
97
+    }
98
+
99
+    /**
100
+     * return the content of a file or return a zip file containing multiple files
101
+     *
102
+     * @param string $dir
103
+     * @param string $files ; separated list of files to download
104
+     * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
105
+     */
106
+    public static function get($dir, $files, $params = null) {
107
+
108
+        $view = \OC\Files\Filesystem::getView();
109
+        $getType = self::FILE;
110
+        $filename = $dir;
111
+        try {
112
+
113
+            if (is_array($files) && count($files) === 1) {
114
+                $files = $files[0];
115
+            }
116
+
117
+            if (!is_array($files)) {
118
+                $filename = $dir . '/' . $files;
119
+                if (!$view->is_dir($filename)) {
120
+                    self::getSingleFile($view, $dir, $files, is_null($params) ? array() : $params);
121
+                    return;
122
+                }
123
+            }
124
+
125
+            $name = 'download';
126
+            if (is_array($files)) {
127
+                $getType = self::ZIP_FILES;
128
+                $basename = basename($dir);
129
+                if ($basename) {
130
+                    $name = $basename;
131
+                }
132
+
133
+                $filename = $dir . '/' . $name;
134
+            } else {
135
+                $filename = $dir . '/' . $files;
136
+                $getType = self::ZIP_DIR;
137
+                // downloading root ?
138
+                if ($files !== '') {
139
+                    $name = $files;
140
+                }
141
+            }
142
+
143
+            $streamer = new Streamer();
144
+            OC_Util::obEnd();
145
+
146
+            self::lockFiles($view, $dir, $files);
147
+
148
+            $streamer->sendHeaders($name);
149
+            $executionTime = intval(OC::$server->getIniWrapper()->getNumeric('max_execution_time'));
150
+            if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
151
+                @set_time_limit(0);
152
+            }
153
+            ignore_user_abort(true);
154
+            if ($getType === self::ZIP_FILES) {
155
+                foreach ($files as $file) {
156
+                    $file = $dir . '/' . $file;
157
+                    if (\OC\Files\Filesystem::is_file($file)) {
158
+                        $fileSize = \OC\Files\Filesystem::filesize($file);
159
+                        $fileTime = \OC\Files\Filesystem::filemtime($file);
160
+                        $fh = \OC\Files\Filesystem::fopen($file, 'r');
161
+                        $streamer->addFileFromStream($fh, basename($file), $fileSize, $fileTime);
162
+                        fclose($fh);
163
+                    } elseif (\OC\Files\Filesystem::is_dir($file)) {
164
+                        $streamer->addDirRecursive($file);
165
+                    }
166
+                }
167
+            } elseif ($getType === self::ZIP_DIR) {
168
+                $file = $dir . '/' . $files;
169
+                $streamer->addDirRecursive($file);
170
+            }
171
+            $streamer->finalize();
172
+            set_time_limit($executionTime);
173
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
174
+        } catch (\OCP\Lock\LockedException $ex) {
175
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
176
+            OC::$server->getLogger()->logException($ex);
177
+            $l = \OC::$server->getL10N('core');
178
+            $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
179
+            \OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint);
180
+        } catch (\OCP\Files\ForbiddenException $ex) {
181
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
182
+            OC::$server->getLogger()->logException($ex);
183
+            $l = \OC::$server->getL10N('core');
184
+            \OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage());
185
+        } catch (\Exception $ex) {
186
+            self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
187
+            OC::$server->getLogger()->logException($ex);
188
+            $l = \OC::$server->getL10N('core');
189
+            $hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
190
+            \OC_Template::printErrorPage($l->t('Can\'t read file'), $hint);
191
+        }
192
+    }
193
+
194
+    /**
195
+     * @param string $rangeHeaderPos
196
+     * @param int $fileSize
197
+     * @return array $rangeArray ('from'=>int,'to'=>int), ...
198
+     */
199
+    private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
200
+        $rArray=explode(',', $rangeHeaderPos);
201
+        $minOffset = 0;
202
+        $ind = 0;
203
+
204
+        $rangeArray = array();
205
+
206
+        foreach ($rArray as $value) {
207
+            $ranges = explode('-', $value);
208
+            if (is_numeric($ranges[0])) {
209
+                if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
210
+                    $ranges[0] = $minOffset;
211
+                }
212
+                if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999
213
+                    $ind--;
214
+                    $ranges[0] = $rangeArray[$ind]['from'];
215
+                }
216
+            }
217
+
218
+            if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
219
+                // case: x-x
220
+                if ($ranges[1] >= $fileSize) {
221
+                    $ranges[1] = $fileSize-1;
222
+                }
223
+                $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize );
224
+                $minOffset = $ranges[1] + 1;
225
+                if ($minOffset >= $fileSize) {
226
+                    break;
227
+                }
228
+            }
229
+            elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
230
+                // case: x-
231
+                $rangeArray[$ind++] = array( 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize );
232
+                break;
233
+            }
234
+            elseif (is_numeric($ranges[1])) {
235
+                // case: -x
236
+                if ($ranges[1] > $fileSize) {
237
+                    $ranges[1] = $fileSize;
238
+                }
239
+                $rangeArray[$ind++] = array( 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize );
240
+                break;
241
+            }
242
+        }
243
+        return $rangeArray;
244
+    }
245
+
246
+    /**
247
+     * @param View $view
248
+     * @param string $name
249
+     * @param string $dir
250
+     * @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
251
+     */
252
+    private static function getSingleFile($view, $dir, $name, $params) {
253
+        $filename = $dir . '/' . $name;
254
+        OC_Util::obEnd();
255
+        $view->lockFile($filename, ILockingProvider::LOCK_SHARED);
256 256
 		
257
-		$rangeArray = array();
257
+        $rangeArray = array();
258 258
 
259
-		if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
260
-			$rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), 
261
-								 \OC\Files\Filesystem::filesize($filename));
262
-		}
259
+        if (isset($params['range']) && substr($params['range'], 0, 6) === 'bytes=') {
260
+            $rangeArray = self::parseHttpRangeHeader(substr($params['range'], 6), 
261
+                                    \OC\Files\Filesystem::filesize($filename));
262
+        }
263 263
 		
264
-		if (\OC\Files\Filesystem::isReadable($filename)) {
265
-			self::sendHeaders($filename, $name, $rangeArray);
266
-		} elseif (!\OC\Files\Filesystem::file_exists($filename)) {
267
-			header("HTTP/1.1 404 Not Found");
268
-			$tmpl = new OC_Template('', '404', 'guest');
269
-			$tmpl->printPage();
270
-			exit();
271
-		} else {
272
-			header("HTTP/1.1 403 Forbidden");
273
-			die('403 Forbidden');
274
-		}
275
-		if (isset($params['head']) && $params['head']) {
276
-			return;
277
-		}
278
-		if (!empty($rangeArray)) {
279
-			try {
280
-			    if (count($rangeArray) == 1) {
281
-				$view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
282
-			    }
283
-			    else {
284
-				// check if file is seekable (if not throw UnseekableException)
285
-				// we have to check it before body contents
286
-				$view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
287
-
288
-				$type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
289
-
290
-				foreach ($rangeArray as $range) {
291
-				    echo "\r\n--".self::getBoundary()."\r\n".
292
-				         "Content-type: ".$type."\r\n".
293
-				         "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
294
-				    $view->readfilePart($filename, $range['from'], $range['to']);
295
-				}
296
-				echo "\r\n--".self::getBoundary()."--\r\n";
297
-			    }
298
-			} catch (\OCP\Files\UnseekableException $ex) {
299
-			    // file is unseekable
300
-			    header_remove('Accept-Ranges');
301
-			    header_remove('Content-Range');
302
-			    header("HTTP/1.1 200 OK");
303
-			    self::sendHeaders($filename, $name, array());
304
-			    $view->readfile($filename);
305
-			}
306
-		}
307
-		else {
308
-		    $view->readfile($filename);
309
-		}
310
-	}
311
-
312
-	/**
313
-	 * @param View $view
314
-	 * @param string $dir
315
-	 * @param string[]|string $files
316
-	 */
317
-	public static function lockFiles($view, $dir, $files) {
318
-		if (!is_array($files)) {
319
-			$file = $dir . '/' . $files;
320
-			$files = [$file];
321
-		}
322
-		foreach ($files as $file) {
323
-			$file = $dir . '/' . $file;
324
-			$view->lockFile($file, ILockingProvider::LOCK_SHARED);
325
-			if ($view->is_dir($file)) {
326
-				$contents = $view->getDirectoryContent($file);
327
-				$contents = array_map(function($fileInfo) use ($file) {
328
-					/** @var \OCP\Files\FileInfo $fileInfo */
329
-					return $file . '/' . $fileInfo->getName();
330
-				}, $contents);
331
-				self::lockFiles($view, $dir, $contents);
332
-			}
333
-		}
334
-	}
335
-
336
-	/**
337
-	 * set the maximum upload size limit for apache hosts using .htaccess
338
-	 *
339
-	 * @param int $size file size in bytes
340
-	 * @param array $files override '.htaccess' and '.user.ini' locations
341
-	 * @return bool|int false on failure, size on success
342
-	 */
343
-	public static function setUploadLimit($size, $files = []) {
344
-		//don't allow user to break his config
345
-		$size = intval($size);
346
-		if ($size < self::UPLOAD_MIN_LIMIT_BYTES) {
347
-			return false;
348
-		}
349
-		$size = OC_Helper::phpFileSize($size);
350
-
351
-		$phpValueKeys = array(
352
-			'upload_max_filesize',
353
-			'post_max_size'
354
-		);
355
-
356
-		// default locations if not overridden by $files
357
-		$files = array_merge([
358
-			'.htaccess' => OC::$SERVERROOT . '/.htaccess',
359
-			'.user.ini' => OC::$SERVERROOT . '/.user.ini'
360
-		], $files);
361
-
362
-		$updateFiles = [
363
-			$files['.htaccess'] => [
364
-				'pattern' => '/php_value %1$s (\S)*/',
365
-				'setting' => 'php_value %1$s %2$s'
366
-			],
367
-			$files['.user.ini'] => [
368
-				'pattern' => '/%1$s=(\S)*/',
369
-				'setting' => '%1$s=%2$s'
370
-			]
371
-		];
372
-
373
-		$success = true;
374
-
375
-		foreach ($updateFiles as $filename => $patternMap) {
376
-			// suppress warnings from fopen()
377
-			$handle = @fopen($filename, 'r+');
378
-			if (!$handle) {
379
-				\OCP\Util::writeLog('files',
380
-					'Can\'t write upload limit to ' . $filename . '. Please check the file permissions',
381
-					\OCP\Util::WARN);
382
-				$success = false;
383
-				continue; // try to update as many files as possible
384
-			}
385
-
386
-			$content = '';
387
-			while (!feof($handle)) {
388
-				$content .= fread($handle, 1000);
389
-			}
390
-
391
-			foreach ($phpValueKeys as $key) {
392
-				$pattern = vsprintf($patternMap['pattern'], [$key]);
393
-				$setting = vsprintf($patternMap['setting'], [$key, $size]);
394
-				$hasReplaced = 0;
395
-				$newContent = preg_replace($pattern, $setting, $content, 2, $hasReplaced);
396
-				if ($newContent !== null) {
397
-					$content = $newContent;
398
-				}
399
-				if ($hasReplaced === 0) {
400
-					$content .= "\n" . $setting;
401
-				}
402
-			}
403
-
404
-			// write file back
405
-			ftruncate($handle, 0);
406
-			rewind($handle);
407
-			fwrite($handle, $content);
408
-
409
-			fclose($handle);
410
-		}
411
-
412
-		if ($success) {
413
-			return OC_Helper::computerFileSize($size);
414
-		}
415
-		return false;
416
-	}
417
-
418
-	/**
419
-	 * @param string $dir
420
-	 * @param $files
421
-	 * @param integer $getType
422
-	 * @param View $view
423
-	 * @param string $filename
424
-	 */
425
-	private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
426
-		if ($getType === self::FILE) {
427
-			$view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
428
-		}
429
-		if ($getType === self::ZIP_FILES) {
430
-			foreach ($files as $file) {
431
-				$file = $dir . '/' . $file;
432
-				$view->unlockFile($file, ILockingProvider::LOCK_SHARED);
433
-			}
434
-		}
435
-		if ($getType === self::ZIP_DIR) {
436
-			$file = $dir . '/' . $files;
437
-			$view->unlockFile($file, ILockingProvider::LOCK_SHARED);
438
-		}
439
-	}
264
+        if (\OC\Files\Filesystem::isReadable($filename)) {
265
+            self::sendHeaders($filename, $name, $rangeArray);
266
+        } elseif (!\OC\Files\Filesystem::file_exists($filename)) {
267
+            header("HTTP/1.1 404 Not Found");
268
+            $tmpl = new OC_Template('', '404', 'guest');
269
+            $tmpl->printPage();
270
+            exit();
271
+        } else {
272
+            header("HTTP/1.1 403 Forbidden");
273
+            die('403 Forbidden');
274
+        }
275
+        if (isset($params['head']) && $params['head']) {
276
+            return;
277
+        }
278
+        if (!empty($rangeArray)) {
279
+            try {
280
+                if (count($rangeArray) == 1) {
281
+                $view->readfilePart($filename, $rangeArray[0]['from'], $rangeArray[0]['to']);
282
+                }
283
+                else {
284
+                // check if file is seekable (if not throw UnseekableException)
285
+                // we have to check it before body contents
286
+                $view->readfilePart($filename, $rangeArray[0]['size'], $rangeArray[0]['size']);
287
+
288
+                $type = \OC::$server->getMimeTypeDetector()->getSecureMimeType(\OC\Files\Filesystem::getMimeType($filename));
289
+
290
+                foreach ($rangeArray as $range) {
291
+                    echo "\r\n--".self::getBoundary()."\r\n".
292
+                            "Content-type: ".$type."\r\n".
293
+                            "Content-range: bytes ".$range['from']."-".$range['to']."/".$range['size']."\r\n\r\n";
294
+                    $view->readfilePart($filename, $range['from'], $range['to']);
295
+                }
296
+                echo "\r\n--".self::getBoundary()."--\r\n";
297
+                }
298
+            } catch (\OCP\Files\UnseekableException $ex) {
299
+                // file is unseekable
300
+                header_remove('Accept-Ranges');
301
+                header_remove('Content-Range');
302
+                header("HTTP/1.1 200 OK");
303
+                self::sendHeaders($filename, $name, array());
304
+                $view->readfile($filename);
305
+            }
306
+        }
307
+        else {
308
+            $view->readfile($filename);
309
+        }
310
+    }
311
+
312
+    /**
313
+     * @param View $view
314
+     * @param string $dir
315
+     * @param string[]|string $files
316
+     */
317
+    public static function lockFiles($view, $dir, $files) {
318
+        if (!is_array($files)) {
319
+            $file = $dir . '/' . $files;
320
+            $files = [$file];
321
+        }
322
+        foreach ($files as $file) {
323
+            $file = $dir . '/' . $file;
324
+            $view->lockFile($file, ILockingProvider::LOCK_SHARED);
325
+            if ($view->is_dir($file)) {
326
+                $contents = $view->getDirectoryContent($file);
327
+                $contents = array_map(function($fileInfo) use ($file) {
328
+                    /** @var \OCP\Files\FileInfo $fileInfo */
329
+                    return $file . '/' . $fileInfo->getName();
330
+                }, $contents);
331
+                self::lockFiles($view, $dir, $contents);
332
+            }
333
+        }
334
+    }
335
+
336
+    /**
337
+     * set the maximum upload size limit for apache hosts using .htaccess
338
+     *
339
+     * @param int $size file size in bytes
340
+     * @param array $files override '.htaccess' and '.user.ini' locations
341
+     * @return bool|int false on failure, size on success
342
+     */
343
+    public static function setUploadLimit($size, $files = []) {
344
+        //don't allow user to break his config
345
+        $size = intval($size);
346
+        if ($size < self::UPLOAD_MIN_LIMIT_BYTES) {
347
+            return false;
348
+        }
349
+        $size = OC_Helper::phpFileSize($size);
350
+
351
+        $phpValueKeys = array(
352
+            'upload_max_filesize',
353
+            'post_max_size'
354
+        );
355
+
356
+        // default locations if not overridden by $files
357
+        $files = array_merge([
358
+            '.htaccess' => OC::$SERVERROOT . '/.htaccess',
359
+            '.user.ini' => OC::$SERVERROOT . '/.user.ini'
360
+        ], $files);
361
+
362
+        $updateFiles = [
363
+            $files['.htaccess'] => [
364
+                'pattern' => '/php_value %1$s (\S)*/',
365
+                'setting' => 'php_value %1$s %2$s'
366
+            ],
367
+            $files['.user.ini'] => [
368
+                'pattern' => '/%1$s=(\S)*/',
369
+                'setting' => '%1$s=%2$s'
370
+            ]
371
+        ];
372
+
373
+        $success = true;
374
+
375
+        foreach ($updateFiles as $filename => $patternMap) {
376
+            // suppress warnings from fopen()
377
+            $handle = @fopen($filename, 'r+');
378
+            if (!$handle) {
379
+                \OCP\Util::writeLog('files',
380
+                    'Can\'t write upload limit to ' . $filename . '. Please check the file permissions',
381
+                    \OCP\Util::WARN);
382
+                $success = false;
383
+                continue; // try to update as many files as possible
384
+            }
385
+
386
+            $content = '';
387
+            while (!feof($handle)) {
388
+                $content .= fread($handle, 1000);
389
+            }
390
+
391
+            foreach ($phpValueKeys as $key) {
392
+                $pattern = vsprintf($patternMap['pattern'], [$key]);
393
+                $setting = vsprintf($patternMap['setting'], [$key, $size]);
394
+                $hasReplaced = 0;
395
+                $newContent = preg_replace($pattern, $setting, $content, 2, $hasReplaced);
396
+                if ($newContent !== null) {
397
+                    $content = $newContent;
398
+                }
399
+                if ($hasReplaced === 0) {
400
+                    $content .= "\n" . $setting;
401
+                }
402
+            }
403
+
404
+            // write file back
405
+            ftruncate($handle, 0);
406
+            rewind($handle);
407
+            fwrite($handle, $content);
408
+
409
+            fclose($handle);
410
+        }
411
+
412
+        if ($success) {
413
+            return OC_Helper::computerFileSize($size);
414
+        }
415
+        return false;
416
+    }
417
+
418
+    /**
419
+     * @param string $dir
420
+     * @param $files
421
+     * @param integer $getType
422
+     * @param View $view
423
+     * @param string $filename
424
+     */
425
+    private static function unlockAllTheFiles($dir, $files, $getType, $view, $filename) {
426
+        if ($getType === self::FILE) {
427
+            $view->unlockFile($filename, ILockingProvider::LOCK_SHARED);
428
+        }
429
+        if ($getType === self::ZIP_FILES) {
430
+            foreach ($files as $file) {
431
+                $file = $dir . '/' . $file;
432
+                $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
433
+            }
434
+        }
435
+        if ($getType === self::ZIP_DIR) {
436
+            $file = $dir . '/' . $files;
437
+            $view->unlockFile($file, ILockingProvider::LOCK_SHARED);
438
+        }
439
+    }
440 440
 
441 441
 }
Please login to merge, or discard this patch.
apps/dav/lib/DAV/SystemPrincipalBackend.php 2 patches
Indentation   +161 added lines, -161 removed lines patch added patch discarded remove patch
@@ -27,165 +27,165 @@
 block discarded – undo
27 27
 
28 28
 class SystemPrincipalBackend extends AbstractBackend {
29 29
 
30
-	/**
31
-	 * Returns a list of principals based on a prefix.
32
-	 *
33
-	 * This prefix will often contain something like 'principals'. You are only
34
-	 * expected to return principals that are in this base path.
35
-	 *
36
-	 * You are expected to return at least a 'uri' for every user, you can
37
-	 * return any additional properties if you wish so. Common properties are:
38
-	 *   {DAV:}displayname
39
-	 *   {http://sabredav.org/ns}email-address - This is a custom SabreDAV
40
-	 *     field that's actually injected in a number of other properties. If
41
-	 *     you have an email address, use this property.
42
-	 *
43
-	 * @param string $prefixPath
44
-	 * @return array
45
-	 */
46
-	function getPrincipalsByPrefix($prefixPath) {
47
-		$principals = [];
48
-
49
-		if ($prefixPath === 'principals/system') {
50
-			$principals[] = [
51
-				'uri' => 'principals/system/system',
52
-				'{DAV:}displayname' => 'system',
53
-			];
54
-			$principals[] = [
55
-				'uri' => 'principals/system/public',
56
-				'{DAV:}displayname' => 'public',
57
-			];
58
-		}
59
-
60
-		return $principals;
61
-	}
62
-
63
-	/**
64
-	 * Returns a specific principal, specified by it's path.
65
-	 * The returned structure should be the exact same as from
66
-	 * getPrincipalsByPrefix.
67
-	 *
68
-	 * @param string $path
69
-	 * @return array
70
-	 */
71
-	function getPrincipalByPath($path) {
72
-
73
-		if ($path === 'principals/system/system') {
74
-			$principal = [
75
-				'uri' => 'principals/system/system',
76
-				'{DAV:}displayname' => 'system',
77
-			];
78
-			return $principal;
79
-		}
80
-		if ($path === 'principals/system/public') {
81
-			$principal = [
82
-				'uri' => 'principals/system/public',
83
-				'{DAV:}displayname' => 'public',
84
-			];
85
-			return $principal;
86
-		}
87
-
88
-		return null;
89
-	}
90
-
91
-	/**
92
-	 * Updates one ore more webdav properties on a principal.
93
-	 *
94
-	 * The list of mutations is stored in a Sabre\DAV\PropPatch object.
95
-	 * To do the actual updates, you must tell this object which properties
96
-	 * you're going to process with the handle() method.
97
-	 *
98
-	 * Calling the handle method is like telling the PropPatch object "I
99
-	 * promise I can handle updating this property".
100
-	 *
101
-	 * Read the PropPatch documentation for more info and examples.
102
-	 *
103
-	 * @param string $path
104
-	 * @param \Sabre\DAV\PropPatch $propPatch
105
-	 * @return void
106
-	 */
107
-	function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) {
108
-	}
109
-
110
-	/**
111
-	 * This method is used to search for principals matching a set of
112
-	 * properties.
113
-	 *
114
-	 * This search is specifically used by RFC3744's principal-property-search
115
-	 * REPORT.
116
-	 *
117
-	 * The actual search should be a unicode-non-case-sensitive search. The
118
-	 * keys in searchProperties are the WebDAV property names, while the values
119
-	 * are the property values to search on.
120
-	 *
121
-	 * By default, if multiple properties are submitted to this method, the
122
-	 * various properties should be combined with 'AND'. If $test is set to
123
-	 * 'anyof', it should be combined using 'OR'.
124
-	 *
125
-	 * This method should simply return an array with full principal uri's.
126
-	 *
127
-	 * If somebody attempted to search on a property the backend does not
128
-	 * support, you should simply return 0 results.
129
-	 *
130
-	 * You can also just return 0 results if you choose to not support
131
-	 * searching at all, but keep in mind that this may stop certain features
132
-	 * from working.
133
-	 *
134
-	 * @param string $prefixPath
135
-	 * @param array $searchProperties
136
-	 * @param string $test
137
-	 * @return array
138
-	 */
139
-	function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
140
-		return [];
141
-	}
142
-
143
-	/**
144
-	 * Returns the list of members for a group-principal
145
-	 *
146
-	 * @param string $principal
147
-	 * @return array
148
-	 */
149
-	function getGroupMemberSet($principal) {
150
-		// TODO: for now the group principal has only one member, the user itself
151
-		$principal = $this->getPrincipalByPath($principal);
152
-		if (!$principal) {
153
-			throw new \Sabre\DAV\Exception('Principal not found');
154
-		}
155
-
156
-		return [$principal['uri']];
157
-	}
158
-
159
-	/**
160
-	 * Returns the list of groups a principal is a member of
161
-	 *
162
-	 * @param string $principal
163
-	 * @return array
164
-	 */
165
-	function getGroupMembership($principal) {
166
-		list($prefix, ) = \Sabre\Uri\split($principal);
167
-
168
-		if ($prefix === 'principals/system') {
169
-			$principal = $this->getPrincipalByPath($principal);
170
-			if (!$principal) {
171
-				throw new \Sabre\DAV\Exception('Principal not found');
172
-			}
173
-
174
-			return [];
175
-		}
176
-		return [];
177
-	}
178
-
179
-	/**
180
-	 * Updates the list of group members for a group principal.
181
-	 *
182
-	 * The principals should be passed as a list of uri's.
183
-	 *
184
-	 * @param string $principal
185
-	 * @param array $members
186
-	 * @return void
187
-	 */
188
-	function setGroupMemberSet($principal, array $members) {
189
-		throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
190
-	}
30
+    /**
31
+     * Returns a list of principals based on a prefix.
32
+     *
33
+     * This prefix will often contain something like 'principals'. You are only
34
+     * expected to return principals that are in this base path.
35
+     *
36
+     * You are expected to return at least a 'uri' for every user, you can
37
+     * return any additional properties if you wish so. Common properties are:
38
+     *   {DAV:}displayname
39
+     *   {http://sabredav.org/ns}email-address - This is a custom SabreDAV
40
+     *     field that's actually injected in a number of other properties. If
41
+     *     you have an email address, use this property.
42
+     *
43
+     * @param string $prefixPath
44
+     * @return array
45
+     */
46
+    function getPrincipalsByPrefix($prefixPath) {
47
+        $principals = [];
48
+
49
+        if ($prefixPath === 'principals/system') {
50
+            $principals[] = [
51
+                'uri' => 'principals/system/system',
52
+                '{DAV:}displayname' => 'system',
53
+            ];
54
+            $principals[] = [
55
+                'uri' => 'principals/system/public',
56
+                '{DAV:}displayname' => 'public',
57
+            ];
58
+        }
59
+
60
+        return $principals;
61
+    }
62
+
63
+    /**
64
+     * Returns a specific principal, specified by it's path.
65
+     * The returned structure should be the exact same as from
66
+     * getPrincipalsByPrefix.
67
+     *
68
+     * @param string $path
69
+     * @return array
70
+     */
71
+    function getPrincipalByPath($path) {
72
+
73
+        if ($path === 'principals/system/system') {
74
+            $principal = [
75
+                'uri' => 'principals/system/system',
76
+                '{DAV:}displayname' => 'system',
77
+            ];
78
+            return $principal;
79
+        }
80
+        if ($path === 'principals/system/public') {
81
+            $principal = [
82
+                'uri' => 'principals/system/public',
83
+                '{DAV:}displayname' => 'public',
84
+            ];
85
+            return $principal;
86
+        }
87
+
88
+        return null;
89
+    }
90
+
91
+    /**
92
+     * Updates one ore more webdav properties on a principal.
93
+     *
94
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
95
+     * To do the actual updates, you must tell this object which properties
96
+     * you're going to process with the handle() method.
97
+     *
98
+     * Calling the handle method is like telling the PropPatch object "I
99
+     * promise I can handle updating this property".
100
+     *
101
+     * Read the PropPatch documentation for more info and examples.
102
+     *
103
+     * @param string $path
104
+     * @param \Sabre\DAV\PropPatch $propPatch
105
+     * @return void
106
+     */
107
+    function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) {
108
+    }
109
+
110
+    /**
111
+     * This method is used to search for principals matching a set of
112
+     * properties.
113
+     *
114
+     * This search is specifically used by RFC3744's principal-property-search
115
+     * REPORT.
116
+     *
117
+     * The actual search should be a unicode-non-case-sensitive search. The
118
+     * keys in searchProperties are the WebDAV property names, while the values
119
+     * are the property values to search on.
120
+     *
121
+     * By default, if multiple properties are submitted to this method, the
122
+     * various properties should be combined with 'AND'. If $test is set to
123
+     * 'anyof', it should be combined using 'OR'.
124
+     *
125
+     * This method should simply return an array with full principal uri's.
126
+     *
127
+     * If somebody attempted to search on a property the backend does not
128
+     * support, you should simply return 0 results.
129
+     *
130
+     * You can also just return 0 results if you choose to not support
131
+     * searching at all, but keep in mind that this may stop certain features
132
+     * from working.
133
+     *
134
+     * @param string $prefixPath
135
+     * @param array $searchProperties
136
+     * @param string $test
137
+     * @return array
138
+     */
139
+    function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
140
+        return [];
141
+    }
142
+
143
+    /**
144
+     * Returns the list of members for a group-principal
145
+     *
146
+     * @param string $principal
147
+     * @return array
148
+     */
149
+    function getGroupMemberSet($principal) {
150
+        // TODO: for now the group principal has only one member, the user itself
151
+        $principal = $this->getPrincipalByPath($principal);
152
+        if (!$principal) {
153
+            throw new \Sabre\DAV\Exception('Principal not found');
154
+        }
155
+
156
+        return [$principal['uri']];
157
+    }
158
+
159
+    /**
160
+     * Returns the list of groups a principal is a member of
161
+     *
162
+     * @param string $principal
163
+     * @return array
164
+     */
165
+    function getGroupMembership($principal) {
166
+        list($prefix, ) = \Sabre\Uri\split($principal);
167
+
168
+        if ($prefix === 'principals/system') {
169
+            $principal = $this->getPrincipalByPath($principal);
170
+            if (!$principal) {
171
+                throw new \Sabre\DAV\Exception('Principal not found');
172
+            }
173
+
174
+            return [];
175
+        }
176
+        return [];
177
+    }
178
+
179
+    /**
180
+     * Updates the list of group members for a group principal.
181
+     *
182
+     * The principals should be passed as a list of uri's.
183
+     *
184
+     * @param string $principal
185
+     * @param array $members
186
+     * @return void
187
+     */
188
+    function setGroupMemberSet($principal, array $members) {
189
+        throw new \Sabre\DAV\Exception('Setting members of the group is not supported yet');
190
+    }
191 191
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -163,7 +163,7 @@
 block discarded – undo
163 163
 	 * @return array
164 164
 	 */
165 165
 	function getGroupMembership($principal) {
166
-		list($prefix, ) = \Sabre\Uri\split($principal);
166
+		list($prefix,) = \Sabre\Uri\split($principal);
167 167
 
168 168
 		if ($prefix === 'principals/system') {
169 169
 			$principal = $this->getPrincipalByPath($principal);
Please login to merge, or discard this patch.
apps/files/lib/Command/ScanAppData.php 2 patches
Indentation   +262 added lines, -262 removed lines patch added patch discarded remove patch
@@ -19,266 +19,266 @@
 block discarded – undo
19 19
 
20 20
 class ScanAppData extends Base {
21 21
 
22
-	/** @var IRootFolder */
23
-	protected $root;
24
-	/** @var IConfig */
25
-	protected $config;
26
-	/** @var float */
27
-	protected $execTime = 0;
28
-	/** @var int */
29
-	protected $foldersCounter = 0;
30
-	/** @var int */
31
-	protected $filesCounter = 0;
32
-
33
-	public function __construct(IRootFolder $rootFolder, IConfig $config) {
34
-		parent::__construct();
35
-
36
-		$this->root = $rootFolder;
37
-		$this->config = $config;
38
-	}
39
-
40
-	protected function configure() {
41
-		parent::configure();
42
-
43
-		$this
44
-			->setName('files:scan-app-data')
45
-			->setDescription('rescan the AppData folder')
46
-			->addOption(
47
-				'quiet',
48
-				'q',
49
-				InputOption::VALUE_NONE,
50
-				'suppress any output'
51
-			)
52
-			->addOption(
53
-				'verbose',
54
-				'-v|vv|vvv',
55
-				InputOption::VALUE_NONE,
56
-				'verbose the output'
57
-			);
58
-	}
59
-
60
-	public function checkScanWarning($fullPath, OutputInterface $output) {
61
-		$normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
62
-		$path = basename($fullPath);
63
-
64
-		if ($normalizedPath !== $path) {
65
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
66
-		}
67
-	}
68
-
69
-	protected function scanFiles($verbose, OutputInterface $output) {
70
-		try {
71
-			$appData = $this->getAppDataFolder();
72
-		} catch (NotFoundException $e) {
73
-			$output->writeln('NoAppData folder found');
74
-			return;
75
-		}
76
-
77
-		$connection = $this->reconnectToDatabase($output);
78
-		$scanner = new \OC\Files\Utils\Scanner(null, $connection, \OC::$server->getLogger());
79
-		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
80
-		# printout and count
81
-		if ($verbose) {
82
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
83
-				$output->writeln("\tFile   <info>$path</info>");
84
-				$this->filesCounter += 1;
85
-				if ($this->hasBeenInterrupted()) {
86
-					throw new InterruptedException();
87
-				}
88
-			});
89
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
90
-				$output->writeln("\tFolder <info>$path</info>");
91
-				$this->foldersCounter += 1;
92
-				if ($this->hasBeenInterrupted()) {
93
-					throw new InterruptedException();
94
-				}
95
-			});
96
-			$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
97
-				$output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
98
-			});
99
-			# count only
100
-		} else {
101
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
102
-				$this->filesCounter += 1;
103
-				if ($this->hasBeenInterrupted()) {
104
-					throw new InterruptedException();
105
-				}
106
-			});
107
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
108
-				$this->foldersCounter += 1;
109
-				if ($this->hasBeenInterrupted()) {
110
-					throw new InterruptedException();
111
-				}
112
-			});
113
-		}
114
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
115
-			$this->checkScanWarning($path, $output);
116
-		});
117
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
118
-			$this->checkScanWarning($path, $output);
119
-		});
120
-
121
-		try {
122
-			$scanner->scan($appData->getPath());
123
-		} catch (ForbiddenException $e) {
124
-			$output->writeln("<error>Storage not writable</error>");
125
-			$output->writeln("Make sure you're running the scan command only as the user the web server runs as");
126
-		} catch (InterruptedException $e) {
127
-			# exit the function if ctrl-c has been pressed
128
-			$output->writeln('Interrupted by user');
129
-		} catch (NotFoundException $e) {
130
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
131
-		} catch (\Exception $e) {
132
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
133
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
134
-		}
135
-	}
136
-
137
-
138
-	protected function execute(InputInterface $input, OutputInterface $output) {
139
-		# no messaging level option means: no full printout but statistics
140
-		# $quiet   means no print at all
141
-		# $verbose means full printout including statistics
142
-		# -q	-v	full	stat
143
-		#  0	 0	no	yes
144
-		#  0	 1	yes	yes
145
-		#  1	--	no	no  (quiet overrules verbose)
146
-		$verbose = $input->getOption('verbose');
147
-		$quiet = $input->getOption('quiet');
148
-		# restrict the verbosity level to VERBOSITY_VERBOSE
149
-		if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
150
-			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
151
-		}
152
-		if ($quiet) {
153
-			$verbose = false;
154
-		}
155
-
156
-		$output->writeln("\nScanning AppData for files");
157
-
158
-		$this->initTools();
159
-
160
-		$this->scanFiles($verbose, $output);
161
-
162
-		# stat: printout statistics if $quiet was not set
163
-		if (!$quiet) {
164
-			$this->presentStats($output);
165
-		}
166
-	}
167
-
168
-	/**
169
-	 * Initialises some useful tools for the Command
170
-	 */
171
-	protected function initTools() {
172
-		// Start the timer
173
-		$this->execTime = -microtime(true);
174
-		// Convert PHP errors to exceptions
175
-		set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
176
-	}
177
-
178
-	/**
179
-	 * Processes PHP errors as exceptions in order to be able to keep track of problems
180
-	 *
181
-	 * @see https://secure.php.net/manual/en/function.set-error-handler.php
182
-	 *
183
-	 * @param int $severity the level of the error raised
184
-	 * @param string $message
185
-	 * @param string $file the filename that the error was raised in
186
-	 * @param int $line the line number the error was raised
187
-	 *
188
-	 * @throws \ErrorException
189
-	 */
190
-	public function exceptionErrorHandler($severity, $message, $file, $line) {
191
-		if (!(error_reporting() & $severity)) {
192
-			// This error code is not included in error_reporting
193
-			return;
194
-		}
195
-		throw new \ErrorException($message, 0, $severity, $file, $line);
196
-	}
197
-
198
-	/**
199
-	 * @param OutputInterface $output
200
-	 */
201
-	protected function presentStats(OutputInterface $output) {
202
-		// Stop the timer
203
-		$this->execTime += microtime(true);
204
-		$output->writeln("");
205
-
206
-		$headers = [
207
-			'Folders', 'Files', 'Elapsed time'
208
-		];
209
-
210
-		$this->showSummary($headers, null, $output);
211
-	}
212
-
213
-	/**
214
-	 * Shows a summary of operations
215
-	 *
216
-	 * @param string[] $headers
217
-	 * @param string[] $rows
218
-	 * @param OutputInterface $output
219
-	 */
220
-	protected function showSummary($headers, $rows, OutputInterface $output) {
221
-		$niceDate = $this->formatExecTime();
222
-		if (!$rows) {
223
-			$rows = [
224
-				$this->foldersCounter,
225
-				$this->filesCounter,
226
-				$niceDate,
227
-			];
228
-		}
229
-		$table = new Table($output);
230
-		$table
231
-			->setHeaders($headers)
232
-			->setRows([$rows]);
233
-		$table->render();
234
-	}
235
-
236
-
237
-	/**
238
-	 * Formats microtime into a human readable format
239
-	 *
240
-	 * @return string
241
-	 */
242
-	protected function formatExecTime() {
243
-		list($secs, ) = explode('.', sprintf("%.1f", ($this->execTime)));
244
-
245
-		# if you want to have microseconds add this:   . '.' . $tens;
246
-		return date('H:i:s', $secs);
247
-	}
248
-
249
-	/**
250
-	 * @return \OCP\IDBConnection
251
-	 */
252
-	protected function reconnectToDatabase(OutputInterface $output) {
253
-		/** @var Connection | IDBConnection $connection*/
254
-		$connection = \OC::$server->getDatabaseConnection();
255
-		try {
256
-			$connection->close();
257
-		} catch (\Exception $ex) {
258
-			$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
259
-		}
260
-		while (!$connection->isConnected()) {
261
-			try {
262
-				$connection->connect();
263
-			} catch (\Exception $ex) {
264
-				$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
265
-				sleep(60);
266
-			}
267
-		}
268
-		return $connection;
269
-	}
270
-
271
-	/**
272
-	 * @return \OCP\Files\Folder
273
-	 * @throws NotFoundException
274
-	 */
275
-	private function getAppDataFolder() {
276
-		$instanceId = $this->config->getSystemValue('instanceid', null);
277
-
278
-		if ($instanceId === null) {
279
-			throw new NotFoundException();
280
-		}
281
-
282
-		return $this->root->get('appdata_'.$instanceId);
283
-	}
22
+    /** @var IRootFolder */
23
+    protected $root;
24
+    /** @var IConfig */
25
+    protected $config;
26
+    /** @var float */
27
+    protected $execTime = 0;
28
+    /** @var int */
29
+    protected $foldersCounter = 0;
30
+    /** @var int */
31
+    protected $filesCounter = 0;
32
+
33
+    public function __construct(IRootFolder $rootFolder, IConfig $config) {
34
+        parent::__construct();
35
+
36
+        $this->root = $rootFolder;
37
+        $this->config = $config;
38
+    }
39
+
40
+    protected function configure() {
41
+        parent::configure();
42
+
43
+        $this
44
+            ->setName('files:scan-app-data')
45
+            ->setDescription('rescan the AppData folder')
46
+            ->addOption(
47
+                'quiet',
48
+                'q',
49
+                InputOption::VALUE_NONE,
50
+                'suppress any output'
51
+            )
52
+            ->addOption(
53
+                'verbose',
54
+                '-v|vv|vvv',
55
+                InputOption::VALUE_NONE,
56
+                'verbose the output'
57
+            );
58
+    }
59
+
60
+    public function checkScanWarning($fullPath, OutputInterface $output) {
61
+        $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
62
+        $path = basename($fullPath);
63
+
64
+        if ($normalizedPath !== $path) {
65
+            $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
66
+        }
67
+    }
68
+
69
+    protected function scanFiles($verbose, OutputInterface $output) {
70
+        try {
71
+            $appData = $this->getAppDataFolder();
72
+        } catch (NotFoundException $e) {
73
+            $output->writeln('NoAppData folder found');
74
+            return;
75
+        }
76
+
77
+        $connection = $this->reconnectToDatabase($output);
78
+        $scanner = new \OC\Files\Utils\Scanner(null, $connection, \OC::$server->getLogger());
79
+        # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
80
+        # printout and count
81
+        if ($verbose) {
82
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
83
+                $output->writeln("\tFile   <info>$path</info>");
84
+                $this->filesCounter += 1;
85
+                if ($this->hasBeenInterrupted()) {
86
+                    throw new InterruptedException();
87
+                }
88
+            });
89
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
90
+                $output->writeln("\tFolder <info>$path</info>");
91
+                $this->foldersCounter += 1;
92
+                if ($this->hasBeenInterrupted()) {
93
+                    throw new InterruptedException();
94
+                }
95
+            });
96
+            $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
97
+                $output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
98
+            });
99
+            # count only
100
+        } else {
101
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
102
+                $this->filesCounter += 1;
103
+                if ($this->hasBeenInterrupted()) {
104
+                    throw new InterruptedException();
105
+                }
106
+            });
107
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
108
+                $this->foldersCounter += 1;
109
+                if ($this->hasBeenInterrupted()) {
110
+                    throw new InterruptedException();
111
+                }
112
+            });
113
+        }
114
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
115
+            $this->checkScanWarning($path, $output);
116
+        });
117
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
118
+            $this->checkScanWarning($path, $output);
119
+        });
120
+
121
+        try {
122
+            $scanner->scan($appData->getPath());
123
+        } catch (ForbiddenException $e) {
124
+            $output->writeln("<error>Storage not writable</error>");
125
+            $output->writeln("Make sure you're running the scan command only as the user the web server runs as");
126
+        } catch (InterruptedException $e) {
127
+            # exit the function if ctrl-c has been pressed
128
+            $output->writeln('Interrupted by user');
129
+        } catch (NotFoundException $e) {
130
+            $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
131
+        } catch (\Exception $e) {
132
+            $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
133
+            $output->writeln('<error>' . $e->getTraceAsString() . '</error>');
134
+        }
135
+    }
136
+
137
+
138
+    protected function execute(InputInterface $input, OutputInterface $output) {
139
+        # no messaging level option means: no full printout but statistics
140
+        # $quiet   means no print at all
141
+        # $verbose means full printout including statistics
142
+        # -q	-v	full	stat
143
+        #  0	 0	no	yes
144
+        #  0	 1	yes	yes
145
+        #  1	--	no	no  (quiet overrules verbose)
146
+        $verbose = $input->getOption('verbose');
147
+        $quiet = $input->getOption('quiet');
148
+        # restrict the verbosity level to VERBOSITY_VERBOSE
149
+        if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
150
+            $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
151
+        }
152
+        if ($quiet) {
153
+            $verbose = false;
154
+        }
155
+
156
+        $output->writeln("\nScanning AppData for files");
157
+
158
+        $this->initTools();
159
+
160
+        $this->scanFiles($verbose, $output);
161
+
162
+        # stat: printout statistics if $quiet was not set
163
+        if (!$quiet) {
164
+            $this->presentStats($output);
165
+        }
166
+    }
167
+
168
+    /**
169
+     * Initialises some useful tools for the Command
170
+     */
171
+    protected function initTools() {
172
+        // Start the timer
173
+        $this->execTime = -microtime(true);
174
+        // Convert PHP errors to exceptions
175
+        set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
176
+    }
177
+
178
+    /**
179
+     * Processes PHP errors as exceptions in order to be able to keep track of problems
180
+     *
181
+     * @see https://secure.php.net/manual/en/function.set-error-handler.php
182
+     *
183
+     * @param int $severity the level of the error raised
184
+     * @param string $message
185
+     * @param string $file the filename that the error was raised in
186
+     * @param int $line the line number the error was raised
187
+     *
188
+     * @throws \ErrorException
189
+     */
190
+    public function exceptionErrorHandler($severity, $message, $file, $line) {
191
+        if (!(error_reporting() & $severity)) {
192
+            // This error code is not included in error_reporting
193
+            return;
194
+        }
195
+        throw new \ErrorException($message, 0, $severity, $file, $line);
196
+    }
197
+
198
+    /**
199
+     * @param OutputInterface $output
200
+     */
201
+    protected function presentStats(OutputInterface $output) {
202
+        // Stop the timer
203
+        $this->execTime += microtime(true);
204
+        $output->writeln("");
205
+
206
+        $headers = [
207
+            'Folders', 'Files', 'Elapsed time'
208
+        ];
209
+
210
+        $this->showSummary($headers, null, $output);
211
+    }
212
+
213
+    /**
214
+     * Shows a summary of operations
215
+     *
216
+     * @param string[] $headers
217
+     * @param string[] $rows
218
+     * @param OutputInterface $output
219
+     */
220
+    protected function showSummary($headers, $rows, OutputInterface $output) {
221
+        $niceDate = $this->formatExecTime();
222
+        if (!$rows) {
223
+            $rows = [
224
+                $this->foldersCounter,
225
+                $this->filesCounter,
226
+                $niceDate,
227
+            ];
228
+        }
229
+        $table = new Table($output);
230
+        $table
231
+            ->setHeaders($headers)
232
+            ->setRows([$rows]);
233
+        $table->render();
234
+    }
235
+
236
+
237
+    /**
238
+     * Formats microtime into a human readable format
239
+     *
240
+     * @return string
241
+     */
242
+    protected function formatExecTime() {
243
+        list($secs, ) = explode('.', sprintf("%.1f", ($this->execTime)));
244
+
245
+        # if you want to have microseconds add this:   . '.' . $tens;
246
+        return date('H:i:s', $secs);
247
+    }
248
+
249
+    /**
250
+     * @return \OCP\IDBConnection
251
+     */
252
+    protected function reconnectToDatabase(OutputInterface $output) {
253
+        /** @var Connection | IDBConnection $connection*/
254
+        $connection = \OC::$server->getDatabaseConnection();
255
+        try {
256
+            $connection->close();
257
+        } catch (\Exception $ex) {
258
+            $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
259
+        }
260
+        while (!$connection->isConnected()) {
261
+            try {
262
+                $connection->connect();
263
+            } catch (\Exception $ex) {
264
+                $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
265
+                sleep(60);
266
+            }
267
+        }
268
+        return $connection;
269
+    }
270
+
271
+    /**
272
+     * @return \OCP\Files\Folder
273
+     * @throws NotFoundException
274
+     */
275
+    private function getAppDataFolder() {
276
+        $instanceId = $this->config->getSystemValue('instanceid', null);
277
+
278
+        if ($instanceId === null) {
279
+            throw new NotFoundException();
280
+        }
281
+
282
+        return $this->root->get('appdata_'.$instanceId);
283
+    }
284 284
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -62,7 +62,7 @@  discard block
 block discarded – undo
62 62
 		$path = basename($fullPath);
63 63
 
64 64
 		if ($normalizedPath !== $path) {
65
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
65
+			$output->writeln("\t<error>Entry \"".$fullPath.'" will not be accessible due to incompatible encoding</error>');
66 66
 		}
67 67
 	}
68 68
 
@@ -79,32 +79,32 @@  discard block
 block discarded – undo
79 79
 		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
80 80
 		# printout and count
81 81
 		if ($verbose) {
82
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
82
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
83 83
 				$output->writeln("\tFile   <info>$path</info>");
84 84
 				$this->filesCounter += 1;
85 85
 				if ($this->hasBeenInterrupted()) {
86 86
 					throw new InterruptedException();
87 87
 				}
88 88
 			});
89
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
89
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
90 90
 				$output->writeln("\tFolder <info>$path</info>");
91 91
 				$this->foldersCounter += 1;
92 92
 				if ($this->hasBeenInterrupted()) {
93 93
 					throw new InterruptedException();
94 94
 				}
95 95
 			});
96
-			$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
97
-				$output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
96
+			$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function(StorageNotAvailableException $e) use ($output) {
97
+				$output->writeln("Error while scanning, storage not available (".$e->getMessage().")");
98 98
 			});
99 99
 			# count only
100 100
 		} else {
101
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
101
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function() use ($output) {
102 102
 				$this->filesCounter += 1;
103 103
 				if ($this->hasBeenInterrupted()) {
104 104
 					throw new InterruptedException();
105 105
 				}
106 106
 			});
107
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
107
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function() use ($output) {
108 108
 				$this->foldersCounter += 1;
109 109
 				if ($this->hasBeenInterrupted()) {
110 110
 					throw new InterruptedException();
@@ -127,10 +127,10 @@  discard block
 block discarded – undo
127 127
 			# exit the function if ctrl-c has been pressed
128 128
 			$output->writeln('Interrupted by user');
129 129
 		} catch (NotFoundException $e) {
130
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
130
+			$output->writeln('<error>Path not found: '.$e->getMessage().'</error>');
131 131
 		} catch (\Exception $e) {
132
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
133
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
132
+			$output->writeln('<error>Exception during scan: '.$e->getMessage().'</error>');
133
+			$output->writeln('<error>'.$e->getTraceAsString().'</error>');
134 134
 		}
135 135
 	}
136 136
 
@@ -240,7 +240,7 @@  discard block
 block discarded – undo
240 240
 	 * @return string
241 241
 	 */
242 242
 	protected function formatExecTime() {
243
-		list($secs, ) = explode('.', sprintf("%.1f", ($this->execTime)));
243
+		list($secs,) = explode('.', sprintf("%.1f", ($this->execTime)));
244 244
 
245 245
 		# if you want to have microseconds add this:   . '.' . $tens;
246 246
 		return date('H:i:s', $secs);
Please login to merge, or discard this patch.
apps/files/lib/Command/Scan.php 2 patches
Indentation   +281 added lines, -281 removed lines patch added patch discarded remove patch
@@ -44,310 +44,310 @@
 block discarded – undo
44 44
 
45 45
 class Scan extends Base {
46 46
 
47
-	/** @var IUserManager $userManager */
48
-	private $userManager;
49
-	/** @var float */
50
-	protected $execTime = 0;
51
-	/** @var int */
52
-	protected $foldersCounter = 0;
53
-	/** @var int */
54
-	protected $filesCounter = 0;
47
+    /** @var IUserManager $userManager */
48
+    private $userManager;
49
+    /** @var float */
50
+    protected $execTime = 0;
51
+    /** @var int */
52
+    protected $foldersCounter = 0;
53
+    /** @var int */
54
+    protected $filesCounter = 0;
55 55
 
56
-	public function __construct(IUserManager $userManager) {
57
-		$this->userManager = $userManager;
58
-		parent::__construct();
59
-	}
56
+    public function __construct(IUserManager $userManager) {
57
+        $this->userManager = $userManager;
58
+        parent::__construct();
59
+    }
60 60
 
61
-	protected function configure() {
62
-		parent::configure();
61
+    protected function configure() {
62
+        parent::configure();
63 63
 
64
-		$this
65
-			->setName('files:scan')
66
-			->setDescription('rescan filesystem')
67
-			->addArgument(
68
-				'user_id',
69
-				InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
70
-				'will rescan all files of the given user(s)'
71
-			)
72
-			->addOption(
73
-				'path',
74
-				'p',
75
-				InputArgument::OPTIONAL,
76
-				'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored'
77
-			)
78
-			->addOption(
79
-				'quiet',
80
-				'q',
81
-				InputOption::VALUE_NONE,
82
-				'suppress any output'
83
-			)
84
-			->addOption(
85
-				'verbose',
86
-				'-v|vv|vvv',
87
-				InputOption::VALUE_NONE,
88
-				'verbose the output'
89
-			)
90
-			->addOption(
91
-				'all',
92
-				null,
93
-				InputOption::VALUE_NONE,
94
-				'will rescan all files of all known users'
95
-			)->addOption(
96
-				'unscanned',
97
-				null,
98
-				InputOption::VALUE_NONE,
99
-				'only scan files which are marked as not fully scanned'
100
-			);
101
-	}
64
+        $this
65
+            ->setName('files:scan')
66
+            ->setDescription('rescan filesystem')
67
+            ->addArgument(
68
+                'user_id',
69
+                InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
70
+                'will rescan all files of the given user(s)'
71
+            )
72
+            ->addOption(
73
+                'path',
74
+                'p',
75
+                InputArgument::OPTIONAL,
76
+                'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored'
77
+            )
78
+            ->addOption(
79
+                'quiet',
80
+                'q',
81
+                InputOption::VALUE_NONE,
82
+                'suppress any output'
83
+            )
84
+            ->addOption(
85
+                'verbose',
86
+                '-v|vv|vvv',
87
+                InputOption::VALUE_NONE,
88
+                'verbose the output'
89
+            )
90
+            ->addOption(
91
+                'all',
92
+                null,
93
+                InputOption::VALUE_NONE,
94
+                'will rescan all files of all known users'
95
+            )->addOption(
96
+                'unscanned',
97
+                null,
98
+                InputOption::VALUE_NONE,
99
+                'only scan files which are marked as not fully scanned'
100
+            );
101
+    }
102 102
 
103
-	public function checkScanWarning($fullPath, OutputInterface $output) {
104
-		$normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
105
-		$path = basename($fullPath);
103
+    public function checkScanWarning($fullPath, OutputInterface $output) {
104
+        $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
105
+        $path = basename($fullPath);
106 106
 
107
-		if ($normalizedPath !== $path) {
108
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
109
-		}
110
-	}
107
+        if ($normalizedPath !== $path) {
108
+            $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
109
+        }
110
+    }
111 111
 
112
-	protected function scanFiles($user, $path, $verbose, OutputInterface $output, $backgroundScan = false) {
113
-		$connection = $this->reconnectToDatabase($output);
114
-		$scanner = new \OC\Files\Utils\Scanner($user, $connection, \OC::$server->getLogger());
115
-		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
116
-		# printout and count
117
-		if ($verbose) {
118
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
119
-				$output->writeln("\tFile   <info>$path</info>");
120
-				$this->filesCounter += 1;
121
-				if ($this->hasBeenInterrupted()) {
122
-					throw new InterruptedException();
123
-				}
124
-			});
125
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
126
-				$output->writeln("\tFolder <info>$path</info>");
127
-				$this->foldersCounter += 1;
128
-				if ($this->hasBeenInterrupted()) {
129
-					throw new InterruptedException();
130
-				}
131
-			});
132
-			$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
133
-				$output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
134
-			});
135
-			# count only
136
-		} else {
137
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
138
-				$this->filesCounter += 1;
139
-				if ($this->hasBeenInterrupted()) {
140
-					throw new InterruptedException();
141
-				}
142
-			});
143
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
144
-				$this->foldersCounter += 1;
145
-				if ($this->hasBeenInterrupted()) {
146
-					throw new InterruptedException();
147
-				}
148
-			});
149
-		}
150
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
151
-			$this->checkScanWarning($path, $output);
152
-		});
153
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
154
-			$this->checkScanWarning($path, $output);
155
-		});
112
+    protected function scanFiles($user, $path, $verbose, OutputInterface $output, $backgroundScan = false) {
113
+        $connection = $this->reconnectToDatabase($output);
114
+        $scanner = new \OC\Files\Utils\Scanner($user, $connection, \OC::$server->getLogger());
115
+        # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
116
+        # printout and count
117
+        if ($verbose) {
118
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
119
+                $output->writeln("\tFile   <info>$path</info>");
120
+                $this->filesCounter += 1;
121
+                if ($this->hasBeenInterrupted()) {
122
+                    throw new InterruptedException();
123
+                }
124
+            });
125
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
126
+                $output->writeln("\tFolder <info>$path</info>");
127
+                $this->foldersCounter += 1;
128
+                if ($this->hasBeenInterrupted()) {
129
+                    throw new InterruptedException();
130
+                }
131
+            });
132
+            $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
133
+                $output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
134
+            });
135
+            # count only
136
+        } else {
137
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
138
+                $this->filesCounter += 1;
139
+                if ($this->hasBeenInterrupted()) {
140
+                    throw new InterruptedException();
141
+                }
142
+            });
143
+            $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
144
+                $this->foldersCounter += 1;
145
+                if ($this->hasBeenInterrupted()) {
146
+                    throw new InterruptedException();
147
+                }
148
+            });
149
+        }
150
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
151
+            $this->checkScanWarning($path, $output);
152
+        });
153
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
154
+            $this->checkScanWarning($path, $output);
155
+        });
156 156
 
157
-		try {
158
-			if ($backgroundScan) {
159
-				$scanner->backgroundScan($path);
160
-			} else {
161
-				$scanner->scan($path);
162
-			}
163
-		} catch (ForbiddenException $e) {
164
-			$output->writeln("<error>Home storage for user $user not writable</error>");
165
-			$output->writeln("Make sure you're running the scan command only as the user the web server runs as");
166
-		} catch (InterruptedException $e) {
167
-			# exit the function if ctrl-c has been pressed
168
-			$output->writeln('Interrupted by user');
169
-		} catch (NotFoundException $e) {
170
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
171
-		} catch (\Exception $e) {
172
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
173
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
174
-		}
175
-	}
157
+        try {
158
+            if ($backgroundScan) {
159
+                $scanner->backgroundScan($path);
160
+            } else {
161
+                $scanner->scan($path);
162
+            }
163
+        } catch (ForbiddenException $e) {
164
+            $output->writeln("<error>Home storage for user $user not writable</error>");
165
+            $output->writeln("Make sure you're running the scan command only as the user the web server runs as");
166
+        } catch (InterruptedException $e) {
167
+            # exit the function if ctrl-c has been pressed
168
+            $output->writeln('Interrupted by user');
169
+        } catch (NotFoundException $e) {
170
+            $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
171
+        } catch (\Exception $e) {
172
+            $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
173
+            $output->writeln('<error>' . $e->getTraceAsString() . '</error>');
174
+        }
175
+    }
176 176
 
177 177
 
178
-	protected function execute(InputInterface $input, OutputInterface $output) {
179
-		$inputPath = $input->getOption('path');
180
-		if ($inputPath) {
181
-			$inputPath = '/' . trim($inputPath, '/');
182
-			list (, $user,) = explode('/', $inputPath, 3);
183
-			$users = array($user);
184
-		} else if ($input->getOption('all')) {
185
-			$users = $this->userManager->search('');
186
-		} else {
187
-			$users = $input->getArgument('user_id');
188
-		}
178
+    protected function execute(InputInterface $input, OutputInterface $output) {
179
+        $inputPath = $input->getOption('path');
180
+        if ($inputPath) {
181
+            $inputPath = '/' . trim($inputPath, '/');
182
+            list (, $user,) = explode('/', $inputPath, 3);
183
+            $users = array($user);
184
+        } else if ($input->getOption('all')) {
185
+            $users = $this->userManager->search('');
186
+        } else {
187
+            $users = $input->getArgument('user_id');
188
+        }
189 189
 
190
-		# no messaging level option means: no full printout but statistics
191
-		# $quiet   means no print at all
192
-		# $verbose means full printout including statistics
193
-		# -q	-v	full	stat
194
-		#  0	 0	no	yes
195
-		#  0	 1	yes	yes
196
-		#  1	--	no	no  (quiet overrules verbose)
197
-		$verbose = $input->getOption('verbose');
198
-		$quiet = $input->getOption('quiet');
199
-		# restrict the verbosity level to VERBOSITY_VERBOSE
200
-		if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
201
-			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
202
-		}
203
-		if ($quiet) {
204
-			$verbose = false;
205
-		}
190
+        # no messaging level option means: no full printout but statistics
191
+        # $quiet   means no print at all
192
+        # $verbose means full printout including statistics
193
+        # -q	-v	full	stat
194
+        #  0	 0	no	yes
195
+        #  0	 1	yes	yes
196
+        #  1	--	no	no  (quiet overrules verbose)
197
+        $verbose = $input->getOption('verbose');
198
+        $quiet = $input->getOption('quiet');
199
+        # restrict the verbosity level to VERBOSITY_VERBOSE
200
+        if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
201
+            $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
202
+        }
203
+        if ($quiet) {
204
+            $verbose = false;
205
+        }
206 206
 
207
-		# check quantity of users to be process and show it on the command line
208
-		$users_total = count($users);
209
-		if ($users_total === 0) {
210
-			$output->writeln("<error>Please specify the user id to scan, \"--all\" to scan for all users or \"--path=...\"</error>");
211
-			return;
212
-		} else {
213
-			if ($users_total > 1) {
214
-				$output->writeln("\nScanning files for $users_total users");
215
-			}
216
-		}
207
+        # check quantity of users to be process and show it on the command line
208
+        $users_total = count($users);
209
+        if ($users_total === 0) {
210
+            $output->writeln("<error>Please specify the user id to scan, \"--all\" to scan for all users or \"--path=...\"</error>");
211
+            return;
212
+        } else {
213
+            if ($users_total > 1) {
214
+                $output->writeln("\nScanning files for $users_total users");
215
+            }
216
+        }
217 217
 
218
-		$this->initTools();
218
+        $this->initTools();
219 219
 
220
-		$user_count = 0;
221
-		foreach ($users as $user) {
222
-			if (is_object($user)) {
223
-				$user = $user->getUID();
224
-			}
225
-			$path = $inputPath ? $inputPath : '/' . $user;
226
-			$user_count += 1;
227
-			if ($this->userManager->userExists($user)) {
228
-				# add an extra line when verbose is set to optical separate users
229
-				if ($verbose) {
230
-					$output->writeln("");
231
-				}
232
-				$output->writeln("Starting scan for user $user_count out of $users_total ($user)");
233
-				# full: printout data if $verbose was set
234
-				$this->scanFiles($user, $path, $verbose, $output, $input->getOption('unscanned'));
235
-			} else {
236
-				$output->writeln("<error>Unknown user $user_count $user</error>");
237
-			}
238
-			# check on each user if there was a user interrupt (ctrl-c) and exit foreach
239
-			if ($this->hasBeenInterrupted()) {
240
-				break;
241
-			}
242
-		}
220
+        $user_count = 0;
221
+        foreach ($users as $user) {
222
+            if (is_object($user)) {
223
+                $user = $user->getUID();
224
+            }
225
+            $path = $inputPath ? $inputPath : '/' . $user;
226
+            $user_count += 1;
227
+            if ($this->userManager->userExists($user)) {
228
+                # add an extra line when verbose is set to optical separate users
229
+                if ($verbose) {
230
+                    $output->writeln("");
231
+                }
232
+                $output->writeln("Starting scan for user $user_count out of $users_total ($user)");
233
+                # full: printout data if $verbose was set
234
+                $this->scanFiles($user, $path, $verbose, $output, $input->getOption('unscanned'));
235
+            } else {
236
+                $output->writeln("<error>Unknown user $user_count $user</error>");
237
+            }
238
+            # check on each user if there was a user interrupt (ctrl-c) and exit foreach
239
+            if ($this->hasBeenInterrupted()) {
240
+                break;
241
+            }
242
+        }
243 243
 
244
-		# stat: printout statistics if $quiet was not set
245
-		if (!$quiet) {
246
-			$this->presentStats($output);
247
-		}
248
-	}
244
+        # stat: printout statistics if $quiet was not set
245
+        if (!$quiet) {
246
+            $this->presentStats($output);
247
+        }
248
+    }
249 249
 
250
-	/**
251
-	 * Initialises some useful tools for the Command
252
-	 */
253
-	protected function initTools() {
254
-		// Start the timer
255
-		$this->execTime = -microtime(true);
256
-		// Convert PHP errors to exceptions
257
-		set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
258
-	}
250
+    /**
251
+     * Initialises some useful tools for the Command
252
+     */
253
+    protected function initTools() {
254
+        // Start the timer
255
+        $this->execTime = -microtime(true);
256
+        // Convert PHP errors to exceptions
257
+        set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
258
+    }
259 259
 
260
-	/**
261
-	 * Processes PHP errors as exceptions in order to be able to keep track of problems
262
-	 *
263
-	 * @see https://secure.php.net/manual/en/function.set-error-handler.php
264
-	 *
265
-	 * @param int $severity the level of the error raised
266
-	 * @param string $message
267
-	 * @param string $file the filename that the error was raised in
268
-	 * @param int $line the line number the error was raised
269
-	 *
270
-	 * @throws \ErrorException
271
-	 */
272
-	public function exceptionErrorHandler($severity, $message, $file, $line) {
273
-		if (!(error_reporting() & $severity)) {
274
-			// This error code is not included in error_reporting
275
-			return;
276
-		}
277
-		throw new \ErrorException($message, 0, $severity, $file, $line);
278
-	}
260
+    /**
261
+     * Processes PHP errors as exceptions in order to be able to keep track of problems
262
+     *
263
+     * @see https://secure.php.net/manual/en/function.set-error-handler.php
264
+     *
265
+     * @param int $severity the level of the error raised
266
+     * @param string $message
267
+     * @param string $file the filename that the error was raised in
268
+     * @param int $line the line number the error was raised
269
+     *
270
+     * @throws \ErrorException
271
+     */
272
+    public function exceptionErrorHandler($severity, $message, $file, $line) {
273
+        if (!(error_reporting() & $severity)) {
274
+            // This error code is not included in error_reporting
275
+            return;
276
+        }
277
+        throw new \ErrorException($message, 0, $severity, $file, $line);
278
+    }
279 279
 
280
-	/**
281
-	 * @param OutputInterface $output
282
-	 */
283
-	protected function presentStats(OutputInterface $output) {
284
-		// Stop the timer
285
-		$this->execTime += microtime(true);
286
-		$output->writeln("");
280
+    /**
281
+     * @param OutputInterface $output
282
+     */
283
+    protected function presentStats(OutputInterface $output) {
284
+        // Stop the timer
285
+        $this->execTime += microtime(true);
286
+        $output->writeln("");
287 287
 
288
-		$headers = [
289
-			'Folders', 'Files', 'Elapsed time'
290
-		];
288
+        $headers = [
289
+            'Folders', 'Files', 'Elapsed time'
290
+        ];
291 291
 
292
-		$this->showSummary($headers, null, $output);
293
-	}
292
+        $this->showSummary($headers, null, $output);
293
+    }
294 294
 
295
-	/**
296
-	 * Shows a summary of operations
297
-	 *
298
-	 * @param string[] $headers
299
-	 * @param string[] $rows
300
-	 * @param OutputInterface $output
301
-	 */
302
-	protected function showSummary($headers, $rows, OutputInterface $output) {
303
-		$niceDate = $this->formatExecTime();
304
-		if (!$rows) {
305
-			$rows = [
306
-				$this->foldersCounter,
307
-				$this->filesCounter,
308
-				$niceDate,
309
-			];
310
-		}
311
-		$table = new Table($output);
312
-		$table
313
-			->setHeaders($headers)
314
-			->setRows([$rows]);
315
-		$table->render();
316
-	}
295
+    /**
296
+     * Shows a summary of operations
297
+     *
298
+     * @param string[] $headers
299
+     * @param string[] $rows
300
+     * @param OutputInterface $output
301
+     */
302
+    protected function showSummary($headers, $rows, OutputInterface $output) {
303
+        $niceDate = $this->formatExecTime();
304
+        if (!$rows) {
305
+            $rows = [
306
+                $this->foldersCounter,
307
+                $this->filesCounter,
308
+                $niceDate,
309
+            ];
310
+        }
311
+        $table = new Table($output);
312
+        $table
313
+            ->setHeaders($headers)
314
+            ->setRows([$rows]);
315
+        $table->render();
316
+    }
317 317
 
318 318
 
319
-	/**
320
-	 * Formats microtime into a human readable format
321
-	 *
322
-	 * @return string
323
-	 */
324
-	protected function formatExecTime() {
325
-		list($secs, ) = explode('.', sprintf("%.1f", ($this->execTime)));
319
+    /**
320
+     * Formats microtime into a human readable format
321
+     *
322
+     * @return string
323
+     */
324
+    protected function formatExecTime() {
325
+        list($secs, ) = explode('.', sprintf("%.1f", ($this->execTime)));
326 326
 
327
-		# if you want to have microseconds add this:   . '.' . $tens;
328
-		return date('H:i:s', $secs);
329
-	}
327
+        # if you want to have microseconds add this:   . '.' . $tens;
328
+        return date('H:i:s', $secs);
329
+    }
330 330
 
331
-	/**
332
-	 * @return \OCP\IDBConnection
333
-	 */
334
-	protected function reconnectToDatabase(OutputInterface $output) {
335
-		/** @var Connection | IDBConnection $connection */
336
-		$connection = \OC::$server->getDatabaseConnection();
337
-		try {
338
-			$connection->close();
339
-		} catch (\Exception $ex) {
340
-			$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
341
-		}
342
-		while (!$connection->isConnected()) {
343
-			try {
344
-				$connection->connect();
345
-			} catch (\Exception $ex) {
346
-				$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
347
-				sleep(60);
348
-			}
349
-		}
350
-		return $connection;
351
-	}
331
+    /**
332
+     * @return \OCP\IDBConnection
333
+     */
334
+    protected function reconnectToDatabase(OutputInterface $output) {
335
+        /** @var Connection | IDBConnection $connection */
336
+        $connection = \OC::$server->getDatabaseConnection();
337
+        try {
338
+            $connection->close();
339
+        } catch (\Exception $ex) {
340
+            $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
341
+        }
342
+        while (!$connection->isConnected()) {
343
+            try {
344
+                $connection->connect();
345
+            } catch (\Exception $ex) {
346
+                $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
347
+                sleep(60);
348
+            }
349
+        }
350
+        return $connection;
351
+    }
352 352
 
353 353
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
 		$path = basename($fullPath);
106 106
 
107 107
 		if ($normalizedPath !== $path) {
108
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
108
+			$output->writeln("\t<error>Entry \"".$fullPath.'" will not be accessible due to incompatible encoding</error>');
109 109
 		}
110 110
 	}
111 111
 
@@ -115,42 +115,42 @@  discard block
 block discarded – undo
115 115
 		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
116 116
 		# printout and count
117 117
 		if ($verbose) {
118
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
118
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
119 119
 				$output->writeln("\tFile   <info>$path</info>");
120 120
 				$this->filesCounter += 1;
121 121
 				if ($this->hasBeenInterrupted()) {
122 122
 					throw new InterruptedException();
123 123
 				}
124 124
 			});
125
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
125
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
126 126
 				$output->writeln("\tFolder <info>$path</info>");
127 127
 				$this->foldersCounter += 1;
128 128
 				if ($this->hasBeenInterrupted()) {
129 129
 					throw new InterruptedException();
130 130
 				}
131 131
 			});
132
-			$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
133
-				$output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
132
+			$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function(StorageNotAvailableException $e) use ($output) {
133
+				$output->writeln("Error while scanning, storage not available (".$e->getMessage().")");
134 134
 			});
135 135
 			# count only
136 136
 		} else {
137
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
137
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function() use ($output) {
138 138
 				$this->filesCounter += 1;
139 139
 				if ($this->hasBeenInterrupted()) {
140 140
 					throw new InterruptedException();
141 141
 				}
142 142
 			});
143
-			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
143
+			$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function() use ($output) {
144 144
 				$this->foldersCounter += 1;
145 145
 				if ($this->hasBeenInterrupted()) {
146 146
 					throw new InterruptedException();
147 147
 				}
148 148
 			});
149 149
 		}
150
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
150
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
151 151
 			$this->checkScanWarning($path, $output);
152 152
 		});
153
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
153
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
154 154
 			$this->checkScanWarning($path, $output);
155 155
 		});
156 156
 
@@ -167,10 +167,10 @@  discard block
 block discarded – undo
167 167
 			# exit the function if ctrl-c has been pressed
168 168
 			$output->writeln('Interrupted by user');
169 169
 		} catch (NotFoundException $e) {
170
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
170
+			$output->writeln('<error>Path not found: '.$e->getMessage().'</error>');
171 171
 		} catch (\Exception $e) {
172
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
173
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
172
+			$output->writeln('<error>Exception during scan: '.$e->getMessage().'</error>');
173
+			$output->writeln('<error>'.$e->getTraceAsString().'</error>');
174 174
 		}
175 175
 	}
176 176
 
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
 	protected function execute(InputInterface $input, OutputInterface $output) {
179 179
 		$inputPath = $input->getOption('path');
180 180
 		if ($inputPath) {
181
-			$inputPath = '/' . trim($inputPath, '/');
181
+			$inputPath = '/'.trim($inputPath, '/');
182 182
 			list (, $user,) = explode('/', $inputPath, 3);
183 183
 			$users = array($user);
184 184
 		} else if ($input->getOption('all')) {
@@ -222,7 +222,7 @@  discard block
 block discarded – undo
222 222
 			if (is_object($user)) {
223 223
 				$user = $user->getUID();
224 224
 			}
225
-			$path = $inputPath ? $inputPath : '/' . $user;
225
+			$path = $inputPath ? $inputPath : '/'.$user;
226 226
 			$user_count += 1;
227 227
 			if ($this->userManager->userExists($user)) {
228 228
 				# add an extra line when verbose is set to optical separate users
@@ -322,7 +322,7 @@  discard block
 block discarded – undo
322 322
 	 * @return string
323 323
 	 */
324 324
 	protected function formatExecTime() {
325
-		list($secs, ) = explode('.', sprintf("%.1f", ($this->execTime)));
325
+		list($secs,) = explode('.', sprintf("%.1f", ($this->execTime)));
326 326
 
327 327
 		# if you want to have microseconds add this:   . '.' . $tens;
328 328
 		return date('H:i:s', $secs);
Please login to merge, or discard this patch.
lib/public/AppFramework/Db/Mapper.php 1 patch
Indentation   +321 added lines, -321 removed lines patch added patch discarded remove patch
@@ -37,327 +37,327 @@
 block discarded – undo
37 37
  */
38 38
 abstract class Mapper {
39 39
 
40
-	protected $tableName;
41
-	protected $entityClass;
42
-	protected $db;
43
-
44
-	/**
45
-	 * @param IDBConnection $db Instance of the Db abstraction layer
46
-	 * @param string $tableName the name of the table. set this to allow entity
47
-	 * @param string $entityClass the name of the entity that the sql should be
48
-	 * mapped to queries without using sql
49
-	 * @since 7.0.0
50
-	 */
51
-	public function __construct(IDBConnection $db, $tableName, $entityClass=null){
52
-		$this->db = $db;
53
-		$this->tableName = '*PREFIX*' . $tableName;
54
-
55
-		// if not given set the entity name to the class without the mapper part
56
-		// cache it here for later use since reflection is slow
57
-		if($entityClass === null) {
58
-			$this->entityClass = str_replace('Mapper', '', get_class($this));
59
-		} else {
60
-			$this->entityClass = $entityClass;
61
-		}
62
-	}
63
-
64
-
65
-	/**
66
-	 * @return string the table name
67
-	 * @since 7.0.0
68
-	 */
69
-	public function getTableName(){
70
-		return $this->tableName;
71
-	}
72
-
73
-
74
-	/**
75
-	 * Deletes an entity from the table
76
-	 * @param Entity $entity the entity that should be deleted
77
-	 * @return Entity the deleted entity
78
-	 * @since 7.0.0 - return value added in 8.1.0
79
-	 */
80
-	public function delete(Entity $entity){
81
-		$sql = 'DELETE FROM `' . $this->tableName . '` WHERE `id` = ?';
82
-		$stmt = $this->execute($sql, [$entity->getId()]);
83
-		$stmt->closeCursor();
84
-		return $entity;
85
-	}
86
-
87
-
88
-	/**
89
-	 * Creates a new entry in the db from an entity
90
-	 * @param Entity $entity the entity that should be created
91
-	 * @return Entity the saved entity with the set id
92
-	 * @since 7.0.0
93
-	 */
94
-	public function insert(Entity $entity){
95
-		// get updated fields to save, fields have to be set using a setter to
96
-		// be saved
97
-		$properties = $entity->getUpdatedFields();
98
-		$values = '';
99
-		$columns = '';
100
-		$params = [];
101
-
102
-		// build the fields
103
-		$i = 0;
104
-		foreach($properties as $property => $updated) {
105
-			$column = $entity->propertyToColumn($property);
106
-			$getter = 'get' . ucfirst($property);
107
-
108
-			$columns .= '`' . $column . '`';
109
-			$values .= '?';
110
-
111
-			// only append colon if there are more entries
112
-			if($i < count($properties)-1){
113
-				$columns .= ',';
114
-				$values .= ',';
115
-			}
116
-
117
-			$params[] = $entity->$getter();
118
-			$i++;
119
-
120
-		}
121
-
122
-		$sql = 'INSERT INTO `' . $this->tableName . '`(' .
123
-				$columns . ') VALUES(' . $values . ')';
124
-
125
-		$stmt = $this->execute($sql, $params);
126
-
127
-		$entity->setId((int) $this->db->lastInsertId($this->tableName));
128
-
129
-		$stmt->closeCursor();
130
-
131
-		return $entity;
132
-	}
133
-
134
-
135
-
136
-	/**
137
-	 * Updates an entry in the db from an entity
138
-	 * @throws \InvalidArgumentException if entity has no id
139
-	 * @param Entity $entity the entity that should be created
140
-	 * @return Entity the saved entity with the set id
141
-	 * @since 7.0.0 - return value was added in 8.0.0
142
-	 */
143
-	public function update(Entity $entity){
144
-		// if entity wasn't changed it makes no sense to run a db query
145
-		$properties = $entity->getUpdatedFields();
146
-		if(count($properties) === 0) {
147
-			return $entity;
148
-		}
149
-
150
-		// entity needs an id
151
-		$id = $entity->getId();
152
-		if($id === null){
153
-			throw new \InvalidArgumentException(
154
-				'Entity which should be updated has no id');
155
-		}
156
-
157
-		// get updated fields to save, fields have to be set using a setter to
158
-		// be saved
159
-		// do not update the id field
160
-		unset($properties['id']);
161
-
162
-		$columns = '';
163
-		$params = [];
164
-
165
-		// build the fields
166
-		$i = 0;
167
-		foreach($properties as $property => $updated) {
168
-
169
-			$column = $entity->propertyToColumn($property);
170
-			$getter = 'get' . ucfirst($property);
171
-
172
-			$columns .= '`' . $column . '` = ?';
173
-
174
-			// only append colon if there are more entries
175
-			if($i < count($properties)-1){
176
-				$columns .= ',';
177
-			}
178
-
179
-			$params[] = $entity->$getter();
180
-			$i++;
181
-		}
182
-
183
-		$sql = 'UPDATE `' . $this->tableName . '` SET ' .
184
-				$columns . ' WHERE `id` = ?';
185
-		$params[] = $id;
186
-
187
-		$stmt = $this->execute($sql, $params);
188
-		$stmt->closeCursor();
189
-
190
-		return $entity;
191
-	}
192
-
193
-	/**
194
-	 * Checks if an array is associative
195
-	 * @param array $array
196
-	 * @return bool true if associative
197
-	 * @since 8.1.0
198
-	 */
199
-	private function isAssocArray(array $array) {
200
-		return array_values($array) !== $array;
201
-	}
202
-
203
-	/**
204
-	 * Returns the correct PDO constant based on the value type
205
-	 * @param $value
206
-	 * @return int PDO constant
207
-	 * @since 8.1.0
208
-	 */
209
-	private function getPDOType($value) {
210
-		switch (gettype($value)) {
211
-			case 'integer':
212
-				return \PDO::PARAM_INT;
213
-			case 'boolean':
214
-				return \PDO::PARAM_BOOL;
215
-			default:
216
-				return \PDO::PARAM_STR;
217
-		}
218
-	}
219
-
220
-
221
-	/**
222
-	 * Runs an sql query
223
-	 * @param string $sql the prepare string
224
-	 * @param array $params the params which should replace the ? in the sql query
225
-	 * @param int $limit the maximum number of rows
226
-	 * @param int $offset from which row we want to start
227
-	 * @return \PDOStatement the database query result
228
-	 * @since 7.0.0
229
-	 */
230
-	protected function execute($sql, array $params=[], $limit=null, $offset=null){
231
-		$query = $this->db->prepare($sql, $limit, $offset);
232
-
233
-		if ($this->isAssocArray($params)) {
234
-			foreach ($params as $key => $param) {
235
-				$pdoConstant = $this->getPDOType($param);
236
-				$query->bindValue($key, $param, $pdoConstant);
237
-			}
238
-		} else {
239
-			$index = 1;  // bindParam is 1 indexed
240
-			foreach ($params as $param) {
241
-				$pdoConstant = $this->getPDOType($param);
242
-				$query->bindValue($index, $param, $pdoConstant);
243
-				$index++;
244
-			}
245
-		}
246
-
247
-		$query->execute();
248
-
249
-		return $query;
250
-	}
251
-
252
-
253
-	/**
254
-	 * Returns an db result and throws exceptions when there are more or less
255
-	 * results
256
-	 * @see findEntity
257
-	 * @param string $sql the sql query
258
-	 * @param array $params the parameters of the sql query
259
-	 * @param int $limit the maximum number of rows
260
-	 * @param int $offset from which row we want to start
261
-	 * @throws DoesNotExistException if the item does not exist
262
-	 * @throws MultipleObjectsReturnedException if more than one item exist
263
-	 * @return array the result as row
264
-	 * @since 7.0.0
265
-	 */
266
-	protected function findOneQuery($sql, array $params=[], $limit=null, $offset=null){
267
-		$stmt = $this->execute($sql, $params, $limit, $offset);
268
-		$row = $stmt->fetch();
269
-
270
-		if($row === false || $row === null){
271
-			$stmt->closeCursor();
272
-			$msg = $this->buildDebugMessage(
273
-				'Did expect one result but found none when executing', $sql, $params, $limit, $offset
274
-			);
275
-			throw new DoesNotExistException($msg);
276
-		}
277
-		$row2 = $stmt->fetch();
278
-		$stmt->closeCursor();
279
-		//MDB2 returns null, PDO and doctrine false when no row is available
280
-		if( ! ($row2 === false || $row2 === null )) {
281
-			$msg = $this->buildDebugMessage(
282
-				'Did not expect more than one result when executing', $sql, $params, $limit, $offset
283
-			);
284
-			throw new MultipleObjectsReturnedException($msg);
285
-		} else {
286
-			return $row;
287
-		}
288
-	}
289
-
290
-	/**
291
-	 * Builds an error message by prepending the $msg to an error message which
292
-	 * has the parameters
293
-	 * @see findEntity
294
-	 * @param string $sql the sql query
295
-	 * @param array $params the parameters of the sql query
296
-	 * @param int $limit the maximum number of rows
297
-	 * @param int $offset from which row we want to start
298
-	 * @return string formatted error message string
299
-	 * @since 9.1.0
300
-	 */
301
-	private function buildDebugMessage($msg, $sql, array $params=[], $limit=null, $offset=null) {
302
-		return $msg .
303
-					': query "' .	$sql . '"; ' .
304
-					'parameters ' . print_r($params, true) . '; ' .
305
-					'limit "' . $limit . '"; '.
306
-					'offset "' . $offset . '"';
307
-	}
308
-
309
-
310
-	/**
311
-	 * Creates an entity from a row. Automatically determines the entity class
312
-	 * from the current mapper name (MyEntityMapper -> MyEntity)
313
-	 * @param array $row the row which should be converted to an entity
314
-	 * @return Entity the entity
315
-	 * @since 7.0.0
316
-	 */
317
-	protected function mapRowToEntity($row) {
318
-		return call_user_func($this->entityClass .'::fromRow', $row);
319
-	}
320
-
321
-
322
-	/**
323
-	 * Runs a sql query and returns an array of entities
324
-	 * @param string $sql the prepare string
325
-	 * @param array $params the params which should replace the ? in the sql query
326
-	 * @param int $limit the maximum number of rows
327
-	 * @param int $offset from which row we want to start
328
-	 * @return array all fetched entities
329
-	 * @since 7.0.0
330
-	 */
331
-	protected function findEntities($sql, array $params=[], $limit=null, $offset=null) {
332
-		$stmt = $this->execute($sql, $params, $limit, $offset);
333
-
334
-		$entities = [];
335
-
336
-		while($row = $stmt->fetch()){
337
-			$entities[] = $this->mapRowToEntity($row);
338
-		}
339
-
340
-		$stmt->closeCursor();
341
-
342
-		return $entities;
343
-	}
344
-
345
-
346
-	/**
347
-	 * Returns an db result and throws exceptions when there are more or less
348
-	 * results
349
-	 * @param string $sql the sql query
350
-	 * @param array $params the parameters of the sql query
351
-	 * @param int $limit the maximum number of rows
352
-	 * @param int $offset from which row we want to start
353
-	 * @throws DoesNotExistException if the item does not exist
354
-	 * @throws MultipleObjectsReturnedException if more than one item exist
355
-	 * @return Entity the entity
356
-	 * @since 7.0.0
357
-	 */
358
-	protected function findEntity($sql, array $params=[], $limit=null, $offset=null){
359
-		return $this->mapRowToEntity($this->findOneQuery($sql, $params, $limit, $offset));
360
-	}
40
+    protected $tableName;
41
+    protected $entityClass;
42
+    protected $db;
43
+
44
+    /**
45
+     * @param IDBConnection $db Instance of the Db abstraction layer
46
+     * @param string $tableName the name of the table. set this to allow entity
47
+     * @param string $entityClass the name of the entity that the sql should be
48
+     * mapped to queries without using sql
49
+     * @since 7.0.0
50
+     */
51
+    public function __construct(IDBConnection $db, $tableName, $entityClass=null){
52
+        $this->db = $db;
53
+        $this->tableName = '*PREFIX*' . $tableName;
54
+
55
+        // if not given set the entity name to the class without the mapper part
56
+        // cache it here for later use since reflection is slow
57
+        if($entityClass === null) {
58
+            $this->entityClass = str_replace('Mapper', '', get_class($this));
59
+        } else {
60
+            $this->entityClass = $entityClass;
61
+        }
62
+    }
63
+
64
+
65
+    /**
66
+     * @return string the table name
67
+     * @since 7.0.0
68
+     */
69
+    public function getTableName(){
70
+        return $this->tableName;
71
+    }
72
+
73
+
74
+    /**
75
+     * Deletes an entity from the table
76
+     * @param Entity $entity the entity that should be deleted
77
+     * @return Entity the deleted entity
78
+     * @since 7.0.0 - return value added in 8.1.0
79
+     */
80
+    public function delete(Entity $entity){
81
+        $sql = 'DELETE FROM `' . $this->tableName . '` WHERE `id` = ?';
82
+        $stmt = $this->execute($sql, [$entity->getId()]);
83
+        $stmt->closeCursor();
84
+        return $entity;
85
+    }
86
+
87
+
88
+    /**
89
+     * Creates a new entry in the db from an entity
90
+     * @param Entity $entity the entity that should be created
91
+     * @return Entity the saved entity with the set id
92
+     * @since 7.0.0
93
+     */
94
+    public function insert(Entity $entity){
95
+        // get updated fields to save, fields have to be set using a setter to
96
+        // be saved
97
+        $properties = $entity->getUpdatedFields();
98
+        $values = '';
99
+        $columns = '';
100
+        $params = [];
101
+
102
+        // build the fields
103
+        $i = 0;
104
+        foreach($properties as $property => $updated) {
105
+            $column = $entity->propertyToColumn($property);
106
+            $getter = 'get' . ucfirst($property);
107
+
108
+            $columns .= '`' . $column . '`';
109
+            $values .= '?';
110
+
111
+            // only append colon if there are more entries
112
+            if($i < count($properties)-1){
113
+                $columns .= ',';
114
+                $values .= ',';
115
+            }
116
+
117
+            $params[] = $entity->$getter();
118
+            $i++;
119
+
120
+        }
121
+
122
+        $sql = 'INSERT INTO `' . $this->tableName . '`(' .
123
+                $columns . ') VALUES(' . $values . ')';
124
+
125
+        $stmt = $this->execute($sql, $params);
126
+
127
+        $entity->setId((int) $this->db->lastInsertId($this->tableName));
128
+
129
+        $stmt->closeCursor();
130
+
131
+        return $entity;
132
+    }
133
+
134
+
135
+
136
+    /**
137
+     * Updates an entry in the db from an entity
138
+     * @throws \InvalidArgumentException if entity has no id
139
+     * @param Entity $entity the entity that should be created
140
+     * @return Entity the saved entity with the set id
141
+     * @since 7.0.0 - return value was added in 8.0.0
142
+     */
143
+    public function update(Entity $entity){
144
+        // if entity wasn't changed it makes no sense to run a db query
145
+        $properties = $entity->getUpdatedFields();
146
+        if(count($properties) === 0) {
147
+            return $entity;
148
+        }
149
+
150
+        // entity needs an id
151
+        $id = $entity->getId();
152
+        if($id === null){
153
+            throw new \InvalidArgumentException(
154
+                'Entity which should be updated has no id');
155
+        }
156
+
157
+        // get updated fields to save, fields have to be set using a setter to
158
+        // be saved
159
+        // do not update the id field
160
+        unset($properties['id']);
161
+
162
+        $columns = '';
163
+        $params = [];
164
+
165
+        // build the fields
166
+        $i = 0;
167
+        foreach($properties as $property => $updated) {
168
+
169
+            $column = $entity->propertyToColumn($property);
170
+            $getter = 'get' . ucfirst($property);
171
+
172
+            $columns .= '`' . $column . '` = ?';
173
+
174
+            // only append colon if there are more entries
175
+            if($i < count($properties)-1){
176
+                $columns .= ',';
177
+            }
178
+
179
+            $params[] = $entity->$getter();
180
+            $i++;
181
+        }
182
+
183
+        $sql = 'UPDATE `' . $this->tableName . '` SET ' .
184
+                $columns . ' WHERE `id` = ?';
185
+        $params[] = $id;
186
+
187
+        $stmt = $this->execute($sql, $params);
188
+        $stmt->closeCursor();
189
+
190
+        return $entity;
191
+    }
192
+
193
+    /**
194
+     * Checks if an array is associative
195
+     * @param array $array
196
+     * @return bool true if associative
197
+     * @since 8.1.0
198
+     */
199
+    private function isAssocArray(array $array) {
200
+        return array_values($array) !== $array;
201
+    }
202
+
203
+    /**
204
+     * Returns the correct PDO constant based on the value type
205
+     * @param $value
206
+     * @return int PDO constant
207
+     * @since 8.1.0
208
+     */
209
+    private function getPDOType($value) {
210
+        switch (gettype($value)) {
211
+            case 'integer':
212
+                return \PDO::PARAM_INT;
213
+            case 'boolean':
214
+                return \PDO::PARAM_BOOL;
215
+            default:
216
+                return \PDO::PARAM_STR;
217
+        }
218
+    }
219
+
220
+
221
+    /**
222
+     * Runs an sql query
223
+     * @param string $sql the prepare string
224
+     * @param array $params the params which should replace the ? in the sql query
225
+     * @param int $limit the maximum number of rows
226
+     * @param int $offset from which row we want to start
227
+     * @return \PDOStatement the database query result
228
+     * @since 7.0.0
229
+     */
230
+    protected function execute($sql, array $params=[], $limit=null, $offset=null){
231
+        $query = $this->db->prepare($sql, $limit, $offset);
232
+
233
+        if ($this->isAssocArray($params)) {
234
+            foreach ($params as $key => $param) {
235
+                $pdoConstant = $this->getPDOType($param);
236
+                $query->bindValue($key, $param, $pdoConstant);
237
+            }
238
+        } else {
239
+            $index = 1;  // bindParam is 1 indexed
240
+            foreach ($params as $param) {
241
+                $pdoConstant = $this->getPDOType($param);
242
+                $query->bindValue($index, $param, $pdoConstant);
243
+                $index++;
244
+            }
245
+        }
246
+
247
+        $query->execute();
248
+
249
+        return $query;
250
+    }
251
+
252
+
253
+    /**
254
+     * Returns an db result and throws exceptions when there are more or less
255
+     * results
256
+     * @see findEntity
257
+     * @param string $sql the sql query
258
+     * @param array $params the parameters of the sql query
259
+     * @param int $limit the maximum number of rows
260
+     * @param int $offset from which row we want to start
261
+     * @throws DoesNotExistException if the item does not exist
262
+     * @throws MultipleObjectsReturnedException if more than one item exist
263
+     * @return array the result as row
264
+     * @since 7.0.0
265
+     */
266
+    protected function findOneQuery($sql, array $params=[], $limit=null, $offset=null){
267
+        $stmt = $this->execute($sql, $params, $limit, $offset);
268
+        $row = $stmt->fetch();
269
+
270
+        if($row === false || $row === null){
271
+            $stmt->closeCursor();
272
+            $msg = $this->buildDebugMessage(
273
+                'Did expect one result but found none when executing', $sql, $params, $limit, $offset
274
+            );
275
+            throw new DoesNotExistException($msg);
276
+        }
277
+        $row2 = $stmt->fetch();
278
+        $stmt->closeCursor();
279
+        //MDB2 returns null, PDO and doctrine false when no row is available
280
+        if( ! ($row2 === false || $row2 === null )) {
281
+            $msg = $this->buildDebugMessage(
282
+                'Did not expect more than one result when executing', $sql, $params, $limit, $offset
283
+            );
284
+            throw new MultipleObjectsReturnedException($msg);
285
+        } else {
286
+            return $row;
287
+        }
288
+    }
289
+
290
+    /**
291
+     * Builds an error message by prepending the $msg to an error message which
292
+     * has the parameters
293
+     * @see findEntity
294
+     * @param string $sql the sql query
295
+     * @param array $params the parameters of the sql query
296
+     * @param int $limit the maximum number of rows
297
+     * @param int $offset from which row we want to start
298
+     * @return string formatted error message string
299
+     * @since 9.1.0
300
+     */
301
+    private function buildDebugMessage($msg, $sql, array $params=[], $limit=null, $offset=null) {
302
+        return $msg .
303
+                    ': query "' .	$sql . '"; ' .
304
+                    'parameters ' . print_r($params, true) . '; ' .
305
+                    'limit "' . $limit . '"; '.
306
+                    'offset "' . $offset . '"';
307
+    }
308
+
309
+
310
+    /**
311
+     * Creates an entity from a row. Automatically determines the entity class
312
+     * from the current mapper name (MyEntityMapper -> MyEntity)
313
+     * @param array $row the row which should be converted to an entity
314
+     * @return Entity the entity
315
+     * @since 7.0.0
316
+     */
317
+    protected function mapRowToEntity($row) {
318
+        return call_user_func($this->entityClass .'::fromRow', $row);
319
+    }
320
+
321
+
322
+    /**
323
+     * Runs a sql query and returns an array of entities
324
+     * @param string $sql the prepare string
325
+     * @param array $params the params which should replace the ? in the sql query
326
+     * @param int $limit the maximum number of rows
327
+     * @param int $offset from which row we want to start
328
+     * @return array all fetched entities
329
+     * @since 7.0.0
330
+     */
331
+    protected function findEntities($sql, array $params=[], $limit=null, $offset=null) {
332
+        $stmt = $this->execute($sql, $params, $limit, $offset);
333
+
334
+        $entities = [];
335
+
336
+        while($row = $stmt->fetch()){
337
+            $entities[] = $this->mapRowToEntity($row);
338
+        }
339
+
340
+        $stmt->closeCursor();
341
+
342
+        return $entities;
343
+    }
344
+
345
+
346
+    /**
347
+     * Returns an db result and throws exceptions when there are more or less
348
+     * results
349
+     * @param string $sql the sql query
350
+     * @param array $params the parameters of the sql query
351
+     * @param int $limit the maximum number of rows
352
+     * @param int $offset from which row we want to start
353
+     * @throws DoesNotExistException if the item does not exist
354
+     * @throws MultipleObjectsReturnedException if more than one item exist
355
+     * @return Entity the entity
356
+     * @since 7.0.0
357
+     */
358
+    protected function findEntity($sql, array $params=[], $limit=null, $offset=null){
359
+        return $this->mapRowToEntity($this->findOneQuery($sql, $params, $limit, $offset));
360
+    }
361 361
 
362 362
 
363 363
 }
Please login to merge, or discard this patch.