Completed
Push — stable10 ( e55881...b0ab3b )
by Joas
36:13 queued 35:48
created
apps/files/lib/Service/TagService.php 2 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -24,7 +24,6 @@
 block discarded – undo
24 24
 
25 25
 namespace OCA\Files\Service;
26 26
 
27
-use OC\Files\FileInfo;
28 27
 use OCP\Files\Node;
29 28
 
30 29
 /**
Please login to merge, or discard this patch.
Indentation   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -33,83 +33,83 @@
 block discarded – undo
33 33
  */
34 34
 class TagService {
35 35
 
36
-	/**
37
-	 * @var \OCP\IUserSession
38
-	 */
39
-	private $userSession;
36
+    /**
37
+     * @var \OCP\IUserSession
38
+     */
39
+    private $userSession;
40 40
 
41
-	/**
42
-	 * @var \OCP\ITags
43
-	 */
44
-	private $tagger;
41
+    /**
42
+     * @var \OCP\ITags
43
+     */
44
+    private $tagger;
45 45
 
46
-	/**
47
-	 * @var \OCP\Files\Folder
48
-	 */
49
-	private $homeFolder;
46
+    /**
47
+     * @var \OCP\Files\Folder
48
+     */
49
+    private $homeFolder;
50 50
 
51
-	public function __construct(
52
-		\OCP\IUserSession $userSession,
53
-		\OCP\ITags $tagger,
54
-		\OCP\Files\Folder $homeFolder
55
-	) {
56
-		$this->userSession = $userSession;
57
-		$this->tagger = $tagger;
58
-		$this->homeFolder = $homeFolder;
59
-	}
51
+    public function __construct(
52
+        \OCP\IUserSession $userSession,
53
+        \OCP\ITags $tagger,
54
+        \OCP\Files\Folder $homeFolder
55
+    ) {
56
+        $this->userSession = $userSession;
57
+        $this->tagger = $tagger;
58
+        $this->homeFolder = $homeFolder;
59
+    }
60 60
 
61
-	/**
62
-	 * Updates the tags of the specified file path.
63
-	 * The passed tags are absolute, which means they will
64
-	 * replace the actual tag selection.
65
-	 *
66
-	 * @param string $path path
67
-	 * @param array  $tags array of tags
68
-	 * @return array list of tags
69
-	 * @throws \OCP\Files\NotFoundException if the file does not exist
70
-	 */
71
-	public function updateFileTags($path, $tags) {
72
-		$fileId = $this->homeFolder->get($path)->getId();
61
+    /**
62
+     * Updates the tags of the specified file path.
63
+     * The passed tags are absolute, which means they will
64
+     * replace the actual tag selection.
65
+     *
66
+     * @param string $path path
67
+     * @param array  $tags array of tags
68
+     * @return array list of tags
69
+     * @throws \OCP\Files\NotFoundException if the file does not exist
70
+     */
71
+    public function updateFileTags($path, $tags) {
72
+        $fileId = $this->homeFolder->get($path)->getId();
73 73
 
74
-		$currentTags = $this->tagger->getTagsForObjects(array($fileId));
74
+        $currentTags = $this->tagger->getTagsForObjects(array($fileId));
75 75
 
76
-		if (!empty($currentTags)) {
77
-			$currentTags = current($currentTags);
78
-		}
76
+        if (!empty($currentTags)) {
77
+            $currentTags = current($currentTags);
78
+        }
79 79
 
80
-		$newTags = array_diff($tags, $currentTags);
81
-		foreach ($newTags as $tag) {
82
-			$this->tagger->tagAs($fileId, $tag);
83
-		}
84
-		$deletedTags = array_diff($currentTags, $tags);
85
-		foreach ($deletedTags as $tag) {
86
-			$this->tagger->unTag($fileId, $tag);
87
-		}
80
+        $newTags = array_diff($tags, $currentTags);
81
+        foreach ($newTags as $tag) {
82
+            $this->tagger->tagAs($fileId, $tag);
83
+        }
84
+        $deletedTags = array_diff($currentTags, $tags);
85
+        foreach ($deletedTags as $tag) {
86
+            $this->tagger->unTag($fileId, $tag);
87
+        }
88 88
 
89
-		// TODO: re-read from tagger to make sure the
90
-		// list is up to date, in case of concurrent changes ?
91
-		return $tags;
92
-	}
89
+        // TODO: re-read from tagger to make sure the
90
+        // list is up to date, in case of concurrent changes ?
91
+        return $tags;
92
+    }
93 93
 
94
-	/**
95
-	 * Get all files for the given tag
96
-	 *
97
-	 * @param string $tagName tag name to filter by
98
-	 * @return Node[] list of matching files
99
-	 * @throws \Exception if the tag does not exist
100
-	 */
101
-	public function getFilesByTag($tagName) {
102
-		try {
103
-			$fileIds = $this->tagger->getIdsForTag($tagName);
104
-		} catch (\Exception $e) {
105
-			return [];
106
-		}
94
+    /**
95
+     * Get all files for the given tag
96
+     *
97
+     * @param string $tagName tag name to filter by
98
+     * @return Node[] list of matching files
99
+     * @throws \Exception if the tag does not exist
100
+     */
101
+    public function getFilesByTag($tagName) {
102
+        try {
103
+            $fileIds = $this->tagger->getIdsForTag($tagName);
104
+        } catch (\Exception $e) {
105
+            return [];
106
+        }
107 107
 
108
-		$allNodes = [];
109
-		foreach ($fileIds as $fileId) {
110
-			$allNodes = array_merge($allNodes, $this->homeFolder->getById((int) $fileId));
111
-		}
112
-		return $allNodes;
113
-	}
108
+        $allNodes = [];
109
+        foreach ($fileIds as $fileId) {
110
+            $allNodes = array_merge($allNodes, $this->homeFolder->getById((int) $fileId));
111
+        }
112
+        return $allNodes;
113
+    }
114 114
 }
115 115
 
Please login to merge, or discard this patch.
apps/files_external/lib/Command/Config.php 3 patches
Unused Use Statements   -3 removed lines patch added patch discarded remove patch
@@ -27,11 +27,8 @@
 block discarded – undo
27 27
 use OCA\Files_External\NotFoundException;
28 28
 use OCA\Files_External\Service\GlobalStoragesService;
29 29
 use Symfony\Component\Console\Command\Command;
30
-use Symfony\Component\Console\Helper\Table;
31
-use Symfony\Component\Console\Helper\TableHelper;
32 30
 use Symfony\Component\Console\Input\InputArgument;
33 31
 use Symfony\Component\Console\Input\InputInterface;
34
-use Symfony\Component\Console\Input\InputOption;
35 32
 use Symfony\Component\Console\Output\OutputInterface;
36 33
 
37 34
 class Config extends Base {
Please login to merge, or discard this patch.
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -32,87 +32,87 @@
 block discarded – undo
32 32
 use Symfony\Component\Console\Output\OutputInterface;
33 33
 
34 34
 class Config extends Base {
35
-	/**
36
-	 * @var GlobalStoragesService
37
-	 */
38
-	protected $globalService;
35
+    /**
36
+     * @var GlobalStoragesService
37
+     */
38
+    protected $globalService;
39 39
 
40
-	function __construct(GlobalStoragesService $globalService) {
41
-		parent::__construct();
42
-		$this->globalService = $globalService;
43
-	}
40
+    function __construct(GlobalStoragesService $globalService) {
41
+        parent::__construct();
42
+        $this->globalService = $globalService;
43
+    }
44 44
 
45
-	protected function configure() {
46
-		$this
47
-			->setName('files_external:config')
48
-			->setDescription('Manage backend configuration for a mount')
49
-			->addArgument(
50
-				'mount_id',
51
-				InputArgument::REQUIRED,
52
-				'The id of the mount to edit'
53
-			)->addArgument(
54
-				'key',
55
-				InputArgument::REQUIRED,
56
-				'key of the config option to set/get'
57
-			)->addArgument(
58
-				'value',
59
-				InputArgument::OPTIONAL,
60
-				'value to set the config option to, when no value is provided the existing value will be printed'
61
-			);
62
-		parent::configure();
63
-	}
45
+    protected function configure() {
46
+        $this
47
+            ->setName('files_external:config')
48
+            ->setDescription('Manage backend configuration for a mount')
49
+            ->addArgument(
50
+                'mount_id',
51
+                InputArgument::REQUIRED,
52
+                'The id of the mount to edit'
53
+            )->addArgument(
54
+                'key',
55
+                InputArgument::REQUIRED,
56
+                'key of the config option to set/get'
57
+            )->addArgument(
58
+                'value',
59
+                InputArgument::OPTIONAL,
60
+                'value to set the config option to, when no value is provided the existing value will be printed'
61
+            );
62
+        parent::configure();
63
+    }
64 64
 
65
-	protected function execute(InputInterface $input, OutputInterface $output) {
66
-		$mountId = $input->getArgument('mount_id');
67
-		$key = $input->getArgument('key');
68
-		try {
69
-			$mount = $this->globalService->getStorage($mountId);
70
-		} catch (NotFoundException $e) {
71
-			$output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
72
-			return 404;
73
-		}
65
+    protected function execute(InputInterface $input, OutputInterface $output) {
66
+        $mountId = $input->getArgument('mount_id');
67
+        $key = $input->getArgument('key');
68
+        try {
69
+            $mount = $this->globalService->getStorage($mountId);
70
+        } catch (NotFoundException $e) {
71
+            $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
72
+            return 404;
73
+        }
74 74
 
75
-		$value = $input->getArgument('value');
76
-		if ($value) {
77
-			$this->setOption($mount, $key, $value, $output);
78
-		} else {
79
-			$this->getOption($mount, $key, $output);
80
-		}
81
-	}
75
+        $value = $input->getArgument('value');
76
+        if ($value) {
77
+            $this->setOption($mount, $key, $value, $output);
78
+        } else {
79
+            $this->getOption($mount, $key, $output);
80
+        }
81
+    }
82 82
 
83
-	/**
84
-	 * @param StorageConfig $mount
85
-	 * @param string $key
86
-	 * @param OutputInterface $output
87
-	 */
88
-	protected function getOption(StorageConfig $mount, $key, OutputInterface $output) {
89
-		if ($key === 'mountpoint' || $key === 'mount_point') {
90
-			$value = $mount->getMountPoint();
91
-		} else {
92
-			$value = $mount->getBackendOption($key);
93
-		}
94
-		if (!is_string($value)) { // show bools and objects correctly
95
-			$value = json_encode($value);
96
-		}
97
-		$output->writeln($value);
98
-	}
83
+    /**
84
+     * @param StorageConfig $mount
85
+     * @param string $key
86
+     * @param OutputInterface $output
87
+     */
88
+    protected function getOption(StorageConfig $mount, $key, OutputInterface $output) {
89
+        if ($key === 'mountpoint' || $key === 'mount_point') {
90
+            $value = $mount->getMountPoint();
91
+        } else {
92
+            $value = $mount->getBackendOption($key);
93
+        }
94
+        if (!is_string($value)) { // show bools and objects correctly
95
+            $value = json_encode($value);
96
+        }
97
+        $output->writeln($value);
98
+    }
99 99
 
100
-	/**
101
-	 * @param StorageConfig $mount
102
-	 * @param string $key
103
-	 * @param string $value
104
-	 * @param OutputInterface $output
105
-	 */
106
-	protected function setOption(StorageConfig $mount, $key, $value, OutputInterface $output) {
107
-		$decoded = json_decode($value, true);
108
-		if (!is_null($decoded)) {
109
-			$value = $decoded;
110
-		}
111
-		if ($key === 'mountpoint' || $key === 'mount_point') {
112
-			$mount->setMountPoint($value);
113
-		} else {
114
-			$mount->setBackendOption($key, $value);
115
-		}
116
-		$this->globalService->updateStorage($mount);
117
-	}
100
+    /**
101
+     * @param StorageConfig $mount
102
+     * @param string $key
103
+     * @param string $value
104
+     * @param OutputInterface $output
105
+     */
106
+    protected function setOption(StorageConfig $mount, $key, $value, OutputInterface $output) {
107
+        $decoded = json_decode($value, true);
108
+        if (!is_null($decoded)) {
109
+            $value = $decoded;
110
+        }
111
+        if ($key === 'mountpoint' || $key === 'mount_point') {
112
+            $mount->setMountPoint($value);
113
+        } else {
114
+            $mount->setBackendOption($key, $value);
115
+        }
116
+        $this->globalService->updateStorage($mount);
117
+    }
118 118
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -68,7 +68,7 @@
 block discarded – undo
68 68
 		try {
69 69
 			$mount = $this->globalService->getStorage($mountId);
70 70
 		} catch (NotFoundException $e) {
71
-			$output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
71
+			$output->writeln('<error>Mount with id "'.$mountId.' not found, check "occ files_external:list" to get available mounts"</error>');
72 72
 			return 404;
73 73
 		}
74 74
 
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/AmazonS3.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -230,6 +230,9 @@
 block discarded – undo
230 230
 		return false;
231 231
 	}
232 232
 
233
+	/**
234
+	 * @param string $path
235
+	 */
233 236
 	private function batchDelete ($path = null) {
234 237
 		$params = array(
235 238
 			'Bucket' => $this->bucket
Please login to merge, or discard this patch.
Indentation   +589 added lines, -589 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
 namespace OCA\Files_External\Lib\Storage;
38 38
 
39 39
 set_include_path(get_include_path() . PATH_SEPARATOR .
40
-	\OC_App::getAppPath('files_external') . '/3rdparty/aws-sdk-php');
40
+    \OC_App::getAppPath('files_external') . '/3rdparty/aws-sdk-php');
41 41
 require 'aws-autoloader.php';
42 42
 
43 43
 use Aws\S3\S3Client;
@@ -46,593 +46,593 @@  discard block
 block discarded – undo
46 46
 
47 47
 class AmazonS3 extends \OC\Files\Storage\Common {
48 48
 
49
-	/**
50
-	 * @var \Aws\S3\S3Client
51
-	 */
52
-	private $connection;
53
-	/**
54
-	 * @var string
55
-	 */
56
-	private $bucket;
57
-	/**
58
-	 * @var array
59
-	 */
60
-	private static $tmpFiles = array();
61
-	/**
62
-	 * @var array
63
-	 */
64
-	private $params;
65
-	/**
66
-	 * @var bool
67
-	 */
68
-	private $test = false;
69
-	/**
70
-	 * @var int
71
-	 */
72
-	private $timeout = 15;
73
-	/**
74
-	 * @var int in seconds
75
-	 */
76
-	private $rescanDelay = 10;
77
-
78
-	/** @var string  */
79
-	private $id;
80
-
81
-	/**
82
-	 * @param string $path
83
-	 * @return string correctly encoded path
84
-	 */
85
-	private function normalizePath($path) {
86
-		$path = trim($path, '/');
87
-
88
-		if (!$path) {
89
-			$path = '.';
90
-		}
91
-
92
-		return $path;
93
-	}
94
-
95
-	/**
96
-	 * when running the tests wait to let the buckets catch up
97
-	 */
98
-	private function testTimeout() {
99
-		if ($this->test) {
100
-			sleep($this->timeout);
101
-		}
102
-	}
103
-
104
-	private function isRoot($path) {
105
-		return $path === '.';
106
-	}
107
-
108
-	private function cleanKey($path) {
109
-		if ($this->isRoot($path)) {
110
-			return '/';
111
-		}
112
-		return $path;
113
-	}
114
-
115
-	public function __construct($params) {
116
-		if (empty($params['key']) || empty($params['secret']) || empty($params['bucket'])) {
117
-			throw new \Exception("Access Key, Secret and Bucket have to be configured.");
118
-		}
119
-
120
-		$this->id = 'amazon::' . $params['bucket'];
121
-		$this->updateLegacyId($params);
122
-
123
-		$this->bucket = $params['bucket'];
124
-		$this->test = isset($params['test']);
125
-		$this->timeout = (!isset($params['timeout'])) ? 15 : $params['timeout'];
126
-		$this->rescanDelay = (!isset($params['rescanDelay'])) ? 10 : $params['rescanDelay'];
127
-		$params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
128
-		$params['hostname'] = empty($params['hostname']) ? 's3.amazonaws.com' : $params['hostname'];
129
-		if (!isset($params['port']) || $params['port'] === '') {
130
-			$params['port'] = ($params['use_ssl'] === false) ? 80 : 443;
131
-		}
132
-		$this->params = $params;
133
-	}
134
-
135
-	/**
136
-	 * Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
137
-	 * TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
138
-	 *
139
-	 * @param array $params
140
-	 */
141
-	public function updateLegacyId (array $params) {
142
-		$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
143
-
144
-		// find by old id or bucket
145
-		$stmt = \OC::$server->getDatabaseConnection()->prepare(
146
-			'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
147
-		);
148
-		$stmt->execute(array($oldId, $this->id));
149
-		while ($row = $stmt->fetch()) {
150
-			$storages[$row['id']] = $row['numeric_id'];
151
-		}
152
-
153
-		if (isset($storages[$this->id]) && isset($storages[$oldId])) {
154
-			// if both ids exist, delete the old storage and corresponding filecache entries
155
-			\OC\Files\Cache\Storage::remove($oldId);
156
-		} else if (isset($storages[$oldId])) {
157
-			// if only the old id exists do an update
158
-			$stmt = \OC::$server->getDatabaseConnection()->prepare(
159
-				'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
160
-			);
161
-			$stmt->execute(array($this->id, $oldId));
162
-		}
163
-		// only the bucket based id may exist, do nothing
164
-	}
165
-
166
-	/**
167
-	 * Remove a file or folder
168
-	 *
169
-	 * @param string $path
170
-	 * @return bool
171
-	 */
172
-	protected function remove($path) {
173
-		// remember fileType to reduce http calls
174
-		$fileType = $this->filetype($path);
175
-		if ($fileType === 'dir') {
176
-			return $this->rmdir($path);
177
-		} else if ($fileType === 'file') {
178
-			return $this->unlink($path);
179
-		} else {
180
-			return false;
181
-		}
182
-	}
183
-
184
-	public function mkdir($path) {
185
-		$path = $this->normalizePath($path);
186
-
187
-		if ($this->is_dir($path)) {
188
-			return false;
189
-		}
190
-
191
-		try {
192
-			$this->getConnection()->putObject(array(
193
-				'Bucket' => $this->bucket,
194
-				'Key' => $path . '/',
195
-				'Body' => '',
196
-				'ContentType' => 'httpd/unix-directory'
197
-			));
198
-			$this->testTimeout();
199
-		} catch (S3Exception $e) {
200
-			\OCP\Util::logException('files_external', $e);
201
-			return false;
202
-		}
203
-
204
-		return true;
205
-	}
206
-
207
-	public function file_exists($path) {
208
-		return $this->filetype($path) !== false;
209
-	}
210
-
211
-
212
-	public function rmdir($path) {
213
-		$path = $this->normalizePath($path);
214
-
215
-		if ($this->isRoot($path)) {
216
-			return $this->clearBucket();
217
-		}
218
-
219
-		if (!$this->file_exists($path)) {
220
-			return false;
221
-		}
222
-
223
-		return $this->batchDelete($path);
224
-	}
225
-
226
-	protected function clearBucket() {
227
-		try {
228
-			$this->getConnection()->clearBucket($this->bucket);
229
-			return true;
230
-			// clearBucket() is not working with Ceph, so if it fails we try the slower approach
231
-		} catch (\Exception $e) {
232
-			return $this->batchDelete();
233
-		}
234
-		return false;
235
-	}
236
-
237
-	private function batchDelete ($path = null) {
238
-		$params = array(
239
-			'Bucket' => $this->bucket
240
-		);
241
-		if ($path !== null) {
242
-			$params['Prefix'] = $path . '/';
243
-		}
244
-		try {
245
-			// Since there are no real directories on S3, we need
246
-			// to delete all objects prefixed with the path.
247
-			do {
248
-				// instead of the iterator, manually loop over the list ...
249
-				$objects = $this->getConnection()->listObjects($params);
250
-				// ... so we can delete the files in batches
251
-				$this->getConnection()->deleteObjects(array(
252
-					'Bucket' => $this->bucket,
253
-					'Objects' => $objects['Contents']
254
-				));
255
-				$this->testTimeout();
256
-				// we reached the end when the list is no longer truncated
257
-			} while ($objects['IsTruncated']);
258
-		} catch (S3Exception $e) {
259
-			\OCP\Util::logException('files_external', $e);
260
-			return false;
261
-		}
262
-		return true;
263
-	}
264
-
265
-	public function opendir($path) {
266
-		$path = $this->normalizePath($path);
267
-
268
-		if ($this->isRoot($path)) {
269
-			$path = '';
270
-		} else {
271
-			$path .= '/';
272
-		}
273
-
274
-		try {
275
-			$files = array();
276
-			$result = $this->getConnection()->getIterator('ListObjects', array(
277
-				'Bucket' => $this->bucket,
278
-				'Delimiter' => '/',
279
-				'Prefix' => $path
280
-			), array('return_prefixes' => true));
281
-
282
-			foreach ($result as $object) {
283
-				if (isset($object['Key']) && $object['Key'] === $path) {
284
-					// it's the directory itself, skip
285
-					continue;
286
-				}
287
-				$file = basename(
288
-					isset($object['Key']) ? $object['Key'] : $object['Prefix']
289
-				);
290
-				$files[] = $file;
291
-			}
292
-
293
-			return IteratorDirectory::wrap($files);
294
-		} catch (S3Exception $e) {
295
-			\OCP\Util::logException('files_external', $e);
296
-			return false;
297
-		}
298
-	}
299
-
300
-	public function stat($path) {
301
-		$path = $this->normalizePath($path);
302
-
303
-		try {
304
-			$stat = array();
305
-			if ($this->is_dir($path)) {
306
-				//folders don't really exist
307
-				$stat['size'] = -1; //unknown
308
-				$stat['mtime'] = time() - $this->rescanDelay * 1000;
309
-			} else {
310
-				$result = $this->getConnection()->headObject(array(
311
-					'Bucket' => $this->bucket,
312
-					'Key' => $path
313
-				));
314
-
315
-				$stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
316
-				if ($result['Metadata']['lastmodified']) {
317
-					$stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
318
-				} else {
319
-					$stat['mtime'] = strtotime($result['LastModified']);
320
-				}
321
-			}
322
-			$stat['atime'] = time();
323
-
324
-			return $stat;
325
-		} catch(S3Exception $e) {
326
-			\OCP\Util::logException('files_external', $e);
327
-			return false;
328
-		}
329
-	}
330
-
331
-	public function filetype($path) {
332
-		$path = $this->normalizePath($path);
333
-
334
-		if ($this->isRoot($path)) {
335
-			return 'dir';
336
-		}
337
-
338
-		try {
339
-			if ($this->getConnection()->doesObjectExist($this->bucket, $path)) {
340
-				return 'file';
341
-			}
342
-			if ($this->getConnection()->doesObjectExist($this->bucket, $path.'/')) {
343
-				return 'dir';
344
-			}
345
-		} catch (S3Exception $e) {
346
-			\OCP\Util::logException('files_external', $e);
347
-			return false;
348
-		}
349
-
350
-		return false;
351
-	}
352
-
353
-	public function unlink($path) {
354
-		$path = $this->normalizePath($path);
355
-
356
-		if ($this->is_dir($path)) {
357
-			return $this->rmdir($path);
358
-		}
359
-
360
-		try {
361
-			$this->getConnection()->deleteObject(array(
362
-				'Bucket' => $this->bucket,
363
-				'Key' => $path
364
-			));
365
-			$this->testTimeout();
366
-		} catch (S3Exception $e) {
367
-			\OCP\Util::logException('files_external', $e);
368
-			return false;
369
-		}
370
-
371
-		return true;
372
-	}
373
-
374
-	public function fopen($path, $mode) {
375
-		$path = $this->normalizePath($path);
376
-
377
-		switch ($mode) {
378
-			case 'r':
379
-			case 'rb':
380
-				$tmpFile = \OCP\Files::tmpFile();
381
-				self::$tmpFiles[$tmpFile] = $path;
382
-
383
-				try {
384
-					$this->getConnection()->getObject(array(
385
-						'Bucket' => $this->bucket,
386
-						'Key' => $path,
387
-						'SaveAs' => $tmpFile
388
-					));
389
-				} catch (S3Exception $e) {
390
-					\OCP\Util::logException('files_external', $e);
391
-					return false;
392
-				}
393
-
394
-				return fopen($tmpFile, 'r');
395
-			case 'w':
396
-			case 'wb':
397
-			case 'a':
398
-			case 'ab':
399
-			case 'r+':
400
-			case 'w+':
401
-			case 'wb+':
402
-			case 'a+':
403
-			case 'x':
404
-			case 'x+':
405
-			case 'c':
406
-			case 'c+':
407
-				if (strrpos($path, '.') !== false) {
408
-					$ext = substr($path, strrpos($path, '.'));
409
-				} else {
410
-					$ext = '';
411
-				}
412
-				$tmpFile = \OCP\Files::tmpFile($ext);
413
-				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
414
-				if ($this->file_exists($path)) {
415
-					$source = $this->fopen($path, 'r');
416
-					file_put_contents($tmpFile, $source);
417
-				}
418
-				self::$tmpFiles[$tmpFile] = $path;
419
-
420
-				return fopen('close://' . $tmpFile, $mode);
421
-		}
422
-		return false;
423
-	}
424
-
425
-	public function touch($path, $mtime = null) {
426
-		$path = $this->normalizePath($path);
427
-
428
-		$metadata = array();
429
-		if (is_null($mtime)) {
430
-			$mtime = time();
431
-		}
432
-		$metadata = [
433
-			'lastmodified' => gmdate(\Aws\Common\Enum\DateFormat::RFC1123, $mtime)
434
-		];
435
-
436
-		$fileType = $this->filetype($path);
437
-		try {
438
-			if ($fileType !== false) {
439
-				if ($fileType === 'dir' && ! $this->isRoot($path)) {
440
-					$path .= '/';
441
-				}
442
-				$this->getConnection()->copyObject([
443
-					'Bucket' => $this->bucket,
444
-					'Key' => $this->cleanKey($path),
445
-					'Metadata' => $metadata,
446
-					'CopySource' => $this->bucket . '/' . $path,
447
-					'MetadataDirective' => 'REPLACE',
448
-				]);
449
-				$this->testTimeout();
450
-			} else {
451
-				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
452
-				$this->getConnection()->putObject([
453
-					'Bucket' => $this->bucket,
454
-					'Key' => $this->cleanKey($path),
455
-					'Metadata' => $metadata,
456
-					'Body' => '',
457
-					'ContentType' => $mimeType,
458
-					'MetadataDirective' => 'REPLACE',
459
-				]);
460
-				$this->testTimeout();
461
-			}
462
-		} catch (S3Exception $e) {
463
-			\OCP\Util::logException('files_external', $e);
464
-			return false;
465
-		}
466
-
467
-		return true;
468
-	}
469
-
470
-	public function copy($path1, $path2) {
471
-		$path1 = $this->normalizePath($path1);
472
-		$path2 = $this->normalizePath($path2);
473
-
474
-		if ($this->is_file($path1)) {
475
-			try {
476
-				$this->getConnection()->copyObject(array(
477
-					'Bucket' => $this->bucket,
478
-					'Key' => $this->cleanKey($path2),
479
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
480
-				));
481
-				$this->testTimeout();
482
-			} catch (S3Exception $e) {
483
-				\OCP\Util::logException('files_external', $e);
484
-				return false;
485
-			}
486
-		} else {
487
-			$this->remove($path2);
488
-
489
-			try {
490
-				$this->getConnection()->copyObject(array(
491
-					'Bucket' => $this->bucket,
492
-					'Key' => $path2 . '/',
493
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
494
-				));
495
-				$this->testTimeout();
496
-			} catch (S3Exception $e) {
497
-				\OCP\Util::logException('files_external', $e);
498
-				return false;
499
-			}
500
-
501
-			$dh = $this->opendir($path1);
502
-			if (is_resource($dh)) {
503
-				while (($file = readdir($dh)) !== false) {
504
-					if (\OC\Files\Filesystem::isIgnoredDir($file)) {
505
-						continue;
506
-					}
507
-
508
-					$source = $path1 . '/' . $file;
509
-					$target = $path2 . '/' . $file;
510
-					$this->copy($source, $target);
511
-				}
512
-			}
513
-		}
514
-
515
-		return true;
516
-	}
517
-
518
-	public function rename($path1, $path2) {
519
-		$path1 = $this->normalizePath($path1);
520
-		$path2 = $this->normalizePath($path2);
521
-
522
-		if ($this->is_file($path1)) {
523
-
524
-			if ($this->copy($path1, $path2) === false) {
525
-				return false;
526
-			}
527
-
528
-			if ($this->unlink($path1) === false) {
529
-				$this->unlink($path2);
530
-				return false;
531
-			}
532
-		} else {
533
-
534
-			if ($this->copy($path1, $path2) === false) {
535
-				return false;
536
-			}
537
-
538
-			if ($this->rmdir($path1) === false) {
539
-				$this->rmdir($path2);
540
-				return false;
541
-			}
542
-		}
543
-
544
-		return true;
545
-	}
546
-
547
-	public function test() {
548
-		$test = $this->getConnection()->getBucketAcl(array(
549
-			'Bucket' => $this->bucket,
550
-		));
551
-		if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
552
-			return true;
553
-		}
554
-		return false;
555
-	}
556
-
557
-	public function getId() {
558
-		return $this->id;
559
-	}
560
-
561
-	/**
562
-	 * Returns the connection
563
-	 *
564
-	 * @return S3Client connected client
565
-	 * @throws \Exception if connection could not be made
566
-	 */
567
-	public function getConnection() {
568
-		if (!is_null($this->connection)) {
569
-			return $this->connection;
570
-		}
571
-
572
-		$scheme = ($this->params['use_ssl'] === false) ? 'http' : 'https';
573
-		$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
574
-
575
-		$this->connection = S3Client::factory(array(
576
-			'key' => $this->params['key'],
577
-			'secret' => $this->params['secret'],
578
-			'base_url' => $base_url,
579
-			'region' => $this->params['region'],
580
-			S3Client::COMMAND_PARAMS => [
581
-				'PathStyle' => $this->params['use_path_style'],
582
-			],
583
-		));
584
-
585
-		if (!$this->connection->isValidBucketName($this->bucket)) {
586
-			throw new \Exception("The configured bucket name is invalid.");
587
-		}
588
-
589
-		if (!$this->connection->doesBucketExist($this->bucket)) {
590
-			try {
591
-				$this->connection->createBucket(array(
592
-					'Bucket' => $this->bucket
593
-				));
594
-				$this->connection->waitUntilBucketExists(array(
595
-					'Bucket' => $this->bucket,
596
-					'waiter.interval' => 1,
597
-					'waiter.max_attempts' => 15
598
-				));
599
-				$this->testTimeout();
600
-			} catch (S3Exception $e) {
601
-				\OCP\Util::logException('files_external', $e);
602
-				throw new \Exception('Creation of bucket failed. '.$e->getMessage());
603
-			}
604
-		}
605
-
606
-		return $this->connection;
607
-	}
608
-
609
-	public function writeBack($tmpFile) {
610
-		if (!isset(self::$tmpFiles[$tmpFile])) {
611
-			return false;
612
-		}
613
-
614
-		try {
615
-			$this->getConnection()->putObject(array(
616
-				'Bucket' => $this->bucket,
617
-				'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]),
618
-				'SourceFile' => $tmpFile,
619
-				'ContentType' => \OC::$server->getMimeTypeDetector()->detect($tmpFile),
620
-				'ContentLength' => filesize($tmpFile)
621
-			));
622
-			$this->testTimeout();
623
-
624
-			unlink($tmpFile);
625
-		} catch (S3Exception $e) {
626
-			\OCP\Util::logException('files_external', $e);
627
-			return false;
628
-		}
629
-	}
630
-
631
-	/**
632
-	 * check if curl is installed
633
-	 */
634
-	public static function checkDependencies() {
635
-		return true;
636
-	}
49
+    /**
50
+     * @var \Aws\S3\S3Client
51
+     */
52
+    private $connection;
53
+    /**
54
+     * @var string
55
+     */
56
+    private $bucket;
57
+    /**
58
+     * @var array
59
+     */
60
+    private static $tmpFiles = array();
61
+    /**
62
+     * @var array
63
+     */
64
+    private $params;
65
+    /**
66
+     * @var bool
67
+     */
68
+    private $test = false;
69
+    /**
70
+     * @var int
71
+     */
72
+    private $timeout = 15;
73
+    /**
74
+     * @var int in seconds
75
+     */
76
+    private $rescanDelay = 10;
77
+
78
+    /** @var string  */
79
+    private $id;
80
+
81
+    /**
82
+     * @param string $path
83
+     * @return string correctly encoded path
84
+     */
85
+    private function normalizePath($path) {
86
+        $path = trim($path, '/');
87
+
88
+        if (!$path) {
89
+            $path = '.';
90
+        }
91
+
92
+        return $path;
93
+    }
94
+
95
+    /**
96
+     * when running the tests wait to let the buckets catch up
97
+     */
98
+    private function testTimeout() {
99
+        if ($this->test) {
100
+            sleep($this->timeout);
101
+        }
102
+    }
103
+
104
+    private function isRoot($path) {
105
+        return $path === '.';
106
+    }
107
+
108
+    private function cleanKey($path) {
109
+        if ($this->isRoot($path)) {
110
+            return '/';
111
+        }
112
+        return $path;
113
+    }
114
+
115
+    public function __construct($params) {
116
+        if (empty($params['key']) || empty($params['secret']) || empty($params['bucket'])) {
117
+            throw new \Exception("Access Key, Secret and Bucket have to be configured.");
118
+        }
119
+
120
+        $this->id = 'amazon::' . $params['bucket'];
121
+        $this->updateLegacyId($params);
122
+
123
+        $this->bucket = $params['bucket'];
124
+        $this->test = isset($params['test']);
125
+        $this->timeout = (!isset($params['timeout'])) ? 15 : $params['timeout'];
126
+        $this->rescanDelay = (!isset($params['rescanDelay'])) ? 10 : $params['rescanDelay'];
127
+        $params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
128
+        $params['hostname'] = empty($params['hostname']) ? 's3.amazonaws.com' : $params['hostname'];
129
+        if (!isset($params['port']) || $params['port'] === '') {
130
+            $params['port'] = ($params['use_ssl'] === false) ? 80 : 443;
131
+        }
132
+        $this->params = $params;
133
+    }
134
+
135
+    /**
136
+     * Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
137
+     * TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
138
+     *
139
+     * @param array $params
140
+     */
141
+    public function updateLegacyId (array $params) {
142
+        $oldId = 'amazon::' . $params['key'] . md5($params['secret']);
143
+
144
+        // find by old id or bucket
145
+        $stmt = \OC::$server->getDatabaseConnection()->prepare(
146
+            'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
147
+        );
148
+        $stmt->execute(array($oldId, $this->id));
149
+        while ($row = $stmt->fetch()) {
150
+            $storages[$row['id']] = $row['numeric_id'];
151
+        }
152
+
153
+        if (isset($storages[$this->id]) && isset($storages[$oldId])) {
154
+            // if both ids exist, delete the old storage and corresponding filecache entries
155
+            \OC\Files\Cache\Storage::remove($oldId);
156
+        } else if (isset($storages[$oldId])) {
157
+            // if only the old id exists do an update
158
+            $stmt = \OC::$server->getDatabaseConnection()->prepare(
159
+                'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
160
+            );
161
+            $stmt->execute(array($this->id, $oldId));
162
+        }
163
+        // only the bucket based id may exist, do nothing
164
+    }
165
+
166
+    /**
167
+     * Remove a file or folder
168
+     *
169
+     * @param string $path
170
+     * @return bool
171
+     */
172
+    protected function remove($path) {
173
+        // remember fileType to reduce http calls
174
+        $fileType = $this->filetype($path);
175
+        if ($fileType === 'dir') {
176
+            return $this->rmdir($path);
177
+        } else if ($fileType === 'file') {
178
+            return $this->unlink($path);
179
+        } else {
180
+            return false;
181
+        }
182
+    }
183
+
184
+    public function mkdir($path) {
185
+        $path = $this->normalizePath($path);
186
+
187
+        if ($this->is_dir($path)) {
188
+            return false;
189
+        }
190
+
191
+        try {
192
+            $this->getConnection()->putObject(array(
193
+                'Bucket' => $this->bucket,
194
+                'Key' => $path . '/',
195
+                'Body' => '',
196
+                'ContentType' => 'httpd/unix-directory'
197
+            ));
198
+            $this->testTimeout();
199
+        } catch (S3Exception $e) {
200
+            \OCP\Util::logException('files_external', $e);
201
+            return false;
202
+        }
203
+
204
+        return true;
205
+    }
206
+
207
+    public function file_exists($path) {
208
+        return $this->filetype($path) !== false;
209
+    }
210
+
211
+
212
+    public function rmdir($path) {
213
+        $path = $this->normalizePath($path);
214
+
215
+        if ($this->isRoot($path)) {
216
+            return $this->clearBucket();
217
+        }
218
+
219
+        if (!$this->file_exists($path)) {
220
+            return false;
221
+        }
222
+
223
+        return $this->batchDelete($path);
224
+    }
225
+
226
+    protected function clearBucket() {
227
+        try {
228
+            $this->getConnection()->clearBucket($this->bucket);
229
+            return true;
230
+            // clearBucket() is not working with Ceph, so if it fails we try the slower approach
231
+        } catch (\Exception $e) {
232
+            return $this->batchDelete();
233
+        }
234
+        return false;
235
+    }
236
+
237
+    private function batchDelete ($path = null) {
238
+        $params = array(
239
+            'Bucket' => $this->bucket
240
+        );
241
+        if ($path !== null) {
242
+            $params['Prefix'] = $path . '/';
243
+        }
244
+        try {
245
+            // Since there are no real directories on S3, we need
246
+            // to delete all objects prefixed with the path.
247
+            do {
248
+                // instead of the iterator, manually loop over the list ...
249
+                $objects = $this->getConnection()->listObjects($params);
250
+                // ... so we can delete the files in batches
251
+                $this->getConnection()->deleteObjects(array(
252
+                    'Bucket' => $this->bucket,
253
+                    'Objects' => $objects['Contents']
254
+                ));
255
+                $this->testTimeout();
256
+                // we reached the end when the list is no longer truncated
257
+            } while ($objects['IsTruncated']);
258
+        } catch (S3Exception $e) {
259
+            \OCP\Util::logException('files_external', $e);
260
+            return false;
261
+        }
262
+        return true;
263
+    }
264
+
265
+    public function opendir($path) {
266
+        $path = $this->normalizePath($path);
267
+
268
+        if ($this->isRoot($path)) {
269
+            $path = '';
270
+        } else {
271
+            $path .= '/';
272
+        }
273
+
274
+        try {
275
+            $files = array();
276
+            $result = $this->getConnection()->getIterator('ListObjects', array(
277
+                'Bucket' => $this->bucket,
278
+                'Delimiter' => '/',
279
+                'Prefix' => $path
280
+            ), array('return_prefixes' => true));
281
+
282
+            foreach ($result as $object) {
283
+                if (isset($object['Key']) && $object['Key'] === $path) {
284
+                    // it's the directory itself, skip
285
+                    continue;
286
+                }
287
+                $file = basename(
288
+                    isset($object['Key']) ? $object['Key'] : $object['Prefix']
289
+                );
290
+                $files[] = $file;
291
+            }
292
+
293
+            return IteratorDirectory::wrap($files);
294
+        } catch (S3Exception $e) {
295
+            \OCP\Util::logException('files_external', $e);
296
+            return false;
297
+        }
298
+    }
299
+
300
+    public function stat($path) {
301
+        $path = $this->normalizePath($path);
302
+
303
+        try {
304
+            $stat = array();
305
+            if ($this->is_dir($path)) {
306
+                //folders don't really exist
307
+                $stat['size'] = -1; //unknown
308
+                $stat['mtime'] = time() - $this->rescanDelay * 1000;
309
+            } else {
310
+                $result = $this->getConnection()->headObject(array(
311
+                    'Bucket' => $this->bucket,
312
+                    'Key' => $path
313
+                ));
314
+
315
+                $stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
316
+                if ($result['Metadata']['lastmodified']) {
317
+                    $stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
318
+                } else {
319
+                    $stat['mtime'] = strtotime($result['LastModified']);
320
+                }
321
+            }
322
+            $stat['atime'] = time();
323
+
324
+            return $stat;
325
+        } catch(S3Exception $e) {
326
+            \OCP\Util::logException('files_external', $e);
327
+            return false;
328
+        }
329
+    }
330
+
331
+    public function filetype($path) {
332
+        $path = $this->normalizePath($path);
333
+
334
+        if ($this->isRoot($path)) {
335
+            return 'dir';
336
+        }
337
+
338
+        try {
339
+            if ($this->getConnection()->doesObjectExist($this->bucket, $path)) {
340
+                return 'file';
341
+            }
342
+            if ($this->getConnection()->doesObjectExist($this->bucket, $path.'/')) {
343
+                return 'dir';
344
+            }
345
+        } catch (S3Exception $e) {
346
+            \OCP\Util::logException('files_external', $e);
347
+            return false;
348
+        }
349
+
350
+        return false;
351
+    }
352
+
353
+    public function unlink($path) {
354
+        $path = $this->normalizePath($path);
355
+
356
+        if ($this->is_dir($path)) {
357
+            return $this->rmdir($path);
358
+        }
359
+
360
+        try {
361
+            $this->getConnection()->deleteObject(array(
362
+                'Bucket' => $this->bucket,
363
+                'Key' => $path
364
+            ));
365
+            $this->testTimeout();
366
+        } catch (S3Exception $e) {
367
+            \OCP\Util::logException('files_external', $e);
368
+            return false;
369
+        }
370
+
371
+        return true;
372
+    }
373
+
374
+    public function fopen($path, $mode) {
375
+        $path = $this->normalizePath($path);
376
+
377
+        switch ($mode) {
378
+            case 'r':
379
+            case 'rb':
380
+                $tmpFile = \OCP\Files::tmpFile();
381
+                self::$tmpFiles[$tmpFile] = $path;
382
+
383
+                try {
384
+                    $this->getConnection()->getObject(array(
385
+                        'Bucket' => $this->bucket,
386
+                        'Key' => $path,
387
+                        'SaveAs' => $tmpFile
388
+                    ));
389
+                } catch (S3Exception $e) {
390
+                    \OCP\Util::logException('files_external', $e);
391
+                    return false;
392
+                }
393
+
394
+                return fopen($tmpFile, 'r');
395
+            case 'w':
396
+            case 'wb':
397
+            case 'a':
398
+            case 'ab':
399
+            case 'r+':
400
+            case 'w+':
401
+            case 'wb+':
402
+            case 'a+':
403
+            case 'x':
404
+            case 'x+':
405
+            case 'c':
406
+            case 'c+':
407
+                if (strrpos($path, '.') !== false) {
408
+                    $ext = substr($path, strrpos($path, '.'));
409
+                } else {
410
+                    $ext = '';
411
+                }
412
+                $tmpFile = \OCP\Files::tmpFile($ext);
413
+                \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
414
+                if ($this->file_exists($path)) {
415
+                    $source = $this->fopen($path, 'r');
416
+                    file_put_contents($tmpFile, $source);
417
+                }
418
+                self::$tmpFiles[$tmpFile] = $path;
419
+
420
+                return fopen('close://' . $tmpFile, $mode);
421
+        }
422
+        return false;
423
+    }
424
+
425
+    public function touch($path, $mtime = null) {
426
+        $path = $this->normalizePath($path);
427
+
428
+        $metadata = array();
429
+        if (is_null($mtime)) {
430
+            $mtime = time();
431
+        }
432
+        $metadata = [
433
+            'lastmodified' => gmdate(\Aws\Common\Enum\DateFormat::RFC1123, $mtime)
434
+        ];
435
+
436
+        $fileType = $this->filetype($path);
437
+        try {
438
+            if ($fileType !== false) {
439
+                if ($fileType === 'dir' && ! $this->isRoot($path)) {
440
+                    $path .= '/';
441
+                }
442
+                $this->getConnection()->copyObject([
443
+                    'Bucket' => $this->bucket,
444
+                    'Key' => $this->cleanKey($path),
445
+                    'Metadata' => $metadata,
446
+                    'CopySource' => $this->bucket . '/' . $path,
447
+                    'MetadataDirective' => 'REPLACE',
448
+                ]);
449
+                $this->testTimeout();
450
+            } else {
451
+                $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
452
+                $this->getConnection()->putObject([
453
+                    'Bucket' => $this->bucket,
454
+                    'Key' => $this->cleanKey($path),
455
+                    'Metadata' => $metadata,
456
+                    'Body' => '',
457
+                    'ContentType' => $mimeType,
458
+                    'MetadataDirective' => 'REPLACE',
459
+                ]);
460
+                $this->testTimeout();
461
+            }
462
+        } catch (S3Exception $e) {
463
+            \OCP\Util::logException('files_external', $e);
464
+            return false;
465
+        }
466
+
467
+        return true;
468
+    }
469
+
470
+    public function copy($path1, $path2) {
471
+        $path1 = $this->normalizePath($path1);
472
+        $path2 = $this->normalizePath($path2);
473
+
474
+        if ($this->is_file($path1)) {
475
+            try {
476
+                $this->getConnection()->copyObject(array(
477
+                    'Bucket' => $this->bucket,
478
+                    'Key' => $this->cleanKey($path2),
479
+                    'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
480
+                ));
481
+                $this->testTimeout();
482
+            } catch (S3Exception $e) {
483
+                \OCP\Util::logException('files_external', $e);
484
+                return false;
485
+            }
486
+        } else {
487
+            $this->remove($path2);
488
+
489
+            try {
490
+                $this->getConnection()->copyObject(array(
491
+                    'Bucket' => $this->bucket,
492
+                    'Key' => $path2 . '/',
493
+                    'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
494
+                ));
495
+                $this->testTimeout();
496
+            } catch (S3Exception $e) {
497
+                \OCP\Util::logException('files_external', $e);
498
+                return false;
499
+            }
500
+
501
+            $dh = $this->opendir($path1);
502
+            if (is_resource($dh)) {
503
+                while (($file = readdir($dh)) !== false) {
504
+                    if (\OC\Files\Filesystem::isIgnoredDir($file)) {
505
+                        continue;
506
+                    }
507
+
508
+                    $source = $path1 . '/' . $file;
509
+                    $target = $path2 . '/' . $file;
510
+                    $this->copy($source, $target);
511
+                }
512
+            }
513
+        }
514
+
515
+        return true;
516
+    }
517
+
518
+    public function rename($path1, $path2) {
519
+        $path1 = $this->normalizePath($path1);
520
+        $path2 = $this->normalizePath($path2);
521
+
522
+        if ($this->is_file($path1)) {
523
+
524
+            if ($this->copy($path1, $path2) === false) {
525
+                return false;
526
+            }
527
+
528
+            if ($this->unlink($path1) === false) {
529
+                $this->unlink($path2);
530
+                return false;
531
+            }
532
+        } else {
533
+
534
+            if ($this->copy($path1, $path2) === false) {
535
+                return false;
536
+            }
537
+
538
+            if ($this->rmdir($path1) === false) {
539
+                $this->rmdir($path2);
540
+                return false;
541
+            }
542
+        }
543
+
544
+        return true;
545
+    }
546
+
547
+    public function test() {
548
+        $test = $this->getConnection()->getBucketAcl(array(
549
+            'Bucket' => $this->bucket,
550
+        ));
551
+        if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
552
+            return true;
553
+        }
554
+        return false;
555
+    }
556
+
557
+    public function getId() {
558
+        return $this->id;
559
+    }
560
+
561
+    /**
562
+     * Returns the connection
563
+     *
564
+     * @return S3Client connected client
565
+     * @throws \Exception if connection could not be made
566
+     */
567
+    public function getConnection() {
568
+        if (!is_null($this->connection)) {
569
+            return $this->connection;
570
+        }
571
+
572
+        $scheme = ($this->params['use_ssl'] === false) ? 'http' : 'https';
573
+        $base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
574
+
575
+        $this->connection = S3Client::factory(array(
576
+            'key' => $this->params['key'],
577
+            'secret' => $this->params['secret'],
578
+            'base_url' => $base_url,
579
+            'region' => $this->params['region'],
580
+            S3Client::COMMAND_PARAMS => [
581
+                'PathStyle' => $this->params['use_path_style'],
582
+            ],
583
+        ));
584
+
585
+        if (!$this->connection->isValidBucketName($this->bucket)) {
586
+            throw new \Exception("The configured bucket name is invalid.");
587
+        }
588
+
589
+        if (!$this->connection->doesBucketExist($this->bucket)) {
590
+            try {
591
+                $this->connection->createBucket(array(
592
+                    'Bucket' => $this->bucket
593
+                ));
594
+                $this->connection->waitUntilBucketExists(array(
595
+                    'Bucket' => $this->bucket,
596
+                    'waiter.interval' => 1,
597
+                    'waiter.max_attempts' => 15
598
+                ));
599
+                $this->testTimeout();
600
+            } catch (S3Exception $e) {
601
+                \OCP\Util::logException('files_external', $e);
602
+                throw new \Exception('Creation of bucket failed. '.$e->getMessage());
603
+            }
604
+        }
605
+
606
+        return $this->connection;
607
+    }
608
+
609
+    public function writeBack($tmpFile) {
610
+        if (!isset(self::$tmpFiles[$tmpFile])) {
611
+            return false;
612
+        }
613
+
614
+        try {
615
+            $this->getConnection()->putObject(array(
616
+                'Bucket' => $this->bucket,
617
+                'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]),
618
+                'SourceFile' => $tmpFile,
619
+                'ContentType' => \OC::$server->getMimeTypeDetector()->detect($tmpFile),
620
+                'ContentLength' => filesize($tmpFile)
621
+            ));
622
+            $this->testTimeout();
623
+
624
+            unlink($tmpFile);
625
+        } catch (S3Exception $e) {
626
+            \OCP\Util::logException('files_external', $e);
627
+            return false;
628
+        }
629
+    }
630
+
631
+    /**
632
+     * check if curl is installed
633
+     */
634
+    public static function checkDependencies() {
635
+        return true;
636
+    }
637 637
 
638 638
 }
Please login to merge, or discard this patch.
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -36,8 +36,8 @@  discard block
 block discarded – undo
36 36
 
37 37
 namespace OCA\Files_External\Lib\Storage;
38 38
 
39
-set_include_path(get_include_path() . PATH_SEPARATOR .
40
-	\OC_App::getAppPath('files_external') . '/3rdparty/aws-sdk-php');
39
+set_include_path(get_include_path().PATH_SEPARATOR.
40
+	\OC_App::getAppPath('files_external').'/3rdparty/aws-sdk-php');
41 41
 require 'aws-autoloader.php';
42 42
 
43 43
 use Aws\S3\S3Client;
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
 			throw new \Exception("Access Key, Secret and Bucket have to be configured.");
118 118
 		}
119 119
 
120
-		$this->id = 'amazon::' . $params['bucket'];
120
+		$this->id = 'amazon::'.$params['bucket'];
121 121
 		$this->updateLegacyId($params);
122 122
 
123 123
 		$this->bucket = $params['bucket'];
@@ -138,8 +138,8 @@  discard block
 block discarded – undo
138 138
 	 *
139 139
 	 * @param array $params
140 140
 	 */
141
-	public function updateLegacyId (array $params) {
142
-		$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
141
+	public function updateLegacyId(array $params) {
142
+		$oldId = 'amazon::'.$params['key'].md5($params['secret']);
143 143
 
144 144
 		// find by old id or bucket
145 145
 		$stmt = \OC::$server->getDatabaseConnection()->prepare(
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
 		try {
192 192
 			$this->getConnection()->putObject(array(
193 193
 				'Bucket' => $this->bucket,
194
-				'Key' => $path . '/',
194
+				'Key' => $path.'/',
195 195
 				'Body' => '',
196 196
 				'ContentType' => 'httpd/unix-directory'
197 197
 			));
@@ -234,12 +234,12 @@  discard block
 block discarded – undo
234 234
 		return false;
235 235
 	}
236 236
 
237
-	private function batchDelete ($path = null) {
237
+	private function batchDelete($path = null) {
238 238
 		$params = array(
239 239
 			'Bucket' => $this->bucket
240 240
 		);
241 241
 		if ($path !== null) {
242
-			$params['Prefix'] = $path . '/';
242
+			$params['Prefix'] = $path.'/';
243 243
 		}
244 244
 		try {
245 245
 			// Since there are no real directories on S3, we need
@@ -322,7 +322,7 @@  discard block
 block discarded – undo
322 322
 			$stat['atime'] = time();
323 323
 
324 324
 			return $stat;
325
-		} catch(S3Exception $e) {
325
+		} catch (S3Exception $e) {
326 326
 			\OCP\Util::logException('files_external', $e);
327 327
 			return false;
328 328
 		}
@@ -417,7 +417,7 @@  discard block
 block discarded – undo
417 417
 				}
418 418
 				self::$tmpFiles[$tmpFile] = $path;
419 419
 
420
-				return fopen('close://' . $tmpFile, $mode);
420
+				return fopen('close://'.$tmpFile, $mode);
421 421
 		}
422 422
 		return false;
423 423
 	}
@@ -436,14 +436,14 @@  discard block
 block discarded – undo
436 436
 		$fileType = $this->filetype($path);
437 437
 		try {
438 438
 			if ($fileType !== false) {
439
-				if ($fileType === 'dir' && ! $this->isRoot($path)) {
439
+				if ($fileType === 'dir' && !$this->isRoot($path)) {
440 440
 					$path .= '/';
441 441
 				}
442 442
 				$this->getConnection()->copyObject([
443 443
 					'Bucket' => $this->bucket,
444 444
 					'Key' => $this->cleanKey($path),
445 445
 					'Metadata' => $metadata,
446
-					'CopySource' => $this->bucket . '/' . $path,
446
+					'CopySource' => $this->bucket.'/'.$path,
447 447
 					'MetadataDirective' => 'REPLACE',
448 448
 				]);
449 449
 				$this->testTimeout();
@@ -476,7 +476,7 @@  discard block
 block discarded – undo
476 476
 				$this->getConnection()->copyObject(array(
477 477
 					'Bucket' => $this->bucket,
478 478
 					'Key' => $this->cleanKey($path2),
479
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
479
+					'CopySource' => S3Client::encodeKey($this->bucket.'/'.$path1)
480 480
 				));
481 481
 				$this->testTimeout();
482 482
 			} catch (S3Exception $e) {
@@ -489,8 +489,8 @@  discard block
 block discarded – undo
489 489
 			try {
490 490
 				$this->getConnection()->copyObject(array(
491 491
 					'Bucket' => $this->bucket,
492
-					'Key' => $path2 . '/',
493
-					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
492
+					'Key' => $path2.'/',
493
+					'CopySource' => S3Client::encodeKey($this->bucket.'/'.$path1.'/')
494 494
 				));
495 495
 				$this->testTimeout();
496 496
 			} catch (S3Exception $e) {
@@ -505,8 +505,8 @@  discard block
 block discarded – undo
505 505
 						continue;
506 506
 					}
507 507
 
508
-					$source = $path1 . '/' . $file;
509
-					$target = $path2 . '/' . $file;
508
+					$source = $path1.'/'.$file;
509
+					$target = $path2.'/'.$file;
510 510
 					$this->copy($source, $target);
511 511
 				}
512 512
 			}
@@ -570,7 +570,7 @@  discard block
 block discarded – undo
570 570
 		}
571 571
 
572 572
 		$scheme = ($this->params['use_ssl'] === false) ? 'http' : 'https';
573
-		$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
573
+		$base_url = $scheme.'://'.$this->params['hostname'].':'.$this->params['port'].'/';
574 574
 
575 575
 		$this->connection = S3Client::factory(array(
576 576
 			'key' => $this->params['key'],
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/Dropbox.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -75,6 +75,9 @@
 block discarded – undo
75 75
 		return false;
76 76
 	}
77 77
 
78
+	/**
79
+	 * @param string $path
80
+	 */
78 81
 	private function setMetaData($path, $metaData) {
79 82
 		$this->metaData[ltrim($path, '/')] = $metaData;
80 83
 	}
Please login to merge, or discard this patch.
Indentation   +292 added lines, -292 removed lines patch added patch discarded remove patch
@@ -39,320 +39,320 @@
 block discarded – undo
39 39
 
40 40
 class Dropbox extends \OC\Files\Storage\Common {
41 41
 
42
-	private $dropbox;
43
-	private $root;
44
-	private $id;
45
-	private $metaData = array();
46
-	private $oauth;
42
+    private $dropbox;
43
+    private $root;
44
+    private $id;
45
+    private $metaData = array();
46
+    private $oauth;
47 47
 
48
-	private static $tempFiles = array();
48
+    private static $tempFiles = array();
49 49
 
50
-	public function __construct($params) {
51
-		if (isset($params['configured']) && $params['configured'] == 'true'
52
-			&& isset($params['app_key'])
53
-			&& isset($params['app_secret'])
54
-			&& isset($params['token'])
55
-			&& isset($params['token_secret'])
56
-		) {
57
-			$this->root = isset($params['root']) ? $params['root'] : '';
58
-			$this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
59
-			$this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
60
-			$this->oauth->setToken($params['token'], $params['token_secret']);
61
-			// note: Dropbox_API connection is lazy
62
-			$this->dropbox = new \Dropbox_API($this->oauth, 'auto');
63
-		} else {
64
-			throw new \Exception('Creating Dropbox storage failed');
65
-		}
66
-	}
50
+    public function __construct($params) {
51
+        if (isset($params['configured']) && $params['configured'] == 'true'
52
+            && isset($params['app_key'])
53
+            && isset($params['app_secret'])
54
+            && isset($params['token'])
55
+            && isset($params['token_secret'])
56
+        ) {
57
+            $this->root = isset($params['root']) ? $params['root'] : '';
58
+            $this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
59
+            $this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
60
+            $this->oauth->setToken($params['token'], $params['token_secret']);
61
+            // note: Dropbox_API connection is lazy
62
+            $this->dropbox = new \Dropbox_API($this->oauth, 'auto');
63
+        } else {
64
+            throw new \Exception('Creating Dropbox storage failed');
65
+        }
66
+    }
67 67
 
68
-	/**
69
-	 * @param string $path
70
-	 */
71
-	private function deleteMetaData($path) {
72
-		$path = ltrim($this->root.$path, '/');
73
-		if (isset($this->metaData[$path])) {
74
-			unset($this->metaData[$path]);
75
-			return true;
76
-		}
77
-		return false;
78
-	}
68
+    /**
69
+     * @param string $path
70
+     */
71
+    private function deleteMetaData($path) {
72
+        $path = ltrim($this->root.$path, '/');
73
+        if (isset($this->metaData[$path])) {
74
+            unset($this->metaData[$path]);
75
+            return true;
76
+        }
77
+        return false;
78
+    }
79 79
 
80
-	private function setMetaData($path, $metaData) {
81
-		$this->metaData[ltrim($path, '/')] = $metaData;
82
-	}
80
+    private function setMetaData($path, $metaData) {
81
+        $this->metaData[ltrim($path, '/')] = $metaData;
82
+    }
83 83
 
84
-	/**
85
-	 * Returns the path's metadata
86
-	 * @param string $path path for which to return the metadata
87
-	 * @param bool $list if true, also return the directory's contents
88
-	 * @return mixed directory contents if $list is true, file metadata if $list is
89
-	 * false, null if the file doesn't exist or "false" if the operation failed
90
-	 */
91
-	private function getDropBoxMetaData($path, $list = false) {
92
-		$path = ltrim($this->root.$path, '/');
93
-		if ( ! $list && isset($this->metaData[$path])) {
94
-			return $this->metaData[$path];
95
-		} else {
96
-			if ($list) {
97
-				try {
98
-					$response = $this->dropbox->getMetaData($path);
99
-				} catch (\Dropbox_Exception_Forbidden $e) {
100
-					throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
101
-				} catch (\Exception $exception) {
102
-					\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
103
-					return false;
104
-				}
105
-				$contents = array();
106
-				if ($response && isset($response['contents'])) {
107
-					// Cache folder's contents
108
-					foreach ($response['contents'] as $file) {
109
-						if (!isset($file['is_deleted']) || !$file['is_deleted']) {
110
-							$this->setMetaData($path.'/'.basename($file['path']), $file);
111
-							$contents[] = $file;
112
-						}
113
-					}
114
-					unset($response['contents']);
115
-				}
116
-				if (!isset($response['is_deleted']) || !$response['is_deleted']) {
117
-					$this->setMetaData($path, $response);
118
-				}
119
-				// Return contents of folder only
120
-				return $contents;
121
-			} else {
122
-				try {
123
-					$requestPath = $path;
124
-					if ($path === '.') {
125
-						$requestPath = '';
126
-					}
84
+    /**
85
+     * Returns the path's metadata
86
+     * @param string $path path for which to return the metadata
87
+     * @param bool $list if true, also return the directory's contents
88
+     * @return mixed directory contents if $list is true, file metadata if $list is
89
+     * false, null if the file doesn't exist or "false" if the operation failed
90
+     */
91
+    private function getDropBoxMetaData($path, $list = false) {
92
+        $path = ltrim($this->root.$path, '/');
93
+        if ( ! $list && isset($this->metaData[$path])) {
94
+            return $this->metaData[$path];
95
+        } else {
96
+            if ($list) {
97
+                try {
98
+                    $response = $this->dropbox->getMetaData($path);
99
+                } catch (\Dropbox_Exception_Forbidden $e) {
100
+                    throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
101
+                } catch (\Exception $exception) {
102
+                    \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
103
+                    return false;
104
+                }
105
+                $contents = array();
106
+                if ($response && isset($response['contents'])) {
107
+                    // Cache folder's contents
108
+                    foreach ($response['contents'] as $file) {
109
+                        if (!isset($file['is_deleted']) || !$file['is_deleted']) {
110
+                            $this->setMetaData($path.'/'.basename($file['path']), $file);
111
+                            $contents[] = $file;
112
+                        }
113
+                    }
114
+                    unset($response['contents']);
115
+                }
116
+                if (!isset($response['is_deleted']) || !$response['is_deleted']) {
117
+                    $this->setMetaData($path, $response);
118
+                }
119
+                // Return contents of folder only
120
+                return $contents;
121
+            } else {
122
+                try {
123
+                    $requestPath = $path;
124
+                    if ($path === '.') {
125
+                        $requestPath = '';
126
+                    }
127 127
 
128
-					$response = $this->dropbox->getMetaData($requestPath, 'false');
129
-					if (!isset($response['is_deleted']) || !$response['is_deleted']) {
130
-						$this->setMetaData($path, $response);
131
-						return $response;
132
-					}
133
-					return null;
134
-				} catch (\Dropbox_Exception_Forbidden $e) {
135
-					throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
136
-				} catch (\Exception $exception) {
137
-					if ($exception instanceof \Dropbox_Exception_NotFound) {
138
-						// don't log, might be a file_exist check
139
-						return false;
140
-					}
141
-					\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
142
-					return false;
143
-				}
144
-			}
145
-		}
146
-	}
128
+                    $response = $this->dropbox->getMetaData($requestPath, 'false');
129
+                    if (!isset($response['is_deleted']) || !$response['is_deleted']) {
130
+                        $this->setMetaData($path, $response);
131
+                        return $response;
132
+                    }
133
+                    return null;
134
+                } catch (\Dropbox_Exception_Forbidden $e) {
135
+                    throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
136
+                } catch (\Exception $exception) {
137
+                    if ($exception instanceof \Dropbox_Exception_NotFound) {
138
+                        // don't log, might be a file_exist check
139
+                        return false;
140
+                    }
141
+                    \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
142
+                    return false;
143
+                }
144
+            }
145
+        }
146
+    }
147 147
 
148
-	public function getId(){
149
-		return $this->id;
150
-	}
148
+    public function getId(){
149
+        return $this->id;
150
+    }
151 151
 
152
-	public function mkdir($path) {
153
-		$path = $this->root.$path;
154
-		try {
155
-			$this->dropbox->createFolder($path);
156
-			return true;
157
-		} catch (\Exception $exception) {
158
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
159
-			return false;
160
-		}
161
-	}
152
+    public function mkdir($path) {
153
+        $path = $this->root.$path;
154
+        try {
155
+            $this->dropbox->createFolder($path);
156
+            return true;
157
+        } catch (\Exception $exception) {
158
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
159
+            return false;
160
+        }
161
+    }
162 162
 
163
-	public function rmdir($path) {
164
-		return $this->unlink($path);
165
-	}
163
+    public function rmdir($path) {
164
+        return $this->unlink($path);
165
+    }
166 166
 
167
-	public function opendir($path) {
168
-		$contents = $this->getDropBoxMetaData($path, true);
169
-		if ($contents !== false) {
170
-			$files = array();
171
-			foreach ($contents as $file) {
172
-				$files[] = basename($file['path']);
173
-			}
174
-			return IteratorDirectory::wrap($files);
175
-		}
176
-		return false;
177
-	}
167
+    public function opendir($path) {
168
+        $contents = $this->getDropBoxMetaData($path, true);
169
+        if ($contents !== false) {
170
+            $files = array();
171
+            foreach ($contents as $file) {
172
+                $files[] = basename($file['path']);
173
+            }
174
+            return IteratorDirectory::wrap($files);
175
+        }
176
+        return false;
177
+    }
178 178
 
179
-	public function stat($path) {
180
-		$metaData = $this->getDropBoxMetaData($path);
181
-		if ($metaData) {
182
-			$stat['size'] = $metaData['bytes'];
183
-			$stat['atime'] = time();
184
-			$stat['mtime'] = (isset($metaData['modified'])) ? strtotime($metaData['modified']) : time();
185
-			return $stat;
186
-		}
187
-		return false;
188
-	}
179
+    public function stat($path) {
180
+        $metaData = $this->getDropBoxMetaData($path);
181
+        if ($metaData) {
182
+            $stat['size'] = $metaData['bytes'];
183
+            $stat['atime'] = time();
184
+            $stat['mtime'] = (isset($metaData['modified'])) ? strtotime($metaData['modified']) : time();
185
+            return $stat;
186
+        }
187
+        return false;
188
+    }
189 189
 
190
-	public function filetype($path) {
191
-		if ($path == '' || $path == '/') {
192
-			return 'dir';
193
-		} else {
194
-			$metaData = $this->getDropBoxMetaData($path);
195
-			if ($metaData) {
196
-				if ($metaData['is_dir'] == 'true') {
197
-					return 'dir';
198
-				} else {
199
-					return 'file';
200
-				}
201
-			}
202
-		}
203
-		return false;
204
-	}
190
+    public function filetype($path) {
191
+        if ($path == '' || $path == '/') {
192
+            return 'dir';
193
+        } else {
194
+            $metaData = $this->getDropBoxMetaData($path);
195
+            if ($metaData) {
196
+                if ($metaData['is_dir'] == 'true') {
197
+                    return 'dir';
198
+                } else {
199
+                    return 'file';
200
+                }
201
+            }
202
+        }
203
+        return false;
204
+    }
205 205
 
206
-	public function file_exists($path) {
207
-		if ($path == '' || $path == '/') {
208
-			return true;
209
-		}
210
-		if ($this->getDropBoxMetaData($path)) {
211
-			return true;
212
-		}
213
-		return false;
214
-	}
206
+    public function file_exists($path) {
207
+        if ($path == '' || $path == '/') {
208
+            return true;
209
+        }
210
+        if ($this->getDropBoxMetaData($path)) {
211
+            return true;
212
+        }
213
+        return false;
214
+    }
215 215
 
216
-	public function unlink($path) {
217
-		try {
218
-			$this->dropbox->delete($this->root.$path);
219
-			$this->deleteMetaData($path);
220
-			return true;
221
-		} catch (\Exception $exception) {
222
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
223
-			return false;
224
-		}
225
-	}
216
+    public function unlink($path) {
217
+        try {
218
+            $this->dropbox->delete($this->root.$path);
219
+            $this->deleteMetaData($path);
220
+            return true;
221
+        } catch (\Exception $exception) {
222
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
223
+            return false;
224
+        }
225
+    }
226 226
 
227
-	public function rename($path1, $path2) {
228
-		try {
229
-			// overwrite if target file exists and is not a directory
230
-			$destMetaData = $this->getDropBoxMetaData($path2);
231
-			if (isset($destMetaData) && $destMetaData !== false && !$destMetaData['is_dir']) {
232
-				$this->unlink($path2);
233
-			}
234
-			$this->dropbox->move($this->root.$path1, $this->root.$path2);
235
-			$this->deleteMetaData($path1);
236
-			return true;
237
-		} catch (\Exception $exception) {
238
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
239
-			return false;
240
-		}
241
-	}
227
+    public function rename($path1, $path2) {
228
+        try {
229
+            // overwrite if target file exists and is not a directory
230
+            $destMetaData = $this->getDropBoxMetaData($path2);
231
+            if (isset($destMetaData) && $destMetaData !== false && !$destMetaData['is_dir']) {
232
+                $this->unlink($path2);
233
+            }
234
+            $this->dropbox->move($this->root.$path1, $this->root.$path2);
235
+            $this->deleteMetaData($path1);
236
+            return true;
237
+        } catch (\Exception $exception) {
238
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
239
+            return false;
240
+        }
241
+    }
242 242
 
243
-	public function copy($path1, $path2) {
244
-		$path1 = $this->root.$path1;
245
-		$path2 = $this->root.$path2;
246
-		try {
247
-			$this->dropbox->copy($path1, $path2);
248
-			return true;
249
-		} catch (\Exception $exception) {
250
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
251
-			return false;
252
-		}
253
-	}
243
+    public function copy($path1, $path2) {
244
+        $path1 = $this->root.$path1;
245
+        $path2 = $this->root.$path2;
246
+        try {
247
+            $this->dropbox->copy($path1, $path2);
248
+            return true;
249
+        } catch (\Exception $exception) {
250
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
251
+            return false;
252
+        }
253
+    }
254 254
 
255
-	public function fopen($path, $mode) {
256
-		$path = $this->root.$path;
257
-		switch ($mode) {
258
-			case 'r':
259
-			case 'rb':
260
-				try {
261
-					// slashes need to stay
262
-					$encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/')));
263
-					$downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath;
264
-					$headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET');
255
+    public function fopen($path, $mode) {
256
+        $path = $this->root.$path;
257
+        switch ($mode) {
258
+            case 'r':
259
+            case 'rb':
260
+                try {
261
+                    // slashes need to stay
262
+                    $encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/')));
263
+                    $downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath;
264
+                    $headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET');
265 265
 
266
-					$client = \OC::$server->getHTTPClientService()->newClient();
267
-					try {
268
-						$response = $client->get($downloadUrl, [
269
-							'headers' => $headers,
270
-							'stream' => true,
271
-						]);
272
-					} catch (RequestException $e) {
273
-						if (!is_null($e->getResponse())) {
274
-							if ($e->getResponse()->getStatusCode() === 404) {
275
-								return false;
276
-							} else {
277
-								throw $e;
278
-							}
279
-						} else {
280
-							throw $e;
281
-						}
282
-					}
266
+                    $client = \OC::$server->getHTTPClientService()->newClient();
267
+                    try {
268
+                        $response = $client->get($downloadUrl, [
269
+                            'headers' => $headers,
270
+                            'stream' => true,
271
+                        ]);
272
+                    } catch (RequestException $e) {
273
+                        if (!is_null($e->getResponse())) {
274
+                            if ($e->getResponse()->getStatusCode() === 404) {
275
+                                return false;
276
+                            } else {
277
+                                throw $e;
278
+                            }
279
+                        } else {
280
+                            throw $e;
281
+                        }
282
+                    }
283 283
 
284
-					$handle = $response->getBody();
285
-					return RetryWrapper::wrap($handle);
286
-				} catch (\Exception $exception) {
287
-					\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
288
-					return false;
289
-				}
290
-			case 'w':
291
-			case 'wb':
292
-			case 'a':
293
-			case 'ab':
294
-			case 'r+':
295
-			case 'w+':
296
-			case 'wb+':
297
-			case 'a+':
298
-			case 'x':
299
-			case 'x+':
300
-			case 'c':
301
-			case 'c+':
302
-				if (strrpos($path, '.') !== false) {
303
-					$ext = substr($path, strrpos($path, '.'));
304
-				} else {
305
-					$ext = '';
306
-				}
307
-				$tmpFile = \OCP\Files::tmpFile($ext);
308
-				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
309
-				if ($this->file_exists($path)) {
310
-					$source = $this->fopen($path, 'r');
311
-					file_put_contents($tmpFile, $source);
312
-				}
313
-				self::$tempFiles[$tmpFile] = $path;
314
-				return fopen('close://'.$tmpFile, $mode);
315
-		}
316
-		return false;
317
-	}
284
+                    $handle = $response->getBody();
285
+                    return RetryWrapper::wrap($handle);
286
+                } catch (\Exception $exception) {
287
+                    \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
288
+                    return false;
289
+                }
290
+            case 'w':
291
+            case 'wb':
292
+            case 'a':
293
+            case 'ab':
294
+            case 'r+':
295
+            case 'w+':
296
+            case 'wb+':
297
+            case 'a+':
298
+            case 'x':
299
+            case 'x+':
300
+            case 'c':
301
+            case 'c+':
302
+                if (strrpos($path, '.') !== false) {
303
+                    $ext = substr($path, strrpos($path, '.'));
304
+                } else {
305
+                    $ext = '';
306
+                }
307
+                $tmpFile = \OCP\Files::tmpFile($ext);
308
+                \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
309
+                if ($this->file_exists($path)) {
310
+                    $source = $this->fopen($path, 'r');
311
+                    file_put_contents($tmpFile, $source);
312
+                }
313
+                self::$tempFiles[$tmpFile] = $path;
314
+                return fopen('close://'.$tmpFile, $mode);
315
+        }
316
+        return false;
317
+    }
318 318
 
319
-	public function writeBack($tmpFile) {
320
-		if (isset(self::$tempFiles[$tmpFile])) {
321
-			$handle = fopen($tmpFile, 'r');
322
-			try {
323
-				$this->dropbox->putFile(self::$tempFiles[$tmpFile], $handle);
324
-				unlink($tmpFile);
325
-				$this->deleteMetaData(self::$tempFiles[$tmpFile]);
326
-			} catch (\Exception $exception) {
327
-				\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
328
-			}
329
-		}
330
-	}
319
+    public function writeBack($tmpFile) {
320
+        if (isset(self::$tempFiles[$tmpFile])) {
321
+            $handle = fopen($tmpFile, 'r');
322
+            try {
323
+                $this->dropbox->putFile(self::$tempFiles[$tmpFile], $handle);
324
+                unlink($tmpFile);
325
+                $this->deleteMetaData(self::$tempFiles[$tmpFile]);
326
+            } catch (\Exception $exception) {
327
+                \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
328
+            }
329
+        }
330
+    }
331 331
 
332
-	public function free_space($path) {
333
-		try {
334
-			$info = $this->dropbox->getAccountInfo();
335
-			return $info['quota_info']['quota'] - $info['quota_info']['normal'];
336
-		} catch (\Exception $exception) {
337
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
338
-			return false;
339
-		}
340
-	}
332
+    public function free_space($path) {
333
+        try {
334
+            $info = $this->dropbox->getAccountInfo();
335
+            return $info['quota_info']['quota'] - $info['quota_info']['normal'];
336
+        } catch (\Exception $exception) {
337
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
338
+            return false;
339
+        }
340
+    }
341 341
 
342
-	public function touch($path, $mtime = null) {
343
-		if ($this->file_exists($path)) {
344
-			return false;
345
-		} else {
346
-			$this->file_put_contents($path, '');
347
-		}
348
-		return true;
349
-	}
342
+    public function touch($path, $mtime = null) {
343
+        if ($this->file_exists($path)) {
344
+            return false;
345
+        } else {
346
+            $this->file_put_contents($path, '');
347
+        }
348
+        return true;
349
+    }
350 350
 
351
-	/**
352
-	 * check if curl is installed
353
-	 */
354
-	public static function checkDependencies() {
355
-		return true;
356
-	}
351
+    /**
352
+     * check if curl is installed
353
+     */
354
+    public static function checkDependencies() {
355
+        return true;
356
+    }
357 357
 
358 358
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -35,7 +35,7 @@  discard block
 block discarded – undo
35 35
 use Icewind\Streams\RetryWrapper;
36 36
 use OCP\Files\StorageNotAvailableException;
37 37
 
38
-require_once __DIR__ . '/../../../3rdparty/Dropbox/autoload.php';
38
+require_once __DIR__.'/../../../3rdparty/Dropbox/autoload.php';
39 39
 
40 40
 class Dropbox extends \OC\Files\Storage\Common {
41 41
 
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
 			&& isset($params['token_secret'])
56 56
 		) {
57 57
 			$this->root = isset($params['root']) ? $params['root'] : '';
58
-			$this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
58
+			$this->id = 'dropbox::'.$params['app_key'].$params['token'].'/'.$this->root;
59 59
 			$this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
60 60
 			$this->oauth->setToken($params['token'], $params['token_secret']);
61 61
 			// note: Dropbox_API connection is lazy
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
 	 */
91 91
 	private function getDropBoxMetaData($path, $list = false) {
92 92
 		$path = ltrim($this->root.$path, '/');
93
-		if ( ! $list && isset($this->metaData[$path])) {
93
+		if (!$list && isset($this->metaData[$path])) {
94 94
 			return $this->metaData[$path];
95 95
 		} else {
96 96
 			if ($list) {
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
 		}
146 146
 	}
147 147
 
148
-	public function getId(){
148
+	public function getId() {
149 149
 		return $this->id;
150 150
 	}
151 151
 
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
 				try {
261 261
 					// slashes need to stay
262 262
 					$encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/')));
263
-					$downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath;
263
+					$downloadUrl = 'https://api-content.dropbox.com/1/files/auto/'.$encodedPath;
264 264
 					$headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET');
265 265
 
266 266
 					$client = \OC::$server->getHTTPClientService()->newClient();
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/SFTP.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -32,7 +32,6 @@
 block discarded – undo
32 32
  */
33 33
 namespace OCA\Files_External\Lib\Storage;
34 34
 use Icewind\Streams\IteratorDirectory;
35
-
36 35
 use Icewind\Streams\RetryWrapper;
37 36
 use phpseclib\Net\SFTP\Stream;
38 37
 
Please login to merge, or discard this patch.
Indentation   +424 added lines, -424 removed lines patch added patch discarded remove patch
@@ -42,428 +42,428 @@
 block discarded – undo
42 42
 * provide access to SFTP servers.
43 43
 */
44 44
 class SFTP extends \OC\Files\Storage\Common {
45
-	private $host;
46
-	private $user;
47
-	private $root;
48
-	private $port = 22;
49
-
50
-	private $auth;
51
-
52
-	/**
53
-	 * @var \phpseclib\Net\SFTP
54
-	 */
55
-	protected $client;
56
-
57
-	/**
58
-	 * @param string $host protocol://server:port
59
-	 * @return array [$server, $port]
60
-	 */
61
-	private function splitHost($host) {
62
-		$input = $host;
63
-		if (strpos($host, '://') === false) {
64
-			// add a protocol to fix parse_url behavior with ipv6
65
-			$host = 'http://' . $host;
66
-		}
67
-
68
-		$parsed = parse_url($host);
69
-		if(is_array($parsed) && isset($parsed['port'])) {
70
-			return [$parsed['host'], $parsed['port']];
71
-		} else if (is_array($parsed)) {
72
-			return [$parsed['host'], 22];
73
-		} else {
74
-			return [$input, 22];
75
-		}
76
-	}
77
-
78
-	/**
79
-	 * {@inheritdoc}
80
-	 */
81
-	public function __construct($params) {
82
-		// Register sftp://
83
-		Stream::register();
84
-
85
-		$parsedHost =  $this->splitHost($params['host']);
86
-
87
-		$this->host = $parsedHost[0];
88
-		$this->port = $parsedHost[1];
89
-
90
-		if (!isset($params['user'])) {
91
-			throw new \UnexpectedValueException('no authentication parameters specified');
92
-		}
93
-		$this->user = $params['user'];
94
-
95
-		if (isset($params['public_key_auth'])) {
96
-			$this->auth = $params['public_key_auth'];
97
-		} elseif (isset($params['password'])) {
98
-			$this->auth = $params['password'];
99
-		} else {
100
-			throw new \UnexpectedValueException('no authentication parameters specified');
101
-		}
102
-
103
-		$this->root
104
-			= isset($params['root']) ? $this->cleanPath($params['root']) : '/';
105
-
106
-		if ($this->root[0] != '/') {
107
-			 $this->root = '/' . $this->root;
108
-		}
109
-
110
-		if (substr($this->root, -1, 1) != '/') {
111
-			$this->root .= '/';
112
-		}
113
-	}
114
-
115
-	/**
116
-	 * Returns the connection.
117
-	 *
118
-	 * @return \phpseclib\Net\SFTP connected client instance
119
-	 * @throws \Exception when the connection failed
120
-	 */
121
-	public function getConnection() {
122
-		if (!is_null($this->client)) {
123
-			return $this->client;
124
-		}
125
-
126
-		$hostKeys = $this->readHostKeys();
127
-		$this->client = new \phpseclib\Net\SFTP($this->host, $this->port);
128
-
129
-		// The SSH Host Key MUST be verified before login().
130
-		$currentHostKey = $this->client->getServerPublicHostKey();
131
-		if (array_key_exists($this->host, $hostKeys)) {
132
-			if ($hostKeys[$this->host] != $currentHostKey) {
133
-				throw new \Exception('Host public key does not match known key');
134
-			}
135
-		} else {
136
-			$hostKeys[$this->host] = $currentHostKey;
137
-			$this->writeHostKeys($hostKeys);
138
-		}
139
-
140
-		if (!$this->client->login($this->user, $this->auth)) {
141
-			throw new \Exception('Login failed');
142
-		}
143
-		return $this->client;
144
-	}
145
-
146
-	/**
147
-	 * {@inheritdoc}
148
-	 */
149
-	public function test() {
150
-		if (
151
-			!isset($this->host)
152
-			|| !isset($this->user)
153
-		) {
154
-			return false;
155
-		}
156
-		return $this->getConnection()->nlist() !== false;
157
-	}
158
-
159
-	/**
160
-	 * {@inheritdoc}
161
-	 */
162
-	public function getId(){
163
-		$id = 'sftp::' . $this->user . '@' . $this->host;
164
-		if ($this->port !== 22) {
165
-			$id .= ':' . $this->port;
166
-		}
167
-		// note: this will double the root slash,
168
-		// we should not change it to keep compatible with
169
-		// old storage ids
170
-		$id .= '/' . $this->root;
171
-		return $id;
172
-	}
173
-
174
-	/**
175
-	 * @return string
176
-	 */
177
-	public function getHost() {
178
-		return $this->host;
179
-	}
180
-
181
-	/**
182
-	 * @return string
183
-	 */
184
-	public function getRoot() {
185
-		return $this->root;
186
-	}
187
-
188
-	/**
189
-	 * @return mixed
190
-	 */
191
-	public function getUser() {
192
-		return $this->user;
193
-	}
194
-
195
-	/**
196
-	 * @param string $path
197
-	 * @return string
198
-	 */
199
-	private function absPath($path) {
200
-		return $this->root . $this->cleanPath($path);
201
-	}
202
-
203
-	/**
204
-	 * @return string|false
205
-	 */
206
-	private function hostKeysPath() {
207
-		try {
208
-			$storage_view = \OCP\Files::getStorage('files_external');
209
-			if ($storage_view) {
210
-				return \OC::$server->getConfig()->getSystemValue('datadirectory') .
211
-					$storage_view->getAbsolutePath('') .
212
-					'ssh_hostKeys';
213
-			}
214
-		} catch (\Exception $e) {
215
-		}
216
-		return false;
217
-	}
218
-
219
-	/**
220
-	 * @param $keys
221
-	 * @return bool
222
-	 */
223
-	protected function writeHostKeys($keys) {
224
-		try {
225
-			$keyPath = $this->hostKeysPath();
226
-			if ($keyPath && file_exists($keyPath)) {
227
-				$fp = fopen($keyPath, 'w');
228
-				foreach ($keys as $host => $key) {
229
-					fwrite($fp, $host . '::' . $key . "\n");
230
-				}
231
-				fclose($fp);
232
-				return true;
233
-			}
234
-		} catch (\Exception $e) {
235
-		}
236
-		return false;
237
-	}
238
-
239
-	/**
240
-	 * @return array
241
-	 */
242
-	protected function readHostKeys() {
243
-		try {
244
-			$keyPath = $this->hostKeysPath();
245
-			if (file_exists($keyPath)) {
246
-				$hosts = array();
247
-				$keys = array();
248
-				$lines = file($keyPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
249
-				if ($lines) {
250
-					foreach ($lines as $line) {
251
-						$hostKeyArray = explode("::", $line, 2);
252
-						if (count($hostKeyArray) == 2) {
253
-							$hosts[] = $hostKeyArray[0];
254
-							$keys[] = $hostKeyArray[1];
255
-						}
256
-					}
257
-					return array_combine($hosts, $keys);
258
-				}
259
-			}
260
-		} catch (\Exception $e) {
261
-		}
262
-		return array();
263
-	}
264
-
265
-	/**
266
-	 * {@inheritdoc}
267
-	 */
268
-	public function mkdir($path) {
269
-		try {
270
-			return $this->getConnection()->mkdir($this->absPath($path));
271
-		} catch (\Exception $e) {
272
-			return false;
273
-		}
274
-	}
275
-
276
-	/**
277
-	 * {@inheritdoc}
278
-	 */
279
-	public function rmdir($path) {
280
-		try {
281
-			$result = $this->getConnection()->delete($this->absPath($path), true);
282
-			// workaround: stray stat cache entry when deleting empty folders
283
-			// see https://github.com/phpseclib/phpseclib/issues/706
284
-			$this->getConnection()->clearStatCache();
285
-			return $result;
286
-		} catch (\Exception $e) {
287
-			return false;
288
-		}
289
-	}
290
-
291
-	/**
292
-	 * {@inheritdoc}
293
-	 */
294
-	public function opendir($path) {
295
-		try {
296
-			$list = $this->getConnection()->nlist($this->absPath($path));
297
-			if ($list === false) {
298
-				return false;
299
-			}
300
-
301
-			$id = md5('sftp:' . $path);
302
-			$dirStream = array();
303
-			foreach($list as $file) {
304
-				if ($file != '.' && $file != '..') {
305
-					$dirStream[] = $file;
306
-				}
307
-			}
308
-			return IteratorDirectory::wrap($dirStream);
309
-		} catch(\Exception $e) {
310
-			return false;
311
-		}
312
-	}
313
-
314
-	/**
315
-	 * {@inheritdoc}
316
-	 */
317
-	public function filetype($path) {
318
-		try {
319
-			$stat = $this->getConnection()->stat($this->absPath($path));
320
-			if ($stat['type'] == NET_SFTP_TYPE_REGULAR) {
321
-				return 'file';
322
-			}
323
-
324
-			if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
325
-				return 'dir';
326
-			}
327
-		} catch (\Exception $e) {
328
-
329
-		}
330
-		return false;
331
-	}
332
-
333
-	/**
334
-	 * {@inheritdoc}
335
-	 */
336
-	public function file_exists($path) {
337
-		try {
338
-			return $this->getConnection()->stat($this->absPath($path)) !== false;
339
-		} catch (\Exception $e) {
340
-			return false;
341
-		}
342
-	}
343
-
344
-	/**
345
-	 * {@inheritdoc}
346
-	 */
347
-	public function unlink($path) {
348
-		try {
349
-			return $this->getConnection()->delete($this->absPath($path), true);
350
-		} catch (\Exception $e) {
351
-			return false;
352
-		}
353
-	}
354
-
355
-	/**
356
-	 * {@inheritdoc}
357
-	 */
358
-	public function fopen($path, $mode) {
359
-		try {
360
-			$absPath = $this->absPath($path);
361
-			switch($mode) {
362
-				case 'r':
363
-				case 'rb':
364
-					if ( !$this->file_exists($path)) {
365
-						return false;
366
-					}
367
-				case 'w':
368
-				case 'wb':
369
-				case 'a':
370
-				case 'ab':
371
-				case 'r+':
372
-				case 'w+':
373
-				case 'wb+':
374
-				case 'a+':
375
-				case 'x':
376
-				case 'x+':
377
-				case 'c':
378
-				case 'c+':
379
-					$context = stream_context_create(array('sftp' => array('session' => $this->getConnection())));
380
-					$handle = fopen($this->constructUrl($path), $mode, false, $context);
381
-					return RetryWrapper::wrap($handle);
382
-			}
383
-		} catch (\Exception $e) {
384
-		}
385
-		return false;
386
-	}
387
-
388
-	/**
389
-	 * {@inheritdoc}
390
-	 */
391
-	public function touch($path, $mtime=null) {
392
-		try {
393
-			if (!is_null($mtime)) {
394
-				return false;
395
-			}
396
-			if (!$this->file_exists($path)) {
397
-				$this->getConnection()->put($this->absPath($path), '');
398
-			} else {
399
-				return false;
400
-			}
401
-		} catch (\Exception $e) {
402
-			return false;
403
-		}
404
-		return true;
405
-	}
406
-
407
-	/**
408
-	 * @param string $path
409
-	 * @param string $target
410
-	 * @throws \Exception
411
-	 */
412
-	public function getFile($path, $target) {
413
-		$this->getConnection()->get($path, $target);
414
-	}
415
-
416
-	/**
417
-	 * @param string $path
418
-	 * @param string $target
419
-	 * @throws \Exception
420
-	 */
421
-	public function uploadFile($path, $target) {
422
-		$this->getConnection()->put($target, $path, NET_SFTP_LOCAL_FILE);
423
-	}
424
-
425
-	/**
426
-	 * {@inheritdoc}
427
-	 */
428
-	public function rename($source, $target) {
429
-		try {
430
-			if ($this->file_exists($target)) {
431
-				$this->unlink($target);
432
-			}
433
-			return $this->getConnection()->rename(
434
-				$this->absPath($source),
435
-				$this->absPath($target)
436
-			);
437
-		} catch (\Exception $e) {
438
-			return false;
439
-		}
440
-	}
441
-
442
-	/**
443
-	 * {@inheritdoc}
444
-	 */
445
-	public function stat($path) {
446
-		try {
447
-			$stat = $this->getConnection()->stat($this->absPath($path));
448
-
449
-			$mtime = $stat ? $stat['mtime'] : -1;
450
-			$size = $stat ? $stat['size'] : 0;
451
-
452
-			return array('mtime' => $mtime, 'size' => $size, 'ctime' => -1);
453
-		} catch (\Exception $e) {
454
-			return false;
455
-		}
456
-	}
457
-
458
-	/**
459
-	 * @param string $path
460
-	 * @return string
461
-	 */
462
-	public function constructUrl($path) {
463
-		// Do not pass the password here. We want to use the Net_SFTP object
464
-		// supplied via stream context or fail. We only supply username and
465
-		// hostname because this might show up in logs (they are not used).
466
-		$url = 'sftp://' . urlencode($this->user) . '@' . $this->host . ':' . $this->port . $this->root . $path;
467
-		return $url;
468
-	}
45
+    private $host;
46
+    private $user;
47
+    private $root;
48
+    private $port = 22;
49
+
50
+    private $auth;
51
+
52
+    /**
53
+     * @var \phpseclib\Net\SFTP
54
+     */
55
+    protected $client;
56
+
57
+    /**
58
+     * @param string $host protocol://server:port
59
+     * @return array [$server, $port]
60
+     */
61
+    private function splitHost($host) {
62
+        $input = $host;
63
+        if (strpos($host, '://') === false) {
64
+            // add a protocol to fix parse_url behavior with ipv6
65
+            $host = 'http://' . $host;
66
+        }
67
+
68
+        $parsed = parse_url($host);
69
+        if(is_array($parsed) && isset($parsed['port'])) {
70
+            return [$parsed['host'], $parsed['port']];
71
+        } else if (is_array($parsed)) {
72
+            return [$parsed['host'], 22];
73
+        } else {
74
+            return [$input, 22];
75
+        }
76
+    }
77
+
78
+    /**
79
+     * {@inheritdoc}
80
+     */
81
+    public function __construct($params) {
82
+        // Register sftp://
83
+        Stream::register();
84
+
85
+        $parsedHost =  $this->splitHost($params['host']);
86
+
87
+        $this->host = $parsedHost[0];
88
+        $this->port = $parsedHost[1];
89
+
90
+        if (!isset($params['user'])) {
91
+            throw new \UnexpectedValueException('no authentication parameters specified');
92
+        }
93
+        $this->user = $params['user'];
94
+
95
+        if (isset($params['public_key_auth'])) {
96
+            $this->auth = $params['public_key_auth'];
97
+        } elseif (isset($params['password'])) {
98
+            $this->auth = $params['password'];
99
+        } else {
100
+            throw new \UnexpectedValueException('no authentication parameters specified');
101
+        }
102
+
103
+        $this->root
104
+            = isset($params['root']) ? $this->cleanPath($params['root']) : '/';
105
+
106
+        if ($this->root[0] != '/') {
107
+                $this->root = '/' . $this->root;
108
+        }
109
+
110
+        if (substr($this->root, -1, 1) != '/') {
111
+            $this->root .= '/';
112
+        }
113
+    }
114
+
115
+    /**
116
+     * Returns the connection.
117
+     *
118
+     * @return \phpseclib\Net\SFTP connected client instance
119
+     * @throws \Exception when the connection failed
120
+     */
121
+    public function getConnection() {
122
+        if (!is_null($this->client)) {
123
+            return $this->client;
124
+        }
125
+
126
+        $hostKeys = $this->readHostKeys();
127
+        $this->client = new \phpseclib\Net\SFTP($this->host, $this->port);
128
+
129
+        // The SSH Host Key MUST be verified before login().
130
+        $currentHostKey = $this->client->getServerPublicHostKey();
131
+        if (array_key_exists($this->host, $hostKeys)) {
132
+            if ($hostKeys[$this->host] != $currentHostKey) {
133
+                throw new \Exception('Host public key does not match known key');
134
+            }
135
+        } else {
136
+            $hostKeys[$this->host] = $currentHostKey;
137
+            $this->writeHostKeys($hostKeys);
138
+        }
139
+
140
+        if (!$this->client->login($this->user, $this->auth)) {
141
+            throw new \Exception('Login failed');
142
+        }
143
+        return $this->client;
144
+    }
145
+
146
+    /**
147
+     * {@inheritdoc}
148
+     */
149
+    public function test() {
150
+        if (
151
+            !isset($this->host)
152
+            || !isset($this->user)
153
+        ) {
154
+            return false;
155
+        }
156
+        return $this->getConnection()->nlist() !== false;
157
+    }
158
+
159
+    /**
160
+     * {@inheritdoc}
161
+     */
162
+    public function getId(){
163
+        $id = 'sftp::' . $this->user . '@' . $this->host;
164
+        if ($this->port !== 22) {
165
+            $id .= ':' . $this->port;
166
+        }
167
+        // note: this will double the root slash,
168
+        // we should not change it to keep compatible with
169
+        // old storage ids
170
+        $id .= '/' . $this->root;
171
+        return $id;
172
+    }
173
+
174
+    /**
175
+     * @return string
176
+     */
177
+    public function getHost() {
178
+        return $this->host;
179
+    }
180
+
181
+    /**
182
+     * @return string
183
+     */
184
+    public function getRoot() {
185
+        return $this->root;
186
+    }
187
+
188
+    /**
189
+     * @return mixed
190
+     */
191
+    public function getUser() {
192
+        return $this->user;
193
+    }
194
+
195
+    /**
196
+     * @param string $path
197
+     * @return string
198
+     */
199
+    private function absPath($path) {
200
+        return $this->root . $this->cleanPath($path);
201
+    }
202
+
203
+    /**
204
+     * @return string|false
205
+     */
206
+    private function hostKeysPath() {
207
+        try {
208
+            $storage_view = \OCP\Files::getStorage('files_external');
209
+            if ($storage_view) {
210
+                return \OC::$server->getConfig()->getSystemValue('datadirectory') .
211
+                    $storage_view->getAbsolutePath('') .
212
+                    'ssh_hostKeys';
213
+            }
214
+        } catch (\Exception $e) {
215
+        }
216
+        return false;
217
+    }
218
+
219
+    /**
220
+     * @param $keys
221
+     * @return bool
222
+     */
223
+    protected function writeHostKeys($keys) {
224
+        try {
225
+            $keyPath = $this->hostKeysPath();
226
+            if ($keyPath && file_exists($keyPath)) {
227
+                $fp = fopen($keyPath, 'w');
228
+                foreach ($keys as $host => $key) {
229
+                    fwrite($fp, $host . '::' . $key . "\n");
230
+                }
231
+                fclose($fp);
232
+                return true;
233
+            }
234
+        } catch (\Exception $e) {
235
+        }
236
+        return false;
237
+    }
238
+
239
+    /**
240
+     * @return array
241
+     */
242
+    protected function readHostKeys() {
243
+        try {
244
+            $keyPath = $this->hostKeysPath();
245
+            if (file_exists($keyPath)) {
246
+                $hosts = array();
247
+                $keys = array();
248
+                $lines = file($keyPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
249
+                if ($lines) {
250
+                    foreach ($lines as $line) {
251
+                        $hostKeyArray = explode("::", $line, 2);
252
+                        if (count($hostKeyArray) == 2) {
253
+                            $hosts[] = $hostKeyArray[0];
254
+                            $keys[] = $hostKeyArray[1];
255
+                        }
256
+                    }
257
+                    return array_combine($hosts, $keys);
258
+                }
259
+            }
260
+        } catch (\Exception $e) {
261
+        }
262
+        return array();
263
+    }
264
+
265
+    /**
266
+     * {@inheritdoc}
267
+     */
268
+    public function mkdir($path) {
269
+        try {
270
+            return $this->getConnection()->mkdir($this->absPath($path));
271
+        } catch (\Exception $e) {
272
+            return false;
273
+        }
274
+    }
275
+
276
+    /**
277
+     * {@inheritdoc}
278
+     */
279
+    public function rmdir($path) {
280
+        try {
281
+            $result = $this->getConnection()->delete($this->absPath($path), true);
282
+            // workaround: stray stat cache entry when deleting empty folders
283
+            // see https://github.com/phpseclib/phpseclib/issues/706
284
+            $this->getConnection()->clearStatCache();
285
+            return $result;
286
+        } catch (\Exception $e) {
287
+            return false;
288
+        }
289
+    }
290
+
291
+    /**
292
+     * {@inheritdoc}
293
+     */
294
+    public function opendir($path) {
295
+        try {
296
+            $list = $this->getConnection()->nlist($this->absPath($path));
297
+            if ($list === false) {
298
+                return false;
299
+            }
300
+
301
+            $id = md5('sftp:' . $path);
302
+            $dirStream = array();
303
+            foreach($list as $file) {
304
+                if ($file != '.' && $file != '..') {
305
+                    $dirStream[] = $file;
306
+                }
307
+            }
308
+            return IteratorDirectory::wrap($dirStream);
309
+        } catch(\Exception $e) {
310
+            return false;
311
+        }
312
+    }
313
+
314
+    /**
315
+     * {@inheritdoc}
316
+     */
317
+    public function filetype($path) {
318
+        try {
319
+            $stat = $this->getConnection()->stat($this->absPath($path));
320
+            if ($stat['type'] == NET_SFTP_TYPE_REGULAR) {
321
+                return 'file';
322
+            }
323
+
324
+            if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
325
+                return 'dir';
326
+            }
327
+        } catch (\Exception $e) {
328
+
329
+        }
330
+        return false;
331
+    }
332
+
333
+    /**
334
+     * {@inheritdoc}
335
+     */
336
+    public function file_exists($path) {
337
+        try {
338
+            return $this->getConnection()->stat($this->absPath($path)) !== false;
339
+        } catch (\Exception $e) {
340
+            return false;
341
+        }
342
+    }
343
+
344
+    /**
345
+     * {@inheritdoc}
346
+     */
347
+    public function unlink($path) {
348
+        try {
349
+            return $this->getConnection()->delete($this->absPath($path), true);
350
+        } catch (\Exception $e) {
351
+            return false;
352
+        }
353
+    }
354
+
355
+    /**
356
+     * {@inheritdoc}
357
+     */
358
+    public function fopen($path, $mode) {
359
+        try {
360
+            $absPath = $this->absPath($path);
361
+            switch($mode) {
362
+                case 'r':
363
+                case 'rb':
364
+                    if ( !$this->file_exists($path)) {
365
+                        return false;
366
+                    }
367
+                case 'w':
368
+                case 'wb':
369
+                case 'a':
370
+                case 'ab':
371
+                case 'r+':
372
+                case 'w+':
373
+                case 'wb+':
374
+                case 'a+':
375
+                case 'x':
376
+                case 'x+':
377
+                case 'c':
378
+                case 'c+':
379
+                    $context = stream_context_create(array('sftp' => array('session' => $this->getConnection())));
380
+                    $handle = fopen($this->constructUrl($path), $mode, false, $context);
381
+                    return RetryWrapper::wrap($handle);
382
+            }
383
+        } catch (\Exception $e) {
384
+        }
385
+        return false;
386
+    }
387
+
388
+    /**
389
+     * {@inheritdoc}
390
+     */
391
+    public function touch($path, $mtime=null) {
392
+        try {
393
+            if (!is_null($mtime)) {
394
+                return false;
395
+            }
396
+            if (!$this->file_exists($path)) {
397
+                $this->getConnection()->put($this->absPath($path), '');
398
+            } else {
399
+                return false;
400
+            }
401
+        } catch (\Exception $e) {
402
+            return false;
403
+        }
404
+        return true;
405
+    }
406
+
407
+    /**
408
+     * @param string $path
409
+     * @param string $target
410
+     * @throws \Exception
411
+     */
412
+    public function getFile($path, $target) {
413
+        $this->getConnection()->get($path, $target);
414
+    }
415
+
416
+    /**
417
+     * @param string $path
418
+     * @param string $target
419
+     * @throws \Exception
420
+     */
421
+    public function uploadFile($path, $target) {
422
+        $this->getConnection()->put($target, $path, NET_SFTP_LOCAL_FILE);
423
+    }
424
+
425
+    /**
426
+     * {@inheritdoc}
427
+     */
428
+    public function rename($source, $target) {
429
+        try {
430
+            if ($this->file_exists($target)) {
431
+                $this->unlink($target);
432
+            }
433
+            return $this->getConnection()->rename(
434
+                $this->absPath($source),
435
+                $this->absPath($target)
436
+            );
437
+        } catch (\Exception $e) {
438
+            return false;
439
+        }
440
+    }
441
+
442
+    /**
443
+     * {@inheritdoc}
444
+     */
445
+    public function stat($path) {
446
+        try {
447
+            $stat = $this->getConnection()->stat($this->absPath($path));
448
+
449
+            $mtime = $stat ? $stat['mtime'] : -1;
450
+            $size = $stat ? $stat['size'] : 0;
451
+
452
+            return array('mtime' => $mtime, 'size' => $size, 'ctime' => -1);
453
+        } catch (\Exception $e) {
454
+            return false;
455
+        }
456
+    }
457
+
458
+    /**
459
+     * @param string $path
460
+     * @return string
461
+     */
462
+    public function constructUrl($path) {
463
+        // Do not pass the password here. We want to use the Net_SFTP object
464
+        // supplied via stream context or fail. We only supply username and
465
+        // hostname because this might show up in logs (they are not used).
466
+        $url = 'sftp://' . urlencode($this->user) . '@' . $this->host . ':' . $this->port . $this->root . $path;
467
+        return $url;
468
+    }
469 469
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -62,11 +62,11 @@  discard block
 block discarded – undo
62 62
 		$input = $host;
63 63
 		if (strpos($host, '://') === false) {
64 64
 			// add a protocol to fix parse_url behavior with ipv6
65
-			$host = 'http://' . $host;
65
+			$host = 'http://'.$host;
66 66
 		}
67 67
 
68 68
 		$parsed = parse_url($host);
69
-		if(is_array($parsed) && isset($parsed['port'])) {
69
+		if (is_array($parsed) && isset($parsed['port'])) {
70 70
 			return [$parsed['host'], $parsed['port']];
71 71
 		} else if (is_array($parsed)) {
72 72
 			return [$parsed['host'], 22];
@@ -82,7 +82,7 @@  discard block
 block discarded – undo
82 82
 		// Register sftp://
83 83
 		Stream::register();
84 84
 
85
-		$parsedHost =  $this->splitHost($params['host']);
85
+		$parsedHost = $this->splitHost($params['host']);
86 86
 
87 87
 		$this->host = $parsedHost[0];
88 88
 		$this->port = $parsedHost[1];
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
 			= isset($params['root']) ? $this->cleanPath($params['root']) : '/';
105 105
 
106 106
 		if ($this->root[0] != '/') {
107
-			 $this->root = '/' . $this->root;
107
+			 $this->root = '/'.$this->root;
108 108
 		}
109 109
 
110 110
 		if (substr($this->root, -1, 1) != '/') {
@@ -159,15 +159,15 @@  discard block
 block discarded – undo
159 159
 	/**
160 160
 	 * {@inheritdoc}
161 161
 	 */
162
-	public function getId(){
163
-		$id = 'sftp::' . $this->user . '@' . $this->host;
162
+	public function getId() {
163
+		$id = 'sftp::'.$this->user.'@'.$this->host;
164 164
 		if ($this->port !== 22) {
165
-			$id .= ':' . $this->port;
165
+			$id .= ':'.$this->port;
166 166
 		}
167 167
 		// note: this will double the root slash,
168 168
 		// we should not change it to keep compatible with
169 169
 		// old storage ids
170
-		$id .= '/' . $this->root;
170
+		$id .= '/'.$this->root;
171 171
 		return $id;
172 172
 	}
173 173
 
@@ -197,7 +197,7 @@  discard block
 block discarded – undo
197 197
 	 * @return string
198 198
 	 */
199 199
 	private function absPath($path) {
200
-		return $this->root . $this->cleanPath($path);
200
+		return $this->root.$this->cleanPath($path);
201 201
 	}
202 202
 
203 203
 	/**
@@ -207,8 +207,8 @@  discard block
 block discarded – undo
207 207
 		try {
208 208
 			$storage_view = \OCP\Files::getStorage('files_external');
209 209
 			if ($storage_view) {
210
-				return \OC::$server->getConfig()->getSystemValue('datadirectory') .
211
-					$storage_view->getAbsolutePath('') .
210
+				return \OC::$server->getConfig()->getSystemValue('datadirectory').
211
+					$storage_view->getAbsolutePath('').
212 212
 					'ssh_hostKeys';
213 213
 			}
214 214
 		} catch (\Exception $e) {
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
 			if ($keyPath && file_exists($keyPath)) {
227 227
 				$fp = fopen($keyPath, 'w');
228 228
 				foreach ($keys as $host => $key) {
229
-					fwrite($fp, $host . '::' . $key . "\n");
229
+					fwrite($fp, $host.'::'.$key."\n");
230 230
 				}
231 231
 				fclose($fp);
232 232
 				return true;
@@ -298,15 +298,15 @@  discard block
 block discarded – undo
298 298
 				return false;
299 299
 			}
300 300
 
301
-			$id = md5('sftp:' . $path);
301
+			$id = md5('sftp:'.$path);
302 302
 			$dirStream = array();
303
-			foreach($list as $file) {
303
+			foreach ($list as $file) {
304 304
 				if ($file != '.' && $file != '..') {
305 305
 					$dirStream[] = $file;
306 306
 				}
307 307
 			}
308 308
 			return IteratorDirectory::wrap($dirStream);
309
-		} catch(\Exception $e) {
309
+		} catch (\Exception $e) {
310 310
 			return false;
311 311
 		}
312 312
 	}
@@ -358,10 +358,10 @@  discard block
 block discarded – undo
358 358
 	public function fopen($path, $mode) {
359 359
 		try {
360 360
 			$absPath = $this->absPath($path);
361
-			switch($mode) {
361
+			switch ($mode) {
362 362
 				case 'r':
363 363
 				case 'rb':
364
-					if ( !$this->file_exists($path)) {
364
+					if (!$this->file_exists($path)) {
365 365
 						return false;
366 366
 					}
367 367
 				case 'w':
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
 	/**
389 389
 	 * {@inheritdoc}
390 390
 	 */
391
-	public function touch($path, $mtime=null) {
391
+	public function touch($path, $mtime = null) {
392 392
 		try {
393 393
 			if (!is_null($mtime)) {
394 394
 				return false;
@@ -463,7 +463,7 @@  discard block
 block discarded – undo
463 463
 		// Do not pass the password here. We want to use the Net_SFTP object
464 464
 		// supplied via stream context or fail. We only supply username and
465 465
 		// hostname because this might show up in logs (they are not used).
466
-		$url = 'sftp://' . urlencode($this->user) . '@' . $this->host . ':' . $this->port . $this->root . $path;
466
+		$url = 'sftp://'.urlencode($this->user).'@'.$this->host.':'.$this->port.$this->root.$path;
467 467
 		return $url;
468 468
 	}
469 469
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/API/Sharees.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -335,7 +335,7 @@
 block discarded – undo
335 335
 	 * split user and remote from federated cloud id
336 336
 	 *
337 337
 	 * @param string $address federated share address
338
-	 * @return array [user, remoteURL]
338
+	 * @return string[] [user, remoteURL]
339 339
 	 * @throws \Exception
340 340
 	 */
341 341
 	public function splitUserRemote($address) {
Please login to merge, or discard this patch.
Indentation   +495 added lines, -495 removed lines patch added patch discarded remove patch
@@ -39,499 +39,499 @@
 block discarded – undo
39 39
 
40 40
 class Sharees {
41 41
 
42
-	/** @var IGroupManager */
43
-	protected $groupManager;
44
-
45
-	/** @var IUserManager */
46
-	protected $userManager;
47
-
48
-	/** @var IManager */
49
-	protected $contactsManager;
50
-
51
-	/** @var IConfig */
52
-	protected $config;
53
-
54
-	/** @var IUserSession */
55
-	protected $userSession;
56
-
57
-	/** @var IRequest */
58
-	protected $request;
59
-
60
-	/** @var IURLGenerator */
61
-	protected $urlGenerator;
62
-
63
-	/** @var ILogger */
64
-	protected $logger;
65
-
66
-	/** @var \OCP\Share\IManager */
67
-	protected $shareManager;
68
-
69
-	/** @var bool */
70
-	protected $shareWithGroupOnly = false;
71
-
72
-	/** @var bool */
73
-	protected $shareeEnumeration = true;
74
-
75
-	/** @var int */
76
-	protected $offset = 0;
77
-
78
-	/** @var int */
79
-	protected $limit = 10;
80
-
81
-	/** @var array */
82
-	protected $result = [
83
-		'exact' => [
84
-			'users' => [],
85
-			'groups' => [],
86
-			'remotes' => [],
87
-		],
88
-		'users' => [],
89
-		'groups' => [],
90
-		'remotes' => [],
91
-	];
92
-
93
-	protected $reachedEndFor = [];
94
-
95
-	/**
96
-	 * @param IGroupManager $groupManager
97
-	 * @param IUserManager $userManager
98
-	 * @param IManager $contactsManager
99
-	 * @param IConfig $config
100
-	 * @param IUserSession $userSession
101
-	 * @param IURLGenerator $urlGenerator
102
-	 * @param IRequest $request
103
-	 * @param ILogger $logger
104
-	 * @param \OCP\Share\IManager $shareManager
105
-	 */
106
-	public function __construct(IGroupManager $groupManager,
107
-								IUserManager $userManager,
108
-								IManager $contactsManager,
109
-								IConfig $config,
110
-								IUserSession $userSession,
111
-								IURLGenerator $urlGenerator,
112
-								IRequest $request,
113
-								ILogger $logger,
114
-								\OCP\Share\IManager $shareManager) {
115
-		$this->groupManager = $groupManager;
116
-		$this->userManager = $userManager;
117
-		$this->contactsManager = $contactsManager;
118
-		$this->config = $config;
119
-		$this->userSession = $userSession;
120
-		$this->urlGenerator = $urlGenerator;
121
-		$this->request = $request;
122
-		$this->logger = $logger;
123
-		$this->shareManager = $shareManager;
124
-	}
125
-
126
-	/**
127
-	 * @param string $search
128
-	 */
129
-	protected function getUsers($search) {
130
-		$this->result['users'] = $this->result['exact']['users'] = $users = [];
131
-
132
-		$userGroups = [];
133
-		if ($this->shareWithGroupOnly) {
134
-			// Search in all the groups this user is part of
135
-			$userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
136
-			foreach ($userGroups as $userGroup) {
137
-				$usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
138
-				foreach ($usersTmp as $uid => $userDisplayName) {
139
-					$users[$uid] = $userDisplayName;
140
-				}
141
-			}
142
-		} else {
143
-			// Search in all users
144
-			$usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
145
-
146
-			foreach ($usersTmp as $user) {
147
-				$users[$user->getUID()] = $user->getDisplayName();
148
-			}
149
-		}
150
-
151
-		if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
152
-			$this->reachedEndFor[] = 'users';
153
-		}
154
-
155
-		$foundUserById = false;
156
-		foreach ($users as $uid => $userDisplayName) {
157
-			if (strtolower($uid) === strtolower($search) || strtolower($userDisplayName) === strtolower($search)) {
158
-				if (strtolower($uid) === strtolower($search)) {
159
-					$foundUserById = true;
160
-				}
161
-				$this->result['exact']['users'][] = [
162
-					'label' => $userDisplayName,
163
-					'value' => [
164
-						'shareType' => Share::SHARE_TYPE_USER,
165
-						'shareWith' => $uid,
166
-					],
167
-				];
168
-			} else {
169
-				$this->result['users'][] = [
170
-					'label' => $userDisplayName,
171
-					'value' => [
172
-						'shareType' => Share::SHARE_TYPE_USER,
173
-						'shareWith' => $uid,
174
-					],
175
-				];
176
-			}
177
-		}
178
-
179
-		if ($this->offset === 0 && !$foundUserById) {
180
-			// On page one we try if the search result has a direct hit on the
181
-			// user id and if so, we add that to the exact match list
182
-			$user = $this->userManager->get($search);
183
-			if ($user instanceof IUser) {
184
-				$addUser = true;
185
-
186
-				if ($this->shareWithGroupOnly) {
187
-					// Only add, if we have a common group
188
-					$commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
189
-					$addUser = !empty($commonGroups);
190
-				}
191
-
192
-				if ($addUser) {
193
-					array_push($this->result['exact']['users'], [
194
-						'label' => $user->getDisplayName(),
195
-						'value' => [
196
-							'shareType' => Share::SHARE_TYPE_USER,
197
-							'shareWith' => $user->getUID(),
198
-						],
199
-					]);
200
-				}
201
-			}
202
-		}
203
-
204
-		if (!$this->shareeEnumeration) {
205
-			$this->result['users'] = [];
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * @param string $search
211
-	 */
212
-	protected function getGroups($search) {
213
-		$this->result['groups'] = $this->result['exact']['groups'] = [];
214
-
215
-		$groups = $this->groupManager->search($search, $this->limit, $this->offset);
216
-		$groups = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
217
-
218
-		if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
219
-			$this->reachedEndFor[] = 'groups';
220
-		}
221
-
222
-		$userGroups =  [];
223
-		if (!empty($groups) && $this->shareWithGroupOnly) {
224
-			// Intersect all the groups that match with the groups this user is a member of
225
-			$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
226
-			$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
227
-			$groups = array_intersect($groups, $userGroups);
228
-		}
229
-
230
-		foreach ($groups as $gid) {
231
-			if (strtolower($gid) === strtolower($search)) {
232
-				$this->result['exact']['groups'][] = [
233
-					'label' => $gid,
234
-					'value' => [
235
-						'shareType' => Share::SHARE_TYPE_GROUP,
236
-						'shareWith' => $gid,
237
-					],
238
-				];
239
-			} else {
240
-				$this->result['groups'][] = [
241
-					'label' => $gid,
242
-					'value' => [
243
-						'shareType' => Share::SHARE_TYPE_GROUP,
244
-						'shareWith' => $gid,
245
-					],
246
-				];
247
-			}
248
-		}
249
-
250
-		if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
251
-			// On page one we try if the search result has a direct hit on the
252
-			// user id and if so, we add that to the exact match list
253
-			$group = $this->groupManager->get($search);
254
-			if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
255
-				array_push($this->result['exact']['groups'], [
256
-					'label' => $group->getGID(),
257
-					'value' => [
258
-						'shareType' => Share::SHARE_TYPE_GROUP,
259
-						'shareWith' => $group->getGID(),
260
-					],
261
-				]);
262
-			}
263
-		}
264
-
265
-		if (!$this->shareeEnumeration) {
266
-			$this->result['groups'] = [];
267
-		}
268
-	}
269
-
270
-	/**
271
-	 * @param string $search
272
-	 * @return array possible sharees
273
-	 */
274
-	protected function getRemote($search) {
275
-		$this->result['remotes'] = [];
276
-
277
-		// Search in contacts
278
-		//@todo Pagination missing
279
-		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
280
-		$foundRemoteById = false;
281
-		foreach ($addressBookContacts as $contact) {
282
-			if (isset($contact['isLocalSystemBook'])) {
283
-				continue;
284
-			}
285
-			if (isset($contact['CLOUD'])) {
286
-				$cloudIds = $contact['CLOUD'];
287
-				if (!is_array($cloudIds)) {
288
-					$cloudIds = [$cloudIds];
289
-				}
290
-				foreach ($cloudIds as $cloudId) {
291
-					list(, $serverUrl) = $this->splitUserRemote($cloudId);
292
-					if (strtolower($contact['FN']) === strtolower($search) || strtolower($cloudId) === strtolower($search)) {
293
-						if (strtolower($cloudId) === strtolower($search)) {
294
-							$foundRemoteById = true;
295
-						}
296
-						$this->result['exact']['remotes'][] = [
297
-							'label' => $contact['FN'],
298
-							'value' => [
299
-								'shareType' => Share::SHARE_TYPE_REMOTE,
300
-								'shareWith' => $cloudId,
301
-								'server' => $serverUrl,
302
-							],
303
-						];
304
-					} else {
305
-						$this->result['remotes'][] = [
306
-							'label' => $contact['FN'],
307
-							'value' => [
308
-								'shareType' => Share::SHARE_TYPE_REMOTE,
309
-								'shareWith' => $cloudId,
310
-								'server' => $serverUrl,
311
-							],
312
-						];
313
-					}
314
-				}
315
-			}
316
-		}
317
-
318
-		if (!$this->shareeEnumeration) {
319
-			$this->result['remotes'] = [];
320
-		}
321
-
322
-		if (!$foundRemoteById && substr_count($search, '@') >= 1 && $this->offset === 0) {
323
-			$this->result['exact']['remotes'][] = [
324
-				'label' => $search,
325
-				'value' => [
326
-					'shareType' => Share::SHARE_TYPE_REMOTE,
327
-					'shareWith' => $search,
328
-				],
329
-			];
330
-		}
331
-
332
-		$this->reachedEndFor[] = 'remotes';
333
-	}
334
-
335
-	/**
336
-	 * split user and remote from federated cloud id
337
-	 *
338
-	 * @param string $address federated share address
339
-	 * @return array [user, remoteURL]
340
-	 * @throws \Exception
341
-	 */
342
-	public function splitUserRemote($address) {
343
-		if (strpos($address, '@') === false) {
344
-			throw new \Exception('Invalid Federated Cloud ID');
345
-		}
346
-
347
-		// Find the first character that is not allowed in user names
348
-		$id = str_replace('\\', '/', $address);
349
-		$posSlash = strpos($id, '/');
350
-		$posColon = strpos($id, ':');
351
-
352
-		if ($posSlash === false && $posColon === false) {
353
-			$invalidPos = strlen($id);
354
-		} else if ($posSlash === false) {
355
-			$invalidPos = $posColon;
356
-		} else if ($posColon === false) {
357
-			$invalidPos = $posSlash;
358
-		} else {
359
-			$invalidPos = min($posSlash, $posColon);
360
-		}
361
-
362
-		// Find the last @ before $invalidPos
363
-		$pos = $lastAtPos = 0;
364
-		while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
365
-			$pos = $lastAtPos;
366
-			$lastAtPos = strpos($id, '@', $pos + 1);
367
-		}
368
-
369
-		if ($pos !== false) {
370
-			$user = substr($id, 0, $pos);
371
-			$remote = substr($id, $pos + 1);
372
-			$remote = $this->fixRemoteURL($remote);
373
-			if (!empty($user) && !empty($remote)) {
374
-				return array($user, $remote);
375
-			}
376
-		}
377
-
378
-		throw new \Exception('Invalid Federated Cloud ID');
379
-	}
380
-
381
-	/**
382
-	 * Strips away a potential file names and trailing slashes:
383
-	 * - http://localhost
384
-	 * - http://localhost/
385
-	 * - http://localhost/index.php
386
-	 * - http://localhost/index.php/s/{shareToken}
387
-	 *
388
-	 * all return: http://localhost
389
-	 *
390
-	 * @param string $remote
391
-	 * @return string
392
-	 */
393
-	protected function fixRemoteURL($remote) {
394
-		$remote = str_replace('\\', '/', $remote);
395
-		if ($fileNamePosition = strpos($remote, '/index.php')) {
396
-			$remote = substr($remote, 0, $fileNamePosition);
397
-		}
398
-		$remote = rtrim($remote, '/');
399
-
400
-		return $remote;
401
-	}
402
-
403
-	/**
404
-	 * @return \OC_OCS_Result
405
-	 */
406
-	public function search() {
407
-		$search = isset($_GET['search']) ? (string) $_GET['search'] : '';
408
-		$itemType = isset($_GET['itemType']) ? (string) $_GET['itemType'] : null;
409
-		$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
410
-		$perPage = isset($_GET['perPage']) ? (int) $_GET['perPage'] : 200;
411
-
412
-		if ($perPage <= 0) {
413
-			return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Invalid perPage argument');
414
-		}
415
-		if ($page <= 0) {
416
-			return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Invalid page');
417
-		}
418
-
419
-		$shareTypes = [
420
-			Share::SHARE_TYPE_USER,
421
-		];
422
-
423
-		if ($this->shareManager->allowGroupSharing()) {
424
-			$shareTypes[] = Share::SHARE_TYPE_GROUP;
425
-		}
426
-
427
-		$shareTypes[] = Share::SHARE_TYPE_REMOTE;
428
-
429
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
430
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
431
-			sort($shareTypes);
432
-
433
-		} else if (isset($_GET['shareType']) && is_numeric($_GET['shareType'])) {
434
-			$shareTypes = array_intersect($shareTypes, [(int) $_GET['shareType']]);
435
-			sort($shareTypes);
436
-		}
437
-
438
-		if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes) && !$this->isRemoteSharingAllowed($itemType)) {
439
-			// Remove remote shares from type array, because it is not allowed.
440
-			$shareTypes = array_diff($shareTypes, [Share::SHARE_TYPE_REMOTE]);
441
-		}
442
-
443
-		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
444
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
445
-		$this->limit = (int) $perPage;
446
-		$this->offset = $perPage * ($page - 1);
447
-
448
-		return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage);
449
-	}
450
-
451
-	/**
452
-	 * Method to get out the static call for better testing
453
-	 *
454
-	 * @param string $itemType
455
-	 * @return bool
456
-	 */
457
-	protected function isRemoteSharingAllowed($itemType) {
458
-		try {
459
-			$backend = Share::getBackend($itemType);
460
-			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
461
-		} catch (\Exception $e) {
462
-			return false;
463
-		}
464
-	}
465
-
466
-	/**
467
-	 * Testable search function that does not need globals
468
-	 *
469
-	 * @param string $search
470
-	 * @param string $itemType
471
-	 * @param array $shareTypes
472
-	 * @param int $page
473
-	 * @param int $perPage
474
-	 * @return \OC_OCS_Result
475
-	 */
476
-	protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage) {
477
-		// Verify arguments
478
-		if ($itemType === null) {
479
-			return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Missing itemType');
480
-		}
481
-
482
-		// Get users
483
-		if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
484
-			$this->getUsers($search);
485
-		}
486
-
487
-		// Get groups
488
-		if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
489
-			$this->getGroups($search);
490
-		}
491
-
492
-		// Get remote
493
-		if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
494
-			$this->getRemote($search);
495
-		}
496
-
497
-		$response = new \OC_OCS_Result($this->result);
498
-		$response->setItemsPerPage($perPage);
499
-
500
-		if (sizeof($this->reachedEndFor) < 3) {
501
-			$response->addHeader('Link', $this->getPaginationLink($page, [
502
-				'search' => $search,
503
-				'itemType' => $itemType,
504
-				'shareType' => $shareTypes,
505
-				'perPage' => $perPage,
506
-			]));
507
-		}
508
-
509
-		return $response;
510
-	}
511
-
512
-	/**
513
-	 * Generates a bunch of pagination links for the current page
514
-	 *
515
-	 * @param int $page Current page
516
-	 * @param array $params Parameters for the URL
517
-	 * @return string
518
-	 */
519
-	protected function getPaginationLink($page, array $params) {
520
-		if ($this->isV2()) {
521
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
522
-		} else {
523
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
524
-		}
525
-		$params['page'] = $page + 1;
526
-		$link = '<' . $url . http_build_query($params) . '>; rel="next"';
527
-
528
-		return $link;
529
-	}
530
-
531
-	/**
532
-	 * @return bool
533
-	 */
534
-	protected function isV2() {
535
-		return $this->request->getScriptName() === '/ocs/v2.php';
536
-	}
42
+    /** @var IGroupManager */
43
+    protected $groupManager;
44
+
45
+    /** @var IUserManager */
46
+    protected $userManager;
47
+
48
+    /** @var IManager */
49
+    protected $contactsManager;
50
+
51
+    /** @var IConfig */
52
+    protected $config;
53
+
54
+    /** @var IUserSession */
55
+    protected $userSession;
56
+
57
+    /** @var IRequest */
58
+    protected $request;
59
+
60
+    /** @var IURLGenerator */
61
+    protected $urlGenerator;
62
+
63
+    /** @var ILogger */
64
+    protected $logger;
65
+
66
+    /** @var \OCP\Share\IManager */
67
+    protected $shareManager;
68
+
69
+    /** @var bool */
70
+    protected $shareWithGroupOnly = false;
71
+
72
+    /** @var bool */
73
+    protected $shareeEnumeration = true;
74
+
75
+    /** @var int */
76
+    protected $offset = 0;
77
+
78
+    /** @var int */
79
+    protected $limit = 10;
80
+
81
+    /** @var array */
82
+    protected $result = [
83
+        'exact' => [
84
+            'users' => [],
85
+            'groups' => [],
86
+            'remotes' => [],
87
+        ],
88
+        'users' => [],
89
+        'groups' => [],
90
+        'remotes' => [],
91
+    ];
92
+
93
+    protected $reachedEndFor = [];
94
+
95
+    /**
96
+     * @param IGroupManager $groupManager
97
+     * @param IUserManager $userManager
98
+     * @param IManager $contactsManager
99
+     * @param IConfig $config
100
+     * @param IUserSession $userSession
101
+     * @param IURLGenerator $urlGenerator
102
+     * @param IRequest $request
103
+     * @param ILogger $logger
104
+     * @param \OCP\Share\IManager $shareManager
105
+     */
106
+    public function __construct(IGroupManager $groupManager,
107
+                                IUserManager $userManager,
108
+                                IManager $contactsManager,
109
+                                IConfig $config,
110
+                                IUserSession $userSession,
111
+                                IURLGenerator $urlGenerator,
112
+                                IRequest $request,
113
+                                ILogger $logger,
114
+                                \OCP\Share\IManager $shareManager) {
115
+        $this->groupManager = $groupManager;
116
+        $this->userManager = $userManager;
117
+        $this->contactsManager = $contactsManager;
118
+        $this->config = $config;
119
+        $this->userSession = $userSession;
120
+        $this->urlGenerator = $urlGenerator;
121
+        $this->request = $request;
122
+        $this->logger = $logger;
123
+        $this->shareManager = $shareManager;
124
+    }
125
+
126
+    /**
127
+     * @param string $search
128
+     */
129
+    protected function getUsers($search) {
130
+        $this->result['users'] = $this->result['exact']['users'] = $users = [];
131
+
132
+        $userGroups = [];
133
+        if ($this->shareWithGroupOnly) {
134
+            // Search in all the groups this user is part of
135
+            $userGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
136
+            foreach ($userGroups as $userGroup) {
137
+                $usersTmp = $this->groupManager->displayNamesInGroup($userGroup, $search, $this->limit, $this->offset);
138
+                foreach ($usersTmp as $uid => $userDisplayName) {
139
+                    $users[$uid] = $userDisplayName;
140
+                }
141
+            }
142
+        } else {
143
+            // Search in all users
144
+            $usersTmp = $this->userManager->searchDisplayName($search, $this->limit, $this->offset);
145
+
146
+            foreach ($usersTmp as $user) {
147
+                $users[$user->getUID()] = $user->getDisplayName();
148
+            }
149
+        }
150
+
151
+        if (!$this->shareeEnumeration || sizeof($users) < $this->limit) {
152
+            $this->reachedEndFor[] = 'users';
153
+        }
154
+
155
+        $foundUserById = false;
156
+        foreach ($users as $uid => $userDisplayName) {
157
+            if (strtolower($uid) === strtolower($search) || strtolower($userDisplayName) === strtolower($search)) {
158
+                if (strtolower($uid) === strtolower($search)) {
159
+                    $foundUserById = true;
160
+                }
161
+                $this->result['exact']['users'][] = [
162
+                    'label' => $userDisplayName,
163
+                    'value' => [
164
+                        'shareType' => Share::SHARE_TYPE_USER,
165
+                        'shareWith' => $uid,
166
+                    ],
167
+                ];
168
+            } else {
169
+                $this->result['users'][] = [
170
+                    'label' => $userDisplayName,
171
+                    'value' => [
172
+                        'shareType' => Share::SHARE_TYPE_USER,
173
+                        'shareWith' => $uid,
174
+                    ],
175
+                ];
176
+            }
177
+        }
178
+
179
+        if ($this->offset === 0 && !$foundUserById) {
180
+            // On page one we try if the search result has a direct hit on the
181
+            // user id and if so, we add that to the exact match list
182
+            $user = $this->userManager->get($search);
183
+            if ($user instanceof IUser) {
184
+                $addUser = true;
185
+
186
+                if ($this->shareWithGroupOnly) {
187
+                    // Only add, if we have a common group
188
+                    $commonGroups = array_intersect($userGroups, $this->groupManager->getUserGroupIds($user));
189
+                    $addUser = !empty($commonGroups);
190
+                }
191
+
192
+                if ($addUser) {
193
+                    array_push($this->result['exact']['users'], [
194
+                        'label' => $user->getDisplayName(),
195
+                        'value' => [
196
+                            'shareType' => Share::SHARE_TYPE_USER,
197
+                            'shareWith' => $user->getUID(),
198
+                        ],
199
+                    ]);
200
+                }
201
+            }
202
+        }
203
+
204
+        if (!$this->shareeEnumeration) {
205
+            $this->result['users'] = [];
206
+        }
207
+    }
208
+
209
+    /**
210
+     * @param string $search
211
+     */
212
+    protected function getGroups($search) {
213
+        $this->result['groups'] = $this->result['exact']['groups'] = [];
214
+
215
+        $groups = $this->groupManager->search($search, $this->limit, $this->offset);
216
+        $groups = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
217
+
218
+        if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
219
+            $this->reachedEndFor[] = 'groups';
220
+        }
221
+
222
+        $userGroups =  [];
223
+        if (!empty($groups) && $this->shareWithGroupOnly) {
224
+            // Intersect all the groups that match with the groups this user is a member of
225
+            $userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
226
+            $userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
227
+            $groups = array_intersect($groups, $userGroups);
228
+        }
229
+
230
+        foreach ($groups as $gid) {
231
+            if (strtolower($gid) === strtolower($search)) {
232
+                $this->result['exact']['groups'][] = [
233
+                    'label' => $gid,
234
+                    'value' => [
235
+                        'shareType' => Share::SHARE_TYPE_GROUP,
236
+                        'shareWith' => $gid,
237
+                    ],
238
+                ];
239
+            } else {
240
+                $this->result['groups'][] = [
241
+                    'label' => $gid,
242
+                    'value' => [
243
+                        'shareType' => Share::SHARE_TYPE_GROUP,
244
+                        'shareWith' => $gid,
245
+                    ],
246
+                ];
247
+            }
248
+        }
249
+
250
+        if ($this->offset === 0 && empty($this->result['exact']['groups'])) {
251
+            // On page one we try if the search result has a direct hit on the
252
+            // user id and if so, we add that to the exact match list
253
+            $group = $this->groupManager->get($search);
254
+            if ($group instanceof IGroup && (!$this->shareWithGroupOnly || in_array($group->getGID(), $userGroups))) {
255
+                array_push($this->result['exact']['groups'], [
256
+                    'label' => $group->getGID(),
257
+                    'value' => [
258
+                        'shareType' => Share::SHARE_TYPE_GROUP,
259
+                        'shareWith' => $group->getGID(),
260
+                    ],
261
+                ]);
262
+            }
263
+        }
264
+
265
+        if (!$this->shareeEnumeration) {
266
+            $this->result['groups'] = [];
267
+        }
268
+    }
269
+
270
+    /**
271
+     * @param string $search
272
+     * @return array possible sharees
273
+     */
274
+    protected function getRemote($search) {
275
+        $this->result['remotes'] = [];
276
+
277
+        // Search in contacts
278
+        //@todo Pagination missing
279
+        $addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
280
+        $foundRemoteById = false;
281
+        foreach ($addressBookContacts as $contact) {
282
+            if (isset($contact['isLocalSystemBook'])) {
283
+                continue;
284
+            }
285
+            if (isset($contact['CLOUD'])) {
286
+                $cloudIds = $contact['CLOUD'];
287
+                if (!is_array($cloudIds)) {
288
+                    $cloudIds = [$cloudIds];
289
+                }
290
+                foreach ($cloudIds as $cloudId) {
291
+                    list(, $serverUrl) = $this->splitUserRemote($cloudId);
292
+                    if (strtolower($contact['FN']) === strtolower($search) || strtolower($cloudId) === strtolower($search)) {
293
+                        if (strtolower($cloudId) === strtolower($search)) {
294
+                            $foundRemoteById = true;
295
+                        }
296
+                        $this->result['exact']['remotes'][] = [
297
+                            'label' => $contact['FN'],
298
+                            'value' => [
299
+                                'shareType' => Share::SHARE_TYPE_REMOTE,
300
+                                'shareWith' => $cloudId,
301
+                                'server' => $serverUrl,
302
+                            ],
303
+                        ];
304
+                    } else {
305
+                        $this->result['remotes'][] = [
306
+                            'label' => $contact['FN'],
307
+                            'value' => [
308
+                                'shareType' => Share::SHARE_TYPE_REMOTE,
309
+                                'shareWith' => $cloudId,
310
+                                'server' => $serverUrl,
311
+                            ],
312
+                        ];
313
+                    }
314
+                }
315
+            }
316
+        }
317
+
318
+        if (!$this->shareeEnumeration) {
319
+            $this->result['remotes'] = [];
320
+        }
321
+
322
+        if (!$foundRemoteById && substr_count($search, '@') >= 1 && $this->offset === 0) {
323
+            $this->result['exact']['remotes'][] = [
324
+                'label' => $search,
325
+                'value' => [
326
+                    'shareType' => Share::SHARE_TYPE_REMOTE,
327
+                    'shareWith' => $search,
328
+                ],
329
+            ];
330
+        }
331
+
332
+        $this->reachedEndFor[] = 'remotes';
333
+    }
334
+
335
+    /**
336
+     * split user and remote from federated cloud id
337
+     *
338
+     * @param string $address federated share address
339
+     * @return array [user, remoteURL]
340
+     * @throws \Exception
341
+     */
342
+    public function splitUserRemote($address) {
343
+        if (strpos($address, '@') === false) {
344
+            throw new \Exception('Invalid Federated Cloud ID');
345
+        }
346
+
347
+        // Find the first character that is not allowed in user names
348
+        $id = str_replace('\\', '/', $address);
349
+        $posSlash = strpos($id, '/');
350
+        $posColon = strpos($id, ':');
351
+
352
+        if ($posSlash === false && $posColon === false) {
353
+            $invalidPos = strlen($id);
354
+        } else if ($posSlash === false) {
355
+            $invalidPos = $posColon;
356
+        } else if ($posColon === false) {
357
+            $invalidPos = $posSlash;
358
+        } else {
359
+            $invalidPos = min($posSlash, $posColon);
360
+        }
361
+
362
+        // Find the last @ before $invalidPos
363
+        $pos = $lastAtPos = 0;
364
+        while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
365
+            $pos = $lastAtPos;
366
+            $lastAtPos = strpos($id, '@', $pos + 1);
367
+        }
368
+
369
+        if ($pos !== false) {
370
+            $user = substr($id, 0, $pos);
371
+            $remote = substr($id, $pos + 1);
372
+            $remote = $this->fixRemoteURL($remote);
373
+            if (!empty($user) && !empty($remote)) {
374
+                return array($user, $remote);
375
+            }
376
+        }
377
+
378
+        throw new \Exception('Invalid Federated Cloud ID');
379
+    }
380
+
381
+    /**
382
+     * Strips away a potential file names and trailing slashes:
383
+     * - http://localhost
384
+     * - http://localhost/
385
+     * - http://localhost/index.php
386
+     * - http://localhost/index.php/s/{shareToken}
387
+     *
388
+     * all return: http://localhost
389
+     *
390
+     * @param string $remote
391
+     * @return string
392
+     */
393
+    protected function fixRemoteURL($remote) {
394
+        $remote = str_replace('\\', '/', $remote);
395
+        if ($fileNamePosition = strpos($remote, '/index.php')) {
396
+            $remote = substr($remote, 0, $fileNamePosition);
397
+        }
398
+        $remote = rtrim($remote, '/');
399
+
400
+        return $remote;
401
+    }
402
+
403
+    /**
404
+     * @return \OC_OCS_Result
405
+     */
406
+    public function search() {
407
+        $search = isset($_GET['search']) ? (string) $_GET['search'] : '';
408
+        $itemType = isset($_GET['itemType']) ? (string) $_GET['itemType'] : null;
409
+        $page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
410
+        $perPage = isset($_GET['perPage']) ? (int) $_GET['perPage'] : 200;
411
+
412
+        if ($perPage <= 0) {
413
+            return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Invalid perPage argument');
414
+        }
415
+        if ($page <= 0) {
416
+            return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Invalid page');
417
+        }
418
+
419
+        $shareTypes = [
420
+            Share::SHARE_TYPE_USER,
421
+        ];
422
+
423
+        if ($this->shareManager->allowGroupSharing()) {
424
+            $shareTypes[] = Share::SHARE_TYPE_GROUP;
425
+        }
426
+
427
+        $shareTypes[] = Share::SHARE_TYPE_REMOTE;
428
+
429
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
430
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
431
+            sort($shareTypes);
432
+
433
+        } else if (isset($_GET['shareType']) && is_numeric($_GET['shareType'])) {
434
+            $shareTypes = array_intersect($shareTypes, [(int) $_GET['shareType']]);
435
+            sort($shareTypes);
436
+        }
437
+
438
+        if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes) && !$this->isRemoteSharingAllowed($itemType)) {
439
+            // Remove remote shares from type array, because it is not allowed.
440
+            $shareTypes = array_diff($shareTypes, [Share::SHARE_TYPE_REMOTE]);
441
+        }
442
+
443
+        $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
444
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
445
+        $this->limit = (int) $perPage;
446
+        $this->offset = $perPage * ($page - 1);
447
+
448
+        return $this->searchSharees($search, $itemType, $shareTypes, $page, $perPage);
449
+    }
450
+
451
+    /**
452
+     * Method to get out the static call for better testing
453
+     *
454
+     * @param string $itemType
455
+     * @return bool
456
+     */
457
+    protected function isRemoteSharingAllowed($itemType) {
458
+        try {
459
+            $backend = Share::getBackend($itemType);
460
+            return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
461
+        } catch (\Exception $e) {
462
+            return false;
463
+        }
464
+    }
465
+
466
+    /**
467
+     * Testable search function that does not need globals
468
+     *
469
+     * @param string $search
470
+     * @param string $itemType
471
+     * @param array $shareTypes
472
+     * @param int $page
473
+     * @param int $perPage
474
+     * @return \OC_OCS_Result
475
+     */
476
+    protected function searchSharees($search, $itemType, array $shareTypes, $page, $perPage) {
477
+        // Verify arguments
478
+        if ($itemType === null) {
479
+            return new \OC_OCS_Result(null, Http::STATUS_BAD_REQUEST, 'Missing itemType');
480
+        }
481
+
482
+        // Get users
483
+        if (in_array(Share::SHARE_TYPE_USER, $shareTypes)) {
484
+            $this->getUsers($search);
485
+        }
486
+
487
+        // Get groups
488
+        if (in_array(Share::SHARE_TYPE_GROUP, $shareTypes)) {
489
+            $this->getGroups($search);
490
+        }
491
+
492
+        // Get remote
493
+        if (in_array(Share::SHARE_TYPE_REMOTE, $shareTypes)) {
494
+            $this->getRemote($search);
495
+        }
496
+
497
+        $response = new \OC_OCS_Result($this->result);
498
+        $response->setItemsPerPage($perPage);
499
+
500
+        if (sizeof($this->reachedEndFor) < 3) {
501
+            $response->addHeader('Link', $this->getPaginationLink($page, [
502
+                'search' => $search,
503
+                'itemType' => $itemType,
504
+                'shareType' => $shareTypes,
505
+                'perPage' => $perPage,
506
+            ]));
507
+        }
508
+
509
+        return $response;
510
+    }
511
+
512
+    /**
513
+     * Generates a bunch of pagination links for the current page
514
+     *
515
+     * @param int $page Current page
516
+     * @param array $params Parameters for the URL
517
+     * @return string
518
+     */
519
+    protected function getPaginationLink($page, array $params) {
520
+        if ($this->isV2()) {
521
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
522
+        } else {
523
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
524
+        }
525
+        $params['page'] = $page + 1;
526
+        $link = '<' . $url . http_build_query($params) . '>; rel="next"';
527
+
528
+        return $link;
529
+    }
530
+
531
+    /**
532
+     * @return bool
533
+     */
534
+    protected function isV2() {
535
+        return $this->request->getScriptName() === '/ocs/v2.php';
536
+    }
537 537
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -213,17 +213,17 @@  discard block
 block discarded – undo
213 213
 		$this->result['groups'] = $this->result['exact']['groups'] = [];
214 214
 
215 215
 		$groups = $this->groupManager->search($search, $this->limit, $this->offset);
216
-		$groups = array_map(function (IGroup $group) { return $group->getGID(); }, $groups);
216
+		$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
217 217
 
218 218
 		if (!$this->shareeEnumeration || sizeof($groups) < $this->limit) {
219 219
 			$this->reachedEndFor[] = 'groups';
220 220
 		}
221 221
 
222
-		$userGroups =  [];
222
+		$userGroups = [];
223 223
 		if (!empty($groups) && $this->shareWithGroupOnly) {
224 224
 			// Intersect all the groups that match with the groups this user is a member of
225 225
 			$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
226
-			$userGroups = array_map(function (IGroup $group) { return $group->getGID(); }, $userGroups);
226
+			$userGroups = array_map(function(IGroup $group) { return $group->getGID(); }, $userGroups);
227 227
 			$groups = array_intersect($groups, $userGroups);
228 228
 		}
229 229
 
@@ -518,12 +518,12 @@  discard block
 block discarded – undo
518 518
 	 */
519 519
 	protected function getPaginationLink($page, array $params) {
520 520
 		if ($this->isV2()) {
521
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
521
+			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees').'?';
522 522
 		} else {
523
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
523
+			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees').'?';
524 524
 		}
525 525
 		$params['page'] = $page + 1;
526
-		$link = '<' . $url . http_build_query($params) . '>; rel="next"';
526
+		$link = '<'.$url.http_build_query($params).'>; rel="next"';
527 527
 
528 528
 		return $link;
529 529
 	}
Please login to merge, or discard this patch.
apps/files_sharing/lib/Migration.php 3 patches
Doc Comments   -1 removed lines patch added patch discarded remove patch
@@ -130,7 +130,6 @@
 block discarded – undo
130 130
 	/**
131 131
 	 * Get $n re-shares from the database
132 132
 	 *
133
-	 * @param int $n The max number of shares to fetch
134 133
 	 * @return \Doctrine\DBAL\Driver\Statement
135 134
 	 */
136 135
 	private function getReShares() {
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 		$stmt = $this->getReShares();
69 69
 
70 70
 		$owners = [];
71
-		while($share = $stmt->fetch()) {
71
+		while ($share = $stmt->fetch()) {
72 72
 
73 73
 			$this->shareCache[$share['id']] = $share;
74 74
 
@@ -131,11 +131,11 @@  discard block
 block discarded – undo
131 131
 	 */
132 132
 	private function findOwner($share) {
133 133
 		$currentShare = $share;
134
-		while(!is_null($currentShare['parent'])) {
134
+		while (!is_null($currentShare['parent'])) {
135 135
 			if (isset($this->shareCache[$currentShare['parent']])) {
136 136
 				$currentShare = $this->shareCache[$currentShare['parent']];
137 137
 			} else {
138
-				$currentShare = $this->getShare((int)$currentShare['parent']);
138
+				$currentShare = $this->getShare((int) $currentShare['parent']);
139 139
 				$this->shareCache[$currentShare['id']] = $currentShare;
140 140
 			}
141 141
 		}
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
 
183 183
 		$ordered = [];
184 184
 		foreach ($shares as $share) {
185
-			$ordered[(int)$share['id']] = $share;
185
+			$ordered[(int) $share['id']] = $share;
186 186
 		}
187 187
 
188 188
 		return $ordered;
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
 
227 227
 		$ordered = [];
228 228
 		foreach ($shares as $share) {
229
-			$ordered[(int)$share['id']] = $share;
229
+			$ordered[(int) $share['id']] = $share;
230 230
 		}
231 231
 
232 232
 		return $ordered;
@@ -269,7 +269,7 @@  discard block
 block discarded – undo
269 269
 					->set('uid_initiator', $query->createNamedParameter($owner['initiator']));
270 270
 
271 271
 
272
-				if ((int)$owner['type'] !== \OCP\Share::SHARE_TYPE_LINK) {
272
+				if ((int) $owner['type'] !== \OCP\Share::SHARE_TYPE_LINK) {
273 273
 					$query->set('parent', $query->createNamedParameter(null));
274 274
 				}
275 275
 
Please login to merge, or discard this patch.
Indentation   +235 added lines, -235 removed lines patch added patch discarded remove patch
@@ -38,240 +38,240 @@
 block discarded – undo
38 38
  */
39 39
 class Migration {
40 40
 
41
-	/** @var IDBConnection */
42
-	private $connection;
43
-
44
-	/** @var  ICache with all shares we already saw */
45
-	private $shareCache;
46
-
47
-	/** @var string */
48
-	private $table = 'share';
49
-
50
-	public function __construct(IDBConnection $connection) {
51
-		$this->connection = $connection;
52
-
53
-		// We cache up to 10k share items (~20MB)
54
-		$this->shareCache = new CappedMemoryCache(10000);
55
-	}
56
-
57
-	/**
58
-	 * move all re-shares to the owner in order to have a flat list of shares
59
-	 * upgrade from oC 8.2 to 9.0 with the new sharing
60
-	 */
61
-	public function removeReShares() {
62
-
63
-		$stmt = $this->getReShares();
64
-
65
-		$owners = [];
66
-		while($share = $stmt->fetch()) {
67
-
68
-			$this->shareCache[$share['id']] = $share;
69
-
70
-			$owners[$share['id']] = [
71
-					'owner' => $this->findOwner($share),
72
-					'initiator' => $share['uid_owner'],
73
-					'type' => $share['share_type'],
74
-			];
75
-
76
-			if (count($owners) === 1000) {
77
-				$this->updateOwners($owners);
78
-				$owners = [];
79
-			}
80
-		}
81
-
82
-		$stmt->closeCursor();
83
-
84
-		if (count($owners)) {
85
-			$this->updateOwners($owners);
86
-		}
87
-	}
88
-
89
-	/**
90
-	 * update all owner information so that all shares have an owner
91
-	 * and an initiator for the upgrade from oC 8.2 to 9.0 with the new sharing
92
-	 */
93
-	public function updateInitiatorInfo() {
94
-		while (true) {
95
-			$shares = $this->getMissingInitiator(1000);
96
-
97
-			if (empty($shares)) {
98
-				break;
99
-			}
100
-
101
-			$owners = [];
102
-			foreach ($shares as $share) {
103
-				$owners[$share['id']] = [
104
-					'owner' => $share['uid_owner'],
105
-					'initiator' => $share['uid_owner'],
106
-					'type' => $share['share_type'],
107
-				];
108
-			}
109
-			$this->updateOwners($owners);
110
-		}
111
-	}
112
-
113
-	/**
114
-	 * find the owner of a re-shared file/folder
115
-	 *
116
-	 * @param array $share
117
-	 * @return array
118
-	 */
119
-	private function findOwner($share) {
120
-		$currentShare = $share;
121
-		while(!is_null($currentShare['parent'])) {
122
-			if (isset($this->shareCache[$currentShare['parent']])) {
123
-				$currentShare = $this->shareCache[$currentShare['parent']];
124
-			} else {
125
-				$currentShare = $this->getShare((int)$currentShare['parent']);
126
-				$this->shareCache[$currentShare['id']] = $currentShare;
127
-			}
128
-		}
129
-
130
-		return $currentShare['uid_owner'];
131
-	}
132
-
133
-	/**
134
-	 * Get $n re-shares from the database
135
-	 *
136
-	 * @param int $n The max number of shares to fetch
137
-	 * @return \Doctrine\DBAL\Driver\Statement
138
-	 */
139
-	private function getReShares() {
140
-		$query = $this->connection->getQueryBuilder();
141
-		$query->select(['id', 'parent', 'uid_owner', 'share_type'])
142
-			->from($this->table)
143
-			->where($query->expr()->in(
144
-				'share_type',
145
-				$query->createNamedParameter(
146
-					[
147
-						\OCP\Share::SHARE_TYPE_USER,
148
-						\OCP\Share::SHARE_TYPE_GROUP,
149
-						\OCP\Share::SHARE_TYPE_LINK,
150
-						\OCP\Share::SHARE_TYPE_REMOTE,
151
-					],
152
-					Connection::PARAM_INT_ARRAY
153
-				)
154
-			))
155
-			->andWhere($query->expr()->in(
156
-				'item_type',
157
-				$query->createNamedParameter(
158
-					['file', 'folder'],
159
-					Connection::PARAM_STR_ARRAY
160
-				)
161
-			))
162
-			->andWhere($query->expr()->isNotNull('parent'))
163
-			->orderBy('id', 'asc');
164
-		return $query->execute();
165
-
166
-
167
-		$shares = $result->fetchAll();
168
-		$result->closeCursor();
169
-
170
-		$ordered = [];
171
-		foreach ($shares as $share) {
172
-			$ordered[(int)$share['id']] = $share;
173
-		}
174
-
175
-		return $ordered;
176
-	}
177
-
178
-	/**
179
-	 * Get $n re-shares from the database
180
-	 *
181
-	 * @param int $n The max number of shares to fetch
182
-	 * @return array
183
-	 */
184
-	private function getMissingInitiator($n = 1000) {
185
-		$query = $this->connection->getQueryBuilder();
186
-		$query->select(['id', 'uid_owner', 'share_type'])
187
-			->from($this->table)
188
-			->where($query->expr()->in(
189
-				'share_type',
190
-				$query->createNamedParameter(
191
-					[
192
-						\OCP\Share::SHARE_TYPE_USER,
193
-						\OCP\Share::SHARE_TYPE_GROUP,
194
-						\OCP\Share::SHARE_TYPE_LINK,
195
-						\OCP\Share::SHARE_TYPE_REMOTE,
196
-					],
197
-					Connection::PARAM_INT_ARRAY
198
-				)
199
-			))
200
-			->andWhere($query->expr()->in(
201
-				'item_type',
202
-				$query->createNamedParameter(
203
-					['file', 'folder'],
204
-					Connection::PARAM_STR_ARRAY
205
-				)
206
-			))
207
-			->andWhere($query->expr()->isNull('uid_initiator'))
208
-			->orderBy('id', 'asc')
209
-			->setMaxResults($n);
210
-		$result = $query->execute();
211
-		$shares = $result->fetchAll();
212
-		$result->closeCursor();
213
-
214
-		$ordered = [];
215
-		foreach ($shares as $share) {
216
-			$ordered[(int)$share['id']] = $share;
217
-		}
218
-
219
-		return $ordered;
220
-	}
221
-
222
-	/**
223
-	 * get a specific share
224
-	 *
225
-	 * @param int $id
226
-	 * @return array
227
-	 */
228
-	private function getShare($id) {
229
-		$query = $this->connection->getQueryBuilder();
230
-		$query->select(['id', 'parent', 'uid_owner'])
231
-			->from($this->table)
232
-			->where($query->expr()->eq('id', $query->createNamedParameter($id)));
233
-		$result = $query->execute();
234
-		$share = $result->fetchAll();
235
-		$result->closeCursor();
236
-
237
-		return $share[0];
238
-	}
239
-
240
-	/**
241
-	 * update database with the new owners
242
-	 *
243
-	 * @param array $owners
244
-	 * @throws \Exception
245
-	 */
246
-	private function updateOwners($owners) {
247
-
248
-		$this->connection->beginTransaction();
249
-
250
-		try {
251
-
252
-			foreach ($owners as $id => $owner) {
253
-				$query = $this->connection->getQueryBuilder();
254
-				$query->update($this->table)
255
-					->set('uid_owner', $query->createNamedParameter($owner['owner']))
256
-					->set('uid_initiator', $query->createNamedParameter($owner['initiator']));
257
-
258
-
259
-				if ((int)$owner['type'] !== \OCP\Share::SHARE_TYPE_LINK) {
260
-					$query->set('parent', $query->createNamedParameter(null));
261
-				}
262
-
263
-				$query->where($query->expr()->eq('id', $query->createNamedParameter($id)));
264
-
265
-				$query->execute();
266
-			}
267
-
268
-			$this->connection->commit();
269
-
270
-		} catch (\Exception $e) {
271
-			$this->connection->rollBack();
272
-			throw $e;
273
-		}
274
-
275
-	}
41
+    /** @var IDBConnection */
42
+    private $connection;
43
+
44
+    /** @var  ICache with all shares we already saw */
45
+    private $shareCache;
46
+
47
+    /** @var string */
48
+    private $table = 'share';
49
+
50
+    public function __construct(IDBConnection $connection) {
51
+        $this->connection = $connection;
52
+
53
+        // We cache up to 10k share items (~20MB)
54
+        $this->shareCache = new CappedMemoryCache(10000);
55
+    }
56
+
57
+    /**
58
+     * move all re-shares to the owner in order to have a flat list of shares
59
+     * upgrade from oC 8.2 to 9.0 with the new sharing
60
+     */
61
+    public function removeReShares() {
62
+
63
+        $stmt = $this->getReShares();
64
+
65
+        $owners = [];
66
+        while($share = $stmt->fetch()) {
67
+
68
+            $this->shareCache[$share['id']] = $share;
69
+
70
+            $owners[$share['id']] = [
71
+                    'owner' => $this->findOwner($share),
72
+                    'initiator' => $share['uid_owner'],
73
+                    'type' => $share['share_type'],
74
+            ];
75
+
76
+            if (count($owners) === 1000) {
77
+                $this->updateOwners($owners);
78
+                $owners = [];
79
+            }
80
+        }
81
+
82
+        $stmt->closeCursor();
83
+
84
+        if (count($owners)) {
85
+            $this->updateOwners($owners);
86
+        }
87
+    }
88
+
89
+    /**
90
+     * update all owner information so that all shares have an owner
91
+     * and an initiator for the upgrade from oC 8.2 to 9.0 with the new sharing
92
+     */
93
+    public function updateInitiatorInfo() {
94
+        while (true) {
95
+            $shares = $this->getMissingInitiator(1000);
96
+
97
+            if (empty($shares)) {
98
+                break;
99
+            }
100
+
101
+            $owners = [];
102
+            foreach ($shares as $share) {
103
+                $owners[$share['id']] = [
104
+                    'owner' => $share['uid_owner'],
105
+                    'initiator' => $share['uid_owner'],
106
+                    'type' => $share['share_type'],
107
+                ];
108
+            }
109
+            $this->updateOwners($owners);
110
+        }
111
+    }
112
+
113
+    /**
114
+     * find the owner of a re-shared file/folder
115
+     *
116
+     * @param array $share
117
+     * @return array
118
+     */
119
+    private function findOwner($share) {
120
+        $currentShare = $share;
121
+        while(!is_null($currentShare['parent'])) {
122
+            if (isset($this->shareCache[$currentShare['parent']])) {
123
+                $currentShare = $this->shareCache[$currentShare['parent']];
124
+            } else {
125
+                $currentShare = $this->getShare((int)$currentShare['parent']);
126
+                $this->shareCache[$currentShare['id']] = $currentShare;
127
+            }
128
+        }
129
+
130
+        return $currentShare['uid_owner'];
131
+    }
132
+
133
+    /**
134
+     * Get $n re-shares from the database
135
+     *
136
+     * @param int $n The max number of shares to fetch
137
+     * @return \Doctrine\DBAL\Driver\Statement
138
+     */
139
+    private function getReShares() {
140
+        $query = $this->connection->getQueryBuilder();
141
+        $query->select(['id', 'parent', 'uid_owner', 'share_type'])
142
+            ->from($this->table)
143
+            ->where($query->expr()->in(
144
+                'share_type',
145
+                $query->createNamedParameter(
146
+                    [
147
+                        \OCP\Share::SHARE_TYPE_USER,
148
+                        \OCP\Share::SHARE_TYPE_GROUP,
149
+                        \OCP\Share::SHARE_TYPE_LINK,
150
+                        \OCP\Share::SHARE_TYPE_REMOTE,
151
+                    ],
152
+                    Connection::PARAM_INT_ARRAY
153
+                )
154
+            ))
155
+            ->andWhere($query->expr()->in(
156
+                'item_type',
157
+                $query->createNamedParameter(
158
+                    ['file', 'folder'],
159
+                    Connection::PARAM_STR_ARRAY
160
+                )
161
+            ))
162
+            ->andWhere($query->expr()->isNotNull('parent'))
163
+            ->orderBy('id', 'asc');
164
+        return $query->execute();
165
+
166
+
167
+        $shares = $result->fetchAll();
168
+        $result->closeCursor();
169
+
170
+        $ordered = [];
171
+        foreach ($shares as $share) {
172
+            $ordered[(int)$share['id']] = $share;
173
+        }
174
+
175
+        return $ordered;
176
+    }
177
+
178
+    /**
179
+     * Get $n re-shares from the database
180
+     *
181
+     * @param int $n The max number of shares to fetch
182
+     * @return array
183
+     */
184
+    private function getMissingInitiator($n = 1000) {
185
+        $query = $this->connection->getQueryBuilder();
186
+        $query->select(['id', 'uid_owner', 'share_type'])
187
+            ->from($this->table)
188
+            ->where($query->expr()->in(
189
+                'share_type',
190
+                $query->createNamedParameter(
191
+                    [
192
+                        \OCP\Share::SHARE_TYPE_USER,
193
+                        \OCP\Share::SHARE_TYPE_GROUP,
194
+                        \OCP\Share::SHARE_TYPE_LINK,
195
+                        \OCP\Share::SHARE_TYPE_REMOTE,
196
+                    ],
197
+                    Connection::PARAM_INT_ARRAY
198
+                )
199
+            ))
200
+            ->andWhere($query->expr()->in(
201
+                'item_type',
202
+                $query->createNamedParameter(
203
+                    ['file', 'folder'],
204
+                    Connection::PARAM_STR_ARRAY
205
+                )
206
+            ))
207
+            ->andWhere($query->expr()->isNull('uid_initiator'))
208
+            ->orderBy('id', 'asc')
209
+            ->setMaxResults($n);
210
+        $result = $query->execute();
211
+        $shares = $result->fetchAll();
212
+        $result->closeCursor();
213
+
214
+        $ordered = [];
215
+        foreach ($shares as $share) {
216
+            $ordered[(int)$share['id']] = $share;
217
+        }
218
+
219
+        return $ordered;
220
+    }
221
+
222
+    /**
223
+     * get a specific share
224
+     *
225
+     * @param int $id
226
+     * @return array
227
+     */
228
+    private function getShare($id) {
229
+        $query = $this->connection->getQueryBuilder();
230
+        $query->select(['id', 'parent', 'uid_owner'])
231
+            ->from($this->table)
232
+            ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
233
+        $result = $query->execute();
234
+        $share = $result->fetchAll();
235
+        $result->closeCursor();
236
+
237
+        return $share[0];
238
+    }
239
+
240
+    /**
241
+     * update database with the new owners
242
+     *
243
+     * @param array $owners
244
+     * @throws \Exception
245
+     */
246
+    private function updateOwners($owners) {
247
+
248
+        $this->connection->beginTransaction();
249
+
250
+        try {
251
+
252
+            foreach ($owners as $id => $owner) {
253
+                $query = $this->connection->getQueryBuilder();
254
+                $query->update($this->table)
255
+                    ->set('uid_owner', $query->createNamedParameter($owner['owner']))
256
+                    ->set('uid_initiator', $query->createNamedParameter($owner['initiator']));
257
+
258
+
259
+                if ((int)$owner['type'] !== \OCP\Share::SHARE_TYPE_LINK) {
260
+                    $query->set('parent', $query->createNamedParameter(null));
261
+                }
262
+
263
+                $query->where($query->expr()->eq('id', $query->createNamedParameter($id)));
264
+
265
+                $query->execute();
266
+            }
267
+
268
+            $this->connection->commit();
269
+
270
+        } catch (\Exception $e) {
271
+            $this->connection->rollBack();
272
+            throw $e;
273
+        }
274
+
275
+    }
276 276
 
277 277
 }
Please login to merge, or discard this patch.
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.
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.
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 ($user->getLastLogin() === 0 || !$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 ($user->getLastLogin() === 0 || !$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.
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, true, false, true);
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, true, false, true);
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, true, false, true);
154
+		$normalized = Filesystem::normalizePath($this->mountPoint.'/'.$path, true, false, true);
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.