Completed
Push — master ( 0cff70...dba08f )
by Morris
09:32
created

AmazonS3   D

Complexity

Total Complexity 110

Size/Duplication

Total Lines 589
Duplicated Lines 4.41 %

Coupling/Cohesion

Components 2
Dependencies 10

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 110
lcom 2
cbo 10
dl 26
loc 589
rs 4.8717
c 1
b 1
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A normalizePath() 0 9 2
A testTimeout() 0 5 2
A isRoot() 0 3 1
A cleanKey() 0 6 2
B __construct() 0 19 11
B updateLegacyId() 0 24 5
A remove() 0 11 3
A mkdir() 0 22 3
A file_exists() 0 3 1
A rmdir() 0 13 3
A clearBucket() 0 10 2
B batchDelete() 0 27 4
C opendir() 0 34 7
B stat() 0 30 5
B filetype() 0 21 5
A unlink() 0 20 3
C fopen() 15 50 18
B touch() 0 44 6
C copy() 11 47 7
B rename() 0 28 6
A test() 0 9 3
A getId() 0 3 1
B getConnection() 0 41 6
A writeBack() 0 21 3
A checkDependencies() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AmazonS3 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AmazonS3, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @author André Gaul <[email protected]>
4
 * @author Arthur Schiwon <[email protected]>
5
 * @author Bart Visscher <[email protected]>
6
 * @author Christian Berendt <[email protected]>
7
 * @author Christopher T. Johnson <[email protected]>
8
 * @author Johan Björk <[email protected]>
9
 * @author Jörn Friedrich Dreyer <[email protected]>
10
 * @author Martin Mattel <[email protected]>
11
 * @author Michael Gapczynski <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Philipp Kapfer <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Robin McCorkell <[email protected]>
16
 * @author Thomas Müller <[email protected]>
17
 * @author Vincent Petry <[email protected]>
18
 *
19
 * @copyright Copyright (c) 2016, ownCloud, Inc.
20
 * @license AGPL-3.0
21
 *
22
 * This code is free software: you can redistribute it and/or modify
23
 * it under the terms of the GNU Affero General Public License, version 3,
24
 * as published by the Free Software Foundation.
25
 *
26
 * This program is distributed in the hope that it will be useful,
27
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29
 * GNU Affero General Public License for more details.
30
 *
31
 * You should have received a copy of the GNU Affero General Public License, version 3,
32
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
33
 *
34
 */
35
36
namespace OCA\Files_External\Lib\Storage;
37
38
set_include_path(get_include_path() . PATH_SEPARATOR .
39
	\OC_App::getAppPath('files_external') . '/3rdparty/aws-sdk-php');
40
require 'aws-autoloader.php';
41
42
use Aws\S3\S3Client;
43
use Aws\S3\Exception\S3Exception;
44
use Icewind\Streams\IteratorDirectory;
45
46
class AmazonS3 extends \OC\Files\Storage\Common {
47
48
	/**
49
	 * @var \Aws\S3\S3Client
50
	 */
51
	private $connection;
52
	/**
53
	 * @var string
54
	 */
55
	private $bucket;
56
	/**
57
	 * @var array
58
	 */
59
	private static $tmpFiles = array();
60
	/**
61
	 * @var array
62
	 */
63
	private $params;
64
	/**
65
	 * @var bool
66
	 */
67
	private $test = false;
68
	/**
69
	 * @var int
70
	 */
71
	private $timeout = 15;
72
	/**
73
	 * @var int in seconds
74
	 */
75
	private $rescanDelay = 10;
76
77
	/**
78
	 * @param string $path
79
	 * @return string correctly encoded path
80
	 */
81
	private function normalizePath($path) {
82
		$path = trim($path, '/');
83
84
		if (!$path) {
85
			$path = '.';
86
		}
87
88
		return $path;
89
	}
90
91
	/**
92
	 * when running the tests wait to let the buckets catch up
93
	 */
94
	private function testTimeout() {
95
		if ($this->test) {
96
			sleep($this->timeout);
97
		}
98
	}
99
100
	private function isRoot($path) {
101
		return $path === '.';
102
	}
103
104
	private function cleanKey($path) {
105
		if ($this->isRoot($path)) {
106
			return '/';
107
		}
108
		return $path;
109
	}
110
111
	public function __construct($params) {
112
		if (empty($params['key']) || empty($params['secret']) || empty($params['bucket'])) {
113
			throw new \Exception("Access Key, Secret and Bucket have to be configured.");
114
		}
115
116
		$this->id = 'amazon::' . $params['bucket'];
0 ignored issues
show
Bug introduced by
The property id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
117
		$this->updateLegacyId($params);
118
119
		$this->bucket = $params['bucket'];
120
		$this->test = isset($params['test']);
121
		$this->timeout = (!isset($params['timeout'])) ? 15 : $params['timeout'];
122
		$this->rescanDelay = (!isset($params['rescanDelay'])) ? 10 : $params['rescanDelay'];
123
		$params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
124
		$params['hostname'] = empty($params['hostname']) ? 's3.amazonaws.com' : $params['hostname'];
125
		if (!isset($params['port']) || $params['port'] === '') {
126
			$params['port'] = ($params['use_ssl'] === false) ? 80 : 443;
127
		}
128
		$this->params = $params;
129
	}
130
131
	/**
132
	 * Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
133
	 * TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
134
	 *
135
	 * @param array $params
136
	 */
137
	public function updateLegacyId (array $params) {
138
		$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
139
140
		// find by old id or bucket
141
		$stmt = \OC::$server->getDatabaseConnection()->prepare(
142
			'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
143
		);
144
		$stmt->execute(array($oldId, $this->id));
145
		while ($row = $stmt->fetch()) {
146
			$storages[$row['id']] = $row['numeric_id'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$storages was never initialized. Although not strictly required by PHP, it is generally a good practice to add $storages = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
147
		}
148
149
		if (isset($storages[$this->id]) && isset($storages[$oldId])) {
150
			// if both ids exist, delete the old storage and corresponding filecache entries
151
			\OC\Files\Cache\Storage::remove($oldId);
152
		} else if (isset($storages[$oldId])) {
153
			// if only the old id exists do an update
154
			$stmt = \OC::$server->getDatabaseConnection()->prepare(
155
				'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
156
			);
157
			$stmt->execute(array($this->id, $oldId));
158
		}
159
		// only the bucket based id may exist, do nothing
160
	}
161
162
	/**
163
	 * Remove a file or folder
164
	 *
165
	 * @param string $path
166
	 * @return bool
167
	 */
168
	protected function remove($path) {
169
		// remember fileType to reduce http calls
170
		$fileType = $this->filetype($path);
171
		if ($fileType === 'dir') {
172
			return $this->rmdir($path);
173
		} else if ($fileType === 'file') {
174
			return $this->unlink($path);
175
		} else {
176
			return false;
177
		}
178
	}
179
180
	public function mkdir($path) {
181
		$path = $this->normalizePath($path);
182
183
		if ($this->is_dir($path)) {
184
			return false;
185
		}
186
187
		try {
188
			$this->getConnection()->putObject(array(
189
				'Bucket' => $this->bucket,
190
				'Key' => $path . '/',
191
				'Body' => '',
192
				'ContentType' => 'httpd/unix-directory'
193
			));
194
			$this->testTimeout();
195
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
196
			\OCP\Util::logException('files_external', $e);
197
			return false;
198
		}
199
200
		return true;
201
	}
202
203
	public function file_exists($path) {
204
		return $this->filetype($path) !== false;
205
	}
206
207
208
	public function rmdir($path) {
209
		$path = $this->normalizePath($path);
210
211
		if ($this->isRoot($path)) {
212
			return $this->clearBucket();
213
		}
214
215
		if (!$this->file_exists($path)) {
216
			return false;
217
		}
218
219
		return $this->batchDelete($path);
220
	}
221
222
	protected function clearBucket() {
223
		try {
224
			$this->getConnection()->clearBucket($this->bucket);
225
			return true;
226
			// clearBucket() is not working with Ceph, so if it fails we try the slower approach
227
		} catch (\Exception $e) {
228
			return $this->batchDelete();
229
		}
230
		return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
231
	}
232
233
	private function batchDelete ($path = null) {
234
		$params = array(
235
			'Bucket' => $this->bucket
236
		);
237
		if ($path !== null) {
238
			$params['Prefix'] = $path . '/';
239
		}
240
		try {
241
			// Since there are no real directories on S3, we need
242
			// to delete all objects prefixed with the path.
243
			do {
244
				// instead of the iterator, manually loop over the list ...
245
				$objects = $this->getConnection()->listObjects($params);
246
				// ... so we can delete the files in batches
247
				$this->getConnection()->deleteObjects(array(
248
					'Bucket' => $this->bucket,
249
					'Objects' => $objects['Contents']
250
				));
251
				$this->testTimeout();
252
				// we reached the end when the list is no longer truncated
253
			} while ($objects['IsTruncated']);
254
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
255
			\OCP\Util::logException('files_external', $e);
256
			return false;
257
		}
258
		return true;
259
	}
260
261
	public function opendir($path) {
262
		$path = $this->normalizePath($path);
263
264
		if ($this->isRoot($path)) {
265
			$path = '';
266
		} else {
267
			$path .= '/';
268
		}
269
270
		try {
271
			$files = array();
272
			$result = $this->getConnection()->getIterator('ListObjects', array(
273
				'Bucket' => $this->bucket,
274
				'Delimiter' => '/',
275
				'Prefix' => $path
276
			), array('return_prefixes' => true));
277
278
			foreach ($result as $object) {
279
				if (isset($object['Key']) && $object['Key'] === $path) {
280
					// it's the directory itself, skip
281
					continue;
282
				}
283
				$file = basename(
284
					isset($object['Key']) ? $object['Key'] : $object['Prefix']
285
				);
286
				$files[] = $file;
287
			}
288
289
			return IteratorDirectory::wrap($files);
290
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
291
			\OCP\Util::logException('files_external', $e);
292
			return false;
293
		}
294
	}
295
296
	public function stat($path) {
297
		$path = $this->normalizePath($path);
298
299
		try {
300
			$stat = array();
301
			if ($this->is_dir($path)) {
302
				//folders don't really exist
303
				$stat['size'] = -1; //unknown
304
				$stat['mtime'] = time() - $this->rescanDelay * 1000;
305
			} else {
306
				$result = $this->getConnection()->headObject(array(
307
					'Bucket' => $this->bucket,
308
					'Key' => $path
309
				));
310
311
				$stat['size'] = $result['ContentLength'] ? $result['ContentLength'] : 0;
312
				if ($result['Metadata']['lastmodified']) {
313
					$stat['mtime'] = strtotime($result['Metadata']['lastmodified']);
314
				} else {
315
					$stat['mtime'] = strtotime($result['LastModified']);
316
				}
317
			}
318
			$stat['atime'] = time();
319
320
			return $stat;
321
		} catch(S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
322
			\OCP\Util::logException('files_external', $e);
323
			return false;
324
		}
325
	}
326
327
	public function filetype($path) {
328
		$path = $this->normalizePath($path);
329
330
		if ($this->isRoot($path)) {
331
			return 'dir';
332
		}
333
334
		try {
335
			if ($this->getConnection()->doesObjectExist($this->bucket, $path)) {
336
				return 'file';
337
			}
338
			if ($this->getConnection()->doesObjectExist($this->bucket, $path.'/')) {
339
				return 'dir';
340
			}
341
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
342
			\OCP\Util::logException('files_external', $e);
343
			return false;
344
		}
345
346
		return false;
347
	}
348
349
	public function unlink($path) {
350
		$path = $this->normalizePath($path);
351
352
		if ($this->is_dir($path)) {
353
			return $this->rmdir($path);
354
		}
355
356
		try {
357
			$this->getConnection()->deleteObject(array(
358
				'Bucket' => $this->bucket,
359
				'Key' => $path
360
			));
361
			$this->testTimeout();
362
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
363
			\OCP\Util::logException('files_external', $e);
364
			return false;
365
		}
366
367
		return true;
368
	}
369
370
	public function fopen($path, $mode) {
371
		$path = $this->normalizePath($path);
372
373
		switch ($mode) {
374
			case 'r':
375
			case 'rb':
376
				$tmpFile = \OCP\Files::tmpFile();
377
				self::$tmpFiles[$tmpFile] = $path;
378
379
				try {
380
					$this->getConnection()->getObject(array(
381
						'Bucket' => $this->bucket,
382
						'Key' => $path,
383
						'SaveAs' => $tmpFile
384
					));
385
				} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
386
					\OCP\Util::logException('files_external', $e);
387
					return false;
388
				}
389
390
				return fopen($tmpFile, 'r');
391
			case 'w':
392
			case 'wb':
393
			case 'a':
394
			case 'ab':
395
			case 'r+':
396
			case 'w+':
397
			case 'wb+':
398
			case 'a+':
399
			case 'x':
400
			case 'x+':
401
			case 'c':
402 View Code Duplication
			case 'c+':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
403
				if (strrpos($path, '.') !== false) {
404
					$ext = substr($path, strrpos($path, '.'));
405
				} else {
406
					$ext = '';
407
				}
408
				$tmpFile = \OCP\Files::tmpFile($ext);
409
				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
410
				if ($this->file_exists($path)) {
411
					$source = $this->fopen($path, 'r');
412
					file_put_contents($tmpFile, $source);
413
				}
414
				self::$tmpFiles[$tmpFile] = $path;
415
416
				return fopen('close://' . $tmpFile, $mode);
417
		}
418
		return false;
419
	}
420
421
	public function touch($path, $mtime = null) {
422
		$path = $this->normalizePath($path);
423
424
		$metadata = array();
0 ignored issues
show
Unused Code introduced by
$metadata is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
425
		if (is_null($mtime)) {
426
			$mtime = time();
427
		}
428
		$metadata = [
429
			'lastmodified' => gmdate(\Aws\Common\Enum\DateFormat::RFC1123, $mtime)
430
		];
431
432
		$fileType = $this->filetype($path);
433
		try {
434
			if ($fileType !== false) {
435
				if ($fileType === 'dir' && ! $this->isRoot($path)) {
436
					$path .= '/';
437
				}
438
				$this->getConnection()->copyObject([
439
					'Bucket' => $this->bucket,
440
					'Key' => $this->cleanKey($path),
441
					'Metadata' => $metadata,
442
					'CopySource' => $this->bucket . '/' . $path,
443
					'MetadataDirective' => 'REPLACE',
444
				]);
445
				$this->testTimeout();
446
			} else {
447
				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
448
				$this->getConnection()->putObject([
449
					'Bucket' => $this->bucket,
450
					'Key' => $this->cleanKey($path),
451
					'Metadata' => $metadata,
452
					'Body' => '',
453
					'ContentType' => $mimeType,
454
					'MetadataDirective' => 'REPLACE',
455
				]);
456
				$this->testTimeout();
457
			}
458
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
459
			\OCP\Util::logException('files_external', $e);
460
			return false;
461
		}
462
463
		return true;
464
	}
465
466
	public function copy($path1, $path2) {
467
		$path1 = $this->normalizePath($path1);
468
		$path2 = $this->normalizePath($path2);
469
470
		if ($this->is_file($path1)) {
471
			try {
472
				$this->getConnection()->copyObject(array(
473
					'Bucket' => $this->bucket,
474
					'Key' => $this->cleanKey($path2),
475
					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
476
				));
477
				$this->testTimeout();
478
			} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
479
				\OCP\Util::logException('files_external', $e);
480
				return false;
481
			}
482
		} else {
483
			$this->remove($path2);
484
485
			try {
486
				$this->getConnection()->copyObject(array(
487
					'Bucket' => $this->bucket,
488
					'Key' => $path2 . '/',
489
					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
490
				));
491
				$this->testTimeout();
492
			} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
493
				\OCP\Util::logException('files_external', $e);
494
				return false;
495
			}
496
497
			$dh = $this->opendir($path1);
498 View Code Duplication
			if (is_resource($dh)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
499
				while (($file = readdir($dh)) !== false) {
500
					if (\OC\Files\Filesystem::isIgnoredDir($file)) {
501
						continue;
502
					}
503
504
					$source = $path1 . '/' . $file;
505
					$target = $path2 . '/' . $file;
506
					$this->copy($source, $target);
507
				}
508
			}
509
		}
510
511
		return true;
512
	}
513
514
	public function rename($path1, $path2) {
515
		$path1 = $this->normalizePath($path1);
516
		$path2 = $this->normalizePath($path2);
517
518
		if ($this->is_file($path1)) {
519
520
			if ($this->copy($path1, $path2) === false) {
521
				return false;
522
			}
523
524
			if ($this->unlink($path1) === false) {
525
				$this->unlink($path2);
526
				return false;
527
			}
528
		} else {
529
530
			if ($this->copy($path1, $path2) === false) {
531
				return false;
532
			}
533
534
			if ($this->rmdir($path1) === false) {
535
				$this->rmdir($path2);
536
				return false;
537
			}
538
		}
539
540
		return true;
541
	}
542
543
	public function test() {
544
		$test = $this->getConnection()->getBucketAcl(array(
545
			'Bucket' => $this->bucket,
546
		));
547
		if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
548
			return true;
549
		}
550
		return false;
551
	}
552
553
	public function getId() {
554
		return $this->id;
555
	}
556
557
	/**
558
	 * Returns the connection
559
	 *
560
	 * @return S3Client connected client
561
	 * @throws \Exception if connection could not be made
562
	 */
563
	public function getConnection() {
564
		if (!is_null($this->connection)) {
565
			return $this->connection;
566
		}
567
568
		$scheme = ($this->params['use_ssl'] === false) ? 'http' : 'https';
569
		$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
570
571
		$this->connection = S3Client::factory(array(
572
			'key' => $this->params['key'],
573
			'secret' => $this->params['secret'],
574
			'base_url' => $base_url,
575
			'region' => $this->params['region'],
576
			S3Client::COMMAND_PARAMS => [
577
				'PathStyle' => $this->params['use_path_style'],
578
			],
579
		));
580
581
		if (!$this->connection->isValidBucketName($this->bucket)) {
582
			throw new \Exception("The configured bucket name is invalid.");
583
		}
584
585
		if (!$this->connection->doesBucketExist($this->bucket)) {
586
			try {
587
				$this->connection->createBucket(array(
588
					'Bucket' => $this->bucket
589
				));
590
				$this->connection->waitUntilBucketExists(array(
591
					'Bucket' => $this->bucket,
592
					'waiter.interval' => 1,
593
					'waiter.max_attempts' => 15
594
				));
595
				$this->testTimeout();
596
			} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
597
				\OCP\Util::logException('files_external', $e);
598
				throw new \Exception('Creation of bucket failed. '.$e->getMessage());
599
			}
600
		}
601
602
		return $this->connection;
603
	}
604
605
	public function writeBack($tmpFile) {
606
		if (!isset(self::$tmpFiles[$tmpFile])) {
607
			return false;
608
		}
609
610
		try {
611
			$this->getConnection()->putObject(array(
612
				'Bucket' => $this->bucket,
613
				'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]),
614
				'SourceFile' => $tmpFile,
615
				'ContentType' => \OC::$server->getMimeTypeDetector()->detect($tmpFile),
616
				'ContentLength' => filesize($tmpFile)
617
			));
618
			$this->testTimeout();
619
620
			unlink($tmpFile);
621
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
622
			\OCP\Util::logException('files_external', $e);
623
			return false;
624
		}
625
	}
626
627
	/**
628
	 * check if curl is installed
629
	 */
630
	public static function checkDependencies() {
631
		return true;
632
	}
633
634
}
635