Completed
Push — stable9 ( 11047b...318578 )
by Lukas
20:03 queued 09:36
created
apps/files_trashbin/lib/backgroundjob/expiretrash.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -23,7 +23,6 @@
 block discarded – undo
23 23
 
24 24
 namespace OCA\Files_Trashbin\BackgroundJob;
25 25
 
26
-use OCP\IConfig;
27 26
 use OCP\IUser;
28 27
 use OCP\IUserManager;
29 28
 use OCA\Files_Trashbin\AppInfo\Application;
Please login to merge, or discard this patch.
Indentation   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -34,76 +34,76 @@
 block discarded – undo
34 34
 
35 35
 class ExpireTrash extends \OC\BackgroundJob\TimedJob {
36 36
 
37
-	/**
38
-	 * @var Expiration
39
-	 */
40
-	private $expiration;
37
+    /**
38
+     * @var Expiration
39
+     */
40
+    private $expiration;
41 41
 	
42
-	/**
43
-	 * @var IUserManager
44
-	 */
45
-	private $userManager;
42
+    /**
43
+     * @var IUserManager
44
+     */
45
+    private $userManager;
46 46
 
47
-	/**
48
-	 * @param IUserManager|null $userManager
49
-	 * @param Expiration|null $expiration
50
-	 */
51
-	public function __construct(IUserManager $userManager = null,
52
-								Expiration $expiration = null) {
53
-		// Run once per 30 minutes
54
-		$this->setInterval(60 * 30);
47
+    /**
48
+     * @param IUserManager|null $userManager
49
+     * @param Expiration|null $expiration
50
+     */
51
+    public function __construct(IUserManager $userManager = null,
52
+                                Expiration $expiration = null) {
53
+        // Run once per 30 minutes
54
+        $this->setInterval(60 * 30);
55 55
 
56
-		if (is_null($expiration) || is_null($userManager)) {
57
-			$this->fixDIForJobs();
58
-		} else {
59
-			$this->userManager = $userManager;
60
-			$this->expiration = $expiration;
61
-		}
62
-	}
56
+        if (is_null($expiration) || is_null($userManager)) {
57
+            $this->fixDIForJobs();
58
+        } else {
59
+            $this->userManager = $userManager;
60
+            $this->expiration = $expiration;
61
+        }
62
+    }
63 63
 
64
-	protected function fixDIForJobs() {
65
-		$application = new Application();
66
-		$this->userManager = \OC::$server->getUserManager();
67
-		$this->expiration = $application->getContainer()->query('Expiration');
68
-	}
64
+    protected function fixDIForJobs() {
65
+        $application = new Application();
66
+        $this->userManager = \OC::$server->getUserManager();
67
+        $this->expiration = $application->getContainer()->query('Expiration');
68
+    }
69 69
 
70
-	/**
71
-	 * @param $argument
72
-	 * @throws \Exception
73
-	 */
74
-	protected function run($argument) {
75
-		$maxAge = $this->expiration->getMaxAgeAsTimestamp();
76
-		if (!$maxAge) {
77
-			return;
78
-		}
70
+    /**
71
+     * @param $argument
72
+     * @throws \Exception
73
+     */
74
+    protected function run($argument) {
75
+        $maxAge = $this->expiration->getMaxAgeAsTimestamp();
76
+        if (!$maxAge) {
77
+            return;
78
+        }
79 79
 
80
-		$this->userManager->callForAllUsers(function(IUser $user) {
81
-			$uid = $user->getUID();
82
-			if (!$this->setupFS($uid)) {
83
-				return;
84
-			}
85
-			$dirContent = Helper::getTrashFiles('/', $uid, 'mtime');
86
-			Trashbin::deleteExpiredFiles($dirContent, $uid);
87
-		});
80
+        $this->userManager->callForAllUsers(function(IUser $user) {
81
+            $uid = $user->getUID();
82
+            if (!$this->setupFS($uid)) {
83
+                return;
84
+            }
85
+            $dirContent = Helper::getTrashFiles('/', $uid, 'mtime');
86
+            Trashbin::deleteExpiredFiles($dirContent, $uid);
87
+        });
88 88
 		
89
-		\OC_Util::tearDownFS();
90
-	}
89
+        \OC_Util::tearDownFS();
90
+    }
91 91
 
92
-	/**
93
-	 * Act on behalf on trash item owner
94
-	 * @param string $user
95
-	 * @return boolean
96
-	 */
97
-	protected function setupFS($user) {
98
-		\OC_Util::tearDownFS();
99
-		\OC_Util::setupFS($user);
92
+    /**
93
+     * Act on behalf on trash item owner
94
+     * @param string $user
95
+     * @return boolean
96
+     */
97
+    protected function setupFS($user) {
98
+        \OC_Util::tearDownFS();
99
+        \OC_Util::setupFS($user);
100 100
 
101
-		// Check if this user has a trashbin directory
102
-		$view = new \OC\Files\View('/' . $user);
103
-		if (!$view->is_dir('/files_trashbin/files')) {
104
-			return false;
105
-		}
101
+        // Check if this user has a trashbin directory
102
+        $view = new \OC\Files\View('/' . $user);
103
+        if (!$view->is_dir('/files_trashbin/files')) {
104
+            return false;
105
+        }
106 106
 
107
-		return true;
108
-	}
107
+        return true;
108
+    }
109 109
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -117,7 +117,7 @@
 block discarded – undo
117 117
 		\OC_Util::setupFS($user);
118 118
 
119 119
 		// Check if this user has a trashbin directory
120
-		$view = new \OC\Files\View('/' . $user);
120
+		$view = new \OC\Files\View('/'.$user);
121 121
 		if (!$view->is_dir('/files_trashbin/files')) {
122 122
 			return false;
123 123
 		}
Please login to merge, or discard this patch.
apps/files_trashbin/lib/storage.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -110,7 +110,7 @@
 block discarded – undo
110 110
 	 * check if it is a file located in data/user/files only files in the
111 111
 	 * 'files' directory should be moved to the trash
112 112
 	 *
113
-	 * @param $path
113
+	 * @param string $path
114 114
 	 * @return bool
115 115
 	 */
116 116
 	protected function shouldMoveToTrash($path){
Please login to merge, or discard this patch.
Indentation   +154 added lines, -154 removed lines patch added patch discarded remove patch
@@ -32,159 +32,159 @@
 block discarded – undo
32 32
 
33 33
 class Storage extends Wrapper {
34 34
 
35
-	private $mountPoint;
36
-	// remember already deleted files to avoid infinite loops if the trash bin
37
-	// move files across storages
38
-	private $deletedFiles = array();
39
-
40
-	/**
41
-	 * Disable trash logic
42
-	 *
43
-	 * @var bool
44
-	 */
45
-	private static $disableTrash = false;
46
-
47
-	/** @var  IUserManager */
48
-	private $userManager;
49
-
50
-	function __construct($parameters, IUserManager $userManager = null) {
51
-		$this->mountPoint = $parameters['mountPoint'];
52
-		$this->userManager = $userManager;
53
-		parent::__construct($parameters);
54
-	}
55
-
56
-	/**
57
-	 * @internal
58
-	 */
59
-	public static function preRenameHook($params) {
60
-		// in cross-storage cases, a rename is a copy + unlink,
61
-		// that last unlink must not go to trash
62
-		self::$disableTrash = true;
63
-	}
64
-
65
-	/**
66
-	 * @internal
67
-	 */
68
-	public static function postRenameHook($params) {
69
-		self::$disableTrash = false;
70
-	}
71
-
72
-	/**
73
-	 * Rename path1 to path2 by calling the wrapped storage.
74
-	 *
75
-	 * @param string $path1 first path
76
-	 * @param string $path2 second path
77
-	 */
78
-	public function rename($path1, $path2) {
79
-		$result = $this->storage->rename($path1, $path2);
80
-		if ($result === false) {
81
-			// when rename failed, the post_rename hook isn't triggered,
82
-			// but we still want to reenable the trash logic
83
-			self::$disableTrash = false;
84
-		}
85
-		return $result;
86
-	}
87
-
88
-	/**
89
-	 * Deletes the given file by moving it into the trashbin.
90
-	 *
91
-	 * @param string $path path of file or folder to delete
92
-	 *
93
-	 * @return bool true if the operation succeeded, false otherwise
94
-	 */
95
-	public function unlink($path) {
96
-		return $this->doDelete($path, 'unlink');
97
-	}
98
-
99
-	/**
100
-	 * Deletes the given folder by moving it into the trashbin.
101
-	 *
102
-	 * @param string $path path of folder to delete
103
-	 *
104
-	 * @return bool true if the operation succeeded, false otherwise
105
-	 */
106
-	public function rmdir($path) {
107
-		return $this->doDelete($path, 'rmdir');
108
-	}
109
-
110
-	/**
111
-	 * check if it is a file located in data/user/files only files in the
112
-	 * 'files' directory should be moved to the trash
113
-	 *
114
-	 * @param $path
115
-	 * @return bool
116
-	 */
117
-	protected function shouldMoveToTrash($path){
118
-		$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
119
-		$parts = explode('/', $normalized);
120
-		if (count($parts) < 4) {
121
-			return false;
122
-		}
123
-
124
-		if ($this->userManager->userExists($parts[1]) && $parts[2] == 'files') {
125
-			return true;
126
-		}
127
-
128
-		return false;
129
-	}
130
-
131
-	/**
132
-	 * Run the delete operation with the given method
133
-	 *
134
-	 * @param string $path path of file or folder to delete
135
-	 * @param string $method either "unlink" or "rmdir"
136
-	 *
137
-	 * @return bool true if the operation succeeded, false otherwise
138
-	 */
139
-	private function doDelete($path, $method) {
140
-		if (self::$disableTrash
141
-			|| !\OC_App::isEnabled('files_trashbin')
142
-			|| (pathinfo($path, PATHINFO_EXTENSION) === 'part')
143
-			|| $this->shouldMoveToTrash($path) === false
144
-		) {
145
-			return call_user_func_array([$this->storage, $method], [$path]);
146
-		}
147
-
148
-		// check permissions before we continue, this is especially important for
149
-		// shared files
150
-		if (!$this->isDeletable($path)) {
151
-			return false;
152
-		}
153
-
154
-		$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
155
-		$result = true;
156
-		$view = Filesystem::getView();
157
-		if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) {
158
-			$this->deletedFiles[$normalized] = $normalized;
159
-			if ($filesPath = $view->getRelativePath($normalized)) {
160
-				$filesPath = trim($filesPath, '/');
161
-				$result = \OCA\Files_Trashbin\Trashbin::move2trash($filesPath);
162
-				// in cross-storage cases the file will be copied
163
-				// but not deleted, so we delete it here
164
-				if ($result) {
165
-					call_user_func_array([$this->storage, $method], [$path]);
166
-				}
167
-			} else {
168
-				$result = call_user_func_array([$this->storage, $method], [$path]);
169
-			}
170
-			unset($this->deletedFiles[$normalized]);
171
-		} else if ($this->storage->file_exists($path)) {
172
-			$result = call_user_func_array([$this->storage, $method], [$path]);
173
-		}
174
-
175
-		return $result;
176
-	}
177
-
178
-	/**
179
-	 * Setup the storate wrapper callback
180
-	 */
181
-	public static function setupStorage() {
182
-		\OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
183
-			return new \OCA\Files_Trashbin\Storage(
184
-				array('storage' => $storage, 'mountPoint' => $mountPoint),
185
-				\OC::$server->getUserManager()
186
-			);
187
-		}, 1);
188
-	}
35
+    private $mountPoint;
36
+    // remember already deleted files to avoid infinite loops if the trash bin
37
+    // move files across storages
38
+    private $deletedFiles = array();
39
+
40
+    /**
41
+     * Disable trash logic
42
+     *
43
+     * @var bool
44
+     */
45
+    private static $disableTrash = false;
46
+
47
+    /** @var  IUserManager */
48
+    private $userManager;
49
+
50
+    function __construct($parameters, IUserManager $userManager = null) {
51
+        $this->mountPoint = $parameters['mountPoint'];
52
+        $this->userManager = $userManager;
53
+        parent::__construct($parameters);
54
+    }
55
+
56
+    /**
57
+     * @internal
58
+     */
59
+    public static function preRenameHook($params) {
60
+        // in cross-storage cases, a rename is a copy + unlink,
61
+        // that last unlink must not go to trash
62
+        self::$disableTrash = true;
63
+    }
64
+
65
+    /**
66
+     * @internal
67
+     */
68
+    public static function postRenameHook($params) {
69
+        self::$disableTrash = false;
70
+    }
71
+
72
+    /**
73
+     * Rename path1 to path2 by calling the wrapped storage.
74
+     *
75
+     * @param string $path1 first path
76
+     * @param string $path2 second path
77
+     */
78
+    public function rename($path1, $path2) {
79
+        $result = $this->storage->rename($path1, $path2);
80
+        if ($result === false) {
81
+            // when rename failed, the post_rename hook isn't triggered,
82
+            // but we still want to reenable the trash logic
83
+            self::$disableTrash = false;
84
+        }
85
+        return $result;
86
+    }
87
+
88
+    /**
89
+     * Deletes the given file by moving it into the trashbin.
90
+     *
91
+     * @param string $path path of file or folder to delete
92
+     *
93
+     * @return bool true if the operation succeeded, false otherwise
94
+     */
95
+    public function unlink($path) {
96
+        return $this->doDelete($path, 'unlink');
97
+    }
98
+
99
+    /**
100
+     * Deletes the given folder by moving it into the trashbin.
101
+     *
102
+     * @param string $path path of folder to delete
103
+     *
104
+     * @return bool true if the operation succeeded, false otherwise
105
+     */
106
+    public function rmdir($path) {
107
+        return $this->doDelete($path, 'rmdir');
108
+    }
109
+
110
+    /**
111
+     * check if it is a file located in data/user/files only files in the
112
+     * 'files' directory should be moved to the trash
113
+     *
114
+     * @param $path
115
+     * @return bool
116
+     */
117
+    protected function shouldMoveToTrash($path){
118
+        $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
119
+        $parts = explode('/', $normalized);
120
+        if (count($parts) < 4) {
121
+            return false;
122
+        }
123
+
124
+        if ($this->userManager->userExists($parts[1]) && $parts[2] == 'files') {
125
+            return true;
126
+        }
127
+
128
+        return false;
129
+    }
130
+
131
+    /**
132
+     * Run the delete operation with the given method
133
+     *
134
+     * @param string $path path of file or folder to delete
135
+     * @param string $method either "unlink" or "rmdir"
136
+     *
137
+     * @return bool true if the operation succeeded, false otherwise
138
+     */
139
+    private function doDelete($path, $method) {
140
+        if (self::$disableTrash
141
+            || !\OC_App::isEnabled('files_trashbin')
142
+            || (pathinfo($path, PATHINFO_EXTENSION) === 'part')
143
+            || $this->shouldMoveToTrash($path) === false
144
+        ) {
145
+            return call_user_func_array([$this->storage, $method], [$path]);
146
+        }
147
+
148
+        // check permissions before we continue, this is especially important for
149
+        // shared files
150
+        if (!$this->isDeletable($path)) {
151
+            return false;
152
+        }
153
+
154
+        $normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
155
+        $result = true;
156
+        $view = Filesystem::getView();
157
+        if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) {
158
+            $this->deletedFiles[$normalized] = $normalized;
159
+            if ($filesPath = $view->getRelativePath($normalized)) {
160
+                $filesPath = trim($filesPath, '/');
161
+                $result = \OCA\Files_Trashbin\Trashbin::move2trash($filesPath);
162
+                // in cross-storage cases the file will be copied
163
+                // but not deleted, so we delete it here
164
+                if ($result) {
165
+                    call_user_func_array([$this->storage, $method], [$path]);
166
+                }
167
+            } else {
168
+                $result = call_user_func_array([$this->storage, $method], [$path]);
169
+            }
170
+            unset($this->deletedFiles[$normalized]);
171
+        } else if ($this->storage->file_exists($path)) {
172
+            $result = call_user_func_array([$this->storage, $method], [$path]);
173
+        }
174
+
175
+        return $result;
176
+    }
177
+
178
+    /**
179
+     * Setup the storate wrapper callback
180
+     */
181
+    public static function setupStorage() {
182
+        \OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
183
+            return new \OCA\Files_Trashbin\Storage(
184
+                array('storage' => $storage, 'mountPoint' => $mountPoint),
185
+                \OC::$server->getUserManager()
186
+            );
187
+        }, 1);
188
+    }
189 189
 
190 190
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -114,8 +114,8 @@  discard block
 block discarded – undo
114 114
 	 * @param $path
115 115
 	 * @return bool
116 116
 	 */
117
-	protected function shouldMoveToTrash($path){
118
-		$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
117
+	protected function shouldMoveToTrash($path) {
118
+		$normalized = Filesystem::normalizePath($this->mountPoint.'/'.$path);
119 119
 		$parts = explode('/', $normalized);
120 120
 		if (count($parts) < 4) {
121 121
 			return false;
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
 			return false;
152 152
 		}
153 153
 
154
-		$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
154
+		$normalized = Filesystem::normalizePath($this->mountPoint.'/'.$path);
155 155
 		$result = true;
156 156
 		$view = Filesystem::getView();
157 157
 		if (!isset($this->deletedFiles[$normalized]) && $view instanceof View) {
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
 	 * Setup the storate wrapper callback
180 180
 	 */
181 181
 	public static function setupStorage() {
182
-		\OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
182
+		\OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function($mountPoint, $storage) {
183 183
 			return new \OCA\Files_Trashbin\Storage(
184 184
 				array('storage' => $storage, 'mountPoint' => $mountPoint),
185 185
 				\OC::$server->getUserManager()
Please login to merge, or discard this patch.
lib/private/app.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -1333,6 +1333,9 @@
 block discarded – undo
1333 1333
 		}
1334 1334
 	}
1335 1335
 
1336
+	/**
1337
+	 * @param string $lang
1338
+	 */
1336 1339
 	protected static function findBestL10NOption($options, $lang) {
1337 1340
 		$fallback = $similarLangFallback = $englishFallback = false;
1338 1341
 
Please login to merge, or discard this patch.
Indentation   +1241 added lines, -1241 removed lines patch added patch discarded remove patch
@@ -55,1245 +55,1245 @@
 block discarded – undo
55 55
  * upgrading and removing apps.
56 56
  */
57 57
 class OC_App {
58
-	static private $appVersion = [];
59
-	static private $adminForms = array();
60
-	static private $personalForms = array();
61
-	static private $appInfo = array();
62
-	static private $appTypes = array();
63
-	static private $loadedApps = array();
64
-	static private $altLogin = array();
65
-	const officialApp = 200;
66
-
67
-	/**
68
-	 * clean the appId
69
-	 *
70
-	 * @param string|boolean $app AppId that needs to be cleaned
71
-	 * @return string
72
-	 */
73
-	public static function cleanAppId($app) {
74
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
75
-	}
76
-
77
-	/**
78
-	 * Check if an app is loaded
79
-	 *
80
-	 * @param string $app
81
-	 * @return bool
82
-	 */
83
-	public static function isAppLoaded($app) {
84
-		return in_array($app, self::$loadedApps, true);
85
-	}
86
-
87
-	/**
88
-	 * loads all apps
89
-	 *
90
-	 * @param string[] | string | null $types
91
-	 * @return bool
92
-	 *
93
-	 * This function walks through the ownCloud directory and loads all apps
94
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
95
-	 * exists.
96
-	 *
97
-	 * if $types is set, only apps of those types will be loaded
98
-	 */
99
-	public static function loadApps($types = null) {
100
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
101
-			return false;
102
-		}
103
-		// Load the enabled apps here
104
-		$apps = self::getEnabledApps();
105
-
106
-		// Add each apps' folder as allowed class path
107
-		foreach($apps as $app) {
108
-			$path = self::getAppPath($app);
109
-			if($path !== false) {
110
-				\OC::$loader->addValidRoot($path);
111
-			}
112
-		}
113
-
114
-		// prevent app.php from printing output
115
-		ob_start();
116
-		foreach ($apps as $app) {
117
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
118
-				self::loadApp($app);
119
-			}
120
-		}
121
-		ob_end_clean();
122
-
123
-		return true;
124
-	}
125
-
126
-	/**
127
-	 * load a single app
128
-	 *
129
-	 * @param string $app
130
-	 * @param bool $checkUpgrade whether an upgrade check should be done
131
-	 * @throws \OC\NeedsUpdateException
132
-	 */
133
-	public static function loadApp($app, $checkUpgrade = true) {
134
-		self::$loadedApps[] = $app;
135
-		$appPath = self::getAppPath($app);
136
-		if($appPath === false) {
137
-			return;
138
-		}
139
-		\OC::$loader->addValidRoot($appPath); // in case someone calls loadApp() directly
140
-		if (is_file($appPath . '/appinfo/app.php')) {
141
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
142
-			if ($checkUpgrade and self::shouldUpgrade($app)) {
143
-				throw new \OC\NeedsUpdateException();
144
-			}
145
-			self::requireAppFile($app);
146
-			if (self::isType($app, array('authentication'))) {
147
-				// since authentication apps affect the "is app enabled for group" check,
148
-				// the enabled apps cache needs to be cleared to make sure that the
149
-				// next time getEnableApps() is called it will also include apps that were
150
-				// enabled for groups
151
-				self::$enabledAppsCache = array();
152
-			}
153
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
154
-		}
155
-	}
156
-
157
-	/**
158
-	 * Load app.php from the given app
159
-	 *
160
-	 * @param string $app app name
161
-	 */
162
-	private static function requireAppFile($app) {
163
-		// encapsulated here to avoid variable scope conflicts
164
-		require_once $app . '/appinfo/app.php';
165
-	}
166
-
167
-	/**
168
-	 * check if an app is of a specific type
169
-	 *
170
-	 * @param string $app
171
-	 * @param string|array $types
172
-	 * @return bool
173
-	 */
174
-	public static function isType($app, $types) {
175
-		if (is_string($types)) {
176
-			$types = array($types);
177
-		}
178
-		$appTypes = self::getAppTypes($app);
179
-		foreach ($types as $type) {
180
-			if (array_search($type, $appTypes) !== false) {
181
-				return true;
182
-			}
183
-		}
184
-		return false;
185
-	}
186
-
187
-	/**
188
-	 * get the types of an app
189
-	 *
190
-	 * @param string $app
191
-	 * @return array
192
-	 */
193
-	private static function getAppTypes($app) {
194
-		//load the cache
195
-		if (count(self::$appTypes) == 0) {
196
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
197
-		}
198
-
199
-		if (isset(self::$appTypes[$app])) {
200
-			return explode(',', self::$appTypes[$app]);
201
-		} else {
202
-			return array();
203
-		}
204
-	}
205
-
206
-	/**
207
-	 * read app types from info.xml and cache them in the database
208
-	 */
209
-	public static function setAppTypes($app) {
210
-		$appData = self::getAppInfo($app);
211
-		if(!is_array($appData)) {
212
-			return;
213
-		}
214
-
215
-		if (isset($appData['types'])) {
216
-			$appTypes = implode(',', $appData['types']);
217
-		} else {
218
-			$appTypes = '';
219
-		}
220
-
221
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
222
-	}
223
-
224
-	/**
225
-	 * check if app is shipped
226
-	 *
227
-	 * @param string $appId the id of the app to check
228
-	 * @return bool
229
-	 *
230
-	 * Check if an app that is installed is a shipped app or installed from the appstore.
231
-	 */
232
-	public static function isShipped($appId) {
233
-		return \OC::$server->getAppManager()->isShipped($appId);
234
-	}
235
-
236
-	/**
237
-	 * get all enabled apps
238
-	 */
239
-	protected static $enabledAppsCache = array();
240
-
241
-	/**
242
-	 * Returns apps enabled for the current user.
243
-	 *
244
-	 * @param bool $forceRefresh whether to refresh the cache
245
-	 * @param bool $all whether to return apps for all users, not only the
246
-	 * currently logged in one
247
-	 * @return string[]
248
-	 */
249
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
250
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
251
-			return array();
252
-		}
253
-		// in incognito mode or when logged out, $user will be false,
254
-		// which is also the case during an upgrade
255
-		$appManager = \OC::$server->getAppManager();
256
-		if ($all) {
257
-			$user = null;
258
-		} else {
259
-			$user = \OC::$server->getUserSession()->getUser();
260
-		}
261
-
262
-		if (is_null($user)) {
263
-			$apps = $appManager->getInstalledApps();
264
-		} else {
265
-			$apps = $appManager->getEnabledAppsForUser($user);
266
-		}
267
-		$apps = array_filter($apps, function ($app) {
268
-			return $app !== 'files';//we add this manually
269
-		});
270
-		sort($apps);
271
-		array_unshift($apps, 'files');
272
-		return $apps;
273
-	}
274
-
275
-	/**
276
-	 * checks whether or not an app is enabled
277
-	 *
278
-	 * @param string $app app
279
-	 * @return bool
280
-	 *
281
-	 * This function checks whether or not an app is enabled.
282
-	 */
283
-	public static function isEnabled($app) {
284
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
285
-	}
286
-
287
-	/**
288
-	 * enables an app
289
-	 *
290
-	 * @param mixed $app app
291
-	 * @param array $groups (optional) when set, only these groups will have access to the app
292
-	 * @throws \Exception
293
-	 * @return void
294
-	 *
295
-	 * This function set an app as enabled in appconfig.
296
-	 */
297
-	public static function enable($app, $groups = null) {
298
-		self::$enabledAppsCache = array(); // flush
299
-		if (!OC_Installer::isInstalled($app)) {
300
-			$app = self::installApp($app);
301
-		}
302
-
303
-		$appManager = \OC::$server->getAppManager();
304
-		if (!is_null($groups)) {
305
-			$groupManager = \OC::$server->getGroupManager();
306
-			$groupsList = [];
307
-			foreach ($groups as $group) {
308
-				$groupItem = $groupManager->get($group);
309
-				if ($groupItem instanceof \OCP\IGroup) {
310
-					$groupsList[] = $groupManager->get($group);
311
-				}
312
-			}
313
-			$appManager->enableAppForGroups($app, $groupsList);
314
-		} else {
315
-			$appManager->enableApp($app);
316
-		}
317
-	}
318
-
319
-	/**
320
-	 * @param string $app
321
-	 * @return int
322
-	 */
323
-	private static function downloadApp($app) {
324
-		$ocsClient = new OCSClient(
325
-			\OC::$server->getHTTPClientService(),
326
-			\OC::$server->getConfig(),
327
-			\OC::$server->getLogger()
328
-		);
329
-		$appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
330
-		$download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
331
-		if(isset($download['downloadlink']) and $download['downloadlink']!='') {
332
-			// Replace spaces in download link without encoding entire URL
333
-			$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
334
-			$info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
335
-			$app = OC_Installer::installApp($info);
336
-		}
337
-		return $app;
338
-	}
339
-
340
-	/**
341
-	 * @param string $app
342
-	 * @return bool
343
-	 */
344
-	public static function removeApp($app) {
345
-		if (self::isShipped($app)) {
346
-			return false;
347
-		}
348
-
349
-		return OC_Installer::removeApp($app);
350
-	}
351
-
352
-	/**
353
-	 * This function set an app as disabled in appconfig.
354
-	 *
355
-	 * @param string $app app
356
-	 * @throws Exception
357
-	 */
358
-	public static function disable($app) {
359
-		// Convert OCS ID to regular application identifier
360
-		if(self::getInternalAppIdByOcs($app) !== false) {
361
-			$app = self::getInternalAppIdByOcs($app);
362
-		}
363
-
364
-		self::$enabledAppsCache = array(); // flush
365
-		// check if app is a shipped app or not. if not delete
366
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
367
-		$appManager = \OC::$server->getAppManager();
368
-		$appManager->disableApp($app);
369
-	}
370
-
371
-	/**
372
-	 * Returns the Settings Navigation
373
-	 *
374
-	 * @return string[]
375
-	 *
376
-	 * This function returns an array containing all settings pages added. The
377
-	 * entries are sorted by the key 'order' ascending.
378
-	 */
379
-	public static function getSettingsNavigation() {
380
-		$l = \OC::$server->getL10N('lib');
381
-		$urlGenerator = \OC::$server->getURLGenerator();
382
-
383
-		$settings = array();
384
-		// by default, settings only contain the help menu
385
-		if (OC_Util::getEditionString() === '' &&
386
-			\OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true
387
-		) {
388
-			$settings = array(
389
-				array(
390
-					"id" => "help",
391
-					"order" => 1000,
392
-					"href" => $urlGenerator->linkToRoute('settings_help'),
393
-					"name" => $l->t("Help"),
394
-					"icon" => $urlGenerator->imagePath("settings", "help.svg")
395
-				)
396
-			);
397
-		}
398
-
399
-		// if the user is logged-in
400
-		if (OC_User::isLoggedIn()) {
401
-			// personal menu
402
-			$settings[] = array(
403
-				"id" => "personal",
404
-				"order" => 1,
405
-				"href" => $urlGenerator->linkToRoute('settings_personal'),
406
-				"name" => $l->t("Personal"),
407
-				"icon" => $urlGenerator->imagePath("settings", "personal.svg")
408
-			);
409
-
410
-			//SubAdmins are also allowed to access user management
411
-			$userObject = \OC::$server->getUserSession()->getUser();
412
-			$isSubAdmin = false;
413
-			if($userObject !== null) {
414
-				$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
415
-			}
416
-			if ($isSubAdmin) {
417
-				// admin users menu
418
-				$settings[] = array(
419
-					"id" => "core_users",
420
-					"order" => 2,
421
-					"href" => $urlGenerator->linkToRoute('settings_users'),
422
-					"name" => $l->t("Users"),
423
-					"icon" => $urlGenerator->imagePath("settings", "users.svg")
424
-				);
425
-			}
426
-
427
-			// if the user is an admin
428
-			if (OC_User::isAdminUser(OC_User::getUser())) {
429
-				// admin settings
430
-				$settings[] = array(
431
-					"id" => "admin",
432
-					"order" => 1000,
433
-					"href" => $urlGenerator->linkToRoute('settings_admin'),
434
-					"name" => $l->t("Admin"),
435
-					"icon" => $urlGenerator->imagePath("settings", "admin.svg")
436
-				);
437
-			}
438
-		}
439
-
440
-		$navigation = self::proceedNavigation($settings);
441
-		return $navigation;
442
-	}
443
-
444
-	// This is private as well. It simply works, so don't ask for more details
445
-	private static function proceedNavigation($list) {
446
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
447
-		foreach ($list as &$navEntry) {
448
-			if ($navEntry['id'] == $activeApp) {
449
-				$navEntry['active'] = true;
450
-			} else {
451
-				$navEntry['active'] = false;
452
-			}
453
-		}
454
-		unset($navEntry);
455
-
456
-		usort($list, create_function('$a, $b', 'if( $a["order"] == $b["order"] ) {return 0;}elseif( $a["order"] < $b["order"] ) {return -1;}else{return 1;}'));
457
-
458
-		return $list;
459
-	}
460
-
461
-	/**
462
-	 * Get the path where to install apps
463
-	 *
464
-	 * @return string|false
465
-	 */
466
-	public static function getInstallPath() {
467
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
468
-			return false;
469
-		}
470
-
471
-		foreach (OC::$APPSROOTS as $dir) {
472
-			if (isset($dir['writable']) && $dir['writable'] === true) {
473
-				return $dir['path'];
474
-			}
475
-		}
476
-
477
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
478
-		return null;
479
-	}
480
-
481
-
482
-	/**
483
-	 * search for an app in all app-directories
484
-	 *
485
-	 * @param string $appId
486
-	 * @return false|string
487
-	 */
488
-	protected static function findAppInDirectories($appId) {
489
-		$sanitizedAppId = self::cleanAppId($appId);
490
-		if($sanitizedAppId !== $appId) {
491
-			return false;
492
-		}
493
-		static $app_dir = array();
494
-
495
-		if (isset($app_dir[$appId])) {
496
-			return $app_dir[$appId];
497
-		}
498
-
499
-		$possibleApps = array();
500
-		foreach (OC::$APPSROOTS as $dir) {
501
-			if (file_exists($dir['path'] . '/' . $appId)) {
502
-				$possibleApps[] = $dir;
503
-			}
504
-		}
505
-
506
-		if (empty($possibleApps)) {
507
-			return false;
508
-		} elseif (count($possibleApps) === 1) {
509
-			$dir = array_shift($possibleApps);
510
-			$app_dir[$appId] = $dir;
511
-			return $dir;
512
-		} else {
513
-			$versionToLoad = array();
514
-			foreach ($possibleApps as $possibleApp) {
515
-				$version = self::getAppVersionByPath($possibleApp['path']);
516
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
517
-					$versionToLoad = array(
518
-						'dir' => $possibleApp,
519
-						'version' => $version,
520
-					);
521
-				}
522
-			}
523
-			$app_dir[$appId] = $versionToLoad['dir'];
524
-			return $versionToLoad['dir'];
525
-			//TODO - write test
526
-		}
527
-	}
528
-
529
-	/**
530
-	 * Get the directory for the given app.
531
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
532
-	 *
533
-	 * @param string $appId
534
-	 * @return string|false
535
-	 */
536
-	public static function getAppPath($appId) {
537
-		if ($appId === null || trim($appId) === '') {
538
-			return false;
539
-		}
540
-
541
-		if (($dir = self::findAppInDirectories($appId)) != false) {
542
-			return $dir['path'] . '/' . $appId;
543
-		}
544
-		return false;
545
-	}
546
-
547
-
548
-	/**
549
-	 * check if an app's directory is writable
550
-	 *
551
-	 * @param string $appId
552
-	 * @return bool
553
-	 */
554
-	public static function isAppDirWritable($appId) {
555
-		$path = self::getAppPath($appId);
556
-		return ($path !== false) ? is_writable($path) : false;
557
-	}
558
-
559
-	/**
560
-	 * Get the path for the given app on the access
561
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
562
-	 *
563
-	 * @param string $appId
564
-	 * @return string|false
565
-	 */
566
-	public static function getAppWebPath($appId) {
567
-		if (($dir = self::findAppInDirectories($appId)) != false) {
568
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
569
-		}
570
-		return false;
571
-	}
572
-
573
-	/**
574
-	 * get the last version of the app, either from appinfo/version or from appinfo/info.xml
575
-	 *
576
-	 * @param string $appId
577
-	 * @return string
578
-	 */
579
-	public static function getAppVersion($appId) {
580
-		if (!isset(self::$appVersion[$appId])) {
581
-			$file = self::getAppPath($appId);
582
-			self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
583
-		}
584
-		return self::$appVersion[$appId];
585
-	}
586
-
587
-	/**
588
-	 * get app's version based on it's path
589
-	 *
590
-	 * @param string $path
591
-	 * @return string
592
-	 */
593
-	public static function getAppVersionByPath($path) {
594
-		$versionFile = $path . '/appinfo/version';
595
-		$infoFile = $path . '/appinfo/info.xml';
596
-		if (is_file($versionFile)) {
597
-			return trim(file_get_contents($versionFile));
598
-		} else {
599
-			$appData = self::getAppInfo($infoFile, true);
600
-			return isset($appData['version']) ? $appData['version'] : '';
601
-		}
602
-	}
603
-
604
-
605
-	/**
606
-	 * Read all app metadata from the info.xml file
607
-	 *
608
-	 * @param string $appId id of the app or the path of the info.xml file
609
-	 * @param boolean $path
610
-	 * @param string $lang
611
-	 * @return array|null
612
-	 * @note all data is read from info.xml, not just pre-defined fields
613
-	 */
614
-	public static function getAppInfo($appId, $path = false, $lang = null) {
615
-		if ($path) {
616
-			$file = $appId;
617
-		} else {
618
-			if ($lang === null && isset(self::$appInfo[$appId])) {
619
-				return self::$appInfo[$appId];
620
-			}
621
-			$appPath = self::getAppPath($appId);
622
-			if($appPath === false) {
623
-				return null;
624
-			}
625
-			$file = $appPath . '/appinfo/info.xml';
626
-		}
627
-
628
-		$parser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
629
-		$data = $parser->parse($file);
630
-
631
-		if (is_array($data)) {
632
-			$data = OC_App::parseAppInfo($data, $lang);
633
-		}
634
-		if(isset($data['ocsid'])) {
635
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
636
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
637
-				$data['ocsid'] = $storedId;
638
-			}
639
-		}
640
-
641
-		if ($lang === null) {
642
-			self::$appInfo[$appId] = $data;
643
-		}
644
-
645
-		return $data;
646
-	}
647
-
648
-	/**
649
-	 * Returns the navigation
650
-	 *
651
-	 * @return array
652
-	 *
653
-	 * This function returns an array containing all entries added. The
654
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
655
-	 * given for each app the following keys exist:
656
-	 *   - active: boolean, signals if the user is on this navigation entry
657
-	 */
658
-	public static function getNavigation() {
659
-		$entries = OC::$server->getNavigationManager()->getAll();
660
-		$navigation = self::proceedNavigation($entries);
661
-		return $navigation;
662
-	}
663
-
664
-	/**
665
-	 * get the id of loaded app
666
-	 *
667
-	 * @return string
668
-	 */
669
-	public static function getCurrentApp() {
670
-		$request = \OC::$server->getRequest();
671
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
672
-		$topFolder = substr($script, 0, strpos($script, '/'));
673
-		if (empty($topFolder)) {
674
-			$path_info = $request->getPathInfo();
675
-			if ($path_info) {
676
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
677
-			}
678
-		}
679
-		if ($topFolder == 'apps') {
680
-			$length = strlen($topFolder);
681
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
682
-		} else {
683
-			return $topFolder;
684
-		}
685
-	}
686
-
687
-	/**
688
-	 * @param string $type
689
-	 * @return array
690
-	 */
691
-	public static function getForms($type) {
692
-		$forms = array();
693
-		switch ($type) {
694
-			case 'admin':
695
-				$source = self::$adminForms;
696
-				break;
697
-			case 'personal':
698
-				$source = self::$personalForms;
699
-				break;
700
-			default:
701
-				return array();
702
-		}
703
-		foreach ($source as $form) {
704
-			$forms[] = include $form;
705
-		}
706
-		return $forms;
707
-	}
708
-
709
-	/**
710
-	 * register an admin form to be shown
711
-	 *
712
-	 * @param string $app
713
-	 * @param string $page
714
-	 */
715
-	public static function registerAdmin($app, $page) {
716
-		self::$adminForms[] = $app . '/' . $page . '.php';
717
-	}
718
-
719
-	/**
720
-	 * register a personal form to be shown
721
-	 * @param string $app
722
-	 * @param string $page
723
-	 */
724
-	public static function registerPersonal($app, $page) {
725
-		self::$personalForms[] = $app . '/' . $page . '.php';
726
-	}
727
-
728
-	/**
729
-	 * @param array $entry
730
-	 */
731
-	public static function registerLogIn(array $entry) {
732
-		self::$altLogin[] = $entry;
733
-	}
734
-
735
-	/**
736
-	 * @return array
737
-	 */
738
-	public static function getAlternativeLogIns() {
739
-		return self::$altLogin;
740
-	}
741
-
742
-	/**
743
-	 * get a list of all apps in the apps folder
744
-	 *
745
-	 * @return array an array of app names (string IDs)
746
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
747
-	 */
748
-	public static function getAllApps() {
749
-
750
-		$apps = array();
751
-
752
-		foreach (OC::$APPSROOTS as $apps_dir) {
753
-			if (!is_readable($apps_dir['path'])) {
754
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
755
-				continue;
756
-			}
757
-			$dh = opendir($apps_dir['path']);
758
-
759
-			if (is_resource($dh)) {
760
-				while (($file = readdir($dh)) !== false) {
761
-
762
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
763
-
764
-						$apps[] = $file;
765
-					}
766
-				}
767
-			}
768
-		}
769
-
770
-		return $apps;
771
-	}
772
-
773
-	/**
774
-	 * List all apps, this is used in apps.php
775
-	 *
776
-	 * @param bool $onlyLocal
777
-	 * @param bool $includeUpdateInfo Should we check whether there is an update
778
-	 *                                in the app store?
779
-	 * @param OCSClient $ocsClient
780
-	 * @return array
781
-	 */
782
-	public static function listAllApps($onlyLocal = false,
783
-									   $includeUpdateInfo = true,
784
-									   OCSClient $ocsClient) {
785
-		$installedApps = OC_App::getAllApps();
786
-
787
-		//TODO which apps do we want to blacklist and how do we integrate
788
-		// blacklisting with the multi apps folder feature?
789
-
790
-		//we don't want to show configuration for these
791
-		$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
792
-		$appList = array();
793
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
794
-
795
-		foreach ($installedApps as $app) {
796
-			if (array_search($app, $blacklist) === false) {
797
-
798
-				$info = OC_App::getAppInfo($app, false, $langCode);
799
-				if (!is_array($info)) {
800
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
801
-					continue;
802
-				}
803
-
804
-				if (!isset($info['name'])) {
805
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
806
-					continue;
807
-				}
808
-
809
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
810
-				$info['groups'] = null;
811
-				if ($enabled === 'yes') {
812
-					$active = true;
813
-				} else if ($enabled === 'no') {
814
-					$active = false;
815
-				} else {
816
-					$active = true;
817
-					$info['groups'] = $enabled;
818
-				}
819
-
820
-				$info['active'] = $active;
821
-
822
-				if (self::isShipped($app)) {
823
-					$info['internal'] = true;
824
-					$info['level'] = self::officialApp;
825
-					$info['removable'] = false;
826
-				} else {
827
-					$info['internal'] = false;
828
-					$info['removable'] = true;
829
-				}
830
-
831
-				$info['update'] = ($includeUpdateInfo) ? OC_Installer::isUpdateAvailable($app) : null;
832
-
833
-				$appPath = self::getAppPath($app);
834
-				if($appPath !== false) {
835
-					$appIcon = $appPath . '/img/' . $app . '.svg';
836
-					if (file_exists($appIcon)) {
837
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
838
-						$info['previewAsIcon'] = true;
839
-					} else {
840
-						$appIcon = $appPath . '/img/app.svg';
841
-						if (file_exists($appIcon)) {
842
-							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
843
-							$info['previewAsIcon'] = true;
844
-						}
845
-					}
846
-				}
847
-				$info['version'] = OC_App::getAppVersion($app);
848
-				$appList[] = $info;
849
-			}
850
-		}
851
-		if ($onlyLocal) {
852
-			$remoteApps = [];
853
-		} else {
854
-			$remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
855
-		}
856
-		if ($remoteApps) {
857
-			// Remove duplicates
858
-			foreach ($appList as $app) {
859
-				foreach ($remoteApps AS $key => $remote) {
860
-					if ($app['name'] === $remote['name'] ||
861
-						(isset($app['ocsid']) &&
862
-							$app['ocsid'] === $remote['id'])
863
-					) {
864
-						unset($remoteApps[$key]);
865
-					}
866
-				}
867
-			}
868
-			$combinedApps = array_merge($appList, $remoteApps);
869
-		} else {
870
-			$combinedApps = $appList;
871
-		}
872
-
873
-		return $combinedApps;
874
-	}
875
-
876
-	/**
877
-	 * Returns the internal app ID or false
878
-	 * @param string $ocsID
879
-	 * @return string|false
880
-	 */
881
-	public static function getInternalAppIdByOcs($ocsID) {
882
-		if(is_numeric($ocsID)) {
883
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
884
-			if(array_search($ocsID, $idArray)) {
885
-				return array_search($ocsID, $idArray);
886
-			}
887
-		}
888
-		return false;
889
-	}
890
-
891
-	/**
892
-	 * Get a list of all apps on the appstore
893
-	 * @param string $filter
894
-	 * @param string|null $category
895
-	 * @param OCSClient $ocsClient
896
-	 * @return array|bool  multi-dimensional array of apps.
897
-	 *                     Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
898
-	 */
899
-	public static function getAppstoreApps($filter = 'approved',
900
-										   $category = null,
901
-										   OCSClient $ocsClient) {
902
-		$categories = [$category];
903
-
904
-		if (is_null($category)) {
905
-			$categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
906
-			if (is_array($categoryNames)) {
907
-				// Check that categories of apps were retrieved correctly
908
-				if (!$categories = array_keys($categoryNames)) {
909
-					return false;
910
-				}
911
-			} else {
912
-				return false;
913
-			}
914
-		}
915
-
916
-		$page = 0;
917
-		$remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
918
-		$apps = [];
919
-		$i = 0;
920
-		$l = \OC::$server->getL10N('core');
921
-		foreach ($remoteApps as $app) {
922
-			$potentialCleanId = self::getInternalAppIdByOcs($app['id']);
923
-			// enhance app info (for example the description)
924
-			$apps[$i] = OC_App::parseAppInfo($app);
925
-			$apps[$i]['author'] = $app['personid'];
926
-			$apps[$i]['ocs_id'] = $app['id'];
927
-			$apps[$i]['internal'] = 0;
928
-			$apps[$i]['active'] = ($potentialCleanId !== false) ? self::isEnabled($potentialCleanId) : false;
929
-			$apps[$i]['update'] = false;
930
-			$apps[$i]['groups'] = false;
931
-			$apps[$i]['score'] = $app['score'];
932
-			$apps[$i]['removable'] = false;
933
-			if ($app['label'] == 'recommended') {
934
-				$apps[$i]['internallabel'] = (string)$l->t('Recommended');
935
-				$apps[$i]['internalclass'] = 'recommendedapp';
936
-			}
937
-
938
-			// Apps from the appstore are always assumed to be compatible with the
939
-			// the current release as the initial filtering is done on the appstore
940
-			$apps[$i]['dependencies']['owncloud']['@attributes']['min-version'] = implode('.', \OCP\Util::getVersion());
941
-			$apps[$i]['dependencies']['owncloud']['@attributes']['max-version'] = implode('.', \OCP\Util::getVersion());
942
-
943
-			$i++;
944
-		}
945
-
946
-
947
-
948
-		if (empty($apps)) {
949
-			return false;
950
-		} else {
951
-			return $apps;
952
-		}
953
-	}
954
-
955
-	public static function shouldUpgrade($app) {
956
-		$versions = self::getAppVersions();
957
-		$currentVersion = OC_App::getAppVersion($app);
958
-		if ($currentVersion && isset($versions[$app])) {
959
-			$installedVersion = $versions[$app];
960
-			if (version_compare($currentVersion, $installedVersion, '>')) {
961
-				return true;
962
-			}
963
-		}
964
-		return false;
965
-	}
966
-
967
-	/**
968
-	 * Adjust the number of version parts of $version1 to match
969
-	 * the number of version parts of $version2.
970
-	 *
971
-	 * @param string $version1 version to adjust
972
-	 * @param string $version2 version to take the number of parts from
973
-	 * @return string shortened $version1
974
-	 */
975
-	private static function adjustVersionParts($version1, $version2) {
976
-		$version1 = explode('.', $version1);
977
-		$version2 = explode('.', $version2);
978
-		// reduce $version1 to match the number of parts in $version2
979
-		while (count($version1) > count($version2)) {
980
-			array_pop($version1);
981
-		}
982
-		// if $version1 does not have enough parts, add some
983
-		while (count($version1) < count($version2)) {
984
-			$version1[] = '0';
985
-		}
986
-		return implode('.', $version1);
987
-	}
988
-
989
-	/**
990
-	 * Check whether the current ownCloud version matches the given
991
-	 * application's version requirements.
992
-	 *
993
-	 * The comparison is made based on the number of parts that the
994
-	 * app info version has. For example for ownCloud 6.0.3 if the
995
-	 * app info version is expecting version 6.0, the comparison is
996
-	 * made on the first two parts of the ownCloud version.
997
-	 * This means that it's possible to specify "requiremin" => 6
998
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
999
-	 *
1000
-	 * @param string $ocVersion ownCloud version to check against
1001
-	 * @param array $appInfo app info (from xml)
1002
-	 *
1003
-	 * @return boolean true if compatible, otherwise false
1004
-	 */
1005
-	public static function isAppCompatible($ocVersion, $appInfo) {
1006
-		$requireMin = '';
1007
-		$requireMax = '';
1008
-		if (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1009
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1010
-		} else if (isset($appInfo['requiremin'])) {
1011
-			$requireMin = $appInfo['requiremin'];
1012
-		} else if (isset($appInfo['require'])) {
1013
-			$requireMin = $appInfo['require'];
1014
-		}
1015
-
1016
-		if (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1017
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1018
-		} else if (isset($appInfo['requiremax'])) {
1019
-			$requireMax = $appInfo['requiremax'];
1020
-		}
1021
-
1022
-		if (is_array($ocVersion)) {
1023
-			$ocVersion = implode('.', $ocVersion);
1024
-		}
1025
-
1026
-		if (!empty($requireMin)
1027
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1028
-		) {
1029
-
1030
-			return false;
1031
-		}
1032
-
1033
-		if (!empty($requireMax)
1034
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1035
-		) {
1036
-
1037
-			return false;
1038
-		}
1039
-
1040
-		return true;
1041
-	}
1042
-
1043
-	/**
1044
-	 * get the installed version of all apps
1045
-	 */
1046
-	public static function getAppVersions() {
1047
-		static $versions;
1048
-
1049
-		if(!$versions) {
1050
-			$appConfig = \OC::$server->getAppConfig();
1051
-			$versions = $appConfig->getValues(false, 'installed_version');
1052
-		}
1053
-		return $versions;
1054
-	}
1055
-
1056
-
1057
-	/**
1058
-	 * @param string $app
1059
-	 * @return bool
1060
-	 * @throws Exception if app is not compatible with this version of ownCloud
1061
-	 * @throws Exception if no app-name was specified
1062
-	 */
1063
-	public static function installApp($app) {
1064
-		$l = \OC::$server->getL10N('core');
1065
-		$config = \OC::$server->getConfig();
1066
-		$ocsClient = new OCSClient(
1067
-			\OC::$server->getHTTPClientService(),
1068
-			$config,
1069
-			\OC::$server->getLogger()
1070
-		);
1071
-		$appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
1072
-
1073
-		// check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
1074
-		if (!is_numeric($app)) {
1075
-			$shippedVersion = self::getAppVersion($app);
1076
-			if ($appData && version_compare($shippedVersion, $appData['version'], '<')) {
1077
-				$app = self::downloadApp($app);
1078
-			} else {
1079
-				$app = OC_Installer::installShippedApp($app);
1080
-			}
1081
-		} else {
1082
-			// Maybe the app is already installed - compare the version in this
1083
-			// case and use the local already installed one.
1084
-			// FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
1085
-			$internalAppId = self::getInternalAppIdByOcs($app);
1086
-			if($internalAppId !== false) {
1087
-				if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1088
-					$app = self::downloadApp($app);
1089
-				} else {
1090
-					self::enable($internalAppId);
1091
-					$app = $internalAppId;
1092
-				}
1093
-			} else {
1094
-				$app = self::downloadApp($app);
1095
-			}
1096
-		}
1097
-
1098
-		if ($app !== false) {
1099
-			// check if the app is compatible with this version of ownCloud
1100
-			$info = self::getAppInfo($app);
1101
-			if(!is_array($info)) {
1102
-				throw new \Exception(
1103
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1104
-						[$info['name']]
1105
-					)
1106
-				);
1107
-			}
1108
-
1109
-			$version = \OCP\Util::getVersion();
1110
-			if (!self::isAppCompatible($version, $info)) {
1111
-				throw new \Exception(
1112
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of Nextcloud.',
1113
-						array($info['name'])
1114
-					)
1115
-				);
1116
-			}
1117
-
1118
-			// check for required dependencies
1119
-			$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1120
-			$missing = $dependencyAnalyzer->analyze($info);
1121
-			if (!empty($missing)) {
1122
-				$missingMsg = join(PHP_EOL, $missing);
1123
-				throw new \Exception(
1124
-					$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1125
-						array($info['name'], $missingMsg)
1126
-					)
1127
-				);
1128
-			}
1129
-
1130
-			$config->setAppValue($app, 'enabled', 'yes');
1131
-			if (isset($appData['id'])) {
1132
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1133
-			}
1134
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1135
-		} else {
1136
-			throw new \Exception($l->t("No app name specified"));
1137
-		}
1138
-
1139
-		return $app;
1140
-	}
1141
-
1142
-	/**
1143
-	 * update the database for the app and call the update script
1144
-	 *
1145
-	 * @param string $appId
1146
-	 * @return bool
1147
-	 */
1148
-	public static function updateApp($appId) {
1149
-		$appPath = self::getAppPath($appId);
1150
-		if($appPath === false) {
1151
-			return false;
1152
-		}
1153
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1154
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1155
-		}
1156
-		unset(self::$appVersion[$appId]);
1157
-		// run upgrade code
1158
-		if (file_exists($appPath . '/appinfo/update.php')) {
1159
-			self::loadApp($appId, false);
1160
-			include $appPath . '/appinfo/update.php';
1161
-		}
1162
-
1163
-		//set remote/public handlers
1164
-		$appData = self::getAppInfo($appId);
1165
-		if (array_key_exists('ocsid', $appData)) {
1166
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1167
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1168
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1169
-		}
1170
-		foreach ($appData['remote'] as $name => $path) {
1171
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1172
-		}
1173
-		foreach ($appData['public'] as $name => $path) {
1174
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1175
-		}
1176
-
1177
-		self::setAppTypes($appId);
1178
-
1179
-		$version = \OC_App::getAppVersion($appId);
1180
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1181
-
1182
-		return true;
1183
-	}
1184
-
1185
-	/**
1186
-	 * @param string $appId
1187
-	 * @return \OC\Files\View|false
1188
-	 */
1189
-	public static function getStorage($appId) {
1190
-		if (OC_App::isEnabled($appId)) { //sanity check
1191
-			if (OC_User::isLoggedIn()) {
1192
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1193
-				if (!$view->file_exists($appId)) {
1194
-					$view->mkdir($appId);
1195
-				}
1196
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1197
-			} else {
1198
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1199
-				return false;
1200
-			}
1201
-		} else {
1202
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1203
-			return false;
1204
-		}
1205
-	}
1206
-
1207
-	protected static function findBestL10NOption($options, $lang) {
1208
-		$fallback = $similarLangFallback = $englishFallback = false;
1209
-
1210
-		$lang = strtolower($lang);
1211
-		$similarLang = $lang;
1212
-		if (strpos($similarLang, '_')) {
1213
-			// For "de_DE" we want to find "de" and the other way around
1214
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1215
-		}
1216
-
1217
-		foreach ($options as $option) {
1218
-			if (is_array($option)) {
1219
-				if ($fallback === false) {
1220
-					$fallback = $option['@value'];
1221
-				}
1222
-
1223
-				if (!isset($option['@attributes']['lang'])) {
1224
-					continue;
1225
-				}
1226
-
1227
-				$attributeLang = strtolower($option['@attributes']['lang']);
1228
-				if ($attributeLang === $lang) {
1229
-					return $option['@value'];
1230
-				}
1231
-
1232
-				if ($attributeLang === $similarLang) {
1233
-					$similarLangFallback = $option['@value'];
1234
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1235
-					if ($similarLangFallback === false) {
1236
-						$similarLangFallback =  $option['@value'];
1237
-					}
1238
-				}
1239
-			} else {
1240
-				$englishFallback = $option;
1241
-			}
1242
-		}
1243
-
1244
-		if ($similarLangFallback !== false) {
1245
-			return $similarLangFallback;
1246
-		} else if ($englishFallback !== false) {
1247
-			return $englishFallback;
1248
-		}
1249
-		return (string) $fallback;
1250
-	}
1251
-
1252
-	/**
1253
-	 * parses the app data array and enhanced the 'description' value
1254
-	 *
1255
-	 * @param array $data the app data
1256
-	 * @param string $lang
1257
-	 * @return array improved app data
1258
-	 */
1259
-	public static function parseAppInfo(array $data, $lang = null) {
1260
-
1261
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1262
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1263
-		}
1264
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1265
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1266
-		}
1267
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1268
-			$data['description'] = self::findBestL10NOption($data['description'], $lang);
1269
-		}
1270
-
1271
-		// just modify the description if it is available
1272
-		// otherwise this will create a $data element with an empty 'description'
1273
-		if (isset($data['description'])) {
1274
-			if (is_string($data['description'])) {
1275
-				// sometimes the description contains line breaks and they are then also
1276
-				// shown in this way in the app management which isn't wanted as HTML
1277
-				// manages line breaks itself
1278
-
1279
-				// first of all we split on empty lines
1280
-				$paragraphs = preg_split("!\n[[:space:]]*\n!mu", $data['description']);
1281
-
1282
-				$result = [];
1283
-				foreach ($paragraphs as $value) {
1284
-					// replace multiple whitespace (tabs, space, newlines) inside a paragraph
1285
-					// with a single space - also trims whitespace
1286
-					$result[] = trim(preg_replace('![[:space:]]+!mu', ' ', $value));
1287
-				}
1288
-
1289
-				// join the single paragraphs with a empty line in between
1290
-				$data['description'] = implode("\n\n", $result);
1291
-
1292
-			} else {
1293
-				$data['description'] = '';
1294
-			}
1295
-		}
1296
-
1297
-		return $data;
1298
-	}
58
+    static private $appVersion = [];
59
+    static private $adminForms = array();
60
+    static private $personalForms = array();
61
+    static private $appInfo = array();
62
+    static private $appTypes = array();
63
+    static private $loadedApps = array();
64
+    static private $altLogin = array();
65
+    const officialApp = 200;
66
+
67
+    /**
68
+     * clean the appId
69
+     *
70
+     * @param string|boolean $app AppId that needs to be cleaned
71
+     * @return string
72
+     */
73
+    public static function cleanAppId($app) {
74
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
75
+    }
76
+
77
+    /**
78
+     * Check if an app is loaded
79
+     *
80
+     * @param string $app
81
+     * @return bool
82
+     */
83
+    public static function isAppLoaded($app) {
84
+        return in_array($app, self::$loadedApps, true);
85
+    }
86
+
87
+    /**
88
+     * loads all apps
89
+     *
90
+     * @param string[] | string | null $types
91
+     * @return bool
92
+     *
93
+     * This function walks through the ownCloud directory and loads all apps
94
+     * it can find. A directory contains an app if the file /appinfo/info.xml
95
+     * exists.
96
+     *
97
+     * if $types is set, only apps of those types will be loaded
98
+     */
99
+    public static function loadApps($types = null) {
100
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
101
+            return false;
102
+        }
103
+        // Load the enabled apps here
104
+        $apps = self::getEnabledApps();
105
+
106
+        // Add each apps' folder as allowed class path
107
+        foreach($apps as $app) {
108
+            $path = self::getAppPath($app);
109
+            if($path !== false) {
110
+                \OC::$loader->addValidRoot($path);
111
+            }
112
+        }
113
+
114
+        // prevent app.php from printing output
115
+        ob_start();
116
+        foreach ($apps as $app) {
117
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
118
+                self::loadApp($app);
119
+            }
120
+        }
121
+        ob_end_clean();
122
+
123
+        return true;
124
+    }
125
+
126
+    /**
127
+     * load a single app
128
+     *
129
+     * @param string $app
130
+     * @param bool $checkUpgrade whether an upgrade check should be done
131
+     * @throws \OC\NeedsUpdateException
132
+     */
133
+    public static function loadApp($app, $checkUpgrade = true) {
134
+        self::$loadedApps[] = $app;
135
+        $appPath = self::getAppPath($app);
136
+        if($appPath === false) {
137
+            return;
138
+        }
139
+        \OC::$loader->addValidRoot($appPath); // in case someone calls loadApp() directly
140
+        if (is_file($appPath . '/appinfo/app.php')) {
141
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
142
+            if ($checkUpgrade and self::shouldUpgrade($app)) {
143
+                throw new \OC\NeedsUpdateException();
144
+            }
145
+            self::requireAppFile($app);
146
+            if (self::isType($app, array('authentication'))) {
147
+                // since authentication apps affect the "is app enabled for group" check,
148
+                // the enabled apps cache needs to be cleared to make sure that the
149
+                // next time getEnableApps() is called it will also include apps that were
150
+                // enabled for groups
151
+                self::$enabledAppsCache = array();
152
+            }
153
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
154
+        }
155
+    }
156
+
157
+    /**
158
+     * Load app.php from the given app
159
+     *
160
+     * @param string $app app name
161
+     */
162
+    private static function requireAppFile($app) {
163
+        // encapsulated here to avoid variable scope conflicts
164
+        require_once $app . '/appinfo/app.php';
165
+    }
166
+
167
+    /**
168
+     * check if an app is of a specific type
169
+     *
170
+     * @param string $app
171
+     * @param string|array $types
172
+     * @return bool
173
+     */
174
+    public static function isType($app, $types) {
175
+        if (is_string($types)) {
176
+            $types = array($types);
177
+        }
178
+        $appTypes = self::getAppTypes($app);
179
+        foreach ($types as $type) {
180
+            if (array_search($type, $appTypes) !== false) {
181
+                return true;
182
+            }
183
+        }
184
+        return false;
185
+    }
186
+
187
+    /**
188
+     * get the types of an app
189
+     *
190
+     * @param string $app
191
+     * @return array
192
+     */
193
+    private static function getAppTypes($app) {
194
+        //load the cache
195
+        if (count(self::$appTypes) == 0) {
196
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
197
+        }
198
+
199
+        if (isset(self::$appTypes[$app])) {
200
+            return explode(',', self::$appTypes[$app]);
201
+        } else {
202
+            return array();
203
+        }
204
+    }
205
+
206
+    /**
207
+     * read app types from info.xml and cache them in the database
208
+     */
209
+    public static function setAppTypes($app) {
210
+        $appData = self::getAppInfo($app);
211
+        if(!is_array($appData)) {
212
+            return;
213
+        }
214
+
215
+        if (isset($appData['types'])) {
216
+            $appTypes = implode(',', $appData['types']);
217
+        } else {
218
+            $appTypes = '';
219
+        }
220
+
221
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
222
+    }
223
+
224
+    /**
225
+     * check if app is shipped
226
+     *
227
+     * @param string $appId the id of the app to check
228
+     * @return bool
229
+     *
230
+     * Check if an app that is installed is a shipped app or installed from the appstore.
231
+     */
232
+    public static function isShipped($appId) {
233
+        return \OC::$server->getAppManager()->isShipped($appId);
234
+    }
235
+
236
+    /**
237
+     * get all enabled apps
238
+     */
239
+    protected static $enabledAppsCache = array();
240
+
241
+    /**
242
+     * Returns apps enabled for the current user.
243
+     *
244
+     * @param bool $forceRefresh whether to refresh the cache
245
+     * @param bool $all whether to return apps for all users, not only the
246
+     * currently logged in one
247
+     * @return string[]
248
+     */
249
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
250
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
251
+            return array();
252
+        }
253
+        // in incognito mode or when logged out, $user will be false,
254
+        // which is also the case during an upgrade
255
+        $appManager = \OC::$server->getAppManager();
256
+        if ($all) {
257
+            $user = null;
258
+        } else {
259
+            $user = \OC::$server->getUserSession()->getUser();
260
+        }
261
+
262
+        if (is_null($user)) {
263
+            $apps = $appManager->getInstalledApps();
264
+        } else {
265
+            $apps = $appManager->getEnabledAppsForUser($user);
266
+        }
267
+        $apps = array_filter($apps, function ($app) {
268
+            return $app !== 'files';//we add this manually
269
+        });
270
+        sort($apps);
271
+        array_unshift($apps, 'files');
272
+        return $apps;
273
+    }
274
+
275
+    /**
276
+     * checks whether or not an app is enabled
277
+     *
278
+     * @param string $app app
279
+     * @return bool
280
+     *
281
+     * This function checks whether or not an app is enabled.
282
+     */
283
+    public static function isEnabled($app) {
284
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
285
+    }
286
+
287
+    /**
288
+     * enables an app
289
+     *
290
+     * @param mixed $app app
291
+     * @param array $groups (optional) when set, only these groups will have access to the app
292
+     * @throws \Exception
293
+     * @return void
294
+     *
295
+     * This function set an app as enabled in appconfig.
296
+     */
297
+    public static function enable($app, $groups = null) {
298
+        self::$enabledAppsCache = array(); // flush
299
+        if (!OC_Installer::isInstalled($app)) {
300
+            $app = self::installApp($app);
301
+        }
302
+
303
+        $appManager = \OC::$server->getAppManager();
304
+        if (!is_null($groups)) {
305
+            $groupManager = \OC::$server->getGroupManager();
306
+            $groupsList = [];
307
+            foreach ($groups as $group) {
308
+                $groupItem = $groupManager->get($group);
309
+                if ($groupItem instanceof \OCP\IGroup) {
310
+                    $groupsList[] = $groupManager->get($group);
311
+                }
312
+            }
313
+            $appManager->enableAppForGroups($app, $groupsList);
314
+        } else {
315
+            $appManager->enableApp($app);
316
+        }
317
+    }
318
+
319
+    /**
320
+     * @param string $app
321
+     * @return int
322
+     */
323
+    private static function downloadApp($app) {
324
+        $ocsClient = new OCSClient(
325
+            \OC::$server->getHTTPClientService(),
326
+            \OC::$server->getConfig(),
327
+            \OC::$server->getLogger()
328
+        );
329
+        $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
330
+        $download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
331
+        if(isset($download['downloadlink']) and $download['downloadlink']!='') {
332
+            // Replace spaces in download link without encoding entire URL
333
+            $download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
334
+            $info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
335
+            $app = OC_Installer::installApp($info);
336
+        }
337
+        return $app;
338
+    }
339
+
340
+    /**
341
+     * @param string $app
342
+     * @return bool
343
+     */
344
+    public static function removeApp($app) {
345
+        if (self::isShipped($app)) {
346
+            return false;
347
+        }
348
+
349
+        return OC_Installer::removeApp($app);
350
+    }
351
+
352
+    /**
353
+     * This function set an app as disabled in appconfig.
354
+     *
355
+     * @param string $app app
356
+     * @throws Exception
357
+     */
358
+    public static function disable($app) {
359
+        // Convert OCS ID to regular application identifier
360
+        if(self::getInternalAppIdByOcs($app) !== false) {
361
+            $app = self::getInternalAppIdByOcs($app);
362
+        }
363
+
364
+        self::$enabledAppsCache = array(); // flush
365
+        // check if app is a shipped app or not. if not delete
366
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
367
+        $appManager = \OC::$server->getAppManager();
368
+        $appManager->disableApp($app);
369
+    }
370
+
371
+    /**
372
+     * Returns the Settings Navigation
373
+     *
374
+     * @return string[]
375
+     *
376
+     * This function returns an array containing all settings pages added. The
377
+     * entries are sorted by the key 'order' ascending.
378
+     */
379
+    public static function getSettingsNavigation() {
380
+        $l = \OC::$server->getL10N('lib');
381
+        $urlGenerator = \OC::$server->getURLGenerator();
382
+
383
+        $settings = array();
384
+        // by default, settings only contain the help menu
385
+        if (OC_Util::getEditionString() === '' &&
386
+            \OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true) == true
387
+        ) {
388
+            $settings = array(
389
+                array(
390
+                    "id" => "help",
391
+                    "order" => 1000,
392
+                    "href" => $urlGenerator->linkToRoute('settings_help'),
393
+                    "name" => $l->t("Help"),
394
+                    "icon" => $urlGenerator->imagePath("settings", "help.svg")
395
+                )
396
+            );
397
+        }
398
+
399
+        // if the user is logged-in
400
+        if (OC_User::isLoggedIn()) {
401
+            // personal menu
402
+            $settings[] = array(
403
+                "id" => "personal",
404
+                "order" => 1,
405
+                "href" => $urlGenerator->linkToRoute('settings_personal'),
406
+                "name" => $l->t("Personal"),
407
+                "icon" => $urlGenerator->imagePath("settings", "personal.svg")
408
+            );
409
+
410
+            //SubAdmins are also allowed to access user management
411
+            $userObject = \OC::$server->getUserSession()->getUser();
412
+            $isSubAdmin = false;
413
+            if($userObject !== null) {
414
+                $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
415
+            }
416
+            if ($isSubAdmin) {
417
+                // admin users menu
418
+                $settings[] = array(
419
+                    "id" => "core_users",
420
+                    "order" => 2,
421
+                    "href" => $urlGenerator->linkToRoute('settings_users'),
422
+                    "name" => $l->t("Users"),
423
+                    "icon" => $urlGenerator->imagePath("settings", "users.svg")
424
+                );
425
+            }
426
+
427
+            // if the user is an admin
428
+            if (OC_User::isAdminUser(OC_User::getUser())) {
429
+                // admin settings
430
+                $settings[] = array(
431
+                    "id" => "admin",
432
+                    "order" => 1000,
433
+                    "href" => $urlGenerator->linkToRoute('settings_admin'),
434
+                    "name" => $l->t("Admin"),
435
+                    "icon" => $urlGenerator->imagePath("settings", "admin.svg")
436
+                );
437
+            }
438
+        }
439
+
440
+        $navigation = self::proceedNavigation($settings);
441
+        return $navigation;
442
+    }
443
+
444
+    // This is private as well. It simply works, so don't ask for more details
445
+    private static function proceedNavigation($list) {
446
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
447
+        foreach ($list as &$navEntry) {
448
+            if ($navEntry['id'] == $activeApp) {
449
+                $navEntry['active'] = true;
450
+            } else {
451
+                $navEntry['active'] = false;
452
+            }
453
+        }
454
+        unset($navEntry);
455
+
456
+        usort($list, create_function('$a, $b', 'if( $a["order"] == $b["order"] ) {return 0;}elseif( $a["order"] < $b["order"] ) {return -1;}else{return 1;}'));
457
+
458
+        return $list;
459
+    }
460
+
461
+    /**
462
+     * Get the path where to install apps
463
+     *
464
+     * @return string|false
465
+     */
466
+    public static function getInstallPath() {
467
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
468
+            return false;
469
+        }
470
+
471
+        foreach (OC::$APPSROOTS as $dir) {
472
+            if (isset($dir['writable']) && $dir['writable'] === true) {
473
+                return $dir['path'];
474
+            }
475
+        }
476
+
477
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
478
+        return null;
479
+    }
480
+
481
+
482
+    /**
483
+     * search for an app in all app-directories
484
+     *
485
+     * @param string $appId
486
+     * @return false|string
487
+     */
488
+    protected static function findAppInDirectories($appId) {
489
+        $sanitizedAppId = self::cleanAppId($appId);
490
+        if($sanitizedAppId !== $appId) {
491
+            return false;
492
+        }
493
+        static $app_dir = array();
494
+
495
+        if (isset($app_dir[$appId])) {
496
+            return $app_dir[$appId];
497
+        }
498
+
499
+        $possibleApps = array();
500
+        foreach (OC::$APPSROOTS as $dir) {
501
+            if (file_exists($dir['path'] . '/' . $appId)) {
502
+                $possibleApps[] = $dir;
503
+            }
504
+        }
505
+
506
+        if (empty($possibleApps)) {
507
+            return false;
508
+        } elseif (count($possibleApps) === 1) {
509
+            $dir = array_shift($possibleApps);
510
+            $app_dir[$appId] = $dir;
511
+            return $dir;
512
+        } else {
513
+            $versionToLoad = array();
514
+            foreach ($possibleApps as $possibleApp) {
515
+                $version = self::getAppVersionByPath($possibleApp['path']);
516
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
517
+                    $versionToLoad = array(
518
+                        'dir' => $possibleApp,
519
+                        'version' => $version,
520
+                    );
521
+                }
522
+            }
523
+            $app_dir[$appId] = $versionToLoad['dir'];
524
+            return $versionToLoad['dir'];
525
+            //TODO - write test
526
+        }
527
+    }
528
+
529
+    /**
530
+     * Get the directory for the given app.
531
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
532
+     *
533
+     * @param string $appId
534
+     * @return string|false
535
+     */
536
+    public static function getAppPath($appId) {
537
+        if ($appId === null || trim($appId) === '') {
538
+            return false;
539
+        }
540
+
541
+        if (($dir = self::findAppInDirectories($appId)) != false) {
542
+            return $dir['path'] . '/' . $appId;
543
+        }
544
+        return false;
545
+    }
546
+
547
+
548
+    /**
549
+     * check if an app's directory is writable
550
+     *
551
+     * @param string $appId
552
+     * @return bool
553
+     */
554
+    public static function isAppDirWritable($appId) {
555
+        $path = self::getAppPath($appId);
556
+        return ($path !== false) ? is_writable($path) : false;
557
+    }
558
+
559
+    /**
560
+     * Get the path for the given app on the access
561
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
562
+     *
563
+     * @param string $appId
564
+     * @return string|false
565
+     */
566
+    public static function getAppWebPath($appId) {
567
+        if (($dir = self::findAppInDirectories($appId)) != false) {
568
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
569
+        }
570
+        return false;
571
+    }
572
+
573
+    /**
574
+     * get the last version of the app, either from appinfo/version or from appinfo/info.xml
575
+     *
576
+     * @param string $appId
577
+     * @return string
578
+     */
579
+    public static function getAppVersion($appId) {
580
+        if (!isset(self::$appVersion[$appId])) {
581
+            $file = self::getAppPath($appId);
582
+            self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
583
+        }
584
+        return self::$appVersion[$appId];
585
+    }
586
+
587
+    /**
588
+     * get app's version based on it's path
589
+     *
590
+     * @param string $path
591
+     * @return string
592
+     */
593
+    public static function getAppVersionByPath($path) {
594
+        $versionFile = $path . '/appinfo/version';
595
+        $infoFile = $path . '/appinfo/info.xml';
596
+        if (is_file($versionFile)) {
597
+            return trim(file_get_contents($versionFile));
598
+        } else {
599
+            $appData = self::getAppInfo($infoFile, true);
600
+            return isset($appData['version']) ? $appData['version'] : '';
601
+        }
602
+    }
603
+
604
+
605
+    /**
606
+     * Read all app metadata from the info.xml file
607
+     *
608
+     * @param string $appId id of the app or the path of the info.xml file
609
+     * @param boolean $path
610
+     * @param string $lang
611
+     * @return array|null
612
+     * @note all data is read from info.xml, not just pre-defined fields
613
+     */
614
+    public static function getAppInfo($appId, $path = false, $lang = null) {
615
+        if ($path) {
616
+            $file = $appId;
617
+        } else {
618
+            if ($lang === null && isset(self::$appInfo[$appId])) {
619
+                return self::$appInfo[$appId];
620
+            }
621
+            $appPath = self::getAppPath($appId);
622
+            if($appPath === false) {
623
+                return null;
624
+            }
625
+            $file = $appPath . '/appinfo/info.xml';
626
+        }
627
+
628
+        $parser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
629
+        $data = $parser->parse($file);
630
+
631
+        if (is_array($data)) {
632
+            $data = OC_App::parseAppInfo($data, $lang);
633
+        }
634
+        if(isset($data['ocsid'])) {
635
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
636
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
637
+                $data['ocsid'] = $storedId;
638
+            }
639
+        }
640
+
641
+        if ($lang === null) {
642
+            self::$appInfo[$appId] = $data;
643
+        }
644
+
645
+        return $data;
646
+    }
647
+
648
+    /**
649
+     * Returns the navigation
650
+     *
651
+     * @return array
652
+     *
653
+     * This function returns an array containing all entries added. The
654
+     * entries are sorted by the key 'order' ascending. Additional to the keys
655
+     * given for each app the following keys exist:
656
+     *   - active: boolean, signals if the user is on this navigation entry
657
+     */
658
+    public static function getNavigation() {
659
+        $entries = OC::$server->getNavigationManager()->getAll();
660
+        $navigation = self::proceedNavigation($entries);
661
+        return $navigation;
662
+    }
663
+
664
+    /**
665
+     * get the id of loaded app
666
+     *
667
+     * @return string
668
+     */
669
+    public static function getCurrentApp() {
670
+        $request = \OC::$server->getRequest();
671
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
672
+        $topFolder = substr($script, 0, strpos($script, '/'));
673
+        if (empty($topFolder)) {
674
+            $path_info = $request->getPathInfo();
675
+            if ($path_info) {
676
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
677
+            }
678
+        }
679
+        if ($topFolder == 'apps') {
680
+            $length = strlen($topFolder);
681
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
682
+        } else {
683
+            return $topFolder;
684
+        }
685
+    }
686
+
687
+    /**
688
+     * @param string $type
689
+     * @return array
690
+     */
691
+    public static function getForms($type) {
692
+        $forms = array();
693
+        switch ($type) {
694
+            case 'admin':
695
+                $source = self::$adminForms;
696
+                break;
697
+            case 'personal':
698
+                $source = self::$personalForms;
699
+                break;
700
+            default:
701
+                return array();
702
+        }
703
+        foreach ($source as $form) {
704
+            $forms[] = include $form;
705
+        }
706
+        return $forms;
707
+    }
708
+
709
+    /**
710
+     * register an admin form to be shown
711
+     *
712
+     * @param string $app
713
+     * @param string $page
714
+     */
715
+    public static function registerAdmin($app, $page) {
716
+        self::$adminForms[] = $app . '/' . $page . '.php';
717
+    }
718
+
719
+    /**
720
+     * register a personal form to be shown
721
+     * @param string $app
722
+     * @param string $page
723
+     */
724
+    public static function registerPersonal($app, $page) {
725
+        self::$personalForms[] = $app . '/' . $page . '.php';
726
+    }
727
+
728
+    /**
729
+     * @param array $entry
730
+     */
731
+    public static function registerLogIn(array $entry) {
732
+        self::$altLogin[] = $entry;
733
+    }
734
+
735
+    /**
736
+     * @return array
737
+     */
738
+    public static function getAlternativeLogIns() {
739
+        return self::$altLogin;
740
+    }
741
+
742
+    /**
743
+     * get a list of all apps in the apps folder
744
+     *
745
+     * @return array an array of app names (string IDs)
746
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
747
+     */
748
+    public static function getAllApps() {
749
+
750
+        $apps = array();
751
+
752
+        foreach (OC::$APPSROOTS as $apps_dir) {
753
+            if (!is_readable($apps_dir['path'])) {
754
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
755
+                continue;
756
+            }
757
+            $dh = opendir($apps_dir['path']);
758
+
759
+            if (is_resource($dh)) {
760
+                while (($file = readdir($dh)) !== false) {
761
+
762
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
763
+
764
+                        $apps[] = $file;
765
+                    }
766
+                }
767
+            }
768
+        }
769
+
770
+        return $apps;
771
+    }
772
+
773
+    /**
774
+     * List all apps, this is used in apps.php
775
+     *
776
+     * @param bool $onlyLocal
777
+     * @param bool $includeUpdateInfo Should we check whether there is an update
778
+     *                                in the app store?
779
+     * @param OCSClient $ocsClient
780
+     * @return array
781
+     */
782
+    public static function listAllApps($onlyLocal = false,
783
+                                        $includeUpdateInfo = true,
784
+                                        OCSClient $ocsClient) {
785
+        $installedApps = OC_App::getAllApps();
786
+
787
+        //TODO which apps do we want to blacklist and how do we integrate
788
+        // blacklisting with the multi apps folder feature?
789
+
790
+        //we don't want to show configuration for these
791
+        $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
792
+        $appList = array();
793
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
794
+
795
+        foreach ($installedApps as $app) {
796
+            if (array_search($app, $blacklist) === false) {
797
+
798
+                $info = OC_App::getAppInfo($app, false, $langCode);
799
+                if (!is_array($info)) {
800
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
801
+                    continue;
802
+                }
803
+
804
+                if (!isset($info['name'])) {
805
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
806
+                    continue;
807
+                }
808
+
809
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
810
+                $info['groups'] = null;
811
+                if ($enabled === 'yes') {
812
+                    $active = true;
813
+                } else if ($enabled === 'no') {
814
+                    $active = false;
815
+                } else {
816
+                    $active = true;
817
+                    $info['groups'] = $enabled;
818
+                }
819
+
820
+                $info['active'] = $active;
821
+
822
+                if (self::isShipped($app)) {
823
+                    $info['internal'] = true;
824
+                    $info['level'] = self::officialApp;
825
+                    $info['removable'] = false;
826
+                } else {
827
+                    $info['internal'] = false;
828
+                    $info['removable'] = true;
829
+                }
830
+
831
+                $info['update'] = ($includeUpdateInfo) ? OC_Installer::isUpdateAvailable($app) : null;
832
+
833
+                $appPath = self::getAppPath($app);
834
+                if($appPath !== false) {
835
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
836
+                    if (file_exists($appIcon)) {
837
+                        $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
838
+                        $info['previewAsIcon'] = true;
839
+                    } else {
840
+                        $appIcon = $appPath . '/img/app.svg';
841
+                        if (file_exists($appIcon)) {
842
+                            $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
843
+                            $info['previewAsIcon'] = true;
844
+                        }
845
+                    }
846
+                }
847
+                $info['version'] = OC_App::getAppVersion($app);
848
+                $appList[] = $info;
849
+            }
850
+        }
851
+        if ($onlyLocal) {
852
+            $remoteApps = [];
853
+        } else {
854
+            $remoteApps = OC_App::getAppstoreApps('approved', null, $ocsClient);
855
+        }
856
+        if ($remoteApps) {
857
+            // Remove duplicates
858
+            foreach ($appList as $app) {
859
+                foreach ($remoteApps AS $key => $remote) {
860
+                    if ($app['name'] === $remote['name'] ||
861
+                        (isset($app['ocsid']) &&
862
+                            $app['ocsid'] === $remote['id'])
863
+                    ) {
864
+                        unset($remoteApps[$key]);
865
+                    }
866
+                }
867
+            }
868
+            $combinedApps = array_merge($appList, $remoteApps);
869
+        } else {
870
+            $combinedApps = $appList;
871
+        }
872
+
873
+        return $combinedApps;
874
+    }
875
+
876
+    /**
877
+     * Returns the internal app ID or false
878
+     * @param string $ocsID
879
+     * @return string|false
880
+     */
881
+    public static function getInternalAppIdByOcs($ocsID) {
882
+        if(is_numeric($ocsID)) {
883
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
884
+            if(array_search($ocsID, $idArray)) {
885
+                return array_search($ocsID, $idArray);
886
+            }
887
+        }
888
+        return false;
889
+    }
890
+
891
+    /**
892
+     * Get a list of all apps on the appstore
893
+     * @param string $filter
894
+     * @param string|null $category
895
+     * @param OCSClient $ocsClient
896
+     * @return array|bool  multi-dimensional array of apps.
897
+     *                     Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description
898
+     */
899
+    public static function getAppstoreApps($filter = 'approved',
900
+                                            $category = null,
901
+                                            OCSClient $ocsClient) {
902
+        $categories = [$category];
903
+
904
+        if (is_null($category)) {
905
+            $categoryNames = $ocsClient->getCategories(\OCP\Util::getVersion());
906
+            if (is_array($categoryNames)) {
907
+                // Check that categories of apps were retrieved correctly
908
+                if (!$categories = array_keys($categoryNames)) {
909
+                    return false;
910
+                }
911
+            } else {
912
+                return false;
913
+            }
914
+        }
915
+
916
+        $page = 0;
917
+        $remoteApps = $ocsClient->getApplications($categories, $page, $filter, \OCP\Util::getVersion());
918
+        $apps = [];
919
+        $i = 0;
920
+        $l = \OC::$server->getL10N('core');
921
+        foreach ($remoteApps as $app) {
922
+            $potentialCleanId = self::getInternalAppIdByOcs($app['id']);
923
+            // enhance app info (for example the description)
924
+            $apps[$i] = OC_App::parseAppInfo($app);
925
+            $apps[$i]['author'] = $app['personid'];
926
+            $apps[$i]['ocs_id'] = $app['id'];
927
+            $apps[$i]['internal'] = 0;
928
+            $apps[$i]['active'] = ($potentialCleanId !== false) ? self::isEnabled($potentialCleanId) : false;
929
+            $apps[$i]['update'] = false;
930
+            $apps[$i]['groups'] = false;
931
+            $apps[$i]['score'] = $app['score'];
932
+            $apps[$i]['removable'] = false;
933
+            if ($app['label'] == 'recommended') {
934
+                $apps[$i]['internallabel'] = (string)$l->t('Recommended');
935
+                $apps[$i]['internalclass'] = 'recommendedapp';
936
+            }
937
+
938
+            // Apps from the appstore are always assumed to be compatible with the
939
+            // the current release as the initial filtering is done on the appstore
940
+            $apps[$i]['dependencies']['owncloud']['@attributes']['min-version'] = implode('.', \OCP\Util::getVersion());
941
+            $apps[$i]['dependencies']['owncloud']['@attributes']['max-version'] = implode('.', \OCP\Util::getVersion());
942
+
943
+            $i++;
944
+        }
945
+
946
+
947
+
948
+        if (empty($apps)) {
949
+            return false;
950
+        } else {
951
+            return $apps;
952
+        }
953
+    }
954
+
955
+    public static function shouldUpgrade($app) {
956
+        $versions = self::getAppVersions();
957
+        $currentVersion = OC_App::getAppVersion($app);
958
+        if ($currentVersion && isset($versions[$app])) {
959
+            $installedVersion = $versions[$app];
960
+            if (version_compare($currentVersion, $installedVersion, '>')) {
961
+                return true;
962
+            }
963
+        }
964
+        return false;
965
+    }
966
+
967
+    /**
968
+     * Adjust the number of version parts of $version1 to match
969
+     * the number of version parts of $version2.
970
+     *
971
+     * @param string $version1 version to adjust
972
+     * @param string $version2 version to take the number of parts from
973
+     * @return string shortened $version1
974
+     */
975
+    private static function adjustVersionParts($version1, $version2) {
976
+        $version1 = explode('.', $version1);
977
+        $version2 = explode('.', $version2);
978
+        // reduce $version1 to match the number of parts in $version2
979
+        while (count($version1) > count($version2)) {
980
+            array_pop($version1);
981
+        }
982
+        // if $version1 does not have enough parts, add some
983
+        while (count($version1) < count($version2)) {
984
+            $version1[] = '0';
985
+        }
986
+        return implode('.', $version1);
987
+    }
988
+
989
+    /**
990
+     * Check whether the current ownCloud version matches the given
991
+     * application's version requirements.
992
+     *
993
+     * The comparison is made based on the number of parts that the
994
+     * app info version has. For example for ownCloud 6.0.3 if the
995
+     * app info version is expecting version 6.0, the comparison is
996
+     * made on the first two parts of the ownCloud version.
997
+     * This means that it's possible to specify "requiremin" => 6
998
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
999
+     *
1000
+     * @param string $ocVersion ownCloud version to check against
1001
+     * @param array $appInfo app info (from xml)
1002
+     *
1003
+     * @return boolean true if compatible, otherwise false
1004
+     */
1005
+    public static function isAppCompatible($ocVersion, $appInfo) {
1006
+        $requireMin = '';
1007
+        $requireMax = '';
1008
+        if (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1009
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1010
+        } else if (isset($appInfo['requiremin'])) {
1011
+            $requireMin = $appInfo['requiremin'];
1012
+        } else if (isset($appInfo['require'])) {
1013
+            $requireMin = $appInfo['require'];
1014
+        }
1015
+
1016
+        if (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1017
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1018
+        } else if (isset($appInfo['requiremax'])) {
1019
+            $requireMax = $appInfo['requiremax'];
1020
+        }
1021
+
1022
+        if (is_array($ocVersion)) {
1023
+            $ocVersion = implode('.', $ocVersion);
1024
+        }
1025
+
1026
+        if (!empty($requireMin)
1027
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1028
+        ) {
1029
+
1030
+            return false;
1031
+        }
1032
+
1033
+        if (!empty($requireMax)
1034
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1035
+        ) {
1036
+
1037
+            return false;
1038
+        }
1039
+
1040
+        return true;
1041
+    }
1042
+
1043
+    /**
1044
+     * get the installed version of all apps
1045
+     */
1046
+    public static function getAppVersions() {
1047
+        static $versions;
1048
+
1049
+        if(!$versions) {
1050
+            $appConfig = \OC::$server->getAppConfig();
1051
+            $versions = $appConfig->getValues(false, 'installed_version');
1052
+        }
1053
+        return $versions;
1054
+    }
1055
+
1056
+
1057
+    /**
1058
+     * @param string $app
1059
+     * @return bool
1060
+     * @throws Exception if app is not compatible with this version of ownCloud
1061
+     * @throws Exception if no app-name was specified
1062
+     */
1063
+    public static function installApp($app) {
1064
+        $l = \OC::$server->getL10N('core');
1065
+        $config = \OC::$server->getConfig();
1066
+        $ocsClient = new OCSClient(
1067
+            \OC::$server->getHTTPClientService(),
1068
+            $config,
1069
+            \OC::$server->getLogger()
1070
+        );
1071
+        $appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
1072
+
1073
+        // check if app is a shipped app or not. OCS apps have an integer as id, shipped apps use a string
1074
+        if (!is_numeric($app)) {
1075
+            $shippedVersion = self::getAppVersion($app);
1076
+            if ($appData && version_compare($shippedVersion, $appData['version'], '<')) {
1077
+                $app = self::downloadApp($app);
1078
+            } else {
1079
+                $app = OC_Installer::installShippedApp($app);
1080
+            }
1081
+        } else {
1082
+            // Maybe the app is already installed - compare the version in this
1083
+            // case and use the local already installed one.
1084
+            // FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
1085
+            $internalAppId = self::getInternalAppIdByOcs($app);
1086
+            if($internalAppId !== false) {
1087
+                if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1088
+                    $app = self::downloadApp($app);
1089
+                } else {
1090
+                    self::enable($internalAppId);
1091
+                    $app = $internalAppId;
1092
+                }
1093
+            } else {
1094
+                $app = self::downloadApp($app);
1095
+            }
1096
+        }
1097
+
1098
+        if ($app !== false) {
1099
+            // check if the app is compatible with this version of ownCloud
1100
+            $info = self::getAppInfo($app);
1101
+            if(!is_array($info)) {
1102
+                throw new \Exception(
1103
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1104
+                        [$info['name']]
1105
+                    )
1106
+                );
1107
+            }
1108
+
1109
+            $version = \OCP\Util::getVersion();
1110
+            if (!self::isAppCompatible($version, $info)) {
1111
+                throw new \Exception(
1112
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of Nextcloud.',
1113
+                        array($info['name'])
1114
+                    )
1115
+                );
1116
+            }
1117
+
1118
+            // check for required dependencies
1119
+            $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1120
+            $missing = $dependencyAnalyzer->analyze($info);
1121
+            if (!empty($missing)) {
1122
+                $missingMsg = join(PHP_EOL, $missing);
1123
+                throw new \Exception(
1124
+                    $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1125
+                        array($info['name'], $missingMsg)
1126
+                    )
1127
+                );
1128
+            }
1129
+
1130
+            $config->setAppValue($app, 'enabled', 'yes');
1131
+            if (isset($appData['id'])) {
1132
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1133
+            }
1134
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1135
+        } else {
1136
+            throw new \Exception($l->t("No app name specified"));
1137
+        }
1138
+
1139
+        return $app;
1140
+    }
1141
+
1142
+    /**
1143
+     * update the database for the app and call the update script
1144
+     *
1145
+     * @param string $appId
1146
+     * @return bool
1147
+     */
1148
+    public static function updateApp($appId) {
1149
+        $appPath = self::getAppPath($appId);
1150
+        if($appPath === false) {
1151
+            return false;
1152
+        }
1153
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1154
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1155
+        }
1156
+        unset(self::$appVersion[$appId]);
1157
+        // run upgrade code
1158
+        if (file_exists($appPath . '/appinfo/update.php')) {
1159
+            self::loadApp($appId, false);
1160
+            include $appPath . '/appinfo/update.php';
1161
+        }
1162
+
1163
+        //set remote/public handlers
1164
+        $appData = self::getAppInfo($appId);
1165
+        if (array_key_exists('ocsid', $appData)) {
1166
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1167
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1168
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1169
+        }
1170
+        foreach ($appData['remote'] as $name => $path) {
1171
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1172
+        }
1173
+        foreach ($appData['public'] as $name => $path) {
1174
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1175
+        }
1176
+
1177
+        self::setAppTypes($appId);
1178
+
1179
+        $version = \OC_App::getAppVersion($appId);
1180
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1181
+
1182
+        return true;
1183
+    }
1184
+
1185
+    /**
1186
+     * @param string $appId
1187
+     * @return \OC\Files\View|false
1188
+     */
1189
+    public static function getStorage($appId) {
1190
+        if (OC_App::isEnabled($appId)) { //sanity check
1191
+            if (OC_User::isLoggedIn()) {
1192
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1193
+                if (!$view->file_exists($appId)) {
1194
+                    $view->mkdir($appId);
1195
+                }
1196
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1197
+            } else {
1198
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1199
+                return false;
1200
+            }
1201
+        } else {
1202
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1203
+            return false;
1204
+        }
1205
+    }
1206
+
1207
+    protected static function findBestL10NOption($options, $lang) {
1208
+        $fallback = $similarLangFallback = $englishFallback = false;
1209
+
1210
+        $lang = strtolower($lang);
1211
+        $similarLang = $lang;
1212
+        if (strpos($similarLang, '_')) {
1213
+            // For "de_DE" we want to find "de" and the other way around
1214
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1215
+        }
1216
+
1217
+        foreach ($options as $option) {
1218
+            if (is_array($option)) {
1219
+                if ($fallback === false) {
1220
+                    $fallback = $option['@value'];
1221
+                }
1222
+
1223
+                if (!isset($option['@attributes']['lang'])) {
1224
+                    continue;
1225
+                }
1226
+
1227
+                $attributeLang = strtolower($option['@attributes']['lang']);
1228
+                if ($attributeLang === $lang) {
1229
+                    return $option['@value'];
1230
+                }
1231
+
1232
+                if ($attributeLang === $similarLang) {
1233
+                    $similarLangFallback = $option['@value'];
1234
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1235
+                    if ($similarLangFallback === false) {
1236
+                        $similarLangFallback =  $option['@value'];
1237
+                    }
1238
+                }
1239
+            } else {
1240
+                $englishFallback = $option;
1241
+            }
1242
+        }
1243
+
1244
+        if ($similarLangFallback !== false) {
1245
+            return $similarLangFallback;
1246
+        } else if ($englishFallback !== false) {
1247
+            return $englishFallback;
1248
+        }
1249
+        return (string) $fallback;
1250
+    }
1251
+
1252
+    /**
1253
+     * parses the app data array and enhanced the 'description' value
1254
+     *
1255
+     * @param array $data the app data
1256
+     * @param string $lang
1257
+     * @return array improved app data
1258
+     */
1259
+    public static function parseAppInfo(array $data, $lang = null) {
1260
+
1261
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1262
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1263
+        }
1264
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1265
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1266
+        }
1267
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1268
+            $data['description'] = self::findBestL10NOption($data['description'], $lang);
1269
+        }
1270
+
1271
+        // just modify the description if it is available
1272
+        // otherwise this will create a $data element with an empty 'description'
1273
+        if (isset($data['description'])) {
1274
+            if (is_string($data['description'])) {
1275
+                // sometimes the description contains line breaks and they are then also
1276
+                // shown in this way in the app management which isn't wanted as HTML
1277
+                // manages line breaks itself
1278
+
1279
+                // first of all we split on empty lines
1280
+                $paragraphs = preg_split("!\n[[:space:]]*\n!mu", $data['description']);
1281
+
1282
+                $result = [];
1283
+                foreach ($paragraphs as $value) {
1284
+                    // replace multiple whitespace (tabs, space, newlines) inside a paragraph
1285
+                    // with a single space - also trims whitespace
1286
+                    $result[] = trim(preg_replace('![[:space:]]+!mu', ' ', $value));
1287
+                }
1288
+
1289
+                // join the single paragraphs with a empty line in between
1290
+                $data['description'] = implode("\n\n", $result);
1291
+
1292
+            } else {
1293
+                $data['description'] = '';
1294
+            }
1295
+        }
1296
+
1297
+        return $data;
1298
+    }
1299 1299
 }
Please login to merge, or discard this patch.
Spacing   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -104,9 +104,9 @@  discard block
 block discarded – undo
104 104
 		$apps = self::getEnabledApps();
105 105
 
106 106
 		// Add each apps' folder as allowed class path
107
-		foreach($apps as $app) {
107
+		foreach ($apps as $app) {
108 108
 			$path = self::getAppPath($app);
109
-			if($path !== false) {
109
+			if ($path !== false) {
110 110
 				\OC::$loader->addValidRoot($path);
111 111
 			}
112 112
 		}
@@ -133,12 +133,12 @@  discard block
 block discarded – undo
133 133
 	public static function loadApp($app, $checkUpgrade = true) {
134 134
 		self::$loadedApps[] = $app;
135 135
 		$appPath = self::getAppPath($app);
136
-		if($appPath === false) {
136
+		if ($appPath === false) {
137 137
 			return;
138 138
 		}
139 139
 		\OC::$loader->addValidRoot($appPath); // in case someone calls loadApp() directly
140
-		if (is_file($appPath . '/appinfo/app.php')) {
141
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
140
+		if (is_file($appPath.'/appinfo/app.php')) {
141
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
142 142
 			if ($checkUpgrade and self::shouldUpgrade($app)) {
143 143
 				throw new \OC\NeedsUpdateException();
144 144
 			}
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
 				// enabled for groups
151 151
 				self::$enabledAppsCache = array();
152 152
 			}
153
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
153
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
154 154
 		}
155 155
 	}
156 156
 
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
 	 */
162 162
 	private static function requireAppFile($app) {
163 163
 		// encapsulated here to avoid variable scope conflicts
164
-		require_once $app . '/appinfo/app.php';
164
+		require_once $app.'/appinfo/app.php';
165 165
 	}
166 166
 
167 167
 	/**
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 	 */
209 209
 	public static function setAppTypes($app) {
210 210
 		$appData = self::getAppInfo($app);
211
-		if(!is_array($appData)) {
211
+		if (!is_array($appData)) {
212 212
 			return;
213 213
 		}
214 214
 
@@ -264,8 +264,8 @@  discard block
 block discarded – undo
264 264
 		} else {
265 265
 			$apps = $appManager->getEnabledAppsForUser($user);
266 266
 		}
267
-		$apps = array_filter($apps, function ($app) {
268
-			return $app !== 'files';//we add this manually
267
+		$apps = array_filter($apps, function($app) {
268
+			return $app !== 'files'; //we add this manually
269 269
 		});
270 270
 		sort($apps);
271 271
 		array_unshift($apps, 'files');
@@ -328,7 +328,7 @@  discard block
 block discarded – undo
328 328
 		);
329 329
 		$appData = $ocsClient->getApplication($app, \OCP\Util::getVersion());
330 330
 		$download = $ocsClient->getApplicationDownload($app, \OCP\Util::getVersion());
331
-		if(isset($download['downloadlink']) and $download['downloadlink']!='') {
331
+		if (isset($download['downloadlink']) and $download['downloadlink'] != '') {
332 332
 			// Replace spaces in download link without encoding entire URL
333 333
 			$download['downloadlink'] = str_replace(' ', '%20', $download['downloadlink']);
334 334
 			$info = array('source' => 'http', 'href' => $download['downloadlink'], 'appdata' => $appData);
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 	 */
358 358
 	public static function disable($app) {
359 359
 		// Convert OCS ID to regular application identifier
360
-		if(self::getInternalAppIdByOcs($app) !== false) {
360
+		if (self::getInternalAppIdByOcs($app) !== false) {
361 361
 			$app = self::getInternalAppIdByOcs($app);
362 362
 		}
363 363
 
@@ -410,7 +410,7 @@  discard block
 block discarded – undo
410 410
 			//SubAdmins are also allowed to access user management
411 411
 			$userObject = \OC::$server->getUserSession()->getUser();
412 412
 			$isSubAdmin = false;
413
-			if($userObject !== null) {
413
+			if ($userObject !== null) {
414 414
 				$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
415 415
 			}
416 416
 			if ($isSubAdmin) {
@@ -487,7 +487,7 @@  discard block
 block discarded – undo
487 487
 	 */
488 488
 	protected static function findAppInDirectories($appId) {
489 489
 		$sanitizedAppId = self::cleanAppId($appId);
490
-		if($sanitizedAppId !== $appId) {
490
+		if ($sanitizedAppId !== $appId) {
491 491
 			return false;
492 492
 		}
493 493
 		static $app_dir = array();
@@ -498,7 +498,7 @@  discard block
 block discarded – undo
498 498
 
499 499
 		$possibleApps = array();
500 500
 		foreach (OC::$APPSROOTS as $dir) {
501
-			if (file_exists($dir['path'] . '/' . $appId)) {
501
+			if (file_exists($dir['path'].'/'.$appId)) {
502 502
 				$possibleApps[] = $dir;
503 503
 			}
504 504
 		}
@@ -539,7 +539,7 @@  discard block
 block discarded – undo
539 539
 		}
540 540
 
541 541
 		if (($dir = self::findAppInDirectories($appId)) != false) {
542
-			return $dir['path'] . '/' . $appId;
542
+			return $dir['path'].'/'.$appId;
543 543
 		}
544 544
 		return false;
545 545
 	}
@@ -565,7 +565,7 @@  discard block
 block discarded – undo
565 565
 	 */
566 566
 	public static function getAppWebPath($appId) {
567 567
 		if (($dir = self::findAppInDirectories($appId)) != false) {
568
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
568
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
569 569
 		}
570 570
 		return false;
571 571
 	}
@@ -591,8 +591,8 @@  discard block
 block discarded – undo
591 591
 	 * @return string
592 592
 	 */
593 593
 	public static function getAppVersionByPath($path) {
594
-		$versionFile = $path . '/appinfo/version';
595
-		$infoFile = $path . '/appinfo/info.xml';
594
+		$versionFile = $path.'/appinfo/version';
595
+		$infoFile = $path.'/appinfo/info.xml';
596 596
 		if (is_file($versionFile)) {
597 597
 			return trim(file_get_contents($versionFile));
598 598
 		} else {
@@ -619,10 +619,10 @@  discard block
 block discarded – undo
619 619
 				return self::$appInfo[$appId];
620 620
 			}
621 621
 			$appPath = self::getAppPath($appId);
622
-			if($appPath === false) {
622
+			if ($appPath === false) {
623 623
 				return null;
624 624
 			}
625
-			$file = $appPath . '/appinfo/info.xml';
625
+			$file = $appPath.'/appinfo/info.xml';
626 626
 		}
627 627
 
628 628
 		$parser = new \OC\App\InfoParser(\OC::$server->getHTTPHelper(), \OC::$server->getURLGenerator());
@@ -631,9 +631,9 @@  discard block
 block discarded – undo
631 631
 		if (is_array($data)) {
632 632
 			$data = OC_App::parseAppInfo($data, $lang);
633 633
 		}
634
-		if(isset($data['ocsid'])) {
634
+		if (isset($data['ocsid'])) {
635 635
 			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
636
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
636
+			if ($storedId !== '' && $storedId !== $data['ocsid']) {
637 637
 				$data['ocsid'] = $storedId;
638 638
 			}
639 639
 		}
@@ -713,7 +713,7 @@  discard block
 block discarded – undo
713 713
 	 * @param string $page
714 714
 	 */
715 715
 	public static function registerAdmin($app, $page) {
716
-		self::$adminForms[] = $app . '/' . $page . '.php';
716
+		self::$adminForms[] = $app.'/'.$page.'.php';
717 717
 	}
718 718
 
719 719
 	/**
@@ -722,7 +722,7 @@  discard block
 block discarded – undo
722 722
 	 * @param string $page
723 723
 	 */
724 724
 	public static function registerPersonal($app, $page) {
725
-		self::$personalForms[] = $app . '/' . $page . '.php';
725
+		self::$personalForms[] = $app.'/'.$page.'.php';
726 726
 	}
727 727
 
728 728
 	/**
@@ -751,7 +751,7 @@  discard block
 block discarded – undo
751 751
 
752 752
 		foreach (OC::$APPSROOTS as $apps_dir) {
753 753
 			if (!is_readable($apps_dir['path'])) {
754
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
754
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
755 755
 				continue;
756 756
 			}
757 757
 			$dh = opendir($apps_dir['path']);
@@ -759,7 +759,7 @@  discard block
 block discarded – undo
759 759
 			if (is_resource($dh)) {
760 760
 				while (($file = readdir($dh)) !== false) {
761 761
 
762
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
762
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
763 763
 
764 764
 						$apps[] = $file;
765 765
 					}
@@ -797,12 +797,12 @@  discard block
 block discarded – undo
797 797
 
798 798
 				$info = OC_App::getAppInfo($app, false, $langCode);
799 799
 				if (!is_array($info)) {
800
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
800
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
801 801
 					continue;
802 802
 				}
803 803
 
804 804
 				if (!isset($info['name'])) {
805
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
805
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
806 806
 					continue;
807 807
 				}
808 808
 
@@ -831,13 +831,13 @@  discard block
 block discarded – undo
831 831
 				$info['update'] = ($includeUpdateInfo) ? OC_Installer::isUpdateAvailable($app) : null;
832 832
 
833 833
 				$appPath = self::getAppPath($app);
834
-				if($appPath !== false) {
835
-					$appIcon = $appPath . '/img/' . $app . '.svg';
834
+				if ($appPath !== false) {
835
+					$appIcon = $appPath.'/img/'.$app.'.svg';
836 836
 					if (file_exists($appIcon)) {
837
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
837
+						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app.'.svg');
838 838
 						$info['previewAsIcon'] = true;
839 839
 					} else {
840
-						$appIcon = $appPath . '/img/app.svg';
840
+						$appIcon = $appPath.'/img/app.svg';
841 841
 						if (file_exists($appIcon)) {
842 842
 							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
843 843
 							$info['previewAsIcon'] = true;
@@ -879,9 +879,9 @@  discard block
 block discarded – undo
879 879
 	 * @return string|false
880 880
 	 */
881 881
 	public static function getInternalAppIdByOcs($ocsID) {
882
-		if(is_numeric($ocsID)) {
882
+		if (is_numeric($ocsID)) {
883 883
 			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
884
-			if(array_search($ocsID, $idArray)) {
884
+			if (array_search($ocsID, $idArray)) {
885 885
 				return array_search($ocsID, $idArray);
886 886
 			}
887 887
 		}
@@ -931,7 +931,7 @@  discard block
 block discarded – undo
931 931
 			$apps[$i]['score'] = $app['score'];
932 932
 			$apps[$i]['removable'] = false;
933 933
 			if ($app['label'] == 'recommended') {
934
-				$apps[$i]['internallabel'] = (string)$l->t('Recommended');
934
+				$apps[$i]['internallabel'] = (string) $l->t('Recommended');
935 935
 				$apps[$i]['internalclass'] = 'recommendedapp';
936 936
 			}
937 937
 
@@ -1046,7 +1046,7 @@  discard block
 block discarded – undo
1046 1046
 	public static function getAppVersions() {
1047 1047
 		static $versions;
1048 1048
 
1049
-		if(!$versions) {
1049
+		if (!$versions) {
1050 1050
 			$appConfig = \OC::$server->getAppConfig();
1051 1051
 			$versions = $appConfig->getValues(false, 'installed_version');
1052 1052
 		}
@@ -1083,8 +1083,8 @@  discard block
 block discarded – undo
1083 1083
 			// case and use the local already installed one.
1084 1084
 			// FIXME: This is a horrible hack. I feel sad. The god of code cleanness may forgive me.
1085 1085
 			$internalAppId = self::getInternalAppIdByOcs($app);
1086
-			if($internalAppId !== false) {
1087
-				if($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1086
+			if ($internalAppId !== false) {
1087
+				if ($appData && version_compare(\OC_App::getAppVersion($internalAppId), $appData['version'], '<')) {
1088 1088
 					$app = self::downloadApp($app);
1089 1089
 				} else {
1090 1090
 					self::enable($internalAppId);
@@ -1098,7 +1098,7 @@  discard block
 block discarded – undo
1098 1098
 		if ($app !== false) {
1099 1099
 			// check if the app is compatible with this version of ownCloud
1100 1100
 			$info = self::getAppInfo($app);
1101
-			if(!is_array($info)) {
1101
+			if (!is_array($info)) {
1102 1102
 				throw new \Exception(
1103 1103
 					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1104 1104
 						[$info['name']]
@@ -1147,31 +1147,31 @@  discard block
 block discarded – undo
1147 1147
 	 */
1148 1148
 	public static function updateApp($appId) {
1149 1149
 		$appPath = self::getAppPath($appId);
1150
-		if($appPath === false) {
1150
+		if ($appPath === false) {
1151 1151
 			return false;
1152 1152
 		}
1153
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1154
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1153
+		if (file_exists($appPath.'/appinfo/database.xml')) {
1154
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
1155 1155
 		}
1156 1156
 		unset(self::$appVersion[$appId]);
1157 1157
 		// run upgrade code
1158
-		if (file_exists($appPath . '/appinfo/update.php')) {
1158
+		if (file_exists($appPath.'/appinfo/update.php')) {
1159 1159
 			self::loadApp($appId, false);
1160
-			include $appPath . '/appinfo/update.php';
1160
+			include $appPath.'/appinfo/update.php';
1161 1161
 		}
1162 1162
 
1163 1163
 		//set remote/public handlers
1164 1164
 		$appData = self::getAppInfo($appId);
1165 1165
 		if (array_key_exists('ocsid', $appData)) {
1166 1166
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1167
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1167
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1168 1168
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1169 1169
 		}
1170 1170
 		foreach ($appData['remote'] as $name => $path) {
1171
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1171
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
1172 1172
 		}
1173 1173
 		foreach ($appData['public'] as $name => $path) {
1174
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1174
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
1175 1175
 		}
1176 1176
 
1177 1177
 		self::setAppTypes($appId);
@@ -1189,17 +1189,17 @@  discard block
 block discarded – undo
1189 1189
 	public static function getStorage($appId) {
1190 1190
 		if (OC_App::isEnabled($appId)) { //sanity check
1191 1191
 			if (OC_User::isLoggedIn()) {
1192
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1192
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1193 1193
 				if (!$view->file_exists($appId)) {
1194 1194
 					$view->mkdir($appId);
1195 1195
 				}
1196
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1196
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1197 1197
 			} else {
1198
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1198
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1199 1199
 				return false;
1200 1200
 			}
1201 1201
 		} else {
1202
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1202
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1203 1203
 			return false;
1204 1204
 		}
1205 1205
 	}
@@ -1231,9 +1231,9 @@  discard block
 block discarded – undo
1231 1231
 
1232 1232
 				if ($attributeLang === $similarLang) {
1233 1233
 					$similarLangFallback = $option['@value'];
1234
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1234
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1235 1235
 					if ($similarLangFallback === false) {
1236
-						$similarLangFallback =  $option['@value'];
1236
+						$similarLangFallback = $option['@value'];
1237 1237
 					}
1238 1238
 				}
1239 1239
 			} else {
Please login to merge, or discard this patch.
lib/private/files/cache/cache.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -402,6 +402,9 @@
 block discarded – undo
402 402
 		}
403 403
 	}
404 404
 
405
+	/**
406
+	 * @param string $path
407
+	 */
405 408
 	private function getParentPath($path) {
406 409
 		$parent = dirname($path);
407 410
 		if ($parent === '.') {
Please login to merge, or discard this patch.
Indentation   +773 added lines, -773 removed lines patch added patch discarded remove patch
@@ -52,787 +52,787 @@
 block discarded – undo
52 52
  * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater
53 53
  */
54 54
 class Cache implements ICache {
55
-	use MoveFromCacheTrait {
56
-		MoveFromCacheTrait::moveFromCache as moveFromCacheFallback;
57
-	}
58
-
59
-	/**
60
-	 * @var array partial data for the cache
61
-	 */
62
-	protected $partial = array();
63
-
64
-	/**
65
-	 * @var string
66
-	 */
67
-	protected $storageId;
68
-
69
-	/**
70
-	 * @var Storage $storageCache
71
-	 */
72
-	protected $storageCache;
73
-
74
-	/** @var IMimeTypeLoader */
75
-	protected $mimetypeLoader;
76
-
77
-	/**
78
-	 * @var IDBConnection
79
-	 */
80
-	protected $connection;
81
-
82
-	/**
83
-	 * @param \OC\Files\Storage\Storage|string $storage
84
-	 */
85
-	public function __construct($storage) {
86
-		if ($storage instanceof \OC\Files\Storage\Storage) {
87
-			$this->storageId = $storage->getId();
88
-		} else {
89
-			$this->storageId = $storage;
90
-		}
91
-		if (strlen($this->storageId) > 64) {
92
-			$this->storageId = md5($this->storageId);
93
-		}
94
-
95
-		$this->storageCache = new Storage($storage);
96
-		$this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
97
-		$this->connection = \OC::$server->getDatabaseConnection();
98
-	}
99
-
100
-	/**
101
-	 * Get the numeric storage id for this cache's storage
102
-	 *
103
-	 * @return int
104
-	 */
105
-	public function getNumericStorageId() {
106
-		return $this->storageCache->getNumericId();
107
-	}
108
-
109
-	/**
110
-	 * get the stored metadata of a file or folder
111
-	 *
112
-	 * @param string | int $file either the path of a file or folder or the file id for a file or folder
113
-	 * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache
114
-	 */
115
-	public function get($file) {
116
-		if (is_string($file) or $file == '') {
117
-			// normalize file
118
-			$file = $this->normalize($file);
119
-
120
-			$where = 'WHERE `storage` = ? AND `path_hash` = ?';
121
-			$params = array($this->getNumericStorageId(), md5($file));
122
-		} else { //file id
123
-			$where = 'WHERE `fileid` = ?';
124
-			$params = array($file);
125
-		}
126
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
55
+    use MoveFromCacheTrait {
56
+        MoveFromCacheTrait::moveFromCache as moveFromCacheFallback;
57
+    }
58
+
59
+    /**
60
+     * @var array partial data for the cache
61
+     */
62
+    protected $partial = array();
63
+
64
+    /**
65
+     * @var string
66
+     */
67
+    protected $storageId;
68
+
69
+    /**
70
+     * @var Storage $storageCache
71
+     */
72
+    protected $storageCache;
73
+
74
+    /** @var IMimeTypeLoader */
75
+    protected $mimetypeLoader;
76
+
77
+    /**
78
+     * @var IDBConnection
79
+     */
80
+    protected $connection;
81
+
82
+    /**
83
+     * @param \OC\Files\Storage\Storage|string $storage
84
+     */
85
+    public function __construct($storage) {
86
+        if ($storage instanceof \OC\Files\Storage\Storage) {
87
+            $this->storageId = $storage->getId();
88
+        } else {
89
+            $this->storageId = $storage;
90
+        }
91
+        if (strlen($this->storageId) > 64) {
92
+            $this->storageId = md5($this->storageId);
93
+        }
94
+
95
+        $this->storageCache = new Storage($storage);
96
+        $this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
97
+        $this->connection = \OC::$server->getDatabaseConnection();
98
+    }
99
+
100
+    /**
101
+     * Get the numeric storage id for this cache's storage
102
+     *
103
+     * @return int
104
+     */
105
+    public function getNumericStorageId() {
106
+        return $this->storageCache->getNumericId();
107
+    }
108
+
109
+    /**
110
+     * get the stored metadata of a file or folder
111
+     *
112
+     * @param string | int $file either the path of a file or folder or the file id for a file or folder
113
+     * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache
114
+     */
115
+    public function get($file) {
116
+        if (is_string($file) or $file == '') {
117
+            // normalize file
118
+            $file = $this->normalize($file);
119
+
120
+            $where = 'WHERE `storage` = ? AND `path_hash` = ?';
121
+            $params = array($this->getNumericStorageId(), md5($file));
122
+        } else { //file id
123
+            $where = 'WHERE `fileid` = ?';
124
+            $params = array($file);
125
+        }
126
+        $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
127 127
 					   `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
128 128
 				FROM `*PREFIX*filecache` ' . $where;
129
-		$result = $this->connection->executeQuery($sql, $params);
130
-		$data = $result->fetch();
131
-
132
-		//FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO
133
-		//PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false
134
-		if ($data === null) {
135
-			$data = false;
136
-		}
137
-
138
-		//merge partial data
139
-		if (!$data and is_string($file)) {
140
-			if (isset($this->partial[$file])) {
141
-				$data = $this->partial[$file];
142
-			}
143
-			return $data;
144
-		} else {
145
-			//fix types
146
-			$data['fileid'] = (int)$data['fileid'];
147
-			$data['parent'] = (int)$data['parent'];
148
-			$data['size'] = 0 + $data['size'];
149
-			$data['mtime'] = (int)$data['mtime'];
150
-			$data['storage_mtime'] = (int)$data['storage_mtime'];
151
-			$data['encryptedVersion'] = (int)$data['encrypted'];
152
-			$data['encrypted'] = (bool)$data['encrypted'];
153
-			$data['storage'] = $this->storageId;
154
-			$data['mimetype'] = $this->mimetypeLoader->getMimetypeById($data['mimetype']);
155
-			$data['mimepart'] = $this->mimetypeLoader->getMimetypeById($data['mimepart']);
156
-			if ($data['storage_mtime'] == 0) {
157
-				$data['storage_mtime'] = $data['mtime'];
158
-			}
159
-			$data['permissions'] = (int)$data['permissions'];
160
-			return new CacheEntry($data);
161
-		}
162
-	}
163
-
164
-	/**
165
-	 * get the metadata of all files stored in $folder
166
-	 *
167
-	 * @param string $folder
168
-	 * @return ICacheEntry[]
169
-	 */
170
-	public function getFolderContents($folder) {
171
-		$fileId = $this->getId($folder);
172
-		return $this->getFolderContentsById($fileId);
173
-	}
174
-
175
-	/**
176
-	 * get the metadata of all files stored in $folder
177
-	 *
178
-	 * @param int $fileId the file id of the folder
179
-	 * @return ICacheEntry[]
180
-	 */
181
-	public function getFolderContentsById($fileId) {
182
-		if ($fileId > -1) {
183
-			$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
129
+        $result = $this->connection->executeQuery($sql, $params);
130
+        $data = $result->fetch();
131
+
132
+        //FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO
133
+        //PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false
134
+        if ($data === null) {
135
+            $data = false;
136
+        }
137
+
138
+        //merge partial data
139
+        if (!$data and is_string($file)) {
140
+            if (isset($this->partial[$file])) {
141
+                $data = $this->partial[$file];
142
+            }
143
+            return $data;
144
+        } else {
145
+            //fix types
146
+            $data['fileid'] = (int)$data['fileid'];
147
+            $data['parent'] = (int)$data['parent'];
148
+            $data['size'] = 0 + $data['size'];
149
+            $data['mtime'] = (int)$data['mtime'];
150
+            $data['storage_mtime'] = (int)$data['storage_mtime'];
151
+            $data['encryptedVersion'] = (int)$data['encrypted'];
152
+            $data['encrypted'] = (bool)$data['encrypted'];
153
+            $data['storage'] = $this->storageId;
154
+            $data['mimetype'] = $this->mimetypeLoader->getMimetypeById($data['mimetype']);
155
+            $data['mimepart'] = $this->mimetypeLoader->getMimetypeById($data['mimepart']);
156
+            if ($data['storage_mtime'] == 0) {
157
+                $data['storage_mtime'] = $data['mtime'];
158
+            }
159
+            $data['permissions'] = (int)$data['permissions'];
160
+            return new CacheEntry($data);
161
+        }
162
+    }
163
+
164
+    /**
165
+     * get the metadata of all files stored in $folder
166
+     *
167
+     * @param string $folder
168
+     * @return ICacheEntry[]
169
+     */
170
+    public function getFolderContents($folder) {
171
+        $fileId = $this->getId($folder);
172
+        return $this->getFolderContentsById($fileId);
173
+    }
174
+
175
+    /**
176
+     * get the metadata of all files stored in $folder
177
+     *
178
+     * @param int $fileId the file id of the folder
179
+     * @return ICacheEntry[]
180
+     */
181
+    public function getFolderContentsById($fileId) {
182
+        if ($fileId > -1) {
183
+            $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
184 184
 						   `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
185 185
 					FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC';
186
-			$result = $this->connection->executeQuery($sql, [$fileId]);
187
-			$files = $result->fetchAll();
188
-			foreach ($files as &$file) {
189
-				$file['mimetype'] = $this->mimetypeLoader->getMimetypeById($file['mimetype']);
190
-				$file['mimepart'] = $this->mimetypeLoader->getMimetypeById($file['mimepart']);
191
-				if ($file['storage_mtime'] == 0) {
192
-					$file['storage_mtime'] = $file['mtime'];
193
-				}
194
-				$file['permissions'] = (int)$file['permissions'];
195
-				$file['mtime'] = (int)$file['mtime'];
196
-				$file['storage_mtime'] = (int)$file['storage_mtime'];
197
-				$file['size'] = 0 + $file['size'];
198
-			}
199
-			return array_map(function (array $data) {
200
-				return new CacheEntry($data);
201
-			}, $files);
202
-		} else {
203
-			return array();
204
-		}
205
-	}
206
-
207
-	/**
208
-	 * insert or update meta data for a file or folder
209
-	 *
210
-	 * @param string $file
211
-	 * @param array $data
212
-	 *
213
-	 * @return int file id
214
-	 * @throws \RuntimeException
215
-	 */
216
-	public function put($file, array $data) {
217
-		if (($id = $this->getId($file)) > -1) {
218
-			$this->update($id, $data);
219
-			return $id;
220
-		} else {
221
-			return $this->insert($file, $data);
222
-		}
223
-	}
224
-
225
-	/**
226
-	 * insert meta data for a new file or folder
227
-	 *
228
-	 * @param string $file
229
-	 * @param array $data
230
-	 *
231
-	 * @return int file id
232
-	 * @throws \RuntimeException
233
-	 */
234
-	public function insert($file, array $data) {
235
-		// normalize file
236
-		$file = $this->normalize($file);
237
-
238
-		if (isset($this->partial[$file])) { //add any saved partial data
239
-			$data = array_merge($this->partial[$file], $data);
240
-			unset($this->partial[$file]);
241
-		}
242
-
243
-		$requiredFields = array('size', 'mtime', 'mimetype');
244
-		foreach ($requiredFields as $field) {
245
-			if (!isset($data[$field])) { //data not complete save as partial and return
246
-				$this->partial[$file] = $data;
247
-				return -1;
248
-			}
249
-		}
250
-
251
-		$data['path'] = $file;
252
-		$data['parent'] = $this->getParentId($file);
253
-		$data['name'] = \OC_Util::basename($file);
254
-
255
-		list($queryParts, $params) = $this->buildParts($data);
256
-		$queryParts[] = '`storage`';
257
-		$params[] = $this->getNumericStorageId();
258
-
259
-		$queryParts = array_map(function ($item) {
260
-			return trim($item, "`");
261
-		}, $queryParts);
262
-		$values = array_combine($queryParts, $params);
263
-		if (\OC::$server->getDatabaseConnection()->insertIfNotExist('*PREFIX*filecache', $values, [
264
-			'storage',
265
-			'path_hash',
266
-		])
267
-		) {
268
-			return (int)$this->connection->lastInsertId('*PREFIX*filecache');
269
-		}
270
-
271
-		// The file was created in the mean time
272
-		if (($id = $this->getId($file)) > -1) {
273
-			$this->update($id, $data);
274
-			return $id;
275
-		} else {
276
-			throw new \RuntimeException('File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.');
277
-		}
278
-	}
279
-
280
-	/**
281
-	 * update the metadata of an existing file or folder in the cache
282
-	 *
283
-	 * @param int $id the fileid of the existing file or folder
284
-	 * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged
285
-	 */
286
-	public function update($id, array $data) {
287
-
288
-		if (isset($data['path'])) {
289
-			// normalize path
290
-			$data['path'] = $this->normalize($data['path']);
291
-		}
292
-
293
-		if (isset($data['name'])) {
294
-			// normalize path
295
-			$data['name'] = $this->normalize($data['name']);
296
-		}
297
-
298
-		list($queryParts, $params) = $this->buildParts($data);
299
-		// duplicate $params because we need the parts twice in the SQL statement
300
-		// once for the SET part, once in the WHERE clause
301
-		$params = array_merge($params, $params);
302
-		$params[] = $id;
303
-
304
-		// don't update if the data we try to set is the same as the one in the record
305
-		// some databases (Postgres) don't like superfluous updates
306
-		$sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
307
-			'WHERE (' .
308
-			implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
309
-			implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
310
-			') AND `fileid` = ? ';
311
-		$this->connection->executeQuery($sql, $params);
312
-
313
-	}
314
-
315
-	/**
316
-	 * extract query parts and params array from data array
317
-	 *
318
-	 * @param array $data
319
-	 * @return array [$queryParts, $params]
320
-	 *        $queryParts: string[], the (escaped) column names to be set in the query
321
-	 *        $params: mixed[], the new values for the columns, to be passed as params to the query
322
-	 */
323
-	protected function buildParts(array $data) {
324
-		$fields = array(
325
-			'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
326
-			'etag', 'permissions', 'checksum');
327
-
328
-		$doNotCopyStorageMTime = false;
329
-		if (array_key_exists('mtime', $data) && $data['mtime'] === null) {
330
-			// this horrific magic tells it to not copy storage_mtime to mtime
331
-			unset($data['mtime']);
332
-			$doNotCopyStorageMTime = true;
333
-		}
334
-
335
-		$params = array();
336
-		$queryParts = array();
337
-		foreach ($data as $name => $value) {
338
-			if (array_search($name, $fields) !== false) {
339
-				if ($name === 'path') {
340
-					$params[] = md5($value);
341
-					$queryParts[] = '`path_hash`';
342
-				} elseif ($name === 'mimetype') {
343
-					$params[] = $this->mimetypeLoader->getId(substr($value, 0, strpos($value, '/')));
344
-					$queryParts[] = '`mimepart`';
345
-					$value = $this->mimetypeLoader->getId($value);
346
-				} elseif ($name === 'storage_mtime') {
347
-					if (!$doNotCopyStorageMTime && !isset($data['mtime'])) {
348
-						$params[] = $value;
349
-						$queryParts[] = '`mtime`';
350
-					}
351
-				} elseif ($name === 'encrypted') {
352
-					if(isset($data['encryptedVersion'])) {
353
-						$value = $data['encryptedVersion'];
354
-					} else {
355
-						// Boolean to integer conversion
356
-						$value = $value ? 1 : 0;
357
-					}
358
-				}
359
-				$params[] = $value;
360
-				$queryParts[] = '`' . $name . '`';
361
-			}
362
-		}
363
-		return array($queryParts, $params);
364
-	}
365
-
366
-	/**
367
-	 * get the file id for a file
368
-	 *
369
-	 * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file
370
-	 *
371
-	 * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing
372
-	 *
373
-	 * @param string $file
374
-	 * @return int
375
-	 */
376
-	public function getId($file) {
377
-		// normalize file
378
-		$file = $this->normalize($file);
379
-
380
-		$pathHash = md5($file);
381
-
382
-		$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
383
-		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
384
-		if ($row = $result->fetch()) {
385
-			return $row['fileid'];
386
-		} else {
387
-			return -1;
388
-		}
389
-	}
390
-
391
-	/**
392
-	 * get the id of the parent folder of a file
393
-	 *
394
-	 * @param string $file
395
-	 * @return int
396
-	 */
397
-	public function getParentId($file) {
398
-		if ($file === '') {
399
-			return -1;
400
-		} else {
401
-			$parent = $this->getParentPath($file);
402
-			return (int)$this->getId($parent);
403
-		}
404
-	}
405
-
406
-	private function getParentPath($path) {
407
-		$parent = dirname($path);
408
-		if ($parent === '.') {
409
-			$parent = '';
410
-		}
411
-		return $parent;
412
-	}
413
-
414
-	/**
415
-	 * check if a file is available in the cache
416
-	 *
417
-	 * @param string $file
418
-	 * @return bool
419
-	 */
420
-	public function inCache($file) {
421
-		return $this->getId($file) != -1;
422
-	}
423
-
424
-	/**
425
-	 * remove a file or folder from the cache
426
-	 *
427
-	 * when removing a folder from the cache all files and folders inside the folder will be removed as well
428
-	 *
429
-	 * @param string $file
430
-	 */
431
-	public function remove($file) {
432
-		$entry = $this->get($file);
433
-		$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?';
434
-		$this->connection->executeQuery($sql, array($entry['fileid']));
435
-		if ($entry['mimetype'] === 'httpd/unix-directory') {
436
-			$this->removeChildren($entry);
437
-		}
438
-	}
439
-
440
-	/**
441
-	 * Get all sub folders of a folder
442
-	 *
443
-	 * @param array $entry the cache entry of the folder to get the subfolders for
444
-	 * @return array[] the cache entries for the subfolders
445
-	 */
446
-	private function getSubFolders($entry) {
447
-		$children = $this->getFolderContentsById($entry['fileid']);
448
-		return array_filter($children, function ($child) {
449
-			return $child['mimetype'] === 'httpd/unix-directory';
450
-		});
451
-	}
452
-
453
-	/**
454
-	 * Recursively remove all children of a folder
455
-	 *
456
-	 * @param array $entry the cache entry of the folder to remove the children of
457
-	 * @throws \OC\DatabaseException
458
-	 */
459
-	private function removeChildren($entry) {
460
-		$subFolders = $this->getSubFolders($entry);
461
-		foreach ($subFolders as $folder) {
462
-			$this->removeChildren($folder);
463
-		}
464
-		$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `parent` = ?';
465
-		$this->connection->executeQuery($sql, array($entry['fileid']));
466
-	}
467
-
468
-	/**
469
-	 * Move a file or folder in the cache
470
-	 *
471
-	 * @param string $source
472
-	 * @param string $target
473
-	 */
474
-	public function move($source, $target) {
475
-		$this->moveFromCache($this, $source, $target);
476
-	}
477
-
478
-	/**
479
-	 * Get the storage id and path needed for a move
480
-	 *
481
-	 * @param string $path
482
-	 * @return array [$storageId, $internalPath]
483
-	 */
484
-	protected function getMoveInfo($path) {
485
-		return [$this->getNumericStorageId(), $path];
486
-	}
487
-
488
-	/**
489
-	 * Move a file or folder in the cache
490
-	 *
491
-	 * @param \OCP\Files\Cache\ICache $sourceCache
492
-	 * @param string $sourcePath
493
-	 * @param string $targetPath
494
-	 * @throws \OC\DatabaseException
495
-	 */
496
-	public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
497
-		if ($sourceCache instanceof Cache) {
498
-			// normalize source and target
499
-			$sourcePath = $this->normalize($sourcePath);
500
-			$targetPath = $this->normalize($targetPath);
501
-
502
-			$sourceData = $sourceCache->get($sourcePath);
503
-			$sourceId = $sourceData['fileid'];
504
-			$newParentId = $this->getParentId($targetPath);
505
-
506
-			list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath);
507
-			list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
508
-
509
-			// sql for final update
510
-			$moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` =  ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
511
-
512
-			if ($sourceData['mimetype'] === 'httpd/unix-directory') {
513
-				//find all child entries
514
-				$sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
515
-				$result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']);
516
-				$childEntries = $result->fetchAll();
517
-				$sourceLength = strlen($sourcePath);
518
-				$this->connection->beginTransaction();
519
-				$query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
520
-
521
-				foreach ($childEntries as $child) {
522
-					$newTargetPath = $targetPath . substr($child['path'], $sourceLength);
523
-					$query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]);
524
-				}
525
-				$this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
526
-				$this->connection->commit();
527
-			} else {
528
-				$this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
529
-			}
530
-		} else {
531
-			$this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
532
-		}
533
-	}
534
-
535
-	/**
536
-	 * remove all entries for files that are stored on the storage from the cache
537
-	 */
538
-	public function clear() {
539
-		$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
540
-		$this->connection->executeQuery($sql, array($this->getNumericStorageId()));
541
-
542
-		$sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
543
-		$this->connection->executeQuery($sql, array($this->storageId));
544
-	}
545
-
546
-	/**
547
-	 * Get the scan status of a file
548
-	 *
549
-	 * - Cache::NOT_FOUND: File is not in the cache
550
-	 * - Cache::PARTIAL: File is not stored in the cache but some incomplete data is known
551
-	 * - Cache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned
552
-	 * - Cache::COMPLETE: The file or folder, with all it's children) are fully scanned
553
-	 *
554
-	 * @param string $file
555
-	 *
556
-	 * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
557
-	 */
558
-	public function getStatus($file) {
559
-		// normalize file
560
-		$file = $this->normalize($file);
561
-
562
-		$pathHash = md5($file);
563
-		$sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
564
-		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
565
-		if ($row = $result->fetch()) {
566
-			if ((int)$row['size'] === -1) {
567
-				return self::SHALLOW;
568
-			} else {
569
-				return self::COMPLETE;
570
-			}
571
-		} else {
572
-			if (isset($this->partial[$file])) {
573
-				return self::PARTIAL;
574
-			} else {
575
-				return self::NOT_FOUND;
576
-			}
577
-		}
578
-	}
579
-
580
-	/**
581
-	 * search for files matching $pattern
582
-	 *
583
-	 * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
584
-	 * @return ICacheEntry[] an array of cache entries where the name matches the search pattern
585
-	 */
586
-	public function search($pattern) {
587
-		// normalize pattern
588
-		$pattern = $this->normalize($pattern);
589
-
590
-
591
-		$sql = '
186
+            $result = $this->connection->executeQuery($sql, [$fileId]);
187
+            $files = $result->fetchAll();
188
+            foreach ($files as &$file) {
189
+                $file['mimetype'] = $this->mimetypeLoader->getMimetypeById($file['mimetype']);
190
+                $file['mimepart'] = $this->mimetypeLoader->getMimetypeById($file['mimepart']);
191
+                if ($file['storage_mtime'] == 0) {
192
+                    $file['storage_mtime'] = $file['mtime'];
193
+                }
194
+                $file['permissions'] = (int)$file['permissions'];
195
+                $file['mtime'] = (int)$file['mtime'];
196
+                $file['storage_mtime'] = (int)$file['storage_mtime'];
197
+                $file['size'] = 0 + $file['size'];
198
+            }
199
+            return array_map(function (array $data) {
200
+                return new CacheEntry($data);
201
+            }, $files);
202
+        } else {
203
+            return array();
204
+        }
205
+    }
206
+
207
+    /**
208
+     * insert or update meta data for a file or folder
209
+     *
210
+     * @param string $file
211
+     * @param array $data
212
+     *
213
+     * @return int file id
214
+     * @throws \RuntimeException
215
+     */
216
+    public function put($file, array $data) {
217
+        if (($id = $this->getId($file)) > -1) {
218
+            $this->update($id, $data);
219
+            return $id;
220
+        } else {
221
+            return $this->insert($file, $data);
222
+        }
223
+    }
224
+
225
+    /**
226
+     * insert meta data for a new file or folder
227
+     *
228
+     * @param string $file
229
+     * @param array $data
230
+     *
231
+     * @return int file id
232
+     * @throws \RuntimeException
233
+     */
234
+    public function insert($file, array $data) {
235
+        // normalize file
236
+        $file = $this->normalize($file);
237
+
238
+        if (isset($this->partial[$file])) { //add any saved partial data
239
+            $data = array_merge($this->partial[$file], $data);
240
+            unset($this->partial[$file]);
241
+        }
242
+
243
+        $requiredFields = array('size', 'mtime', 'mimetype');
244
+        foreach ($requiredFields as $field) {
245
+            if (!isset($data[$field])) { //data not complete save as partial and return
246
+                $this->partial[$file] = $data;
247
+                return -1;
248
+            }
249
+        }
250
+
251
+        $data['path'] = $file;
252
+        $data['parent'] = $this->getParentId($file);
253
+        $data['name'] = \OC_Util::basename($file);
254
+
255
+        list($queryParts, $params) = $this->buildParts($data);
256
+        $queryParts[] = '`storage`';
257
+        $params[] = $this->getNumericStorageId();
258
+
259
+        $queryParts = array_map(function ($item) {
260
+            return trim($item, "`");
261
+        }, $queryParts);
262
+        $values = array_combine($queryParts, $params);
263
+        if (\OC::$server->getDatabaseConnection()->insertIfNotExist('*PREFIX*filecache', $values, [
264
+            'storage',
265
+            'path_hash',
266
+        ])
267
+        ) {
268
+            return (int)$this->connection->lastInsertId('*PREFIX*filecache');
269
+        }
270
+
271
+        // The file was created in the mean time
272
+        if (($id = $this->getId($file)) > -1) {
273
+            $this->update($id, $data);
274
+            return $id;
275
+        } else {
276
+            throw new \RuntimeException('File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.');
277
+        }
278
+    }
279
+
280
+    /**
281
+     * update the metadata of an existing file or folder in the cache
282
+     *
283
+     * @param int $id the fileid of the existing file or folder
284
+     * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged
285
+     */
286
+    public function update($id, array $data) {
287
+
288
+        if (isset($data['path'])) {
289
+            // normalize path
290
+            $data['path'] = $this->normalize($data['path']);
291
+        }
292
+
293
+        if (isset($data['name'])) {
294
+            // normalize path
295
+            $data['name'] = $this->normalize($data['name']);
296
+        }
297
+
298
+        list($queryParts, $params) = $this->buildParts($data);
299
+        // duplicate $params because we need the parts twice in the SQL statement
300
+        // once for the SET part, once in the WHERE clause
301
+        $params = array_merge($params, $params);
302
+        $params[] = $id;
303
+
304
+        // don't update if the data we try to set is the same as the one in the record
305
+        // some databases (Postgres) don't like superfluous updates
306
+        $sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
307
+            'WHERE (' .
308
+            implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
309
+            implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
310
+            ') AND `fileid` = ? ';
311
+        $this->connection->executeQuery($sql, $params);
312
+
313
+    }
314
+
315
+    /**
316
+     * extract query parts and params array from data array
317
+     *
318
+     * @param array $data
319
+     * @return array [$queryParts, $params]
320
+     *        $queryParts: string[], the (escaped) column names to be set in the query
321
+     *        $params: mixed[], the new values for the columns, to be passed as params to the query
322
+     */
323
+    protected function buildParts(array $data) {
324
+        $fields = array(
325
+            'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
326
+            'etag', 'permissions', 'checksum');
327
+
328
+        $doNotCopyStorageMTime = false;
329
+        if (array_key_exists('mtime', $data) && $data['mtime'] === null) {
330
+            // this horrific magic tells it to not copy storage_mtime to mtime
331
+            unset($data['mtime']);
332
+            $doNotCopyStorageMTime = true;
333
+        }
334
+
335
+        $params = array();
336
+        $queryParts = array();
337
+        foreach ($data as $name => $value) {
338
+            if (array_search($name, $fields) !== false) {
339
+                if ($name === 'path') {
340
+                    $params[] = md5($value);
341
+                    $queryParts[] = '`path_hash`';
342
+                } elseif ($name === 'mimetype') {
343
+                    $params[] = $this->mimetypeLoader->getId(substr($value, 0, strpos($value, '/')));
344
+                    $queryParts[] = '`mimepart`';
345
+                    $value = $this->mimetypeLoader->getId($value);
346
+                } elseif ($name === 'storage_mtime') {
347
+                    if (!$doNotCopyStorageMTime && !isset($data['mtime'])) {
348
+                        $params[] = $value;
349
+                        $queryParts[] = '`mtime`';
350
+                    }
351
+                } elseif ($name === 'encrypted') {
352
+                    if(isset($data['encryptedVersion'])) {
353
+                        $value = $data['encryptedVersion'];
354
+                    } else {
355
+                        // Boolean to integer conversion
356
+                        $value = $value ? 1 : 0;
357
+                    }
358
+                }
359
+                $params[] = $value;
360
+                $queryParts[] = '`' . $name . '`';
361
+            }
362
+        }
363
+        return array($queryParts, $params);
364
+    }
365
+
366
+    /**
367
+     * get the file id for a file
368
+     *
369
+     * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file
370
+     *
371
+     * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing
372
+     *
373
+     * @param string $file
374
+     * @return int
375
+     */
376
+    public function getId($file) {
377
+        // normalize file
378
+        $file = $this->normalize($file);
379
+
380
+        $pathHash = md5($file);
381
+
382
+        $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
383
+        $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
384
+        if ($row = $result->fetch()) {
385
+            return $row['fileid'];
386
+        } else {
387
+            return -1;
388
+        }
389
+    }
390
+
391
+    /**
392
+     * get the id of the parent folder of a file
393
+     *
394
+     * @param string $file
395
+     * @return int
396
+     */
397
+    public function getParentId($file) {
398
+        if ($file === '') {
399
+            return -1;
400
+        } else {
401
+            $parent = $this->getParentPath($file);
402
+            return (int)$this->getId($parent);
403
+        }
404
+    }
405
+
406
+    private function getParentPath($path) {
407
+        $parent = dirname($path);
408
+        if ($parent === '.') {
409
+            $parent = '';
410
+        }
411
+        return $parent;
412
+    }
413
+
414
+    /**
415
+     * check if a file is available in the cache
416
+     *
417
+     * @param string $file
418
+     * @return bool
419
+     */
420
+    public function inCache($file) {
421
+        return $this->getId($file) != -1;
422
+    }
423
+
424
+    /**
425
+     * remove a file or folder from the cache
426
+     *
427
+     * when removing a folder from the cache all files and folders inside the folder will be removed as well
428
+     *
429
+     * @param string $file
430
+     */
431
+    public function remove($file) {
432
+        $entry = $this->get($file);
433
+        $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?';
434
+        $this->connection->executeQuery($sql, array($entry['fileid']));
435
+        if ($entry['mimetype'] === 'httpd/unix-directory') {
436
+            $this->removeChildren($entry);
437
+        }
438
+    }
439
+
440
+    /**
441
+     * Get all sub folders of a folder
442
+     *
443
+     * @param array $entry the cache entry of the folder to get the subfolders for
444
+     * @return array[] the cache entries for the subfolders
445
+     */
446
+    private function getSubFolders($entry) {
447
+        $children = $this->getFolderContentsById($entry['fileid']);
448
+        return array_filter($children, function ($child) {
449
+            return $child['mimetype'] === 'httpd/unix-directory';
450
+        });
451
+    }
452
+
453
+    /**
454
+     * Recursively remove all children of a folder
455
+     *
456
+     * @param array $entry the cache entry of the folder to remove the children of
457
+     * @throws \OC\DatabaseException
458
+     */
459
+    private function removeChildren($entry) {
460
+        $subFolders = $this->getSubFolders($entry);
461
+        foreach ($subFolders as $folder) {
462
+            $this->removeChildren($folder);
463
+        }
464
+        $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `parent` = ?';
465
+        $this->connection->executeQuery($sql, array($entry['fileid']));
466
+    }
467
+
468
+    /**
469
+     * Move a file or folder in the cache
470
+     *
471
+     * @param string $source
472
+     * @param string $target
473
+     */
474
+    public function move($source, $target) {
475
+        $this->moveFromCache($this, $source, $target);
476
+    }
477
+
478
+    /**
479
+     * Get the storage id and path needed for a move
480
+     *
481
+     * @param string $path
482
+     * @return array [$storageId, $internalPath]
483
+     */
484
+    protected function getMoveInfo($path) {
485
+        return [$this->getNumericStorageId(), $path];
486
+    }
487
+
488
+    /**
489
+     * Move a file or folder in the cache
490
+     *
491
+     * @param \OCP\Files\Cache\ICache $sourceCache
492
+     * @param string $sourcePath
493
+     * @param string $targetPath
494
+     * @throws \OC\DatabaseException
495
+     */
496
+    public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
497
+        if ($sourceCache instanceof Cache) {
498
+            // normalize source and target
499
+            $sourcePath = $this->normalize($sourcePath);
500
+            $targetPath = $this->normalize($targetPath);
501
+
502
+            $sourceData = $sourceCache->get($sourcePath);
503
+            $sourceId = $sourceData['fileid'];
504
+            $newParentId = $this->getParentId($targetPath);
505
+
506
+            list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath);
507
+            list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
508
+
509
+            // sql for final update
510
+            $moveSql = 'UPDATE `*PREFIX*filecache` SET `storage` =  ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` =? WHERE `fileid` = ?';
511
+
512
+            if ($sourceData['mimetype'] === 'httpd/unix-directory') {
513
+                //find all child entries
514
+                $sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
515
+                $result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']);
516
+                $childEntries = $result->fetchAll();
517
+                $sourceLength = strlen($sourcePath);
518
+                $this->connection->beginTransaction();
519
+                $query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
520
+
521
+                foreach ($childEntries as $child) {
522
+                    $newTargetPath = $targetPath . substr($child['path'], $sourceLength);
523
+                    $query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]);
524
+                }
525
+                $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
526
+                $this->connection->commit();
527
+            } else {
528
+                $this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
529
+            }
530
+        } else {
531
+            $this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
532
+        }
533
+    }
534
+
535
+    /**
536
+     * remove all entries for files that are stored on the storage from the cache
537
+     */
538
+    public function clear() {
539
+        $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
540
+        $this->connection->executeQuery($sql, array($this->getNumericStorageId()));
541
+
542
+        $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
543
+        $this->connection->executeQuery($sql, array($this->storageId));
544
+    }
545
+
546
+    /**
547
+     * Get the scan status of a file
548
+     *
549
+     * - Cache::NOT_FOUND: File is not in the cache
550
+     * - Cache::PARTIAL: File is not stored in the cache but some incomplete data is known
551
+     * - Cache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned
552
+     * - Cache::COMPLETE: The file or folder, with all it's children) are fully scanned
553
+     *
554
+     * @param string $file
555
+     *
556
+     * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
557
+     */
558
+    public function getStatus($file) {
559
+        // normalize file
560
+        $file = $this->normalize($file);
561
+
562
+        $pathHash = md5($file);
563
+        $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
564
+        $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
565
+        if ($row = $result->fetch()) {
566
+            if ((int)$row['size'] === -1) {
567
+                return self::SHALLOW;
568
+            } else {
569
+                return self::COMPLETE;
570
+            }
571
+        } else {
572
+            if (isset($this->partial[$file])) {
573
+                return self::PARTIAL;
574
+            } else {
575
+                return self::NOT_FOUND;
576
+            }
577
+        }
578
+    }
579
+
580
+    /**
581
+     * search for files matching $pattern
582
+     *
583
+     * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
584
+     * @return ICacheEntry[] an array of cache entries where the name matches the search pattern
585
+     */
586
+    public function search($pattern) {
587
+        // normalize pattern
588
+        $pattern = $this->normalize($pattern);
589
+
590
+
591
+        $sql = '
592 592
 			SELECT `fileid`, `storage`, `path`, `parent`, `name`,
593 593
 				`mimetype`, `mimepart`, `size`, `mtime`, `encrypted`,
594 594
 				`etag`, `permissions`, `checksum`
595 595
 			FROM `*PREFIX*filecache`
596 596
 			WHERE `storage` = ? AND `name` ILIKE ?';
597
-		$result = $this->connection->executeQuery($sql,
598
-			[$this->getNumericStorageId(), $pattern]
599
-		);
600
-
601
-		$files = [];
602
-		while ($row = $result->fetch()) {
603
-			$row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']);
604
-			$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
605
-			$files[] = $row;
606
-		}
607
-		return array_map(function(array $data) {
608
-			return new CacheEntry($data);
609
-		}, $files);
610
-	}
611
-
612
-	/**
613
-	 * search for files by mimetype
614
-	 *
615
-	 * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
616
-	 *        where it will search for all mimetypes in the group ('image/*')
617
-	 * @return ICacheEntry[] an array of cache entries where the mimetype matches the search
618
-	 */
619
-	public function searchByMime($mimetype) {
620
-		if (strpos($mimetype, '/')) {
621
-			$where = '`mimetype` = ?';
622
-		} else {
623
-			$where = '`mimepart` = ?';
624
-		}
625
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
597
+        $result = $this->connection->executeQuery($sql,
598
+            [$this->getNumericStorageId(), $pattern]
599
+        );
600
+
601
+        $files = [];
602
+        while ($row = $result->fetch()) {
603
+            $row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']);
604
+            $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
605
+            $files[] = $row;
606
+        }
607
+        return array_map(function(array $data) {
608
+            return new CacheEntry($data);
609
+        }, $files);
610
+    }
611
+
612
+    /**
613
+     * search for files by mimetype
614
+     *
615
+     * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
616
+     *        where it will search for all mimetypes in the group ('image/*')
617
+     * @return ICacheEntry[] an array of cache entries where the mimetype matches the search
618
+     */
619
+    public function searchByMime($mimetype) {
620
+        if (strpos($mimetype, '/')) {
621
+            $where = '`mimetype` = ?';
622
+        } else {
623
+            $where = '`mimepart` = ?';
624
+        }
625
+        $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
626 626
 				FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?';
627
-		$mimetype = $this->mimetypeLoader->getId($mimetype);
628
-		$result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
629
-		$files = array();
630
-		while ($row = $result->fetch()) {
631
-			$row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']);
632
-			$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
633
-			$files[] = $row;
634
-		}
635
-		return array_map(function (array $data) {
636
-			return new CacheEntry($data);
637
-		}, $files);
638
-	}
639
-
640
-	/**
641
-	 * Search for files by tag of a given users.
642
-	 *
643
-	 * Note that every user can tag files differently.
644
-	 *
645
-	 * @param string|int $tag name or tag id
646
-	 * @param string $userId owner of the tags
647
-	 * @return ICacheEntry[] file data
648
-	 */
649
-	public function searchByTag($tag, $userId) {
650
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
651
-			'`mimetype`, `mimepart`, `size`, `mtime`, ' .
652
-			'`encrypted`, `etag`, `permissions`, `checksum` ' .
653
-			'FROM `*PREFIX*filecache` `file`, ' .
654
-			'`*PREFIX*vcategory_to_object` `tagmap`, ' .
655
-			'`*PREFIX*vcategory` `tag` ' .
656
-			// JOIN filecache to vcategory_to_object
657
-			'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
658
-			// JOIN vcategory_to_object to vcategory
659
-			'AND `tagmap`.`type` = `tag`.`type` ' .
660
-			'AND `tagmap`.`categoryid` = `tag`.`id` ' .
661
-			// conditions
662
-			'AND `file`.`storage` = ? ' .
663
-			'AND `tag`.`type` = \'files\' ' .
664
-			'AND `tag`.`uid` = ? ';
665
-		if (is_int($tag)) {
666
-			$sql .= 'AND `tag`.`id` = ? ';
667
-		} else {
668
-			$sql .= 'AND `tag`.`category` = ? ';
669
-		}
670
-		$result = $this->connection->executeQuery(
671
-			$sql,
672
-			[
673
-				$this->getNumericStorageId(),
674
-				$userId,
675
-				$tag
676
-			]
677
-		);
678
-		$files = array();
679
-		while ($row = $result->fetch()) {
680
-			$files[] = $row;
681
-		}
682
-		return array_map(function (array $data) {
683
-			return new CacheEntry($data);
684
-		}, $files);
685
-	}
686
-
687
-	/**
688
-	 * Re-calculate the folder size and the size of all parent folders
689
-	 *
690
-	 * @param string|boolean $path
691
-	 * @param array $data (optional) meta data of the folder
692
-	 */
693
-	public function correctFolderSize($path, $data = null) {
694
-		$this->calculateFolderSize($path, $data);
695
-		if ($path !== '') {
696
-			$parent = dirname($path);
697
-			if ($parent === '.' or $parent === '/') {
698
-				$parent = '';
699
-			}
700
-			$this->correctFolderSize($parent);
701
-		}
702
-	}
703
-
704
-	/**
705
-	 * calculate the size of a folder and set it in the cache
706
-	 *
707
-	 * @param string $path
708
-	 * @param array $entry (optional) meta data of the folder
709
-	 * @return int
710
-	 */
711
-	public function calculateFolderSize($path, $entry = null) {
712
-		$totalSize = 0;
713
-		if (is_null($entry) or !isset($entry['fileid'])) {
714
-			$entry = $this->get($path);
715
-		}
716
-		if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') {
717
-			$id = $entry['fileid'];
718
-			$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
719
-				'FROM `*PREFIX*filecache` ' .
720
-				'WHERE `parent` = ? AND `storage` = ?';
721
-			$result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
722
-			if ($row = $result->fetch()) {
723
-				$result->closeCursor();
724
-				list($sum, $min) = array_values($row);
725
-				$sum = 0 + $sum;
726
-				$min = 0 + $min;
727
-				if ($min === -1) {
728
-					$totalSize = $min;
729
-				} else {
730
-					$totalSize = $sum;
731
-				}
732
-				$update = array();
733
-				if ($entry['size'] !== $totalSize) {
734
-					$update['size'] = $totalSize;
735
-				}
736
-				if (count($update) > 0) {
737
-					$this->update($id, $update);
738
-				}
739
-			} else {
740
-				$result->closeCursor();
741
-			}
742
-		}
743
-		return $totalSize;
744
-	}
745
-
746
-	/**
747
-	 * get all file ids on the files on the storage
748
-	 *
749
-	 * @return int[]
750
-	 */
751
-	public function getAll() {
752
-		$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?';
753
-		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId()));
754
-		$ids = array();
755
-		while ($row = $result->fetch()) {
756
-			$ids[] = $row['fileid'];
757
-		}
758
-		return $ids;
759
-	}
760
-
761
-	/**
762
-	 * find a folder in the cache which has not been fully scanned
763
-	 *
764
-	 * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
765
-	 * use the one with the highest id gives the best result with the background scanner, since that is most
766
-	 * likely the folder where we stopped scanning previously
767
-	 *
768
-	 * @return string|bool the path of the folder or false when no folder matched
769
-	 */
770
-	public function getIncomplete() {
771
-		$query = $this->connection->prepare('SELECT `path` FROM `*PREFIX*filecache`'
772
-			. ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC', 1);
773
-		$query->execute([$this->getNumericStorageId()]);
774
-		if ($row = $query->fetch()) {
775
-			return $row['path'];
776
-		} else {
777
-			return false;
778
-		}
779
-	}
780
-
781
-	/**
782
-	 * get the path of a file on this storage by it's file id
783
-	 *
784
-	 * @param int $id the file id of the file or folder to search
785
-	 * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache
786
-	 */
787
-	public function getPathById($id) {
788
-		$sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?';
789
-		$result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
790
-		if ($row = $result->fetch()) {
791
-			// Oracle stores empty strings as null...
792
-			if ($row['path'] === null) {
793
-				return '';
794
-			}
795
-			return $row['path'];
796
-		} else {
797
-			return null;
798
-		}
799
-	}
800
-
801
-	/**
802
-	 * get the storage id of the storage for a file and the internal path of the file
803
-	 * unlike getPathById this does not limit the search to files on this storage and
804
-	 * instead does a global search in the cache table
805
-	 *
806
-	 * @param int $id
807
-	 * @deprecated use getPathById() instead
808
-	 * @return array first element holding the storage id, second the path
809
-	 */
810
-	static public function getById($id) {
811
-		$connection = \OC::$server->getDatabaseConnection();
812
-		$sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
813
-		$result = $connection->executeQuery($sql, array($id));
814
-		if ($row = $result->fetch()) {
815
-			$numericId = $row['storage'];
816
-			$path = $row['path'];
817
-		} else {
818
-			return null;
819
-		}
820
-
821
-		if ($id = Storage::getStorageId($numericId)) {
822
-			return array($id, $path);
823
-		} else {
824
-			return null;
825
-		}
826
-	}
827
-
828
-	/**
829
-	 * normalize the given path
830
-	 *
831
-	 * @param string $path
832
-	 * @return string
833
-	 */
834
-	public function normalize($path) {
835
-
836
-		return trim(\OC_Util::normalizeUnicode($path), '/');
837
-	}
627
+        $mimetype = $this->mimetypeLoader->getId($mimetype);
628
+        $result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
629
+        $files = array();
630
+        while ($row = $result->fetch()) {
631
+            $row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']);
632
+            $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
633
+            $files[] = $row;
634
+        }
635
+        return array_map(function (array $data) {
636
+            return new CacheEntry($data);
637
+        }, $files);
638
+    }
639
+
640
+    /**
641
+     * Search for files by tag of a given users.
642
+     *
643
+     * Note that every user can tag files differently.
644
+     *
645
+     * @param string|int $tag name or tag id
646
+     * @param string $userId owner of the tags
647
+     * @return ICacheEntry[] file data
648
+     */
649
+    public function searchByTag($tag, $userId) {
650
+        $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
651
+            '`mimetype`, `mimepart`, `size`, `mtime`, ' .
652
+            '`encrypted`, `etag`, `permissions`, `checksum` ' .
653
+            'FROM `*PREFIX*filecache` `file`, ' .
654
+            '`*PREFIX*vcategory_to_object` `tagmap`, ' .
655
+            '`*PREFIX*vcategory` `tag` ' .
656
+            // JOIN filecache to vcategory_to_object
657
+            'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
658
+            // JOIN vcategory_to_object to vcategory
659
+            'AND `tagmap`.`type` = `tag`.`type` ' .
660
+            'AND `tagmap`.`categoryid` = `tag`.`id` ' .
661
+            // conditions
662
+            'AND `file`.`storage` = ? ' .
663
+            'AND `tag`.`type` = \'files\' ' .
664
+            'AND `tag`.`uid` = ? ';
665
+        if (is_int($tag)) {
666
+            $sql .= 'AND `tag`.`id` = ? ';
667
+        } else {
668
+            $sql .= 'AND `tag`.`category` = ? ';
669
+        }
670
+        $result = $this->connection->executeQuery(
671
+            $sql,
672
+            [
673
+                $this->getNumericStorageId(),
674
+                $userId,
675
+                $tag
676
+            ]
677
+        );
678
+        $files = array();
679
+        while ($row = $result->fetch()) {
680
+            $files[] = $row;
681
+        }
682
+        return array_map(function (array $data) {
683
+            return new CacheEntry($data);
684
+        }, $files);
685
+    }
686
+
687
+    /**
688
+     * Re-calculate the folder size and the size of all parent folders
689
+     *
690
+     * @param string|boolean $path
691
+     * @param array $data (optional) meta data of the folder
692
+     */
693
+    public function correctFolderSize($path, $data = null) {
694
+        $this->calculateFolderSize($path, $data);
695
+        if ($path !== '') {
696
+            $parent = dirname($path);
697
+            if ($parent === '.' or $parent === '/') {
698
+                $parent = '';
699
+            }
700
+            $this->correctFolderSize($parent);
701
+        }
702
+    }
703
+
704
+    /**
705
+     * calculate the size of a folder and set it in the cache
706
+     *
707
+     * @param string $path
708
+     * @param array $entry (optional) meta data of the folder
709
+     * @return int
710
+     */
711
+    public function calculateFolderSize($path, $entry = null) {
712
+        $totalSize = 0;
713
+        if (is_null($entry) or !isset($entry['fileid'])) {
714
+            $entry = $this->get($path);
715
+        }
716
+        if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') {
717
+            $id = $entry['fileid'];
718
+            $sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
719
+                'FROM `*PREFIX*filecache` ' .
720
+                'WHERE `parent` = ? AND `storage` = ?';
721
+            $result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
722
+            if ($row = $result->fetch()) {
723
+                $result->closeCursor();
724
+                list($sum, $min) = array_values($row);
725
+                $sum = 0 + $sum;
726
+                $min = 0 + $min;
727
+                if ($min === -1) {
728
+                    $totalSize = $min;
729
+                } else {
730
+                    $totalSize = $sum;
731
+                }
732
+                $update = array();
733
+                if ($entry['size'] !== $totalSize) {
734
+                    $update['size'] = $totalSize;
735
+                }
736
+                if (count($update) > 0) {
737
+                    $this->update($id, $update);
738
+                }
739
+            } else {
740
+                $result->closeCursor();
741
+            }
742
+        }
743
+        return $totalSize;
744
+    }
745
+
746
+    /**
747
+     * get all file ids on the files on the storage
748
+     *
749
+     * @return int[]
750
+     */
751
+    public function getAll() {
752
+        $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?';
753
+        $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId()));
754
+        $ids = array();
755
+        while ($row = $result->fetch()) {
756
+            $ids[] = $row['fileid'];
757
+        }
758
+        return $ids;
759
+    }
760
+
761
+    /**
762
+     * find a folder in the cache which has not been fully scanned
763
+     *
764
+     * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
765
+     * use the one with the highest id gives the best result with the background scanner, since that is most
766
+     * likely the folder where we stopped scanning previously
767
+     *
768
+     * @return string|bool the path of the folder or false when no folder matched
769
+     */
770
+    public function getIncomplete() {
771
+        $query = $this->connection->prepare('SELECT `path` FROM `*PREFIX*filecache`'
772
+            . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC', 1);
773
+        $query->execute([$this->getNumericStorageId()]);
774
+        if ($row = $query->fetch()) {
775
+            return $row['path'];
776
+        } else {
777
+            return false;
778
+        }
779
+    }
780
+
781
+    /**
782
+     * get the path of a file on this storage by it's file id
783
+     *
784
+     * @param int $id the file id of the file or folder to search
785
+     * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache
786
+     */
787
+    public function getPathById($id) {
788
+        $sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?';
789
+        $result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
790
+        if ($row = $result->fetch()) {
791
+            // Oracle stores empty strings as null...
792
+            if ($row['path'] === null) {
793
+                return '';
794
+            }
795
+            return $row['path'];
796
+        } else {
797
+            return null;
798
+        }
799
+    }
800
+
801
+    /**
802
+     * get the storage id of the storage for a file and the internal path of the file
803
+     * unlike getPathById this does not limit the search to files on this storage and
804
+     * instead does a global search in the cache table
805
+     *
806
+     * @param int $id
807
+     * @deprecated use getPathById() instead
808
+     * @return array first element holding the storage id, second the path
809
+     */
810
+    static public function getById($id) {
811
+        $connection = \OC::$server->getDatabaseConnection();
812
+        $sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
813
+        $result = $connection->executeQuery($sql, array($id));
814
+        if ($row = $result->fetch()) {
815
+            $numericId = $row['storage'];
816
+            $path = $row['path'];
817
+        } else {
818
+            return null;
819
+        }
820
+
821
+        if ($id = Storage::getStorageId($numericId)) {
822
+            return array($id, $path);
823
+        } else {
824
+            return null;
825
+        }
826
+    }
827
+
828
+    /**
829
+     * normalize the given path
830
+     *
831
+     * @param string $path
832
+     * @return string
833
+     */
834
+    public function normalize($path) {
835
+
836
+        return trim(\OC_Util::normalizeUnicode($path), '/');
837
+    }
838 838
 }
Please login to merge, or discard this patch.
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -143,20 +143,20 @@  discard block
 block discarded – undo
143 143
 			return $data;
144 144
 		} else {
145 145
 			//fix types
146
-			$data['fileid'] = (int)$data['fileid'];
147
-			$data['parent'] = (int)$data['parent'];
146
+			$data['fileid'] = (int) $data['fileid'];
147
+			$data['parent'] = (int) $data['parent'];
148 148
 			$data['size'] = 0 + $data['size'];
149
-			$data['mtime'] = (int)$data['mtime'];
150
-			$data['storage_mtime'] = (int)$data['storage_mtime'];
151
-			$data['encryptedVersion'] = (int)$data['encrypted'];
152
-			$data['encrypted'] = (bool)$data['encrypted'];
149
+			$data['mtime'] = (int) $data['mtime'];
150
+			$data['storage_mtime'] = (int) $data['storage_mtime'];
151
+			$data['encryptedVersion'] = (int) $data['encrypted'];
152
+			$data['encrypted'] = (bool) $data['encrypted'];
153 153
 			$data['storage'] = $this->storageId;
154 154
 			$data['mimetype'] = $this->mimetypeLoader->getMimetypeById($data['mimetype']);
155 155
 			$data['mimepart'] = $this->mimetypeLoader->getMimetypeById($data['mimepart']);
156 156
 			if ($data['storage_mtime'] == 0) {
157 157
 				$data['storage_mtime'] = $data['mtime'];
158 158
 			}
159
-			$data['permissions'] = (int)$data['permissions'];
159
+			$data['permissions'] = (int) $data['permissions'];
160 160
 			return new CacheEntry($data);
161 161
 		}
162 162
 	}
@@ -191,12 +191,12 @@  discard block
 block discarded – undo
191 191
 				if ($file['storage_mtime'] == 0) {
192 192
 					$file['storage_mtime'] = $file['mtime'];
193 193
 				}
194
-				$file['permissions'] = (int)$file['permissions'];
195
-				$file['mtime'] = (int)$file['mtime'];
196
-				$file['storage_mtime'] = (int)$file['storage_mtime'];
194
+				$file['permissions'] = (int) $file['permissions'];
195
+				$file['mtime'] = (int) $file['mtime'];
196
+				$file['storage_mtime'] = (int) $file['storage_mtime'];
197 197
 				$file['size'] = 0 + $file['size'];
198 198
 			}
199
-			return array_map(function (array $data) {
199
+			return array_map(function(array $data) {
200 200
 				return new CacheEntry($data);
201 201
 			}, $files);
202 202
 		} else {
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
 		$queryParts[] = '`storage`';
257 257
 		$params[] = $this->getNumericStorageId();
258 258
 
259
-		$queryParts = array_map(function ($item) {
259
+		$queryParts = array_map(function($item) {
260 260
 			return trim($item, "`");
261 261
 		}, $queryParts);
262 262
 		$values = array_combine($queryParts, $params);
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
 			'path_hash',
266 266
 		])
267 267
 		) {
268
-			return (int)$this->connection->lastInsertId('*PREFIX*filecache');
268
+			return (int) $this->connection->lastInsertId('*PREFIX*filecache');
269 269
 		}
270 270
 
271 271
 		// The file was created in the mean time
@@ -303,10 +303,10 @@  discard block
 block discarded – undo
303 303
 
304 304
 		// don't update if the data we try to set is the same as the one in the record
305 305
 		// some databases (Postgres) don't like superfluous updates
306
-		$sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
307
-			'WHERE (' .
308
-			implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
309
-			implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
306
+		$sql = 'UPDATE `*PREFIX*filecache` SET '.implode(' = ?, ', $queryParts).'=? '.
307
+			'WHERE ('.
308
+			implode(' <> ? OR ', $queryParts).' <> ? OR '.
309
+			implode(' IS NULL OR ', $queryParts).' IS NULL'.
310 310
 			') AND `fileid` = ? ';
311 311
 		$this->connection->executeQuery($sql, $params);
312 312
 
@@ -349,7 +349,7 @@  discard block
 block discarded – undo
349 349
 						$queryParts[] = '`mtime`';
350 350
 					}
351 351
 				} elseif ($name === 'encrypted') {
352
-					if(isset($data['encryptedVersion'])) {
352
+					if (isset($data['encryptedVersion'])) {
353 353
 						$value = $data['encryptedVersion'];
354 354
 					} else {
355 355
 						// Boolean to integer conversion
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 					}
358 358
 				}
359 359
 				$params[] = $value;
360
-				$queryParts[] = '`' . $name . '`';
360
+				$queryParts[] = '`'.$name.'`';
361 361
 			}
362 362
 		}
363 363
 		return array($queryParts, $params);
@@ -399,7 +399,7 @@  discard block
 block discarded – undo
399 399
 			return -1;
400 400
 		} else {
401 401
 			$parent = $this->getParentPath($file);
402
-			return (int)$this->getId($parent);
402
+			return (int) $this->getId($parent);
403 403
 		}
404 404
 	}
405 405
 
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
 	 */
446 446
 	private function getSubFolders($entry) {
447 447
 		$children = $this->getFolderContentsById($entry['fileid']);
448
-		return array_filter($children, function ($child) {
448
+		return array_filter($children, function($child) {
449 449
 			return $child['mimetype'] === 'httpd/unix-directory';
450 450
 		});
451 451
 	}
@@ -512,14 +512,14 @@  discard block
 block discarded – undo
512 512
 			if ($sourceData['mimetype'] === 'httpd/unix-directory') {
513 513
 				//find all child entries
514 514
 				$sql = 'SELECT `path`, `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path` LIKE ?';
515
-				$result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath) . '/%']);
515
+				$result = $this->connection->executeQuery($sql, [$sourceStorageId, $this->connection->escapeLikeParameter($sourcePath).'/%']);
516 516
 				$childEntries = $result->fetchAll();
517 517
 				$sourceLength = strlen($sourcePath);
518 518
 				$this->connection->beginTransaction();
519 519
 				$query = $this->connection->prepare('UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ? WHERE `fileid` = ?');
520 520
 
521 521
 				foreach ($childEntries as $child) {
522
-					$newTargetPath = $targetPath . substr($child['path'], $sourceLength);
522
+					$newTargetPath = $targetPath.substr($child['path'], $sourceLength);
523 523
 					$query->execute([$targetStorageId, $newTargetPath, md5($newTargetPath), $child['fileid']]);
524 524
 				}
525 525
 				$this->connection->executeQuery($moveSql, [$targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId]);
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
 		$sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
564 564
 		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
565 565
 		if ($row = $result->fetch()) {
566
-			if ((int)$row['size'] === -1) {
566
+			if ((int) $row['size'] === -1) {
567 567
 				return self::SHALLOW;
568 568
 			} else {
569 569
 				return self::COMPLETE;
@@ -623,7 +623,7 @@  discard block
 block discarded – undo
623 623
 			$where = '`mimepart` = ?';
624 624
 		}
625 625
 		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
626
-				FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?';
626
+				FROM `*PREFIX*filecache` WHERE ' . $where.' AND `storage` = ?';
627 627
 		$mimetype = $this->mimetypeLoader->getId($mimetype);
628 628
 		$result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
629 629
 		$files = array();
@@ -632,7 +632,7 @@  discard block
 block discarded – undo
632 632
 			$row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']);
633 633
 			$files[] = $row;
634 634
 		}
635
-		return array_map(function (array $data) {
635
+		return array_map(function(array $data) {
636 636
 			return new CacheEntry($data);
637 637
 		}, $files);
638 638
 	}
@@ -647,20 +647,20 @@  discard block
 block discarded – undo
647 647
 	 * @return ICacheEntry[] file data
648 648
 	 */
649 649
 	public function searchByTag($tag, $userId) {
650
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
651
-			'`mimetype`, `mimepart`, `size`, `mtime`, ' .
652
-			'`encrypted`, `etag`, `permissions`, `checksum` ' .
653
-			'FROM `*PREFIX*filecache` `file`, ' .
654
-			'`*PREFIX*vcategory_to_object` `tagmap`, ' .
655
-			'`*PREFIX*vcategory` `tag` ' .
650
+		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, '.
651
+			'`mimetype`, `mimepart`, `size`, `mtime`, '.
652
+			'`encrypted`, `etag`, `permissions`, `checksum` '.
653
+			'FROM `*PREFIX*filecache` `file`, '.
654
+			'`*PREFIX*vcategory_to_object` `tagmap`, '.
655
+			'`*PREFIX*vcategory` `tag` '.
656 656
 			// JOIN filecache to vcategory_to_object
657
-			'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
657
+			'WHERE `file`.`fileid` = `tagmap`.`objid` '.
658 658
 			// JOIN vcategory_to_object to vcategory
659
-			'AND `tagmap`.`type` = `tag`.`type` ' .
660
-			'AND `tagmap`.`categoryid` = `tag`.`id` ' .
659
+			'AND `tagmap`.`type` = `tag`.`type` '.
660
+			'AND `tagmap`.`categoryid` = `tag`.`id` '.
661 661
 			// conditions
662
-			'AND `file`.`storage` = ? ' .
663
-			'AND `tag`.`type` = \'files\' ' .
662
+			'AND `file`.`storage` = ? '.
663
+			'AND `tag`.`type` = \'files\' '.
664 664
 			'AND `tag`.`uid` = ? ';
665 665
 		if (is_int($tag)) {
666 666
 			$sql .= 'AND `tag`.`id` = ? ';
@@ -679,7 +679,7 @@  discard block
 block discarded – undo
679 679
 		while ($row = $result->fetch()) {
680 680
 			$files[] = $row;
681 681
 		}
682
-		return array_map(function (array $data) {
682
+		return array_map(function(array $data) {
683 683
 			return new CacheEntry($data);
684 684
 		}, $files);
685 685
 	}
@@ -715,8 +715,8 @@  discard block
 block discarded – undo
715 715
 		}
716 716
 		if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') {
717 717
 			$id = $entry['fileid'];
718
-			$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
719
-				'FROM `*PREFIX*filecache` ' .
718
+			$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 '.
719
+				'FROM `*PREFIX*filecache` '.
720 720
 				'WHERE `parent` = ? AND `storage` = ?';
721 721
 			$result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
722 722
 			if ($row = $result->fetch()) {
Please login to merge, or discard this patch.
lib/private/files/objectstore/objectstorestorage.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -160,6 +160,9 @@
 block discarded – undo
160 160
 		return true;
161 161
 	}
162 162
 
163
+	/**
164
+	 * @param string $path
165
+	 */
163 166
 	private function rmObjects($path) {
164 167
 		$children = $this->getCache()->getFolderContents($path);
165 168
 		foreach ($children as $child) {
Please login to merge, or discard this patch.
Indentation   +370 added lines, -370 removed lines patch added patch discarded remove patch
@@ -31,374 +31,374 @@
 block discarded – undo
31 31
 
32 32
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
33 33
 
34
-	/**
35
-	 * @var array
36
-	 */
37
-	private static $tmpFiles = array();
38
-	/**
39
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
40
-	 */
41
-	protected $objectStore;
42
-	/**
43
-	 * @var \OC\User\User $user
44
-	 */
45
-	protected $user;
46
-
47
-	public function __construct($params) {
48
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
49
-			$this->objectStore = $params['objectstore'];
50
-		} else {
51
-			throw new \Exception('missing IObjectStore instance');
52
-		}
53
-		if (isset($params['storageid'])) {
54
-			$this->id = 'object::store:' . $params['storageid'];
55
-		} else {
56
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
57
-		}
58
-		//initialize cache with root directory in cache
59
-		if (!$this->is_dir('/')) {
60
-			$this->mkdir('/');
61
-		}
62
-	}
63
-
64
-	public function mkdir($path) {
65
-		$path = $this->normalizePath($path);
66
-
67
-		if ($this->file_exists($path)) {
68
-			return false;
69
-		}
70
-
71
-		$mTime = time();
72
-		$data = [
73
-			'mimetype' => 'httpd/unix-directory',
74
-			'size' => 0,
75
-			'mtime' => $mTime,
76
-			'storage_mtime' => $mTime,
77
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
78
-		];
79
-		if ($path === '') {
80
-			//create root on the fly
81
-			$data['etag'] = $this->getETag('');
82
-			$this->getCache()->put('', $data);
83
-			return true;
84
-		} else {
85
-			// if parent does not exist, create it
86
-			$parent = $this->normalizePath(dirname($path));
87
-			$parentType = $this->filetype($parent);
88
-			if ($parentType === false) {
89
-				if (!$this->mkdir($parent)) {
90
-					// something went wrong
91
-					return false;
92
-				}
93
-			} else if ($parentType === 'file') {
94
-				// parent is a file
95
-				return false;
96
-			}
97
-			// finally create the new dir
98
-			$mTime = time(); // update mtime
99
-			$data['mtime'] = $mTime;
100
-			$data['storage_mtime'] = $mTime;
101
-			$data['etag'] = $this->getETag($path);
102
-			$this->getCache()->put($path, $data);
103
-			return true;
104
-		}
105
-	}
106
-
107
-	/**
108
-	 * @param string $path
109
-	 * @return string
110
-	 */
111
-	private function normalizePath($path) {
112
-		$path = trim($path, '/');
113
-		//FIXME why do we sometimes get a path like 'files//username'?
114
-		$path = str_replace('//', '/', $path);
115
-
116
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
117
-		if (!$path || $path === '.') {
118
-			$path = '';
119
-		}
120
-
121
-		return $path;
122
-	}
123
-
124
-	/**
125
-	 * Object Stores use a NoopScanner because metadata is directly stored in
126
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
127
-	 *
128
-	 * @param string $path
129
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
130
-	 * @return \OC\Files\ObjectStore\NoopScanner
131
-	 */
132
-	public function getScanner($path = '', $storage = null) {
133
-		if (!$storage) {
134
-			$storage = $this;
135
-		}
136
-		if (!isset($this->scanner)) {
137
-			$this->scanner = new NoopScanner($storage);
138
-		}
139
-		return $this->scanner;
140
-	}
141
-
142
-	public function getId() {
143
-		return $this->id;
144
-	}
145
-
146
-	public function rmdir($path) {
147
-		$path = $this->normalizePath($path);
148
-
149
-		if (!$this->is_dir($path)) {
150
-			return false;
151
-		}
152
-
153
-		$this->rmObjects($path);
154
-
155
-		$this->getCache()->remove($path);
156
-
157
-		return true;
158
-	}
159
-
160
-	private function rmObjects($path) {
161
-		$children = $this->getCache()->getFolderContents($path);
162
-		foreach ($children as $child) {
163
-			if ($child['mimetype'] === 'httpd/unix-directory') {
164
-				$this->rmObjects($child['path']);
165
-			} else {
166
-				$this->unlink($child['path']);
167
-			}
168
-		}
169
-	}
170
-
171
-	public function unlink($path) {
172
-		$path = $this->normalizePath($path);
173
-		$stat = $this->stat($path);
174
-
175
-		if ($stat && isset($stat['fileid'])) {
176
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
177
-				return $this->rmdir($path);
178
-			}
179
-			try {
180
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
181
-			} catch (\Exception $ex) {
182
-				if ($ex->getCode() !== 404) {
183
-					\OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
184
-					return false;
185
-				} else {
186
-					//removing from cache is ok as it does not exist in the objectstore anyway
187
-				}
188
-			}
189
-			$this->getCache()->remove($path);
190
-			return true;
191
-		}
192
-		return false;
193
-	}
194
-
195
-	public function stat($path) {
196
-		$path = $this->normalizePath($path);
197
-		$cacheEntry = $this->getCache()->get($path);
198
-		if ($cacheEntry instanceof CacheEntry) {
199
-			return $cacheEntry->getData();
200
-		} else {
201
-			return false;
202
-		}
203
-	}
204
-
205
-	/**
206
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
207
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
208
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
209
-	 *
210
-	 * @param int $fileId the fileid
211
-	 * @return null|string the unified resource name used to identify the object
212
-	 */
213
-	protected function getURN($fileId) {
214
-		if (is_numeric($fileId)) {
215
-			return 'urn:oid:' . $fileId;
216
-		}
217
-		return null;
218
-	}
219
-
220
-	public function opendir($path) {
221
-		$path = $this->normalizePath($path);
222
-
223
-		try {
224
-			$files = array();
225
-			$folderContents = $this->getCache()->getFolderContents($path);
226
-			foreach ($folderContents as $file) {
227
-				$files[] = $file['name'];
228
-			}
229
-
230
-			return IteratorDirectory::wrap($files);
231
-		} catch (\Exception $e) {
232
-			\OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
233
-			return false;
234
-		}
235
-	}
236
-
237
-	public function filetype($path) {
238
-		$path = $this->normalizePath($path);
239
-		$stat = $this->stat($path);
240
-		if ($stat) {
241
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
242
-				return 'dir';
243
-			}
244
-			return 'file';
245
-		} else {
246
-			return false;
247
-		}
248
-	}
249
-
250
-	public function fopen($path, $mode) {
251
-		$path = $this->normalizePath($path);
252
-
253
-		switch ($mode) {
254
-			case 'r':
255
-			case 'rb':
256
-				$stat = $this->stat($path);
257
-				if (is_array($stat)) {
258
-					try {
259
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
260
-					} catch (\Exception $ex) {
261
-						\OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
262
-						return false;
263
-					}
264
-				} else {
265
-					return false;
266
-				}
267
-			case 'w':
268
-			case 'wb':
269
-			case 'a':
270
-			case 'ab':
271
-			case 'r+':
272
-			case 'w+':
273
-			case 'wb+':
274
-			case 'a+':
275
-			case 'x':
276
-			case 'x+':
277
-			case 'c':
278
-			case 'c+':
279
-				if (strrpos($path, '.') !== false) {
280
-					$ext = substr($path, strrpos($path, '.'));
281
-				} else {
282
-					$ext = '';
283
-				}
284
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
285
-				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
286
-				if ($this->file_exists($path)) {
287
-					$source = $this->fopen($path, 'r');
288
-					file_put_contents($tmpFile, $source);
289
-				}
290
-				self::$tmpFiles[$tmpFile] = $path;
291
-
292
-				return fopen('close://' . $tmpFile, $mode);
293
-		}
294
-		return false;
295
-	}
296
-
297
-	public function file_exists($path) {
298
-		$path = $this->normalizePath($path);
299
-		return (bool)$this->stat($path);
300
-	}
301
-
302
-	public function rename($source, $target) {
303
-		$source = $this->normalizePath($source);
304
-		$target = $this->normalizePath($target);
305
-		$this->remove($target);
306
-		$this->getCache()->move($source, $target);
307
-		$this->touch(dirname($target));
308
-		return true;
309
-	}
310
-
311
-	public function getMimeType($path) {
312
-		$path = $this->normalizePath($path);
313
-		$stat = $this->stat($path);
314
-		if (is_array($stat)) {
315
-			return $stat['mimetype'];
316
-		} else {
317
-			return false;
318
-		}
319
-	}
320
-
321
-	public function touch($path, $mtime = null) {
322
-		if (is_null($mtime)) {
323
-			$mtime = time();
324
-		}
325
-
326
-		$path = $this->normalizePath($path);
327
-		$dirName = dirname($path);
328
-		$parentExists = $this->is_dir($dirName);
329
-		if (!$parentExists) {
330
-			return false;
331
-		}
332
-
333
-		$stat = $this->stat($path);
334
-		if (is_array($stat)) {
335
-			// update existing mtime in db
336
-			$stat['mtime'] = $mtime;
337
-			$this->getCache()->update($stat['fileid'], $stat);
338
-		} else {
339
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
340
-			// create new file
341
-			$stat = array(
342
-				'etag' => $this->getETag($path),
343
-				'mimetype' => $mimeType,
344
-				'size' => 0,
345
-				'mtime' => $mtime,
346
-				'storage_mtime' => $mtime,
347
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
348
-			);
349
-			$fileId = $this->getCache()->put($path, $stat);
350
-			try {
351
-				//read an empty file from memory
352
-				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
353
-			} catch (\Exception $ex) {
354
-				$this->getCache()->remove($path);
355
-				\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
356
-				return false;
357
-			}
358
-		}
359
-		return true;
360
-	}
361
-
362
-	public function writeBack($tmpFile) {
363
-		if (!isset(self::$tmpFiles[$tmpFile])) {
364
-			return;
365
-		}
366
-
367
-		$path = self::$tmpFiles[$tmpFile];
368
-		$stat = $this->stat($path);
369
-		if (empty($stat)) {
370
-			// create new file
371
-			$stat = array(
372
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
373
-			);
374
-		}
375
-		// update stat with new data
376
-		$mTime = time();
377
-		$stat['size'] = filesize($tmpFile);
378
-		$stat['mtime'] = $mTime;
379
-		$stat['storage_mtime'] = $mTime;
380
-		$stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
381
-		$stat['etag'] = $this->getETag($path);
382
-
383
-		$fileId = $this->getCache()->put($path, $stat);
384
-		try {
385
-			//upload to object storage
386
-			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
387
-		} catch (\Exception $ex) {
388
-			$this->getCache()->remove($path);
389
-			\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
390
-			throw $ex; // make this bubble up
391
-		}
392
-	}
393
-
394
-	/**
395
-	 * external changes are not supported, exclusive access to the object storage is assumed
396
-	 *
397
-	 * @param string $path
398
-	 * @param int $time
399
-	 * @return false
400
-	 */
401
-	public function hasUpdated($path, $time) {
402
-		return false;
403
-	}
34
+    /**
35
+     * @var array
36
+     */
37
+    private static $tmpFiles = array();
38
+    /**
39
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
40
+     */
41
+    protected $objectStore;
42
+    /**
43
+     * @var \OC\User\User $user
44
+     */
45
+    protected $user;
46
+
47
+    public function __construct($params) {
48
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
49
+            $this->objectStore = $params['objectstore'];
50
+        } else {
51
+            throw new \Exception('missing IObjectStore instance');
52
+        }
53
+        if (isset($params['storageid'])) {
54
+            $this->id = 'object::store:' . $params['storageid'];
55
+        } else {
56
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
57
+        }
58
+        //initialize cache with root directory in cache
59
+        if (!$this->is_dir('/')) {
60
+            $this->mkdir('/');
61
+        }
62
+    }
63
+
64
+    public function mkdir($path) {
65
+        $path = $this->normalizePath($path);
66
+
67
+        if ($this->file_exists($path)) {
68
+            return false;
69
+        }
70
+
71
+        $mTime = time();
72
+        $data = [
73
+            'mimetype' => 'httpd/unix-directory',
74
+            'size' => 0,
75
+            'mtime' => $mTime,
76
+            'storage_mtime' => $mTime,
77
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
78
+        ];
79
+        if ($path === '') {
80
+            //create root on the fly
81
+            $data['etag'] = $this->getETag('');
82
+            $this->getCache()->put('', $data);
83
+            return true;
84
+        } else {
85
+            // if parent does not exist, create it
86
+            $parent = $this->normalizePath(dirname($path));
87
+            $parentType = $this->filetype($parent);
88
+            if ($parentType === false) {
89
+                if (!$this->mkdir($parent)) {
90
+                    // something went wrong
91
+                    return false;
92
+                }
93
+            } else if ($parentType === 'file') {
94
+                // parent is a file
95
+                return false;
96
+            }
97
+            // finally create the new dir
98
+            $mTime = time(); // update mtime
99
+            $data['mtime'] = $mTime;
100
+            $data['storage_mtime'] = $mTime;
101
+            $data['etag'] = $this->getETag($path);
102
+            $this->getCache()->put($path, $data);
103
+            return true;
104
+        }
105
+    }
106
+
107
+    /**
108
+     * @param string $path
109
+     * @return string
110
+     */
111
+    private function normalizePath($path) {
112
+        $path = trim($path, '/');
113
+        //FIXME why do we sometimes get a path like 'files//username'?
114
+        $path = str_replace('//', '/', $path);
115
+
116
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
117
+        if (!$path || $path === '.') {
118
+            $path = '';
119
+        }
120
+
121
+        return $path;
122
+    }
123
+
124
+    /**
125
+     * Object Stores use a NoopScanner because metadata is directly stored in
126
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
127
+     *
128
+     * @param string $path
129
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
130
+     * @return \OC\Files\ObjectStore\NoopScanner
131
+     */
132
+    public function getScanner($path = '', $storage = null) {
133
+        if (!$storage) {
134
+            $storage = $this;
135
+        }
136
+        if (!isset($this->scanner)) {
137
+            $this->scanner = new NoopScanner($storage);
138
+        }
139
+        return $this->scanner;
140
+    }
141
+
142
+    public function getId() {
143
+        return $this->id;
144
+    }
145
+
146
+    public function rmdir($path) {
147
+        $path = $this->normalizePath($path);
148
+
149
+        if (!$this->is_dir($path)) {
150
+            return false;
151
+        }
152
+
153
+        $this->rmObjects($path);
154
+
155
+        $this->getCache()->remove($path);
156
+
157
+        return true;
158
+    }
159
+
160
+    private function rmObjects($path) {
161
+        $children = $this->getCache()->getFolderContents($path);
162
+        foreach ($children as $child) {
163
+            if ($child['mimetype'] === 'httpd/unix-directory') {
164
+                $this->rmObjects($child['path']);
165
+            } else {
166
+                $this->unlink($child['path']);
167
+            }
168
+        }
169
+    }
170
+
171
+    public function unlink($path) {
172
+        $path = $this->normalizePath($path);
173
+        $stat = $this->stat($path);
174
+
175
+        if ($stat && isset($stat['fileid'])) {
176
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
177
+                return $this->rmdir($path);
178
+            }
179
+            try {
180
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
181
+            } catch (\Exception $ex) {
182
+                if ($ex->getCode() !== 404) {
183
+                    \OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
184
+                    return false;
185
+                } else {
186
+                    //removing from cache is ok as it does not exist in the objectstore anyway
187
+                }
188
+            }
189
+            $this->getCache()->remove($path);
190
+            return true;
191
+        }
192
+        return false;
193
+    }
194
+
195
+    public function stat($path) {
196
+        $path = $this->normalizePath($path);
197
+        $cacheEntry = $this->getCache()->get($path);
198
+        if ($cacheEntry instanceof CacheEntry) {
199
+            return $cacheEntry->getData();
200
+        } else {
201
+            return false;
202
+        }
203
+    }
204
+
205
+    /**
206
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
207
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
208
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
209
+     *
210
+     * @param int $fileId the fileid
211
+     * @return null|string the unified resource name used to identify the object
212
+     */
213
+    protected function getURN($fileId) {
214
+        if (is_numeric($fileId)) {
215
+            return 'urn:oid:' . $fileId;
216
+        }
217
+        return null;
218
+    }
219
+
220
+    public function opendir($path) {
221
+        $path = $this->normalizePath($path);
222
+
223
+        try {
224
+            $files = array();
225
+            $folderContents = $this->getCache()->getFolderContents($path);
226
+            foreach ($folderContents as $file) {
227
+                $files[] = $file['name'];
228
+            }
229
+
230
+            return IteratorDirectory::wrap($files);
231
+        } catch (\Exception $e) {
232
+            \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
233
+            return false;
234
+        }
235
+    }
236
+
237
+    public function filetype($path) {
238
+        $path = $this->normalizePath($path);
239
+        $stat = $this->stat($path);
240
+        if ($stat) {
241
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
242
+                return 'dir';
243
+            }
244
+            return 'file';
245
+        } else {
246
+            return false;
247
+        }
248
+    }
249
+
250
+    public function fopen($path, $mode) {
251
+        $path = $this->normalizePath($path);
252
+
253
+        switch ($mode) {
254
+            case 'r':
255
+            case 'rb':
256
+                $stat = $this->stat($path);
257
+                if (is_array($stat)) {
258
+                    try {
259
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
260
+                    } catch (\Exception $ex) {
261
+                        \OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
262
+                        return false;
263
+                    }
264
+                } else {
265
+                    return false;
266
+                }
267
+            case 'w':
268
+            case 'wb':
269
+            case 'a':
270
+            case 'ab':
271
+            case 'r+':
272
+            case 'w+':
273
+            case 'wb+':
274
+            case 'a+':
275
+            case 'x':
276
+            case 'x+':
277
+            case 'c':
278
+            case 'c+':
279
+                if (strrpos($path, '.') !== false) {
280
+                    $ext = substr($path, strrpos($path, '.'));
281
+                } else {
282
+                    $ext = '';
283
+                }
284
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
285
+                \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
286
+                if ($this->file_exists($path)) {
287
+                    $source = $this->fopen($path, 'r');
288
+                    file_put_contents($tmpFile, $source);
289
+                }
290
+                self::$tmpFiles[$tmpFile] = $path;
291
+
292
+                return fopen('close://' . $tmpFile, $mode);
293
+        }
294
+        return false;
295
+    }
296
+
297
+    public function file_exists($path) {
298
+        $path = $this->normalizePath($path);
299
+        return (bool)$this->stat($path);
300
+    }
301
+
302
+    public function rename($source, $target) {
303
+        $source = $this->normalizePath($source);
304
+        $target = $this->normalizePath($target);
305
+        $this->remove($target);
306
+        $this->getCache()->move($source, $target);
307
+        $this->touch(dirname($target));
308
+        return true;
309
+    }
310
+
311
+    public function getMimeType($path) {
312
+        $path = $this->normalizePath($path);
313
+        $stat = $this->stat($path);
314
+        if (is_array($stat)) {
315
+            return $stat['mimetype'];
316
+        } else {
317
+            return false;
318
+        }
319
+    }
320
+
321
+    public function touch($path, $mtime = null) {
322
+        if (is_null($mtime)) {
323
+            $mtime = time();
324
+        }
325
+
326
+        $path = $this->normalizePath($path);
327
+        $dirName = dirname($path);
328
+        $parentExists = $this->is_dir($dirName);
329
+        if (!$parentExists) {
330
+            return false;
331
+        }
332
+
333
+        $stat = $this->stat($path);
334
+        if (is_array($stat)) {
335
+            // update existing mtime in db
336
+            $stat['mtime'] = $mtime;
337
+            $this->getCache()->update($stat['fileid'], $stat);
338
+        } else {
339
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
340
+            // create new file
341
+            $stat = array(
342
+                'etag' => $this->getETag($path),
343
+                'mimetype' => $mimeType,
344
+                'size' => 0,
345
+                'mtime' => $mtime,
346
+                'storage_mtime' => $mtime,
347
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
348
+            );
349
+            $fileId = $this->getCache()->put($path, $stat);
350
+            try {
351
+                //read an empty file from memory
352
+                $this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
353
+            } catch (\Exception $ex) {
354
+                $this->getCache()->remove($path);
355
+                \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
356
+                return false;
357
+            }
358
+        }
359
+        return true;
360
+    }
361
+
362
+    public function writeBack($tmpFile) {
363
+        if (!isset(self::$tmpFiles[$tmpFile])) {
364
+            return;
365
+        }
366
+
367
+        $path = self::$tmpFiles[$tmpFile];
368
+        $stat = $this->stat($path);
369
+        if (empty($stat)) {
370
+            // create new file
371
+            $stat = array(
372
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
373
+            );
374
+        }
375
+        // update stat with new data
376
+        $mTime = time();
377
+        $stat['size'] = filesize($tmpFile);
378
+        $stat['mtime'] = $mTime;
379
+        $stat['storage_mtime'] = $mTime;
380
+        $stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
381
+        $stat['etag'] = $this->getETag($path);
382
+
383
+        $fileId = $this->getCache()->put($path, $stat);
384
+        try {
385
+            //upload to object storage
386
+            $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
387
+        } catch (\Exception $ex) {
388
+            $this->getCache()->remove($path);
389
+            \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
390
+            throw $ex; // make this bubble up
391
+        }
392
+    }
393
+
394
+    /**
395
+     * external changes are not supported, exclusive access to the object storage is assumed
396
+     *
397
+     * @param string $path
398
+     * @param int $time
399
+     * @return false
400
+     */
401
+    public function hasUpdated($path, $time) {
402
+        return false;
403
+    }
404 404
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -55,9 +55,9 @@  discard block
 block discarded – undo
55 55
 			throw new \Exception('missing IObjectStore instance');
56 56
 		}
57 57
 		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
58
+			$this->id = 'object::store:'.$params['storageid'];
59 59
 		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
60
+			$this->id = 'object::store:'.$this->objectStore->getStorageId();
61 61
 		}
62 62
 		//initialize cache with root directory in cache
63 63
 		if (!$this->is_dir('/')) {
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
 				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
185 185
 			} catch (\Exception $ex) {
186 186
 				if ($ex->getCode() !== 404) {
187
-					\OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
187
+					\OCP\Util::writeLog('objectstore', 'Could not delete object: '.$ex->getMessage(), \OCP\Util::ERROR);
188 188
 					return false;
189 189
 				} else {
190 190
 					//removing from cache is ok as it does not exist in the objectstore anyway
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 	 */
217 217
 	protected function getURN($fileId) {
218 218
 		if (is_numeric($fileId)) {
219
-			return 'urn:oid:' . $fileId;
219
+			return 'urn:oid:'.$fileId;
220 220
 		}
221 221
 		return null;
222 222
 	}
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 					try {
263 263
 						return $this->objectStore->readObject($this->getURN($stat['fileid']));
264 264
 					} catch (\Exception $ex) {
265
-						\OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
265
+						\OCP\Util::writeLog('objectstore', 'Could not get object: '.$ex->getMessage(), \OCP\Util::ERROR);
266 266
 						return false;
267 267
 					}
268 268
 				} else {
@@ -293,14 +293,14 @@  discard block
 block discarded – undo
293 293
 				}
294 294
 				self::$tmpFiles[$tmpFile] = $path;
295 295
 
296
-				return fopen('close://' . $tmpFile, $mode);
296
+				return fopen('close://'.$tmpFile, $mode);
297 297
 		}
298 298
 		return false;
299 299
 	}
300 300
 
301 301
 	public function file_exists($path) {
302 302
 		$path = $this->normalizePath($path);
303
-		return (bool)$this->stat($path);
303
+		return (bool) $this->stat($path);
304 304
 	}
305 305
 
306 306
 	public function rename($source, $target) {
@@ -356,7 +356,7 @@  discard block
 block discarded – undo
356 356
 				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
357 357
 			} catch (\Exception $ex) {
358 358
 				$this->getCache()->remove($path);
359
-				\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
359
+				\OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
360 360
 				return false;
361 361
 			}
362 362
 		}
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
 			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
391 391
 		} catch (\Exception $ex) {
392 392
 			$this->getCache()->remove($path);
393
-			\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
393
+			\OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
394 394
 			throw $ex; // make this bubble up
395 395
 		}
396 396
 	}
Please login to merge, or discard this patch.
lib/private/files/storage/flysystem.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -54,6 +54,9 @@
 block discarded – undo
54 54
 		$this->flysystem->addPlugin(new GetWithMetadata());
55 55
 	}
56 56
 
57
+	/**
58
+	 * @param string $path
59
+	 */
57 60
 	protected function buildPath($path) {
58 61
 		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
59 62
 		return ltrim($fullPath, '/');
Please login to merge, or discard this patch.
Indentation   +201 added lines, -201 removed lines patch added patch discarded remove patch
@@ -35,223 +35,223 @@
 block discarded – undo
35 35
  * To use: subclass and call $this->buildFlysystem with the flysystem adapter of choice
36 36
  */
37 37
 abstract class Flysystem extends Common {
38
-	/**
39
-	 * @var Filesystem
40
-	 */
41
-	protected $flysystem;
38
+    /**
39
+     * @var Filesystem
40
+     */
41
+    protected $flysystem;
42 42
 
43
-	/**
44
-	 * @var string
45
-	 */
46
-	protected $root = '';
43
+    /**
44
+     * @var string
45
+     */
46
+    protected $root = '';
47 47
 
48
-	/**
49
-	 * Initialize the storage backend with a flyssytem adapter
50
-	 *
51
-	 * @param \League\Flysystem\AdapterInterface $adapter
52
-	 */
53
-	protected function buildFlySystem(AdapterInterface $adapter) {
54
-		$this->flysystem = new Filesystem($adapter);
55
-		$this->flysystem->addPlugin(new GetWithMetadata());
56
-	}
48
+    /**
49
+     * Initialize the storage backend with a flyssytem adapter
50
+     *
51
+     * @param \League\Flysystem\AdapterInterface $adapter
52
+     */
53
+    protected function buildFlySystem(AdapterInterface $adapter) {
54
+        $this->flysystem = new Filesystem($adapter);
55
+        $this->flysystem->addPlugin(new GetWithMetadata());
56
+    }
57 57
 
58
-	protected function buildPath($path) {
59
-		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
60
-		return ltrim($fullPath, '/');
61
-	}
58
+    protected function buildPath($path) {
59
+        $fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
60
+        return ltrim($fullPath, '/');
61
+    }
62 62
 
63
-	/**
64
-	 * {@inheritdoc}
65
-	 */
66
-	public function file_get_contents($path) {
67
-		return $this->flysystem->read($this->buildPath($path));
68
-	}
63
+    /**
64
+     * {@inheritdoc}
65
+     */
66
+    public function file_get_contents($path) {
67
+        return $this->flysystem->read($this->buildPath($path));
68
+    }
69 69
 
70
-	/**
71
-	 * {@inheritdoc}
72
-	 */
73
-	public function file_put_contents($path, $data) {
74
-		return $this->flysystem->put($this->buildPath($path), $data);
75
-	}
70
+    /**
71
+     * {@inheritdoc}
72
+     */
73
+    public function file_put_contents($path, $data) {
74
+        return $this->flysystem->put($this->buildPath($path), $data);
75
+    }
76 76
 
77
-	/**
78
-	 * {@inheritdoc}
79
-	 */
80
-	public function file_exists($path) {
81
-		return $this->flysystem->has($this->buildPath($path));
82
-	}
77
+    /**
78
+     * {@inheritdoc}
79
+     */
80
+    public function file_exists($path) {
81
+        return $this->flysystem->has($this->buildPath($path));
82
+    }
83 83
 
84
-	/**
85
-	 * {@inheritdoc}
86
-	 */
87
-	public function unlink($path) {
88
-		if ($this->is_dir($path)) {
89
-			return $this->rmdir($path);
90
-		}
91
-		try {
92
-			return $this->flysystem->delete($this->buildPath($path));
93
-		} catch (FileNotFoundException $e) {
94
-			return false;
95
-		}
96
-	}
84
+    /**
85
+     * {@inheritdoc}
86
+     */
87
+    public function unlink($path) {
88
+        if ($this->is_dir($path)) {
89
+            return $this->rmdir($path);
90
+        }
91
+        try {
92
+            return $this->flysystem->delete($this->buildPath($path));
93
+        } catch (FileNotFoundException $e) {
94
+            return false;
95
+        }
96
+    }
97 97
 
98
-	/**
99
-	 * {@inheritdoc}
100
-	 */
101
-	public function rename($source, $target) {
102
-		if ($this->file_exists($target)) {
103
-			$this->unlink($target);
104
-		}
105
-		return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target));
106
-	}
98
+    /**
99
+     * {@inheritdoc}
100
+     */
101
+    public function rename($source, $target) {
102
+        if ($this->file_exists($target)) {
103
+            $this->unlink($target);
104
+        }
105
+        return $this->flysystem->rename($this->buildPath($source), $this->buildPath($target));
106
+    }
107 107
 
108
-	/**
109
-	 * {@inheritdoc}
110
-	 */
111
-	public function copy($source, $target) {
112
-		if ($this->file_exists($target)) {
113
-			$this->unlink($target);
114
-		}
115
-		return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target));
116
-	}
108
+    /**
109
+     * {@inheritdoc}
110
+     */
111
+    public function copy($source, $target) {
112
+        if ($this->file_exists($target)) {
113
+            $this->unlink($target);
114
+        }
115
+        return $this->flysystem->copy($this->buildPath($source), $this->buildPath($target));
116
+    }
117 117
 
118
-	/**
119
-	 * {@inheritdoc}
120
-	 */
121
-	public function filesize($path) {
122
-		if ($this->is_dir($path)) {
123
-			return 0;
124
-		} else {
125
-			return $this->flysystem->getSize($this->buildPath($path));
126
-		}
127
-	}
118
+    /**
119
+     * {@inheritdoc}
120
+     */
121
+    public function filesize($path) {
122
+        if ($this->is_dir($path)) {
123
+            return 0;
124
+        } else {
125
+            return $this->flysystem->getSize($this->buildPath($path));
126
+        }
127
+    }
128 128
 
129
-	/**
130
-	 * {@inheritdoc}
131
-	 */
132
-	public function mkdir($path) {
133
-		if ($this->file_exists($path)) {
134
-			return false;
135
-		}
136
-		return $this->flysystem->createDir($this->buildPath($path));
137
-	}
129
+    /**
130
+     * {@inheritdoc}
131
+     */
132
+    public function mkdir($path) {
133
+        if ($this->file_exists($path)) {
134
+            return false;
135
+        }
136
+        return $this->flysystem->createDir($this->buildPath($path));
137
+    }
138 138
 
139
-	/**
140
-	 * {@inheritdoc}
141
-	 */
142
-	public function filemtime($path) {
143
-		return $this->flysystem->getTimestamp($this->buildPath($path));
144
-	}
139
+    /**
140
+     * {@inheritdoc}
141
+     */
142
+    public function filemtime($path) {
143
+        return $this->flysystem->getTimestamp($this->buildPath($path));
144
+    }
145 145
 
146
-	/**
147
-	 * {@inheritdoc}
148
-	 */
149
-	public function rmdir($path) {
150
-		try {
151
-			return @$this->flysystem->deleteDir($this->buildPath($path));
152
-		} catch (FileNotFoundException $e) {
153
-			return false;
154
-		}
155
-	}
146
+    /**
147
+     * {@inheritdoc}
148
+     */
149
+    public function rmdir($path) {
150
+        try {
151
+            return @$this->flysystem->deleteDir($this->buildPath($path));
152
+        } catch (FileNotFoundException $e) {
153
+            return false;
154
+        }
155
+    }
156 156
 
157
-	/**
158
-	 * {@inheritdoc}
159
-	 */
160
-	public function opendir($path) {
161
-		try {
162
-			$content = $this->flysystem->listContents($this->buildPath($path));
163
-		} catch (FileNotFoundException $e) {
164
-			return false;
165
-		}
166
-		$names = array_map(function ($object) {
167
-			return $object['basename'];
168
-		}, $content);
169
-		return IteratorDirectory::wrap($names);
170
-	}
157
+    /**
158
+     * {@inheritdoc}
159
+     */
160
+    public function opendir($path) {
161
+        try {
162
+            $content = $this->flysystem->listContents($this->buildPath($path));
163
+        } catch (FileNotFoundException $e) {
164
+            return false;
165
+        }
166
+        $names = array_map(function ($object) {
167
+            return $object['basename'];
168
+        }, $content);
169
+        return IteratorDirectory::wrap($names);
170
+    }
171 171
 
172
-	/**
173
-	 * {@inheritdoc}
174
-	 */
175
-	public function fopen($path, $mode) {
176
-		$fullPath = $this->buildPath($path);
177
-		$useExisting = true;
178
-		switch ($mode) {
179
-			case 'r':
180
-			case 'rb':
181
-				try {
182
-					return $this->flysystem->readStream($fullPath);
183
-				} catch (FileNotFoundException $e) {
184
-					return false;
185
-				}
186
-			case 'w':
187
-			case 'w+':
188
-			case 'wb':
189
-			case 'wb+':
190
-				$useExisting = false;
191
-			case 'a':
192
-			case 'ab':
193
-			case 'r+':
194
-			case 'a+':
195
-			case 'x':
196
-			case 'x+':
197
-			case 'c':
198
-			case 'c+':
199
-				//emulate these
200
-				if ($useExisting and $this->file_exists($path)) {
201
-					if (!$this->isUpdatable($path)) {
202
-						return false;
203
-					}
204
-					$tmpFile = $this->getCachedFile($path);
205
-				} else {
206
-					if (!$this->isCreatable(dirname($path))) {
207
-						return false;
208
-					}
209
-					$tmpFile = \OCP\Files::tmpFile();
210
-				}
211
-				$source = fopen($tmpFile, $mode);
212
-				return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
213
-					$this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
214
-					unlink($tmpFile);
215
-				});
216
-		}
217
-		return false;
218
-	}
172
+    /**
173
+     * {@inheritdoc}
174
+     */
175
+    public function fopen($path, $mode) {
176
+        $fullPath = $this->buildPath($path);
177
+        $useExisting = true;
178
+        switch ($mode) {
179
+            case 'r':
180
+            case 'rb':
181
+                try {
182
+                    return $this->flysystem->readStream($fullPath);
183
+                } catch (FileNotFoundException $e) {
184
+                    return false;
185
+                }
186
+            case 'w':
187
+            case 'w+':
188
+            case 'wb':
189
+            case 'wb+':
190
+                $useExisting = false;
191
+            case 'a':
192
+            case 'ab':
193
+            case 'r+':
194
+            case 'a+':
195
+            case 'x':
196
+            case 'x+':
197
+            case 'c':
198
+            case 'c+':
199
+                //emulate these
200
+                if ($useExisting and $this->file_exists($path)) {
201
+                    if (!$this->isUpdatable($path)) {
202
+                        return false;
203
+                    }
204
+                    $tmpFile = $this->getCachedFile($path);
205
+                } else {
206
+                    if (!$this->isCreatable(dirname($path))) {
207
+                        return false;
208
+                    }
209
+                    $tmpFile = \OCP\Files::tmpFile();
210
+                }
211
+                $source = fopen($tmpFile, $mode);
212
+                return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
213
+                    $this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
214
+                    unlink($tmpFile);
215
+                });
216
+        }
217
+        return false;
218
+    }
219 219
 
220
-	/**
221
-	 * {@inheritdoc}
222
-	 */
223
-	public function touch($path, $mtime = null) {
224
-		if ($this->file_exists($path)) {
225
-			return false;
226
-		} else {
227
-			$this->file_put_contents($path, '');
228
-			return true;
229
-		}
230
-	}
220
+    /**
221
+     * {@inheritdoc}
222
+     */
223
+    public function touch($path, $mtime = null) {
224
+        if ($this->file_exists($path)) {
225
+            return false;
226
+        } else {
227
+            $this->file_put_contents($path, '');
228
+            return true;
229
+        }
230
+    }
231 231
 
232
-	/**
233
-	 * {@inheritdoc}
234
-	 */
235
-	public function stat($path) {
236
-		$info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']);
237
-		return [
238
-			'mtime' => $info['timestamp'],
239
-			'size' => $info['size']
240
-		];
241
-	}
232
+    /**
233
+     * {@inheritdoc}
234
+     */
235
+    public function stat($path) {
236
+        $info = $this->flysystem->getWithMetadata($this->buildPath($path), ['timestamp', 'size']);
237
+        return [
238
+            'mtime' => $info['timestamp'],
239
+            'size' => $info['size']
240
+        ];
241
+    }
242 242
 
243
-	/**
244
-	 * {@inheritdoc}
245
-	 */
246
-	public function filetype($path) {
247
-		if ($path === '' or $path === '/' or $path === '.') {
248
-			return 'dir';
249
-		}
250
-		try {
251
-			$info = $this->flysystem->getMetadata($this->buildPath($path));
252
-		} catch (FileNotFoundException $e) {
253
-			return false;
254
-		}
255
-		return $info['type'];
256
-	}
243
+    /**
244
+     * {@inheritdoc}
245
+     */
246
+    public function filetype($path) {
247
+        if ($path === '' or $path === '/' or $path === '.') {
248
+            return 'dir';
249
+        }
250
+        try {
251
+            $info = $this->flysystem->getMetadata($this->buildPath($path));
252
+        } catch (FileNotFoundException $e) {
253
+            return false;
254
+        }
255
+        return $info['type'];
256
+    }
257 257
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -56,7 +56,7 @@  discard block
 block discarded – undo
56 56
 	}
57 57
 
58 58
 	protected function buildPath($path) {
59
-		$fullPath = \OC\Files\Filesystem::normalizePath($this->root . '/' . $path);
59
+		$fullPath = \OC\Files\Filesystem::normalizePath($this->root.'/'.$path);
60 60
 		return ltrim($fullPath, '/');
61 61
 	}
62 62
 
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 		} catch (FileNotFoundException $e) {
164 164
 			return false;
165 165
 		}
166
-		$names = array_map(function ($object) {
166
+		$names = array_map(function($object) {
167 167
 			return $object['basename'];
168 168
 		}, $content);
169 169
 		return IteratorDirectory::wrap($names);
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
 					$tmpFile = \OCP\Files::tmpFile();
210 210
 				}
211 211
 				$source = fopen($tmpFile, $mode);
212
-				return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath) {
212
+				return CallbackWrapper::wrap($source, null, null, function() use ($tmpFile, $fullPath) {
213 213
 					$this->flysystem->putStream($fullPath, fopen($tmpFile, 'r'));
214 214
 					unlink($tmpFile);
215 215
 				});
Please login to merge, or discard this patch.
lib/private/memcache/apc.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@
 block discarded – undo
65 65
 	 * Set a value in the cache if it's not already stored
66 66
 	 *
67 67
 	 * @param string $key
68
-	 * @param mixed $value
68
+	 * @param integer $value
69 69
 	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
70 70
 	 * @return bool
71 71
 	 */
Please login to merge, or discard this patch.
Indentation   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -29,108 +29,108 @@
 block discarded – undo
29 29
 use OCP\IMemcache;
30 30
 
31 31
 class APC extends Cache implements IMemcache {
32
-	use CASTrait {
33
-		cas as casEmulated;
34
-	}
32
+    use CASTrait {
33
+        cas as casEmulated;
34
+    }
35 35
 
36
-	use CADTrait;
36
+    use CADTrait;
37 37
 
38
-	public function get($key) {
39
-		$result = apc_fetch($this->getPrefix() . $key, $success);
40
-		if (!$success) {
41
-			return null;
42
-		}
43
-		return $result;
44
-	}
38
+    public function get($key) {
39
+        $result = apc_fetch($this->getPrefix() . $key, $success);
40
+        if (!$success) {
41
+            return null;
42
+        }
43
+        return $result;
44
+    }
45 45
 
46
-	public function set($key, $value, $ttl = 0) {
47
-		return apc_store($this->getPrefix() . $key, $value, $ttl);
48
-	}
46
+    public function set($key, $value, $ttl = 0) {
47
+        return apc_store($this->getPrefix() . $key, $value, $ttl);
48
+    }
49 49
 
50
-	public function hasKey($key) {
51
-		return apc_exists($this->getPrefix() . $key);
52
-	}
50
+    public function hasKey($key) {
51
+        return apc_exists($this->getPrefix() . $key);
52
+    }
53 53
 
54
-	public function remove($key) {
55
-		return apc_delete($this->getPrefix() . $key);
56
-	}
54
+    public function remove($key) {
55
+        return apc_delete($this->getPrefix() . $key);
56
+    }
57 57
 
58
-	public function clear($prefix = '') {
59
-		$ns = $this->getPrefix() . $prefix;
60
-		$ns = preg_quote($ns, '/');
61
-		$iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
62
-		return apc_delete($iter);
63
-	}
58
+    public function clear($prefix = '') {
59
+        $ns = $this->getPrefix() . $prefix;
60
+        $ns = preg_quote($ns, '/');
61
+        $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
62
+        return apc_delete($iter);
63
+    }
64 64
 
65
-	/**
66
-	 * Set a value in the cache if it's not already stored
67
-	 *
68
-	 * @param string $key
69
-	 * @param mixed $value
70
-	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
71
-	 * @return bool
72
-	 */
73
-	public function add($key, $value, $ttl = 0) {
74
-		return apc_add($this->getPrefix() . $key, $value, $ttl);
75
-	}
65
+    /**
66
+     * Set a value in the cache if it's not already stored
67
+     *
68
+     * @param string $key
69
+     * @param mixed $value
70
+     * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
71
+     * @return bool
72
+     */
73
+    public function add($key, $value, $ttl = 0) {
74
+        return apc_add($this->getPrefix() . $key, $value, $ttl);
75
+    }
76 76
 
77
-	/**
78
-	 * Increase a stored number
79
-	 *
80
-	 * @param string $key
81
-	 * @param int $step
82
-	 * @return int | bool
83
-	 */
84
-	public function inc($key, $step = 1) {
85
-		$this->add($key, 0);
86
-		return apc_inc($this->getPrefix() . $key, $step);
87
-	}
77
+    /**
78
+     * Increase a stored number
79
+     *
80
+     * @param string $key
81
+     * @param int $step
82
+     * @return int | bool
83
+     */
84
+    public function inc($key, $step = 1) {
85
+        $this->add($key, 0);
86
+        return apc_inc($this->getPrefix() . $key, $step);
87
+    }
88 88
 
89
-	/**
90
-	 * Decrease a stored number
91
-	 *
92
-	 * @param string $key
93
-	 * @param int $step
94
-	 * @return int | bool
95
-	 */
96
-	public function dec($key, $step = 1) {
97
-		return apc_dec($this->getPrefix() . $key, $step);
98
-	}
89
+    /**
90
+     * Decrease a stored number
91
+     *
92
+     * @param string $key
93
+     * @param int $step
94
+     * @return int | bool
95
+     */
96
+    public function dec($key, $step = 1) {
97
+        return apc_dec($this->getPrefix() . $key, $step);
98
+    }
99 99
 
100
-	/**
101
-	 * Compare and set
102
-	 *
103
-	 * @param string $key
104
-	 * @param mixed $old
105
-	 * @param mixed $new
106
-	 * @return bool
107
-	 */
108
-	public function cas($key, $old, $new) {
109
-		// apc only does cas for ints
110
-		if (is_int($old) and is_int($new)) {
111
-			return apc_cas($this->getPrefix() . $key, $old, $new);
112
-		} else {
113
-			return $this->casEmulated($key, $old, $new);
114
-		}
115
-	}
100
+    /**
101
+     * Compare and set
102
+     *
103
+     * @param string $key
104
+     * @param mixed $old
105
+     * @param mixed $new
106
+     * @return bool
107
+     */
108
+    public function cas($key, $old, $new) {
109
+        // apc only does cas for ints
110
+        if (is_int($old) and is_int($new)) {
111
+            return apc_cas($this->getPrefix() . $key, $old, $new);
112
+        } else {
113
+            return $this->casEmulated($key, $old, $new);
114
+        }
115
+    }
116 116
 
117
-	static public function isAvailable() {
118
-		if (!extension_loaded('apc')) {
119
-			return false;
120
-		} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
121
-			return false;
122
-		} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
123
-			return false;
124
-		} else {
125
-			return true;
126
-		}
127
-	}
117
+    static public function isAvailable() {
118
+        if (!extension_loaded('apc')) {
119
+            return false;
120
+        } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
121
+            return false;
122
+        } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
123
+            return false;
124
+        } else {
125
+            return true;
126
+        }
127
+    }
128 128
 }
129 129
 
130 130
 if (!function_exists('apc_exists')) {
131
-	function apc_exists($keys) {
132
-		$result = false;
133
-		apc_fetch($keys, $result);
134
-		return $result;
135
-	}
131
+    function apc_exists($keys) {
132
+        $result = false;
133
+        apc_fetch($keys, $result);
134
+        return $result;
135
+    }
136 136
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
 	use CADTrait;
37 37
 
38 38
 	public function get($key) {
39
-		$result = apc_fetch($this->getPrefix() . $key, $success);
39
+		$result = apc_fetch($this->getPrefix().$key, $success);
40 40
 		if (!$success) {
41 41
 			return null;
42 42
 		}
@@ -44,21 +44,21 @@  discard block
 block discarded – undo
44 44
 	}
45 45
 
46 46
 	public function set($key, $value, $ttl = 0) {
47
-		return apc_store($this->getPrefix() . $key, $value, $ttl);
47
+		return apc_store($this->getPrefix().$key, $value, $ttl);
48 48
 	}
49 49
 
50 50
 	public function hasKey($key) {
51
-		return apc_exists($this->getPrefix() . $key);
51
+		return apc_exists($this->getPrefix().$key);
52 52
 	}
53 53
 
54 54
 	public function remove($key) {
55
-		return apc_delete($this->getPrefix() . $key);
55
+		return apc_delete($this->getPrefix().$key);
56 56
 	}
57 57
 
58 58
 	public function clear($prefix = '') {
59
-		$ns = $this->getPrefix() . $prefix;
59
+		$ns = $this->getPrefix().$prefix;
60 60
 		$ns = preg_quote($ns, '/');
61
-		$iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
61
+		$iter = new \APCIterator('user', '/^'.$ns.'/', APC_ITER_KEY);
62 62
 		return apc_delete($iter);
63 63
 	}
64 64
 
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
 	 * @return bool
72 72
 	 */
73 73
 	public function add($key, $value, $ttl = 0) {
74
-		return apc_add($this->getPrefix() . $key, $value, $ttl);
74
+		return apc_add($this->getPrefix().$key, $value, $ttl);
75 75
 	}
76 76
 
77 77
 	/**
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 	 */
84 84
 	public function inc($key, $step = 1) {
85 85
 		$this->add($key, 0);
86
-		return apc_inc($this->getPrefix() . $key, $step);
86
+		return apc_inc($this->getPrefix().$key, $step);
87 87
 	}
88 88
 
89 89
 	/**
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 	 * @return int | bool
95 95
 	 */
96 96
 	public function dec($key, $step = 1) {
97
-		return apc_dec($this->getPrefix() . $key, $step);
97
+		return apc_dec($this->getPrefix().$key, $step);
98 98
 	}
99 99
 
100 100
 	/**
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 	public function cas($key, $old, $new) {
109 109
 		// apc only does cas for ints
110 110
 		if (is_int($old) and is_int($new)) {
111
-			return apc_cas($this->getPrefix() . $key, $old, $new);
111
+			return apc_cas($this->getPrefix().$key, $old, $new);
112 112
 		} else {
113 113
 			return $this->casEmulated($key, $old, $new);
114 114
 		}
Please login to merge, or discard this patch.
lib/private/memcache/apcu.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@
 block discarded – undo
65 65
 	 * Set a value in the cache if it's not already stored
66 66
 	 *
67 67
 	 * @param string $key
68
-	 * @param mixed $value
68
+	 * @param integer $value
69 69
 	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
70 70
 	 * @return bool
71 71
 	 */
Please login to merge, or discard this patch.
Indentation   +97 added lines, -97 removed lines patch added patch discarded remove patch
@@ -30,112 +30,112 @@
 block discarded – undo
30 30
 use OCP\IMemcache;
31 31
 
32 32
 class APCu extends Cache implements IMemcache {
33
-	use CASTrait {
34
-		cas as casEmulated;
35
-	}
33
+    use CASTrait {
34
+        cas as casEmulated;
35
+    }
36 36
 
37
-	use CADTrait;
37
+    use CADTrait;
38 38
 
39
-	public function get($key) {
40
-		$result = apcu_fetch($this->getPrefix() . $key, $success);
41
-		if (!$success) {
42
-			return null;
43
-		}
44
-		return $result;
45
-	}
39
+    public function get($key) {
40
+        $result = apcu_fetch($this->getPrefix() . $key, $success);
41
+        if (!$success) {
42
+            return null;
43
+        }
44
+        return $result;
45
+    }
46 46
 
47
-	public function set($key, $value, $ttl = 0) {
48
-		return apcu_store($this->getPrefix() . $key, $value, $ttl);
49
-	}
47
+    public function set($key, $value, $ttl = 0) {
48
+        return apcu_store($this->getPrefix() . $key, $value, $ttl);
49
+    }
50 50
 
51
-	public function hasKey($key) {
52
-		return apcu_exists($this->getPrefix() . $key);
53
-	}
51
+    public function hasKey($key) {
52
+        return apcu_exists($this->getPrefix() . $key);
53
+    }
54 54
 
55
-	public function remove($key) {
56
-		return apcu_delete($this->getPrefix() . $key);
57
-	}
55
+    public function remove($key) {
56
+        return apcu_delete($this->getPrefix() . $key);
57
+    }
58 58
 
59
-	public function clear($prefix = '') {
60
-		$ns = $this->getPrefix() . $prefix;
61
-		$ns = preg_quote($ns, '/');
62
-		if(class_exists('\APCIterator')) {
63
-			$iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
64
-		} else {
65
-			$iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
66
-		}
67
-		return apcu_delete($iter);
68
-	}
59
+    public function clear($prefix = '') {
60
+        $ns = $this->getPrefix() . $prefix;
61
+        $ns = preg_quote($ns, '/');
62
+        if(class_exists('\APCIterator')) {
63
+            $iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
64
+        } else {
65
+            $iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
66
+        }
67
+        return apcu_delete($iter);
68
+    }
69 69
 
70
-	/**
71
-	 * Set a value in the cache if it's not already stored
72
-	 *
73
-	 * @param string $key
74
-	 * @param mixed $value
75
-	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
76
-	 * @return bool
77
-	 */
78
-	public function add($key, $value, $ttl = 0) {
79
-		return apcu_add($this->getPrefix() . $key, $value, $ttl);
80
-	}
70
+    /**
71
+     * Set a value in the cache if it's not already stored
72
+     *
73
+     * @param string $key
74
+     * @param mixed $value
75
+     * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
76
+     * @return bool
77
+     */
78
+    public function add($key, $value, $ttl = 0) {
79
+        return apcu_add($this->getPrefix() . $key, $value, $ttl);
80
+    }
81 81
 
82
-	/**
83
-	 * Increase a stored number
84
-	 *
85
-	 * @param string $key
86
-	 * @param int $step
87
-	 * @return int | bool
88
-	 */
89
-	public function inc($key, $step = 1) {
90
-		$this->add($key, 0);
91
-		return apcu_inc($this->getPrefix() . $key, $step);
92
-	}
82
+    /**
83
+     * Increase a stored number
84
+     *
85
+     * @param string $key
86
+     * @param int $step
87
+     * @return int | bool
88
+     */
89
+    public function inc($key, $step = 1) {
90
+        $this->add($key, 0);
91
+        return apcu_inc($this->getPrefix() . $key, $step);
92
+    }
93 93
 
94
-	/**
95
-	 * Decrease a stored number
96
-	 *
97
-	 * @param string $key
98
-	 * @param int $step
99
-	 * @return int | bool
100
-	 */
101
-	public function dec($key, $step = 1) {
102
-		return apcu_dec($this->getPrefix() . $key, $step);
103
-	}
94
+    /**
95
+     * Decrease a stored number
96
+     *
97
+     * @param string $key
98
+     * @param int $step
99
+     * @return int | bool
100
+     */
101
+    public function dec($key, $step = 1) {
102
+        return apcu_dec($this->getPrefix() . $key, $step);
103
+    }
104 104
 
105
-	/**
106
-	 * Compare and set
107
-	 *
108
-	 * @param string $key
109
-	 * @param mixed $old
110
-	 * @param mixed $new
111
-	 * @return bool
112
-	 */
113
-	public function cas($key, $old, $new) {
114
-		// apc only does cas for ints
115
-		if (is_int($old) and is_int($new)) {
116
-			return apcu_cas($this->getPrefix() . $key, $old, $new);
117
-		} else {
118
-			return $this->casEmulated($key, $old, $new);
119
-		}
120
-	}
105
+    /**
106
+     * Compare and set
107
+     *
108
+     * @param string $key
109
+     * @param mixed $old
110
+     * @param mixed $new
111
+     * @return bool
112
+     */
113
+    public function cas($key, $old, $new) {
114
+        // apc only does cas for ints
115
+        if (is_int($old) and is_int($new)) {
116
+            return apcu_cas($this->getPrefix() . $key, $old, $new);
117
+        } else {
118
+            return $this->casEmulated($key, $old, $new);
119
+        }
120
+    }
121 121
 
122
-	/**
123
-	 * @return bool
124
-	 */
125
-	static public function isAvailable() {
126
-		if (!extension_loaded('apcu')) {
127
-			return false;
128
-		} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
129
-			return false;
130
-		} elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
131
-			return false;
132
-		} elseif (
133
-				version_compare(phpversion('apc'), '4.0.6') === -1 &&
134
-				version_compare(phpversion('apcu'), '5.1.0') === -1
135
-		) {
136
-			return false;
137
-		} else {
138
-			return true;
139
-		}
140
-	}
122
+    /**
123
+     * @return bool
124
+     */
125
+    static public function isAvailable() {
126
+        if (!extension_loaded('apcu')) {
127
+            return false;
128
+        } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
129
+            return false;
130
+        } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
131
+            return false;
132
+        } elseif (
133
+                version_compare(phpversion('apc'), '4.0.6') === -1 &&
134
+                version_compare(phpversion('apcu'), '5.1.0') === -1
135
+        ) {
136
+            return false;
137
+        } else {
138
+            return true;
139
+        }
140
+    }
141 141
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
 	use CADTrait;
38 38
 
39 39
 	public function get($key) {
40
-		$result = apcu_fetch($this->getPrefix() . $key, $success);
40
+		$result = apcu_fetch($this->getPrefix().$key, $success);
41 41
 		if (!$success) {
42 42
 			return null;
43 43
 		}
@@ -45,24 +45,24 @@  discard block
 block discarded – undo
45 45
 	}
46 46
 
47 47
 	public function set($key, $value, $ttl = 0) {
48
-		return apcu_store($this->getPrefix() . $key, $value, $ttl);
48
+		return apcu_store($this->getPrefix().$key, $value, $ttl);
49 49
 	}
50 50
 
51 51
 	public function hasKey($key) {
52
-		return apcu_exists($this->getPrefix() . $key);
52
+		return apcu_exists($this->getPrefix().$key);
53 53
 	}
54 54
 
55 55
 	public function remove($key) {
56
-		return apcu_delete($this->getPrefix() . $key);
56
+		return apcu_delete($this->getPrefix().$key);
57 57
 	}
58 58
 
59 59
 	public function clear($prefix = '') {
60
-		$ns = $this->getPrefix() . $prefix;
60
+		$ns = $this->getPrefix().$prefix;
61 61
 		$ns = preg_quote($ns, '/');
62
-		if(class_exists('\APCIterator')) {
63
-			$iter = new \APCIterator('user', '/^' . $ns . '/', APC_ITER_KEY);
62
+		if (class_exists('\APCIterator')) {
63
+			$iter = new \APCIterator('user', '/^'.$ns.'/', APC_ITER_KEY);
64 64
 		} else {
65
-			$iter = new \APCUIterator('/^' . $ns . '/', APC_ITER_KEY);
65
+			$iter = new \APCUIterator('/^'.$ns.'/', APC_ITER_KEY);
66 66
 		}
67 67
 		return apcu_delete($iter);
68 68
 	}
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 	 * @return bool
77 77
 	 */
78 78
 	public function add($key, $value, $ttl = 0) {
79
-		return apcu_add($this->getPrefix() . $key, $value, $ttl);
79
+		return apcu_add($this->getPrefix().$key, $value, $ttl);
80 80
 	}
81 81
 
82 82
 	/**
@@ -88,7 +88,7 @@  discard block
 block discarded – undo
88 88
 	 */
89 89
 	public function inc($key, $step = 1) {
90 90
 		$this->add($key, 0);
91
-		return apcu_inc($this->getPrefix() . $key, $step);
91
+		return apcu_inc($this->getPrefix().$key, $step);
92 92
 	}
93 93
 
94 94
 	/**
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
 	 * @return int | bool
100 100
 	 */
101 101
 	public function dec($key, $step = 1) {
102
-		return apcu_dec($this->getPrefix() . $key, $step);
102
+		return apcu_dec($this->getPrefix().$key, $step);
103 103
 	}
104 104
 
105 105
 	/**
@@ -113,7 +113,7 @@  discard block
 block discarded – undo
113 113
 	public function cas($key, $old, $new) {
114 114
 		// apc only does cas for ints
115 115
 		if (is_int($old) and is_int($new)) {
116
-			return apcu_cas($this->getPrefix() . $key, $old, $new);
116
+			return apcu_cas($this->getPrefix().$key, $old, $new);
117 117
 		} else {
118 118
 			return $this->casEmulated($key, $old, $new);
119 119
 		}
Please login to merge, or discard this patch.
lib/private/memcache/arraycache.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@
 block discarded – undo
65 65
 	 * Set a value in the cache if it's not already stored
66 66
 	 *
67 67
 	 * @param string $key
68
-	 * @param mixed $value
68
+	 * @param integer $value
69 69
 	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
70 70
 	 * @return bool
71 71
 	 */
Please login to merge, or discard this patch.
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -27,133 +27,133 @@
 block discarded – undo
27 27
 use OCP\IMemcache;
28 28
 
29 29
 class ArrayCache extends Cache implements IMemcache {
30
-	/** @var array Array with the cached data */
31
-	protected $cachedData = array();
30
+    /** @var array Array with the cached data */
31
+    protected $cachedData = array();
32 32
 
33
-	use CADTrait;
33
+    use CADTrait;
34 34
 
35
-	/**
36
-	 * {@inheritDoc}
37
-	 */
38
-	public function get($key) {
39
-		if ($this->hasKey($key)) {
40
-			return $this->cachedData[$key];
41
-		}
42
-		return null;
43
-	}
35
+    /**
36
+     * {@inheritDoc}
37
+     */
38
+    public function get($key) {
39
+        if ($this->hasKey($key)) {
40
+            return $this->cachedData[$key];
41
+        }
42
+        return null;
43
+    }
44 44
 
45
-	/**
46
-	 * {@inheritDoc}
47
-	 */
48
-	public function set($key, $value, $ttl = 0) {
49
-		$this->cachedData[$key] = $value;
50
-		return true;
51
-	}
45
+    /**
46
+     * {@inheritDoc}
47
+     */
48
+    public function set($key, $value, $ttl = 0) {
49
+        $this->cachedData[$key] = $value;
50
+        return true;
51
+    }
52 52
 
53
-	/**
54
-	 * {@inheritDoc}
55
-	 */
56
-	public function hasKey($key) {
57
-		return isset($this->cachedData[$key]);
58
-	}
53
+    /**
54
+     * {@inheritDoc}
55
+     */
56
+    public function hasKey($key) {
57
+        return isset($this->cachedData[$key]);
58
+    }
59 59
 
60
-	/**
61
-	 * {@inheritDoc}
62
-	 */
63
-	public function remove($key) {
64
-		unset($this->cachedData[$key]);
65
-		return true;
66
-	}
60
+    /**
61
+     * {@inheritDoc}
62
+     */
63
+    public function remove($key) {
64
+        unset($this->cachedData[$key]);
65
+        return true;
66
+    }
67 67
 
68
-	/**
69
-	 * {@inheritDoc}
70
-	 */
71
-	public function clear($prefix = '') {
72
-		if ($prefix === '') {
73
-			$this->cachedData = [];
74
-			return true;
75
-		}
68
+    /**
69
+     * {@inheritDoc}
70
+     */
71
+    public function clear($prefix = '') {
72
+        if ($prefix === '') {
73
+            $this->cachedData = [];
74
+            return true;
75
+        }
76 76
 
77
-		foreach ($this->cachedData as $key => $value) {
78
-			if (strpos($key, $prefix) === 0) {
79
-				$this->remove($key);
80
-			}
81
-		}
82
-		return true;
83
-	}
77
+        foreach ($this->cachedData as $key => $value) {
78
+            if (strpos($key, $prefix) === 0) {
79
+                $this->remove($key);
80
+            }
81
+        }
82
+        return true;
83
+    }
84 84
 
85
-	/**
86
-	 * Set a value in the cache if it's not already stored
87
-	 *
88
-	 * @param string $key
89
-	 * @param mixed $value
90
-	 * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
91
-	 * @return bool
92
-	 */
93
-	public function add($key, $value, $ttl = 0) {
94
-		// since this cache is not shared race conditions aren't an issue
95
-		if ($this->hasKey($key)) {
96
-			return false;
97
-		} else {
98
-			return $this->set($key, $value, $ttl);
99
-		}
100
-	}
85
+    /**
86
+     * Set a value in the cache if it's not already stored
87
+     *
88
+     * @param string $key
89
+     * @param mixed $value
90
+     * @param int $ttl Time To Live in seconds. Defaults to 60*60*24
91
+     * @return bool
92
+     */
93
+    public function add($key, $value, $ttl = 0) {
94
+        // since this cache is not shared race conditions aren't an issue
95
+        if ($this->hasKey($key)) {
96
+            return false;
97
+        } else {
98
+            return $this->set($key, $value, $ttl);
99
+        }
100
+    }
101 101
 
102
-	/**
103
-	 * Increase a stored number
104
-	 *
105
-	 * @param string $key
106
-	 * @param int $step
107
-	 * @return int | bool
108
-	 */
109
-	public function inc($key, $step = 1) {
110
-		$oldValue = $this->get($key);
111
-		if (is_int($oldValue)) {
112
-			$this->set($key, $oldValue + $step);
113
-			return $oldValue + $step;
114
-		} else {
115
-			$success = $this->add($key, $step);
116
-			return ($success) ? $step : false;
117
-		}
118
-	}
102
+    /**
103
+     * Increase a stored number
104
+     *
105
+     * @param string $key
106
+     * @param int $step
107
+     * @return int | bool
108
+     */
109
+    public function inc($key, $step = 1) {
110
+        $oldValue = $this->get($key);
111
+        if (is_int($oldValue)) {
112
+            $this->set($key, $oldValue + $step);
113
+            return $oldValue + $step;
114
+        } else {
115
+            $success = $this->add($key, $step);
116
+            return ($success) ? $step : false;
117
+        }
118
+    }
119 119
 
120
-	/**
121
-	 * Decrease a stored number
122
-	 *
123
-	 * @param string $key
124
-	 * @param int $step
125
-	 * @return int | bool
126
-	 */
127
-	public function dec($key, $step = 1) {
128
-		$oldValue = $this->get($key);
129
-		if (is_int($oldValue)) {
130
-			$this->set($key, $oldValue - $step);
131
-			return $oldValue - $step;
132
-		} else {
133
-			return false;
134
-		}
135
-	}
120
+    /**
121
+     * Decrease a stored number
122
+     *
123
+     * @param string $key
124
+     * @param int $step
125
+     * @return int | bool
126
+     */
127
+    public function dec($key, $step = 1) {
128
+        $oldValue = $this->get($key);
129
+        if (is_int($oldValue)) {
130
+            $this->set($key, $oldValue - $step);
131
+            return $oldValue - $step;
132
+        } else {
133
+            return false;
134
+        }
135
+    }
136 136
 
137
-	/**
138
-	 * Compare and set
139
-	 *
140
-	 * @param string $key
141
-	 * @param mixed $old
142
-	 * @param mixed $new
143
-	 * @return bool
144
-	 */
145
-	public function cas($key, $old, $new) {
146
-		if ($this->get($key) === $old) {
147
-			return $this->set($key, $new);
148
-		} else {
149
-			return false;
150
-		}
151
-	}
137
+    /**
138
+     * Compare and set
139
+     *
140
+     * @param string $key
141
+     * @param mixed $old
142
+     * @param mixed $new
143
+     * @return bool
144
+     */
145
+    public function cas($key, $old, $new) {
146
+        if ($this->get($key) === $old) {
147
+            return $this->set($key, $new);
148
+        } else {
149
+            return false;
150
+        }
151
+    }
152 152
 
153
-	/**
154
-	 * {@inheritDoc}
155
-	 */
156
-	static public function isAvailable() {
157
-		return true;
158
-	}
153
+    /**
154
+     * {@inheritDoc}
155
+     */
156
+    static public function isAvailable() {
157
+        return true;
158
+    }
159 159
 }
Please login to merge, or discard this patch.