elFinder::resize()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 19
Code Lines 15

Duplication

Lines 4
Ratio 21.05 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 3
nop 1
dl 4
loc 19
rs 9.2
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 20 and the first side effect is on line 10.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @package     Arastta eCommerce
4
 * @copyright   2015-2017 Arastta Association. All rights reserved.
5
 * @copyright   See CREDITS.txt for credits and other copyright notices.
6
 * @license     GNU GPL version 3; see LICENSE.txt
7
 * @link        https://arastta.org
8
 */
9
 
10
defined('AREXE') or die;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
11
/**
12
 * elFinder - file manager for web.
13
 * Core class.
14
 *
15
 * @package elfinder
16
 * @author Dmitry (dio) Levashov
17
 * @author Troex Nevelin
18
 * @author Alexey Sukhotin
19
 **/
20
class elFinder {
21
	
22
	/**
23
	 * API version number
24
	 *
25
	 * @var string
26
	 **/
27
	protected $version = '2.0';
28
	
29
	/**
30
	 * Storages (root dirs)
31
	 *
32
	 * @var array
33
	 **/
34
	protected $volumes = array();
35
	
36
	public static $netDrivers = array();
37
38
	/**
39
	 * Mounted volumes count
40
	 * Required to create unique volume id
41
	 *
42
	 * @var int
43
	 **/
44
	public static $volumesCnt = 1;
45
	
46
	/**
47
	 * Default root (storage)
48
	 *
49
	 * @var elFinderStorageDriver
50
	 **/
51
	protected $default = null;
52
	
53
	/**
54
	 * Commands and required arguments list
55
	 *
56
	 * @var array
57
	 **/
58
	protected $commands = array(
59
		'open'      => array('target' => false, 'tree' => false, 'init' => false, 'mimes' => false),
60
		'ls'        => array('target' => true, 'mimes' => false),
61
		'tree'      => array('target' => true),
62
		'parents'   => array('target' => true),
63
		'tmb'       => array('targets' => true),
64
		'file'      => array('target' => true, 'download' => false),
65
		'size'      => array('targets' => true),
66
		'mkdir'     => array('target' => true, 'name' => true),
67
		'mkfile'    => array('target' => true, 'name' => true, 'mimes' => false),
68
		'rm'        => array('targets' => true),
69
		'rename'    => array('target' => true, 'name' => true, 'mimes' => false),
70
		'duplicate' => array('targets' => true, 'suffix' => false),
71
		'paste'     => array('dst' => true, 'targets' => true, 'cut' => false, 'mimes' => false),
72
		'upload'    => array('target' => true, 'FILES' => true, 'mimes' => false, 'html' => false),
73
		'get'       => array('target' => true),
74
		'put'       => array('target' => true, 'content' => '', 'mimes' => false),
75
		'archive'   => array('targets' => true, 'type' => true, 'mimes' => false),
76
		'extract'   => array('target' => true, 'mimes' => false),
77
		'search'    => array('q' => true, 'mimes' => false),
78
		'info'      => array('targets' => true),
79
		'dim'       => array('target' => true),
80
		'resize'    => array('target' => true, 'width' => true, 'height' => true, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false),
81
		'netmount'  => array('protocol' => true, 'host' => true, 'path' => false, 'port' => false, 'user' => true, 'pass' => true, 'alias' => false, 'options' => false)
82
	);
83
	
84
	/**
85
	 * Commands listeners
86
	 *
87
	 * @var array
88
	 **/
89
	protected $listeners = array();
90
	
91
	/**
92
	 * script work time for debug
93
	 *
94
	 * @var string
95
	 **/
96
	protected $time = 0;
97
	/**
98
	 * Is elFinder init correctly?
99
	 *
100
	 * @var bool
101
	 **/
102
	protected $loaded = false;
103
	/**
104
	 * Send debug to client?
105
	 *
106
	 * @var string
107
	 **/
108
	protected $debug = false;
109
110
	/**
111
	 * session expires timeout
112
	 *
113
	 * @var int
114
	 **/
115
	protected $timeout = 0;
116
	
117
	/**
118
	 * undocumented class variable
119
	 *
120
	 * @var string
121
	 **/
122
	protected $uploadDebug = '';
123
	
124
	/**
125
	 * Errors from not mounted volumes
126
	 *
127
	 * @var array
128
	 **/
129
	public $mountErrors = array();
130
	
131
	// Errors messages
132
	const ERROR_UNKNOWN           = 'errUnknown';
133
	const ERROR_UNKNOWN_CMD       = 'errUnknownCmd';
134
	const ERROR_CONF              = 'errConf';
135
	const ERROR_CONF_NO_JSON      = 'errJSON';
136
	const ERROR_CONF_NO_VOL       = 'errNoVolumes';
137
	const ERROR_INV_PARAMS        = 'errCmdParams';
138
	const ERROR_OPEN              = 'errOpen';
139
	const ERROR_DIR_NOT_FOUND     = 'errFolderNotFound';
140
	const ERROR_FILE_NOT_FOUND    = 'errFileNotFound';     // 'File not found.'
141
	const ERROR_TRGDIR_NOT_FOUND  = 'errTrgFolderNotFound'; // 'Target folder "$1" not found.'
142
	const ERROR_NOT_DIR           = 'errNotFolder';
143
	const ERROR_NOT_FILE          = 'errNotFile';
144
	const ERROR_PERM_DENIED       = 'errPerm';
145
	const ERROR_LOCKED            = 'errLocked';        // '"$1" is locked and can not be renamed, moved or removed.'
146
	const ERROR_EXISTS            = 'errExists';        // 'File named "$1" already exists.'
147
	const ERROR_INVALID_NAME      = 'errInvName';       // 'Invalid file name.'
148
	const ERROR_MKDIR             = 'errMkdir';
149
	const ERROR_MKFILE            = 'errMkfile';
150
	const ERROR_RENAME            = 'errRename';
151
	const ERROR_COPY              = 'errCopy';
152
	const ERROR_MOVE              = 'errMove';
153
	const ERROR_COPY_FROM         = 'errCopyFrom';
154
	const ERROR_COPY_TO           = 'errCopyTo';
155
	const ERROR_COPY_ITSELF       = 'errCopyInItself';
156
	const ERROR_REPLACE           = 'errReplace';          // 'Unable to replace "$1".'
157
	const ERROR_RM                = 'errRm';               // 'Unable to remove "$1".'
158
	const ERROR_RM_SRC            = 'errRmSrc';            // 'Unable remove source file(s)'
159
	const ERROR_UPLOAD            = 'errUpload';           // 'Upload error.'
160
	const ERROR_UPLOAD_FILE       = 'errUploadFile';       // 'Unable to upload "$1".'
161
	const ERROR_UPLOAD_NO_FILES   = 'errUploadNoFiles';    // 'No files found for upload.'
162
	const ERROR_UPLOAD_TOTAL_SIZE = 'errUploadTotalSize';  // 'Data exceeds the maximum allowed size.'
163
	const ERROR_UPLOAD_FILE_SIZE  = 'errUploadFileSize';   // 'File exceeds maximum allowed size.'
164
	const ERROR_UPLOAD_FILE_MIME  = 'errUploadMime';       // 'File type not allowed.'
165
	const ERROR_UPLOAD_TRANSFER   = 'errUploadTransfer';   // '"$1" transfer error.'
166
	// const ERROR_ACCESS_DENIED     = 'errAccess';
167
	const ERROR_NOT_REPLACE       = 'errNotReplace';       // Object "$1" already exists at this location and can not be replaced with object of another type.
168
	const ERROR_SAVE              = 'errSave';
169
	const ERROR_EXTRACT           = 'errExtract';
170
	const ERROR_ARCHIVE           = 'errArchive';
171
	const ERROR_NOT_ARCHIVE       = 'errNoArchive';
172
	const ERROR_ARCHIVE_TYPE      = 'errArcType';
173
	const ERROR_ARC_SYMLINKS      = 'errArcSymlinks';
174
	const ERROR_ARC_MAXSIZE       = 'errArcMaxSize';
175
	const ERROR_RESIZE            = 'errResize';
176
	const ERROR_UNSUPPORT_TYPE    = 'errUsupportType';
177
	const ERROR_NOT_UTF8_CONTENT  = 'errNotUTF8Content';
178
	const ERROR_NETMOUNT          = 'errNetMount';
179
	const ERROR_NETMOUNT_NO_DRIVER = 'errNetMountNoDriver';
180
	const ERROR_NETMOUNT_FAILED       = 'errNetMountFailed';
181
182
	const ERROR_SESSION_EXPIRES 	= 'errSessionExpires';
183
184
	const ERROR_CREATING_TEMP_DIR 	= 'errCreatingTempDir';
185
	const ERROR_FTP_DOWNLOAD_FILE 	= 'errFtpDownloadFile';
186
	const ERROR_FTP_UPLOAD_FILE 	= 'errFtpUploadFile';
187
	const ERROR_FTP_MKDIR 		= 'errFtpMkdir';
188
	const ERROR_ARCHIVE_EXEC 	= 'errArchiveExec';
189
	const ERROR_EXTRACT_EXEC 	= 'errExtractExec';
190
191
	/**
192
	 * Constructor
193
	 *
194
	 * @param  array  elFinder and roots configurations
195
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
196
	 * @author Dmitry (dio) Levashov
197
	 **/
198
	public function __construct($opts) {
199
		if (session_id() == '') {
200
			session_start();
201
		}
202
203
		$this->time  = $this->utime();
0 ignored issues
show
Documentation Bug introduced by
The property $time was declared of type string, but $this->utime() is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
204
		$this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false);
0 ignored issues
show
Documentation Bug introduced by
The property $debug was declared of type string, but isset($opts['debug']) &&...'debug'] ? true : false is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
205
		$this->timeout = (isset($opts['timeout']) ? $opts['timeout'] : 0);
206
		
207
		setlocale(LC_ALL, !empty($opts['locale']) ? $opts['locale'] : 'en_US.UTF-8');
208
209
		// bind events listeners
210
		if (!empty($opts['bind']) && is_array($opts['bind'])) {
211
			foreach ($opts['bind'] as $cmd => $handler) {
212
				$this->bind($cmd, $handler);
213
			}
214
		}
215
216
		if (!isset($opts['roots']) || !is_array($opts['roots'])) {
217
			$opts['roots'] = array();
218
		}
219
220
		// check for net volumes stored in session
221
		foreach ($this->getNetVolumes() as $root) {
222
			$opts['roots'][] = $root;
223
		}
224
225
		// "mount" volumes
226
		foreach ($opts['roots'] as $i => $o) {
227
			$class = 'elFinderVolume'.(isset($o['driver']) ? $o['driver'] : '');
228
229
			if (class_exists($class)) {
230
				$volume = new $class();
231
232
				try {
233
					if ($volume->mount($o)) {
234
						// unique volume id (ends on "_") - used as prefix to files hash
235
						$id = $volume->id();
236
						
237
						$this->volumes[$id] = $volume;
238
						if (!$this->default && $volume->isReadable()) {
239
							$this->default = $this->volumes[$id]; 
240
						}
241
					} else {
242
						$this->mountErrors[] = 'Driver "'.$class.'" : '.implode(' ', $volume->error());
243
					}
244
				} catch (Exception $e) {
245
					$this->mountErrors[] = 'Driver "'.$class.'" : '.$e->getMessage();
246
				}
247
			} else {
248
				$this->mountErrors[] = 'Driver "'.$class.'" does not exists';
249
			}
250
		}
251
252
		// if at least one readable volume - ii desu >_<
253
		$this->loaded = !empty($this->default);
254
	}
255
	
256
	/**
257
	 * Return true if fm init correctly
258
	 *
259
	 * @return bool
260
	 * @author Dmitry (dio) Levashov
261
	 **/
262
	public function loaded() {
263
		return $this->loaded;
264
	}
265
	
266
	/**
267
	 * Return version (api) number
268
	 *
269
	 * @return string
270
	 * @author Dmitry (dio) Levashov
271
	 **/
272
	public function version() {
273
		return $this->version;
274
	}
275
	
276
	/**
277
	 * Add handler to elFinder command
278
	 *
279
	 * @param  string  command name
280
	 * @param  string|array  callback name or array(object, method)
281
	 * @return elFinder
282
	 * @author Dmitry (dio) Levashov
283
	 **/
284
	public function bind($cmd, $handler) {
285
		$cmds = $cmd == '*'
286
			? array_keys($this->commands)
287
			: array_map('trim', explode(' ', $cmd));
288
		
289
		foreach ($cmds as $cmd) {
290
			if ($cmd) {
291
				if (!isset($this->listeners[$cmd])) {
292
					$this->listeners[$cmd] = array();
293
				}
294
295
				if (is_callable($handler)) {
296
					$this->listeners[$cmd][] = $handler;
297
				}
298
			}
299
		}
300
301
		return $this;
302
	}
303
	
304
	/**
305
	 * Remove event (command exec) handler
306
	 *
307
	 * @param  string  command name
308
	 * @param  string|array  callback name or array(object, method)
309
	 * @return elFinder
310
	 * @author Dmitry (dio) Levashov
311
	 **/
312
	public function unbind($cmd, $handler) {
313
		if (!empty($this->listeners[$cmd])) {
314
			foreach ($this->listeners[$cmd] as $i => $h) {
315
				if ($h === $handler) {
316
					unset($this->listeners[$cmd][$i]);
317
					return $this;
318
				}
319
			}
320
		}
321
		return $this;
322
	}
323
	
324
	/**
325
	 * Return true if command exists
326
	 *
327
	 * @param  string  command name
328
	 * @return bool
329
	 * @author Dmitry (dio) Levashov
330
	 **/
331
	public function commandExists($cmd) {
332
		return $this->loaded && isset($this->commands[$cmd]) && method_exists($this, $cmd);
333
	}
334
	
335
	/**
336
	 * Return root - file's owner (public func of volume())
337
	 *
338
	 * @param  string  file hash
339
	 * @return elFinderStorageDriver
340
	 * @author Naoki Sawada
341
	 */
342
	public function getVolume($hash) {
343
		return $this->volume($hash);
344
	}
345
	
346
	/**
347
	 * Return command required arguments info
348
	 *
349
	 * @param  string  command name
350
	 * @return array
351
	 * @author Dmitry (dio) Levashov
352
	 **/
353
	public function commandArgsList($cmd) {
354
		return $this->commandExists($cmd) ? $this->commands[$cmd] : array();
355
	}
356
357
	private function session_expires() {
0 ignored issues
show
Coding Style introduced by
session_expires uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
358
		
359
		if (!isset($_SESSION['LAST_ACTIVITY'])) {
360
			$_SESSION['LAST_ACTIVITY'] = time();
361
			return false;
362
		}
363
364
		if ( ($this->timeout > 0) && (time() - $_SESSION['LAST_ACTIVITY'] > $this->timeout) ) {
365
			return true;
366
		}
367
368
		$_SESSION['LAST_ACTIVITY'] = time();
369
		return false;	
370
	}
371
	
372
	/**
373
	 * Exec command and return result
374
	 *
375
	 * @param  string  $cmd  command name
376
	 * @param  array   $args command arguments
377
	 * @return array
378
	 * @author Dmitry (dio) Levashov
379
	 **/
380
	public function exec($cmd, $args) {
381
		
382
		if (!$this->loaded) {
383
			return array('error' => $this->error(self::ERROR_CONF, self::ERROR_CONF_NO_VOL));
384
		}
385
386
		if ($this->session_expires()) {
387
			return array('error' => $this->error(self::ERROR_SESSION_EXPIRES));
388
		}
389
		
390
		if (!$this->commandExists($cmd)) {
391
			return array('error' => $this->error(self::ERROR_UNKNOWN_CMD));
392
		}
393
		
394
		if (!empty($args['mimes']) && is_array($args['mimes'])) {
395
			foreach ($this->volumes as $id => $v) {
396
				$this->volumes[$id]->setMimesFilter($args['mimes']);
397
			}
398
		}
399
		
400
		$result = $this->$cmd($args);
401
		
402
		if (isset($result['removed'])) {
403
			foreach ($this->volumes as $volume) {
404
				$result['removed'] = array_merge($result['removed'], $volume->removed());
405
				$volume->resetRemoved();
406
			}
407
		}
408
		
409
		// call handlers for this command
410
		if (!empty($this->listeners[$cmd])) {
411
			foreach ($this->listeners[$cmd] as $handler) {
412
				if (call_user_func_array($handler,array($cmd,&$result,$args,$this))) {
413
					// handler return true to force sync client after command completed
414
					$result['sync'] = true;
415
				}
416
			}
417
		}
418
		
419
		// replace removed files info with removed files hashes
420
		if (!empty($result['removed'])) {
421
			$removed = array();
422
			foreach ($result['removed'] as $file) {
423
				$removed[] = $file['hash'];
424
			}
425
			$result['removed'] = array_unique($removed);
426
		}
427
		// remove hidden files and filter files by mimetypes
428
		if (!empty($result['added'])) {
429
			$result['added'] = $this->filter($result['added']);
430
		}
431
		// remove hidden files and filter files by mimetypes
432
		if (!empty($result['changed'])) {
433
			$result['changed'] = $this->filter($result['changed']);
434
		}
435
		
436
		if ($this->debug || !empty($args['debug'])) {
437
			$result['debug'] = array(
438
				'connector' => 'php', 
439
				'phpver'    => PHP_VERSION,
440
				'time'      => $this->utime() - $this->time,
441
				'memory'    => (function_exists('memory_get_peak_usage') ? ceil(memory_get_peak_usage()/1024).'Kb / ' : '').ceil(memory_get_usage()/1024).'Kb / '.ini_get('memory_limit'),
442
				'upload'    => $this->uploadDebug,
443
				'volumes'   => array(),
444
				'mountErrors' => $this->mountErrors
445
				);
446
			
447
			foreach ($this->volumes as $id => $volume) {
448
				$result['debug']['volumes'][] = $volume->debug();
449
			}
450
		}
451
		
452
		foreach ($this->volumes as $volume) {
453
			$volume->umount();
454
		}
455
		
456
		return $result;
457
	}
458
	
459
	/**
460
	 * Return file real path
461
	 *
462
	 * @param  string  $hash  file hash
463
	 * @return string
464
	 * @author Dmitry (dio) Levashov
465
	 **/
466
	public function realpath($hash)	{
467
		if (($volume = $this->volume($hash)) == false) {
468
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by elFinder::realpath of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
469
		}
470
		return $volume->realpath($hash);
471
	}
472
	
473
	/**
474
	 * Return network volumes config.
475
	 *
476
	 * @return array
477
	 * @author Dmitry (dio) Levashov
478
	 */
479
	protected function getNetVolumes() {
0 ignored issues
show
Coding Style introduced by
getNetVolumes uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
480
		return isset($_SESSION['elFinderNetVolumes']) && is_array($_SESSION['elFinderNetVolumes']) ? $_SESSION['elFinderNetVolumes'] : array();
481
	}
482
483
	/**
484
	 * Save network volumes config.
485
	 *
486
	 * @param  array  $volumes  volumes config
487
	 * @return void
488
	 * @author Dmitry (dio) Levashov
489
	 */
490
	protected function saveNetVolumes($volumes) {
0 ignored issues
show
Coding Style introduced by
saveNetVolumes uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
491
		$_SESSION['elFinderNetVolumes'] = $volumes;
492
	}
493
494
	/***************************************************************************/
495
	/*                                 commands                                */
496
	/***************************************************************************/
497
	
498
	/**
499
	 * Normalize error messages
500
	 *
501
	 * @return array
502
	 * @author Dmitry (dio) Levashov
503
	 **/
504
	public function error() {
505
		$errors = array();
506
507
		foreach (func_get_args() as $msg) {
508
			if (is_array($msg)) {
509
				$errors = array_merge($errors, $msg);
510
			} else {
511
				$errors[] = $msg;
512
			}
513
		}
514
		
515
		return count($errors) ? $errors : array(self::ERROR_UNKNOWN);
516
	}
517
	
518
	protected function netmount($args) {
519
		$options  = array();
520
		$protocol = $args['protocol'];
521
		$driver   = isset(self::$netDrivers[$protocol]) ? $protocol : '';
522
		$class    = 'elfindervolume'.$protocol;
523
524
		if (!$driver) {
525
			return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], self::ERROR_NETMOUNT_NO_DRIVER));
526
		}
527
528
		if (!$args['path']) {
529
			$args['path'] = '/';
530
		}
531
532
		foreach ($args as $k => $v) {
533
			if ($k != 'options' && $k != 'protocol' && $v) {
534
				$options[$k] = $v;
535
			}
536
		}
537
538
		if (is_array($args['options'])) {
539
			foreach ($args['options'] as $key => $value) {
540
				$options[$key] = $value;
541
			}
542
		}
543
544
		$volume = new $class();
545
546
		if ($volume->mount($options)) {
547
			$netVolumes        = $this->getNetVolumes();
548
			$options['driver'] = $driver;
549
			$netVolumes[]      = $options;
550
			$netVolumes        = array_unique($netVolumes);
551
			$this->saveNetVolumes($netVolumes);
552
			return array('sync' => true);
553
		} else {
554
			return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], implode(' ', $volume->error())));
555
		}
556
557
	}
558
559
	/**
560
	 * "Open" directory
561
	 * Return array with following elements
562
	 *  - cwd          - opened dir info
563
	 *  - files        - opened dir content [and dirs tree if $args[tree]]
564
	 *  - api          - api version (if $args[init])
565
	 *  - uplMaxSize   - if $args[init]
566
	 *  - error        - on failed
567
	 *
568
	 * @param  array  command arguments
569
	 * @return array
570
	 * @author Dmitry (dio) Levashov
571
	 **/
572
	protected function open($args) {
573
		$target = $args['target'];
574
		$init   = !empty($args['init']);
575
		$tree   = !empty($args['tree']);
0 ignored issues
show
Unused Code introduced by
$tree 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...
576
		$volume = $this->volume($target);
577
		$cwd    = $volume ? $volume->dir($target, true) : false;
578
		$hash   = $init ? 'default folder' : '#'.$target;
579
580
		// on init request we can get invalid dir hash -
581
		// dir which can not be opened now, but remembered by client,
582
		// so open default dir
583
		if ((!$cwd || !$cwd['read']) && $init) {
584
			$volume = $this->default;
585
			$cwd    = $volume->dir($volume->defaultPath(), true);
586
		}
587
		
588
		if (!$cwd) {
589
			return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_DIR_NOT_FOUND));
590
		}
591
		if (!$cwd['read']) {
592
			return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_PERM_DENIED));
593
		}
594
595
		$files = array();
596
597
		// get folders trees
598
		if ($args['tree']) {
599
			foreach ($this->volumes as $id => $v) {
600
				if (($tree = $v->tree('', 0, $cwd['hash'])) != false) {
601
					$files = array_merge($files, $tree);
602
				}
603
			}
604
		}
605
606
		// get current working directory files list and add to $files if not exists in it
607
		if (($ls = $volume->scandir($cwd['hash'])) === false) {
608
			return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error()));
609
		}
610
		
611
		foreach ($ls as $file) {
612
			if (!in_array($file, $files)) {
613
				$files[] = $file;
614
			}
615
		}
616
		
617
		$result = array(
618
			'cwd'     => $cwd,
619
			'options' => $volume->options($cwd['hash']),
620
			'files'   => $files
621
		);
622
623
		if (!empty($args['init'])) {
624
			$result['api'] = $this->version;
625
			$result['uplMaxSize'] = ini_get('upload_max_filesize');
626
			$result['netDrivers'] = array_keys(self::$netDrivers);
627
		}
628
		
629
		return $result;
630
	}
631
	
632
	/**
633
	 * Return dir files names list
634
	 *
635
	 * @param  array  command arguments
636
	 * @return array
637
	 * @author Dmitry (dio) Levashov
638
	 **/
639 View Code Duplication
	protected function ls($args) {
640
		$target = $args['target'];
641
		
642
		if (($volume = $this->volume($target)) == false
643
		|| ($list = $volume->ls($target)) === false) {
644
			return array('error' => $this->error(self::ERROR_OPEN, '#'.$target));
645
		}
646
		return array('list' => $list);
647
	}
648
	
649
	/**
650
	 * Return subdirs for required directory
651
	 *
652
	 * @param  array  command arguments
653
	 * @return array
654
	 * @author Dmitry (dio) Levashov
655
	 **/
656 View Code Duplication
	protected function tree($args) {
657
		$target = $args['target'];
658
		
659
		if (($volume = $this->volume($target)) == false
660
		|| ($tree = $volume->tree($target)) == false) {
661
			return array('error' => $this->error(self::ERROR_OPEN, '#'.$target));
662
		}
663
664
		return array('tree' => $tree);
665
	}
666
	
667
	/**
668
	 * Return parents dir for required directory
669
	 *
670
	 * @param  array  command arguments
671
	 * @return array
672
	 * @author Dmitry (dio) Levashov
673
	 **/
674 View Code Duplication
	protected function parents($args) {
675
		$target = $args['target'];
676
		
677
		if (($volume = $this->volume($target)) == false
678
		|| ($tree = $volume->parents($target)) == false) {
679
			return array('error' => $this->error(self::ERROR_OPEN, '#'.$target));
680
		}
681
682
		return array('tree' => $tree);
683
	}
684
	
685
	/**
686
	 * Return new created thumbnails list
687
	 *
688
	 * @param  array  command arguments
689
	 * @return array
690
	 * @author Dmitry (dio) Levashov
691
	 **/
692
	protected function tmb($args) {
693
		
694
		$result  = array('images' => array());
695
		$targets = $args['targets'];
696
		
697
		foreach ($targets as $target) {
698
			if (($volume = $this->volume($target)) != false
699
			&& (($tmb = $volume->tmb($target)) != false)) {
700
				$result['images'][$target] = $tmb;
701
			}
702
		}
703
		return $result;
704
	}
705
	
706
	/**
707
	 * Required to output file in browser when volume URL is not set 
708
	 * Return array contains opened file pointer, root itself and required headers
709
	 *
710
	 * @param  array  command arguments
711
	 * @return array
712
	 * @author Dmitry (dio) Levashov
713
	 **/
714
	protected function file($args) {
0 ignored issues
show
Coding Style introduced by
file uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
715
		$target   = $args['target'];
716
		$download = !empty($args['download']);
717
		$h403     = 'HTTP/1.x 403 Access Denied';
718
		$h404     = 'HTTP/1.x 404 Not Found';
719
720 View Code Duplication
		if (($volume = $this->volume($target)) == false) { 
721
			return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
722
		}
723
		
724 View Code Duplication
		if (($file = $volume->file($target)) == false) {
725
			return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
726
		}
727
		
728
		if (!$file['read']) {
729
			return array('error' => 'Access denied', 'header' => $h403, 'raw' => true);
730
		}
731
		
732 View Code Duplication
		if (($fp = $volume->open($target)) == false) {
733
			return array('error' => 'File not found', 'header' => $h404, 'raw' => true);
734
		}
735
736
		if ($download) {
737
			$disp = 'attachment';
738
			$mime = 'application/octet-stream';
739
		} else {
740
			$disp  = preg_match('/^(image|text)/i', $file['mime']) || $file['mime'] == 'application/x-shockwave-flash' 
741
					? 'inline' 
742
					: 'attachment';
743
			$mime = $file['mime'];
744
		}
745
		
746
		$filenameEncoded = rawurlencode($file['name']);
747
		if (strpos($filenameEncoded, '%') === false) { // ASCII only
748
			$filename = 'filename="'.$file['name'].'"';
749
		} else {
750
			$ua = $_SERVER["HTTP_USER_AGENT"];
751
			if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987)
752
				$filename = 'filename="'.$filenameEncoded.'"';
753
			} elseif (strpos($ua, 'Chrome') === false && strpos($ua, 'Safari') !== false) { // Safari
754
				$filename = 'filename="'.str_replace('"', '', $file['name']).'"';
755
			} else { // RFC 6266 (RFC 2231/RFC 5987)
756
				$filename = 'filename*=UTF-8\'\''.$filenameEncoded;
757
			}
758
		}
759
		
760
		$result = array(
761
			'volume'  => $volume,
762
			'pointer' => $fp,
763
			'info'    => $file,
764
			'header'  => array(
765
				'Content-Type: '.$mime, 
766
				'Content-Disposition: '.$disp.'; '.$filename,
767
				'Content-Location: '.$file['name'],
768
				'Content-Transfer-Encoding: binary',
769
				'Content-Length: '.$file['size'],
770
				'Connection: close'
771
			)
772
		);
773
		return $result;
774
	}
775
	
776
	/**
777
	 * Count total files size
778
	 *
779
	 * @param  array  command arguments
780
	 * @return array
781
	 * @author Dmitry (dio) Levashov
782
	 **/
783
	protected function size($args) {
784
		$size = 0;
785
		
786
		foreach ($args['targets'] as $target) {
787
			if (($volume = $this->volume($target)) == false
788
			|| ($file = $volume->file($target)) == false
789
			|| !$file['read']) {
790
				return array('error' => $this->error(self::ERROR_OPEN, '#'.$target));
791
			}
792
			
793
			$size += $volume->size($target);
794
		}
795
		return array('size' => $size);
796
	}
797
	
798
	/**
799
	 * Create directory
800
	 *
801
	 * @param  array  command arguments
802
	 * @return array
803
	 * @author Dmitry (dio) Levashov
804
	 **/
805 View Code Duplication
	protected function mkdir($args) {
806
		$target = $args['target'];
807
		$name   = $args['name'];
808
		
809
		if (($volume = $this->volume($target)) == false) {
810
			return array('error' => $this->error(self::ERROR_MKDIR, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target));
811
		}
812
813
		return ($dir = $volume->mkdir($target, $name)) == false
814
			? array('error' => $this->error(self::ERROR_MKDIR, $name, $volume->error()))
815
			: array('added' => array($dir));
816
	}
817
	
818
	/**
819
	 * Create empty file
820
	 *
821
	 * @param  array  command arguments
822
	 * @return array
823
	 * @author Dmitry (dio) Levashov
824
	 **/
825 View Code Duplication
	protected function mkfile($args) {
826
		$target = $args['target'];
827
		$name   = $args['name'];
828
		
829
		if (($volume = $this->volume($target)) == false) {
830
			return array('error' => $this->error(self::ERROR_MKFILE, $name, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target));
831
		}
832
833
		return ($file = $volume->mkfile($target, $args['name'])) == false
834
			? array('error' => $this->error(self::ERROR_MKFILE, $name, $volume->error()))
835
			: array('added' => array($file));
836
	}
837
	
838
	/**
839
	 * Rename file
840
	 *
841
	 * @param  array  $args
842
	 * @return array
843
	 * @author Dmitry (dio) Levashov
844
	 **/
845
	protected function rename($args) {
846
		$target = $args['target'];
847
		$name   = $args['name'];
848
		
849 View Code Duplication
		if (($volume = $this->volume($target)) == false
850
		||  ($rm  = $volume->file($target)) == false) {
851
			return array('error' => $this->error(self::ERROR_RENAME, '#'.$target, self::ERROR_FILE_NOT_FOUND));
852
		}
853
		$rm['realpath'] = $volume->realpath($target);
854
		
855
		return ($file = $volume->rename($target, $name)) == false
856
			? array('error' => $this->error(self::ERROR_RENAME, $rm['name'], $volume->error()))
857
			: array('added' => array($file), 'removed' => array($rm));
858
	}
859
	
860
	/**
861
	 * Duplicate file - create copy with "copy %d" suffix
862
	 *
863
	 * @param array  $args  command arguments
864
	 * @return array
865
	 * @author Dmitry (dio) Levashov
866
	 **/
867
	protected function duplicate($args) {
868
		$targets = is_array($args['targets']) ? $args['targets'] : array();
869
		$result  = array('added' => array());
870
		$suffix  = empty($args['suffix']) ? 'copy' : $args['suffix'];
871
		
872
		foreach ($targets as $target) {
873 View Code Duplication
			if (($volume = $this->volume($target)) == false
874
			|| ($src = $volume->file($target)) == false) {
875
				$result['warning'] = $this->error(self::ERROR_COPY, '#'.$target, self::ERROR_FILE_NOT_FOUND);
876
				break;
877
			}
878
			
879
			if (($file = $volume->duplicate($target, $suffix)) == false) {
880
				$result['warning'] = $this->error($volume->error());
881
				break;
882
			}
883
			
884
			$result['added'][] = $file;
885
		}
886
		
887
		return $result;
888
	}
889
		
890
	/**
891
	 * Remove dirs/files
892
	 *
893
	 * @param array  command arguments
894
	 * @return array
895
	 * @author Dmitry (dio) Levashov
896
	 **/
897
	protected function rm($args) {
898
		$targets = is_array($args['targets']) ? $args['targets'] : array();
899
		$result  = array('removed' => array());
900
		
901
		foreach ($targets as $target) {
902 View Code Duplication
			if (($volume = $this->volume($target)) == false) {
903
				$result['warning'] = $this->error(self::ERROR_RM, '#'.$target, self::ERROR_FILE_NOT_FOUND);
904
				return $result;
905
			}
906
			if (!$volume->rm($target)) {
907
				$result['warning'] = $this->error($volume->error());
908
				return $result;
909
			}
910
		}
911
912
		return $result;
913
	}
914
	
915
	/**
916
	 * Save uploaded files
917
	 *
918
	 * @param  array
919
	 * @return array
920
	 * @author Dmitry (dio) Levashov
921
	 **/
922
	protected function upload($args) {
923
		$target = $args['target'];
924
		$volume = $this->volume($target);
925
		$files  = isset($args['FILES']['upload']) && is_array($args['FILES']['upload']) ? $args['FILES']['upload'] : array();
926
		$result = array('added' => array(), 'header' => empty($args['html']) ? false : 'Content-Type: text/html; charset=utf-8');
927
		
928
		if (empty($files)) {
929
			return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_UPLOAD_NO_FILES), 'header' => $header);
0 ignored issues
show
Bug introduced by
The variable $header does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
930
		}
931
		
932
		if (!$volume) {
933
			return array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, '#'.$target), 'header' => $header);
934
		}
935
		
936
		foreach ($files['name'] as $i => $name) {
937
			if (($error = $files['error'][$i]) > 0) {				
938
				$result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE ? self::ERROR_UPLOAD_FILE_SIZE : self::ERROR_UPLOAD_TRANSFER);
939
				$this->uploadDebug = 'Upload error code: '.$error;
940
				break;
941
			}
942
			
943
			$tmpname = $files['tmp_name'][$i];
944
			
945
			if (($fp = fopen($tmpname, 'rb')) == false) {
946
				$result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, self::ERROR_UPLOAD_TRANSFER);
947
				$this->uploadDebug = 'Upload error: unable open tmp file';
948
				break;
949
			}
950
			
951
			if (($file = $volume->upload($fp, $target, $name, $tmpname)) === false) {
952
				$result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $volume->error());
953
				fclose($fp);
954
				break;
955
			}
956
			
957
			fclose($fp);
958
			$result['added'][] = $file;
959
		}
960
		
961
		return $result;
962
	}
963
		
964
	/**
965
	 * Copy/move files into new destination
966
	 *
967
	 * @param  array  command arguments
968
	 * @return array
969
	 * @author Dmitry (dio) Levashov
970
	 **/
971
	protected function paste($args) {
972
		$dst     = $args['dst'];
973
		$targets = is_array($args['targets']) ? $args['targets'] : array();
974
		$cut     = !empty($args['cut']);
975
		$error   = $cut ? self::ERROR_MOVE : self::ERROR_COPY;
976
		$result  = array('added' => array(), 'removed' => array());
977
		
978
		if (($dstVolume = $this->volume($dst)) == false) {
979
			return array('error' => $this->error($error, '#'.$targets[0], self::ERROR_TRGDIR_NOT_FOUND, '#'.$dst));
980
		}
981
		
982
		foreach ($targets as $target) {
983 View Code Duplication
			if (($srcVolume = $this->volume($target)) == false) {
984
				$result['warning'] = $this->error($error, '#'.$target, self::ERROR_FILE_NOT_FOUND);
985
				break;
986
			}
987
			
988
			if (($file = $dstVolume->paste($srcVolume, $target, $dst, $cut)) == false) {
989
				$result['warning'] = $this->error($dstVolume->error());
990
				break;
991
			}
992
			
993
			$result['added'][] = $file;
994
		}
995
		return $result;
996
	}
997
	
998
	/**
999
	 * Return file content
1000
	 *
1001
	 * @param  array  $args  command arguments
1002
	 * @return array
1003
	 * @author Dmitry (dio) Levashov
1004
	 **/
1005
	protected function get($args) {
1006
		$target = $args['target'];
1007
		$volume = $this->volume($target);
1008
		
1009
		if (!$volume || ($file = $volume->file($target)) == false) {
1010
			return array('error' => $this->error(self::ERROR_OPEN, '#'.$target, self::ERROR_FILE_NOT_FOUND));
1011
		}
1012
		
1013 View Code Duplication
		if (($content = $volume->getContents($target)) === false) {
1014
			return array('error' => $this->error(self::ERROR_OPEN, $volume->path($target), $volume->error()));
1015
		}
1016
		
1017
		$json = json_encode($content);
1018
1019
		if ($json == 'null' && strlen($json) < strlen($content)) {
1020
			return array('error' => $this->error(self::ERROR_NOT_UTF8_CONTENT, $volume->path($target)));
1021
		}
1022
		
1023
		return array('content' => $content);
1024
	}
1025
	
1026
	/**
1027
	 * Save content into text file
1028
	 *
1029
	 * @return array
1030
	 * @author Dmitry (dio) Levashov
1031
	 **/
1032
	protected function put($args) {
1033
		$target = $args['target'];
1034
		
1035 View Code Duplication
		if (($volume = $this->volume($target)) == false
1036
		|| ($file = $volume->file($target)) == false) {
1037
			return array('error' => $this->error(self::ERROR_SAVE, '#'.$target, self::ERROR_FILE_NOT_FOUND));
1038
		}
1039
		
1040 View Code Duplication
		if (($file = $volume->putContents($target, $args['content'])) == false) {
1041
			return array('error' => $this->error(self::ERROR_SAVE, $volume->path($target), $volume->error()));
1042
		}
1043
		
1044
		return array('changed' => array($file));
1045
	}
1046
1047
	/**
1048
	 * Extract files from archive
1049
	 *
1050
	 * @param  array  $args  command arguments
1051
	 * @return array
1052
	 * @author Dmitry (dio) Levashov, 
1053
	 * @author Alexey Sukhotin
1054
	 **/
1055
	protected function extract($args) {
1056
		$target = $args['target'];
1057
		$mimes  = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array();
0 ignored issues
show
Unused Code introduced by
$mimes 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...
1058
		$error  = array(self::ERROR_EXTRACT, '#'.$target);
0 ignored issues
show
Unused Code introduced by
$error 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...
1059
1060 View Code Duplication
		if (($volume = $this->volume($target)) == false
1061
		|| ($file = $volume->file($target)) == false) {
1062
			return array('error' => $this->error(self::ERROR_EXTRACT, '#'.$target, self::ERROR_FILE_NOT_FOUND));
1063
		}  
1064
1065
		return ($file = $volume->extract($target))
1066
			? array('added' => array($file))
1067
			: array('error' => $this->error(self::ERROR_EXTRACT, $volume->path($target), $volume->error()));
1068
	}
1069
	
1070
	/**
1071
	 * Create archive
1072
	 *
1073
	 * @param  array  $args  command arguments
1074
	 * @return array
1075
	 * @author Dmitry (dio) Levashov, 
1076
	 * @author Alexey Sukhotin
1077
	 **/
1078
	protected function archive($args) {
1079
		$type    = $args['type'];
0 ignored issues
show
Unused Code introduced by
$type 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...
1080
		$targets = isset($args['targets']) && is_array($args['targets']) ? $args['targets'] : array();
1081
	
1082
		if (($volume = $this->volume($targets[0])) == false) {
1083
			return $this->error(self::ERROR_ARCHIVE, self::ERROR_TRGDIR_NOT_FOUND);
1084
		}
1085
	
1086
		return ($file = $volume->archive($targets, $args['type']))
1087
			? array('added' => array($file))
1088
			: array('error' => $this->error(self::ERROR_ARCHIVE, $volume->error()));
1089
	}
1090
	
1091
	/**
1092
	 * Search files
1093
	 *
1094
	 * @param  array  $args  command arguments
1095
	 * @return array
1096
	 * @author Dmitry Levashov
1097
	 **/
1098
	protected function search($args) {
1099
		$q      = trim($args['q']);
1100
		$mimes  = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array();
1101
		$result = array();
1102
1103
		foreach ($this->volumes as $volume) {
1104
			$result = array_merge($result, $volume->search($q, $mimes));
1105
		}
1106
		
1107
		return array('files' => $result);
1108
	}
1109
	
1110
	/**
1111
	 * Return file info (used by client "places" ui)
1112
	 *
1113
	 * @param  array  $args  command arguments
1114
	 * @return array
1115
	 * @author Dmitry Levashov
1116
	 **/
1117
	protected function info($args) {
1118
		$files = array();
1119
		
1120
		foreach ($args['targets'] as $hash) {
1121
			if (($volume = $this->volume($hash)) != false
1122
			&& ($info = $volume->file($hash)) != false) {
1123
				$files[] = $info;
1124
			}
1125
		}
1126
		
1127
		return array('files' => $files);
1128
	}
1129
	
1130
	/**
1131
	 * Return image dimmensions
1132
	 *
1133
	 * @param  array  $args  command arguments
1134
	 * @return array
1135
	 * @author Dmitry (dio) Levashov
1136
	 **/
1137
	protected function dim($args) {
1138
		$target = $args['target'];
1139
		
1140
		if (($volume = $this->volume($target)) != false) {
1141
			$dim = $volume->dimensions($target);
1142
			return $dim ? array('dim' => $dim) : array();
1143
		}
1144
		return array();
1145
	}
1146
	
1147
	/**
1148
	 * Resize image
1149
	 *
1150
	 * @param  array  command arguments
1151
	 * @return array
1152
	 * @author Dmitry (dio) Levashov
1153
	 * @author Alexey Sukhotin
1154
	 **/
1155
	protected function resize($args) {
1156
		$target = $args['target'];
1157
		$width  = $args['width'];
1158
		$height = $args['height'];
1159
		$x      = (int)$args['x'];
1160
		$y      = (int)$args['y'];
1161
		$mode   = $args['mode'];
1162
		$bg     = null;
1163
		$degree = (int)$args['degree'];
1164
		
1165 View Code Duplication
		if (($volume = $this->volume($target)) == false
1166
		|| ($file = $volume->file($target)) == false) {
1167
			return array('error' => $this->error(self::ERROR_RESIZE, '#'.$target, self::ERROR_FILE_NOT_FOUND));
1168
		}
1169
1170
		return ($file = $volume->resize($target, $width, $height, $x, $y, $mode, $bg, $degree))
1171
			? array('changed' => array($file))
1172
			: array('error' => $this->error(self::ERROR_RESIZE, $volume->path($target), $volume->error()));
1173
	}
1174
	
1175
	/***************************************************************************/
1176
	/*                                   utils                                 */
1177
	/***************************************************************************/
1178
	
1179
	/**
1180
	 * Return root - file's owner
1181
	 *
1182
	 * @param  string  file hash
1183
	 * @return elFinderStorageDriver
1184
	 * @author Dmitry (dio) Levashov
1185
	 **/
1186
	protected function volume($hash) {
1187
		foreach ($this->volumes as $id => $v) {
1188
			if (strpos(''.$hash, $id) === 0) {
1189
				return $this->volumes[$id];
1190
			} 
1191
		}
1192
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by elFinder::volume of type elFinderStorageDriver.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1193
	}
1194
	
1195
	/**
1196
	 * Return files info array 
1197
	 *
1198
	 * @param  array  $data  one file info or files info
1199
	 * @return array
1200
	 * @author Dmitry (dio) Levashov
1201
	 **/
1202
	protected function toArray($data) {
1203
		return isset($data['hash']) || !is_array($data) ? array($data) : $data;
1204
	}
1205
	
1206
	/**
1207
	 * Return fils hashes list
1208
	 *
1209
	 * @param  array  $files  files info
1210
	 * @return array
1211
	 * @author Dmitry (dio) Levashov
1212
	 **/
1213
	protected function hashes($files) {
1214
		$ret = array();
1215
		foreach ($files as $file) {
1216
			$ret[] = $file['hash'];
1217
		}
1218
		return $ret;
1219
	}
1220
	
1221
	/**
1222
	 * Remove from files list hidden files and files with required mime types
1223
	 *
1224
	 * @param  array  $files  files info
1225
	 * @return array
1226
	 * @author Dmitry (dio) Levashov
1227
	 **/
1228
	protected function filter($files) {
1229
		foreach ($files as $i => $file) {
1230
			if (!empty($file['hidden']) || !$this->default->mimeAccepted($file['mime'])) {
1231
				unset($files[$i]);
1232
			}
1233
		}
1234
		return array_merge($files, array());
1235
	}
1236
	
1237
	protected function utime() {
1238
		$time = explode(" ", microtime());
1239
		return (double)$time[1] + (double)$time[0];
1240
	}
1241
	
1242
} // END class
1243