Completed
Push — master ( e4992c...6d0a35 )
by
unknown
10:42
created

ShareController::validateShare()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Björn Schießle <[email protected]>
5
 * @author Georg Ehrke <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Jörn Friedrich Dreyer <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Piotr Filiciak <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Thomas Müller <[email protected]>
14
 * @author Vincent Petry <[email protected]>
15
 *
16
 * @copyright Copyright (c) 2018, ownCloud GmbH
17
 * @license AGPL-3.0
18
 *
19
 * This code is free software: you can redistribute it and/or modify
20
 * it under the terms of the GNU Affero General Public License, version 3,
21
 * as published by the Free Software Foundation.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License, version 3,
29
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
30
 *
31
 */
32
33
namespace OCA\Files_Sharing\Controllers;
34
35
use OC;
36
use OC_Files;
37
use OC_Util;
38
use OCA\Files_Sharing\Activity;
39
use OCP;
40
use OCP\AppFramework\Controller;
41
use OCP\AppFramework\Http\NotFoundResponse;
42
use OCP\AppFramework\Http\RedirectResponse;
43
use OCP\AppFramework\Http\TemplateResponse;
44
use OCP\Files\IRootFolder;
45
use OCP\Files\NotFoundException;
46
use OCP\IConfig;
47
use OCP\ILogger;
48
use OCP\IPreview;
49
use OCP\IRequest;
50
use OCP\ISession;
51
use OCP\IURLGenerator;
52
use OCP\IUserManager;
53
use OCP\Share;
54
use OCP\Share\Exceptions\ShareNotFound;
55
use OCP\Template;
56
use Symfony\Component\EventDispatcher\EventDispatcher;
57
use Symfony\Component\EventDispatcher\GenericEvent;
58
59
/**
60
 * Class ShareController
61
 *
62
 * @package OCA\Files_Sharing\Controllers
63
 */
64
class ShareController extends Controller {
65
66
	/** @var IConfig */
67
	protected $config;
68
	/** @var IURLGenerator */
69
	protected $urlGenerator;
70
	/** @var IUserManager */
71
	protected $userManager;
72
	/** @var ILogger */
73
	protected $logger;
74
	/** @var OCP\Activity\IManager */
75
	protected $activityManager;
76
	/** @var OCP\Share\IManager */
77
	protected $shareManager;
78
	/** @var ISession */
79
	protected $session;
80
	/** @var IPreview */
81
	protected $previewManager;
82
	/** @var IRootFolder */
83
	protected $rootFolder;
84
	/** @var EventDispatcher  */
85
	protected $eventDispatcher;
86
87
	/**
88
	 * @param string $appName
89
	 * @param IRequest $request
90
	 * @param IConfig $config
91
	 * @param IURLGenerator $urlGenerator
92
	 * @param IUserManager $userManager
93
	 * @param ILogger $logger
94
	 * @param OCP\Activity\IManager $activityManager
95
	 * @param \OCP\Share\IManager $shareManager
96
	 * @param ISession $session
97
	 * @param IPreview $previewManager
98
	 * @param IRootFolder $rootFolder
99
	 */
100
	public function __construct($appName,
101
								IRequest $request,
102
								IConfig $config,
103
								IURLGenerator $urlGenerator,
104
								IUserManager $userManager,
105
								ILogger $logger,
106
								\OCP\Activity\IManager $activityManager,
107
								\OCP\Share\IManager $shareManager,
108
								ISession $session,
109
								IPreview $previewManager,
110
								IRootFolder $rootFolder,
111
								EventDispatcher $eventDispatcher) {
112
		parent::__construct($appName, $request);
113
114
		$this->config = $config;
115
		$this->urlGenerator = $urlGenerator;
116
		$this->userManager = $userManager;
117
		$this->logger = $logger;
118
		$this->activityManager = $activityManager;
119
		$this->shareManager = $shareManager;
120
		$this->session = $session;
121
		$this->previewManager = $previewManager;
122
		$this->rootFolder = $rootFolder;
123
		$this->eventDispatcher = $eventDispatcher;
124
	}
125
126
	/**
127
	 * @PublicPage
128
	 * @NoCSRFRequired
129
	 *
130
	 * @param string $token
131
	 * @return TemplateResponse|RedirectResponse
132
	 */
133
	public function showAuthenticate($token) {
134
		$share = $this->shareManager->getShareByToken($token);
135
136
		if ($this->linkShareAuth($share)) {
137
			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', ['token' => $token]));
138
		}
139
140
		return new TemplateResponse($this->appName, 'authenticate', [], 'guest');
141
	}
142
143
	/**
144
	 * @PublicPage
145
	 * @UseSession
146
	 *
147
	 * Authenticates against password-protected shares
148
	 * @param string $token
149
	 * @param string $password
150
	 * @return RedirectResponse|TemplateResponse
151
	 */
152
	public function authenticate($token, $password = '') {
153
154
		// Check whether share exists
155
		try {
156
			$share = $this->shareManager->getShareByToken($token);
157
		} catch (ShareNotFound $e) {
158
			return new NotFoundResponse();
159
		}
160
161
		$authenticate = $this->linkShareAuth($share, $password);
162
163
		if ($authenticate === true) {
164
			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', ['token' => $token]));
165
		}
166
167
		return new TemplateResponse($this->appName, 'authenticate', ['wrongpw' => true], 'guest');
168
	}
169
170
	/**
171
	 * Authenticate a link item with the given password.
172
	 * Or use the session if no password is provided.
173
	 *
174
	 * This is a modified version of Helper::authenticate
175
	 * TODO: Try to merge back eventually with Helper::authenticate
176
	 *
177
	 * @param \OCP\Share\IShare $share
178
	 * @param string|null $password
179
	 * @return bool
180
	 */
181
	private function linkShareAuth(\OCP\Share\IShare $share, $password = null) {
182
		if ($password !== null) {
183
			if ($this->shareManager->checkPassword($share, $password)) {
184
				$this->session->set('public_link_authenticated', (string)$share->getId());
185
			} else {
186
				$this->emitAccessShareHook($share, 403, 'Wrong password');
187
				return false;
188
			}
189 View Code Duplication
		} else {
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...
190
			// not authenticated ?
191
			if (! $this->session->exists('public_link_authenticated')
192
				|| $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
193
				return false;
194
			}
195
		}
196
		return true;
197
	}
198
199
	/**
200
	 * throws hooks when a share is attempted to be accessed
201
	 *
202
	 * @param \OCP\Share\IShare|string $share the Share instance if available,
203
	 * otherwise token
204
	 * @param int $errorCode
205
	 * @param string $errorMessage
206
	 * @throws OC\HintException
207
	 * @throws OC\ServerNotAvailableException
208
	 */
209
	protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
210
		$itemType = $itemSource = $uidOwner = '';
211
		$token = $share;
212
		$exception = null;
213
		if ($share instanceof \OCP\Share\IShare) {
214
			try {
215
				$token = $share->getToken();
216
				$uidOwner = $share->getSharedBy();
217
				$itemType = $share->getNodeType();
218
				$itemSource = $share->getNodeId();
219
			} catch (\Exception $e) {
220
				// we log what we know and pass on the exception afterwards
221
				$exception = $e;
222
			}
223
		}
224
		\OC_Hook::emit('OCP\Share', 'share_link_access', [
225
			'itemType' => $itemType,
226
			'itemSource' => $itemSource,
227
			'uidOwner' => $uidOwner,
228
			'token' => $token,
229
			'errorCode' => $errorCode,
230
			'errorMessage' => $errorMessage,
231
		]);
232
233
		if ($share instanceof \OCP\Share\IShare) {
234
			$cloneShare = clone $share;
235
			$publicShareLinkAccessEvent = new GenericEvent(null,
236
				['shareObject' => $cloneShare, 'errorCode' => $errorCode,
237
					'errorMessage' => $errorMessage]);
238
239
			$this->eventDispatcher->dispatch('share.linkaccess', $publicShareLinkAccessEvent);
240
		}
241
242
		if ($exception !== null) {
243
			throw $exception;
244
		}
245
	}
246
247
	/**
248
	 * Validate the permissions of the share
249
	 *
250
	 * @param Share\IShare $share
251
	 * @return bool
252
	 */
253
	private function validateShare(\OCP\Share\IShare $share) {
254
		return $share->getNode()->isReadable() && $share->getNode()->isShareable();
255
	}
256
257
	/**
258
	 * @PublicPage
259
	 * @NoCSRFRequired
260
	 *
261
	 * @param string $token
262
	 * @param string $path
263
	 * @return NotFoundResponse|RedirectResponse|TemplateResponse
264
	 * @throws NotFoundException
265
	 */
266
	public function showShare($token, $path = '') {
267
		\OC_User::setIncognitoMode(true);
268
269
		// Check whether share exists
270
		try {
271
			$share = $this->shareManager->getShareByToken($token);
272
		} catch (ShareNotFound $e) {
273
			$this->emitAccessShareHook($token, 404, 'Share not found');
274
			return new NotFoundResponse();
275
		}
276
277
		// Share is password protected - check whether the user is permitted to access the share
278 View Code Duplication
		if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
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...
279
			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
280
				['token' => $token]));
281
		}
282
283
		if (!$this->validateShare($share)) {
284
			throw new NotFoundException();
285
		}
286
		// We can't get the path of a file share
287
		try {
288
			if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
289
				$this->emitAccessShareHook($share, 404, 'Share not found');
290
				throw new NotFoundException();
291
			}
292
		} catch (\Exception $e) {
293
			$this->emitAccessShareHook($share, 404, 'Share not found');
294
			throw $e;
295
		}
296
297
		$rootFolder = null;
298
		if ($share->getNode() instanceof \OCP\Files\Folder) {
299
			/** @var \OCP\Files\Folder $rootFolder */
300
			$rootFolder = $share->getNode();
301
302
			try {
303
				$path = $rootFolder->get($path);
304
			} catch (\OCP\Files\NotFoundException $e) {
305
				$this->emitAccessShareHook($share, 404, 'Share not found');
306
				throw new NotFoundException();
307
			}
308
		}
309
310
		$shareTmpl = [];
311
		$shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
312
		$shareTmpl['owner'] = $share->getShareOwner();
313
		$shareTmpl['filename'] = $share->getNode()->getName();
314
		$shareTmpl['directory_path'] = $share->getTarget();
315
		$shareTmpl['mimetype'] = $share->getNode()->getMimetype();
316
		$shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
317
		$shareTmpl['dirToken'] = $token;
318
		$shareTmpl['sharingToken'] = $token;
319
		$shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
320
		$shareTmpl['dir'] = '';
321
		$shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
322
		$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
323
324
		// Show file list
325
		if ($share->getNode() instanceof \OCP\Files\Folder) {
326
			$shareTmpl['dir'] = $rootFolder->getRelativePath($path->getPath());
0 ignored issues
show
Bug introduced by
It seems like $path is not always an object, but can also be of type string. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
327
328
			/*
329
			 * The OC_Util methods require a view. This just uses the node API
330
			 */
331
			$freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
332 View Code Duplication
			if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
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...
333
				$freeSpace = \max($freeSpace, 0);
334
			} else {
335
				$freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
336
			}
337
338
			$maxUploadFilesize = $freeSpace;
339
340
			if ($share->getPermissions() & \OCP\Constants::PERMISSION_READ > 0) {
341
				$folder = new Template('files', 'list', '');
342
				$folder->assign('dir', $rootFolder->getRelativePath($path->getPath()));
343
				$folder->assign('dirToken', $token);
344
				$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
345
				$folder->assign('isPublic', true);
346
				$folder->assign('publicUploadEnabled', 'no');
347
				$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
348
				$folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
349
				$folder->assign('freeSpace', $freeSpace);
350
				$folder->assign('usedSpacePercent', 0);
351
				$folder->assign('trash', false);
352
				$shareTmpl['folder'] = $folder->fetchPage();
353
			} else {
354
				$folder = new Template('files_sharing', 'upload', '');
355
				$shareTmpl['folder'] = $folder->fetchPage();
356
			}
357
		}
358
359
		$shareTmpl['canDownload'] = !!($share->getPermissions() & \OCP\Constants::PERMISSION_READ > 0);
360
		$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $token]);
361
		$shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]);
362
		$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
363
		$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
364
		$shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
365
		$shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
366
		if ($shareTmpl['previewSupported']) {
367
			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute('core_ajax_public_preview',
368
				['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]);
369
		} else {
370
			$shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
371
		}
372
373
		$csp = new OCP\AppFramework\Http\ContentSecurityPolicy();
374
		$csp->addAllowedFrameDomain('\'self\'');
375
		$response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
376
		$response->setContentSecurityPolicy($csp);
377
378
		$this->emitAccessShareHook($share);
379
380
		return $response;
381
	}
382
383
	/**
384
	 * @PublicPage
385
	 * @NoCSRFRequired
386
	 *
387
	 * @param string $token
388
	 * @param string $files
389
	 * @param string $path
390
	 * @param string $downloadStartSecret
391
	 * @return NotFoundResponse|RedirectResponse|void
392
	 */
393
	public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
394
		\OC_User::setIncognitoMode(true);
395
396
		$share = $this->shareManager->getShareByToken($token);
397
398
		// Share is password protected - check whether the user is permitted to access the share
399 View Code Duplication
		if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
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...
400
			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
401
				['token' => $token]));
402
		}
403
404
		if (($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
405
			throw new NotFoundException();
406
		}
407
408
		$files_list = $files;
409
		if ($files !== null) { // download selected files
410
			// in case we get only a single file
411
			if (!\is_array($files_list)) {
412
				$files_list = [(string)$files_list];
413
			}
414
		}
415
416
		$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
417
		$originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
418
419
		if (!$this->validateShare($share)) {
420
			throw new NotFoundException();
421
		}
422
423
		// Single file share
424
		if ($share->getNode() instanceof \OCP\Files\File) {
425
			// Single file download
426
			$event = $this->activityManager->generateEvent();
427
			$event->setApp('files_sharing')
428
				->setType(Activity::TYPE_PUBLIC_LINKS)
429
				->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($share->getNode()->getPath())])
430
				->setAffectedUser($share->getShareOwner())
431
				->setObject('files', $share->getNode()->getId(), $userFolder->getRelativePath($share->getNode()->getPath()));
432
			$this->activityManager->publish($event);
433
		}
434
		// Directory share
435
		else {
436
			/** @var \OCP\Files\Folder $node */
437
			$node = $share->getNode();
438
439
			// Try to get the path
440
			if ($path !== '') {
441
				try {
442
					$node = $node->get($path);
443
				} catch (NotFoundException $e) {
444
					$this->emitAccessShareHook($share, 404, 'Share not found');
445
					return new NotFoundResponse();
446
				}
447
			}
448
449
			$originalSharePath = $userFolder->getRelativePath($node->getPath());
450
451
			if ($node instanceof \OCP\Files\File) {
452
				// Single file download
453
				$event = $this->activityManager->generateEvent();
454
				$event->setApp('files_sharing')
455
					->setType(Activity::TYPE_PUBLIC_LINKS)
456
					->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($node->getPath())])
457
					->setAffectedUser($share->getShareOwner())
458
					->setObject('files', $node->getId(), $userFolder->getRelativePath($node->getPath()));
459
				$this->activityManager->publish($event);
460
			} elseif (!empty($files_list)) {
461
				/** @var \OCP\Files\Folder $node */
462
463
				// Subset of files is downloaded
464
				foreach ($files_list as $file) {
0 ignored issues
show
Bug introduced by
The expression $files_list of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
465
					$subNode = $node->get($file);
466
467
					$event = $this->activityManager->generateEvent();
468
					$event->setApp('files_sharing')
469
						->setType(Activity::TYPE_PUBLIC_LINKS)
470
						->setAffectedUser($share->getShareOwner())
471
						->setObject('files', $subNode->getId(), $userFolder->getRelativePath($subNode->getPath()));
472
473
					if ($subNode instanceof \OCP\Files\File) {
474
						$event->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED, [$userFolder->getRelativePath($subNode->getPath())]);
475
					} else {
476
						$event->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED, [$userFolder->getRelativePath($subNode->getPath())]);
477
					}
478
479
					$this->activityManager->publish($event);
480
				}
481
			} else {
482
				// The folder is downloaded
483
				$event = $this->activityManager->generateEvent();
484
				$event->setApp('files_sharing')
485
					->setType(Activity::TYPE_PUBLIC_LINKS)
486
					->setSubject(Activity::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED, [$userFolder->getRelativePath($node->getPath())])
487
					->setAffectedUser($share->getShareOwner())
488
					->setObject('files', $node->getId(), $userFolder->getRelativePath($node->getPath()));
489
				$this->activityManager->publish($event);
490
			}
491
		}
492
493
		/* FIXME: We should do this all nicely in OCP */
494
		OC_Util::tearDownFS();
495
		OC_Util::setupFS($share->getShareOwner());
496
497
		/**
498
		 * this sets a cookie to be able to recognize the start of the download
499
		 * the content must not be longer than 32 characters and must only contain
500
		 * alphanumeric characters
501
		 */
502 View Code Duplication
		if (!empty($downloadStartSecret)
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...
503
			&& !isset($downloadStartSecret[32])
504
			&& \preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
505
506
			// FIXME: set on the response once we use an actual app framework response
507
			\setcookie('ocDownloadStarted', $downloadStartSecret, \time() + 20, '/');
508
		}
509
510
		$this->emitAccessShareHook($share);
511
512
		$server_params = ['head' => $this->request->getMethod() == 'HEAD'];
513
514
		/**
515
		 * Http range requests support
516
		 */
517
		if (isset($_SERVER['HTTP_RANGE'])) {
518
			$server_params['range'] = $this->request->getHeader('Range');
519
		}
520
521
		// download selected files
522
		if ($files !== null && $files !== '') {
523
			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
524
			// after dispatching the request which results in a "Cannot modify header information" notice.
525
			OC_Files::get($originalSharePath, $files_list, $server_params);
0 ignored issues
show
Bug introduced by
It seems like $files_list can also be of type array or null; however, OC_Files::get() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
526
			exit();
527
		} else {
528
			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
529
			// after dispatching the request which results in a "Cannot modify header information" notice.
530
			OC_Files::get(\dirname($originalSharePath), \basename($originalSharePath), $server_params);
531
			exit();
532
		}
533
	}
534
}
535