Completed
Push — 2.x ( 69ba55...9c0595 )
by Naoki
03:19
created

elFinderVolumeLocalFileSystem::configure()   F

Complexity

Conditions 20
Paths 720

Size

Total Lines 62
Code Lines 35

Duplication

Lines 5
Ratio 8.06 %
Metric Value
dl 5
loc 62
rs 3.2258
cc 20
eloc 35
nc 720
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * elFinder driver for local filesystem.
5
 *
6
 * @author Dmitry (dio) Levashov
7
 * @author Troex Nevelin
8
 **/
9
class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
10
	
11
	/**
12
	 * Driver id
13
	 * Must be started from letter and contains [a-z0-9]
14
	 * Used as part of volume id
15
	 *
16
	 * @var string
17
	 **/
18
	protected $driverId = 'l';
19
	
20
	/**
21
	 * Required to count total archive files size
22
	 *
23
	 * @var int
24
	 **/
25
	protected $archiveSize = 0;
26
	
27
	/**
28
	 * Constructor
29
	 * Extend options with required fields
30
	 *
31
	 * @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...
32
	 * @author Dmitry (dio) Levashov
33
	 **/
34
	public function __construct() {
35
		$this->options['alias']    = '';              // alias to replace root dir name
36
		$this->options['dirMode']  = 0755;            // new dirs mode
37
		$this->options['fileMode'] = 0644;            // new files mode
38
		$this->options['quarantine'] = '.quarantine';  // quarantine folder name - required to check archive (must be hidden)
39
		$this->options['maxArcFilesSize'] = 0;        // max allowed archive files size (0 - no limit)
40
		$this->options['rootCssClass'] = 'elfinder-navbar-root-local';
41
	}
42
	
43
	/*********************************************************************/
44
	/*                        INIT AND CONFIGURE                         */
45
	/*********************************************************************/
46
	
47
	/**
48
	 * Prepare driver before mount volume.
49
	 * Return true if volume is ready.
50
	 *
51
	 * @return bool
52
	 **/
53
	protected function init() {
54
		// Normalize directory separator for windows
55
		if (DIRECTORY_SEPARATOR !== '/') {
56
			foreach(array('path', 'tmbPath', 'tmpPath', 'quarantine') as $key) {
57
				if (!empty($this->options[$key])) {
58
					$this->options[$key] = str_replace('/', DIRECTORY_SEPARATOR, $this->options[$key]);
59
				}
60
			}
61
		}
62
		if (!$cwd = getcwd()) {
63
			return $this->setError('elFinder LocalVolumeDriver requires a result of getcwd().');
64
		}
65
		// detect systemRoot
66
		if (!isset($this->options['systemRoot'])) {
67
			if ($cwd[0] === $this->separator || $this->root[0] === $this->separator) {
68
				$this->systemRoot = $this->separator;
69
			} else if (preg_match('/^([a-zA-Z]:'.preg_quote($this->separator, '/').')/', $this->root, $m)) {
70
				$this->systemRoot = $m[1];
71
			} else if (preg_match('/^([a-zA-Z]:'.preg_quote($this->separator, '/').')/', $cwd, $m)) {
72
				$this->systemRoot = $m[1];
73
			}
74
		}
75
		$this->root = $this->getFullPath($this->root, $cwd);
76
		if (!empty($this->options['startPath'])) {
77
			$this->options['startPath'] = $this->getFullPath($this->options['startPath'], $cwd);
78
		}
79
		return true;
80
	}
81
	
82
	/**
83
	 * Configure after successfull mount.
84
	 *
85
	 * @return void
86
	 * @author Dmitry (dio) Levashov
87
	 **/
88
	protected function configure() {
89
		$root = $this->stat($this->root);
90
		
91
		// chek thumbnails path
92
		if ($this->options['tmbPath']) {
93
			$this->options['tmbPath'] = strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false
94
				// tmb path set as dirname under root dir
95
				? $this->_abspath($this->options['tmbPath'])
96
				// tmb path as full path
97
				: $this->_normpath($this->options['tmbPath']);
98
		}
99
100
		parent::configure();
101
		
102
		// set $this->tmp by options['tmpPath']
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
103 View Code Duplication
		if (!empty($this->options['tmpPath'])) {
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...
104
			if ((is_dir($this->options['tmpPath']) || @mkdir($this->options['tmpPath'], 0755, true)) && is_writable($this->options['tmpPath'])) {
105
				$this->tmp = $this->options['tmpPath'];
0 ignored issues
show
Bug introduced by
The property tmp 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...
106
			}
107
		}
108
		
109
		// if no thumbnails url - try detect it
110
		if ($root['read'] && !$this->tmbURL && $this->URL) {
111
			if (strpos($this->tmbPath, $this->root) === 0) {
112
				$this->tmbURL = $this->URL.str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root)+1));
113
				if (preg_match("|[^/?&=]$|", $this->tmbURL)) {
114
					$this->tmbURL .= '/';
115
				}
116
			}
117
		}
118
119
		// check quarantine dir
120
		$this->quarantine = '';
0 ignored issues
show
Bug introduced by
The property quarantine 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...
121
		if (!empty($this->options['quarantine'])) {
122
			if (is_dir($this->options['quarantine'])) {
123
				if (is_writable($this->options['quarantine'])) {
124
					$this->quarantine = $this->options['quarantine'];
125
				}
126
				$this->options['quarantine'] = '';
127
			} else {
128
				$this->quarantine = $this->_abspath($this->options['quarantine']);
129
				if ((!is_dir($this->quarantine) && !$this->_mkdir($this->root, $this->options['quarantine'])) || !is_writable($this->quarantine)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_mkdir($this->roo...>options['quarantine']) of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
130
					$this->options['quarantine'] = $this->quarantine = '';
131
				}
132
			}
133
		}
134
		
135
		if (!$this->quarantine) {
136
			$this->archivers['extract'] = array();
137
			$this->disabled[] = 'extract';
138
		}
139
		
140
		if ($this->options['quarantine']) {
141
			$this->attributes[] = array(
142
					'pattern' => '~^'.preg_quote(DIRECTORY_SEPARATOR.$this->options['quarantine']).'$~',
143
					'read'    => false,
144
					'write'   => false,
145
					'locked'  => true,
146
					'hidden'  => true
147
			);
148
		}
149
	}
150
	
151
	/*********************************************************************/
152
	/*                               FS API                              */
153
	/*********************************************************************/
154
155
	/*********************** paths/urls *************************/
156
	
157
	/**
158
	 * Return parent directory path
159
	 *
160
	 * @param  string  $path  file path
161
	 * @return string
162
	 * @author Dmitry (dio) Levashov
163
	 **/
164
	protected function _dirname($path) {
165
		return dirname($path);
166
	}
167
168
	/**
169
	 * Return file name
170
	 *
171
	 * @param  string  $path  file path
172
	 * @return string
173
	 * @author Dmitry (dio) Levashov
174
	 **/
175
	protected function _basename($path) {
176
		return basename($path);
177
	}
178
179
	/**
180
	 * Join dir name and file name and retur full path
181
	 *
182
	 * @param  string  $dir
183
	 * @param  string  $name
184
	 * @return string
185
	 * @author Dmitry (dio) Levashov
186
	 **/
187
	protected function _joinPath($dir, $name) {
188
		return rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name;
189
	}
190
	
191
	/**
192
	 * Return normalized path, this works the same as os.path.normpath() in Python
193
	 *
194
	 * @param  string  $path  path
195
	 * @return string
196
	 * @author Troex Nevelin
197
	 **/
198
	protected function _normpath($path) {
199
		if (empty($path)) {
200
			return '.';
201
		}
202
		
203
		$changeSep = (DIRECTORY_SEPARATOR !== '/');
204
		if ($changeSep) {
205
			$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
206
		}
207
208
		if (strpos($path, '/') === 0) {
209
			$initial_slashes = true;
210
		} else {
211
			$initial_slashes = false;
212
		}
213
			
214 View Code Duplication
		if (($initial_slashes) 
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...
215
		&& (strpos($path, '//') === 0) 
216
		&& (strpos($path, '///') === false)) {
217
			$initial_slashes = 2;
218
		}
219
			
220
		$initial_slashes = (int) $initial_slashes;
221
222
		$comps = explode('/', $path);
223
		$new_comps = array();
224 View Code Duplication
		foreach ($comps as $comp) {
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...
225
			if (in_array($comp, array('', '.'))) {
226
				continue;
227
			}
228
				
229
			if (($comp != '..') 
230
			|| (!$initial_slashes && !$new_comps) 
0 ignored issues
show
Bug Best Practice introduced by
The expression $new_comps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
231
			|| ($new_comps && (end($new_comps) == '..'))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $new_comps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
232
				array_push($new_comps, $comp);
233
			} elseif ($new_comps) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $new_comps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
234
				array_pop($new_comps);
235
			}
236
		}
237
		$comps = $new_comps;
238
		$path = implode('/', $comps);
239
		if ($initial_slashes) {
240
			$path = str_repeat('/', $initial_slashes) . $path;
241
		}
242
		
243
		if ($changeSep) {
244
			$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
245
		}
246
		
247
		return $path ? $path : '.';
248
	}
249
	
250
	/**
251
	 * Return file path related to root dir
252
	 *
253
	 * @param  string  $path  file path
254
	 * @return string
255
	 * @author Dmitry (dio) Levashov
256
	 **/
257 View Code Duplication
	protected function _relpath($path) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
258
		if ($path === $this->root) {
259
			return '';
260
		} else {
261
			if (strpos($path, $this->root) === 0) {
262
				return ltrim(substr($path, strlen($this->root)), DIRECTORY_SEPARATOR);
263
			} else {
264
				// for link
265
				return $path;
266
			}
267
		}
268
	}
269
	
270
	/**
271
	 * Convert path related to root dir into real path
272
	 *
273
	 * @param  string  $path  file path
274
	 * @return string
275
	 * @author Dmitry (dio) Levashov
276
	 **/
277
	protected function _abspath($path) {
278
		if ($path === DIRECTORY_SEPARATOR) {
279
			return $this->root;
280
		} else {
281
			if ($path[0] === DIRECTORY_SEPARATOR) {
282
				// for link
283
				return $path;
284
			} else {
285
				return $this->_joinPath($this->root, $path);
286
			}
287
		}
288
	}
289
	
290
	/**
291
	 * Return fake path started from root dir
292
	 *
293
	 * @param  string  $path  file path
294
	 * @return string
295
	 * @author Dmitry (dio) Levashov
296
	 **/
297
	protected function _path($path) {
298
		return $this->rootName.($path == $this->root ? '' : $this->separator.$this->_relpath($path));
299
	}
300
	
301
	/**
302
	 * Return true if $path is children of $parent
303
	 *
304
	 * @param  string  $path    path to check
305
	 * @param  string  $parent  parent path
306
	 * @return bool
307
	 * @author Dmitry (dio) Levashov
308
	 **/
309
	protected function _inpath($path, $parent) {
310
		$cwd = getcwd();
311
		$real_path   = $this->getFullPath($path,   $cwd);
312
		$real_parent = $this->getFullPath($parent, $cwd);
313
		if ($real_path && $real_parent) {
314
			return $real_path === $real_parent || strpos($real_path, rtrim($real_parent, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR) === 0;
315
		}
316
		return false;
317
	}
318
	
319
	
320
	
321
	/***************** file stat ********************/
322
323
	/**
324
	 * Return stat for given path.
325
	 * Stat contains following fields:
326
	 * - (int)    size    file size in b. required
327
	 * - (int)    ts      file modification time in unix time. required
328
	 * - (string) mime    mimetype. required for folders, others - optionally
329
	 * - (bool)   read    read permissions. required
330
	 * - (bool)   write   write permissions. required
331
	 * - (bool)   locked  is object locked. optionally
332
	 * - (bool)   hidden  is object hidden. optionally
333
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
334
	 * - (string) target  for symlinks - link target path. optionally
335
	 *
336
	 * If file does not exists - returns empty array or false.
337
	 *
338
	 * @param  string  $path    file path 
339
	 * @return array|false
340
	 * @author Dmitry (dio) Levashov
341
	 **/
342
	protected function _stat($path) {
343
		
344
		static $statOwner;
345
		if (is_null($statOwner)) {
346
			$statOwner = (!empty($this->options['statOwner']));
347
		}
348
		
349
		$stat = array();
350
351
		if (!file_exists($path) && !is_link($path)) {
352
			return $stat;
353
		}
354
355
		//Verifies the given path is the root or is inside the root. Prevents directory traveral.
356
		if (!$this->_inpath($path, $this->root)) {
357
			return $stat;
358
		}
359
360
		$gid = $uid = 0;
0 ignored issues
show
Unused Code introduced by
$uid 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...
Unused Code introduced by
$gid 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...
361
		$stat['isowner'] = false;
362
		$linkreadable = false;
363
		if ($path != $this->root && is_link($path)) {
364
			if (!($target = $this->readlink($path))
365
			|| $target == $path) {
366
				if (is_null($target)) {
367
					$stat = array();
368
					return $stat;
369
				} else {
370
					$stat['mime']  = 'symlink-broken';
371
					$target = readlink($path);
372
					$lstat = lstat($path);
373
					$ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']);
374
					$linkreadable = !empty($ostat['isowner']);
375
				}
376
			}
377
			$stat['alias'] = $this->_path($target);
378
			$stat['target'] = $target;
379
		}
380
		$size = sprintf('%u', @filesize($path));
381
		$stat['ts'] = filemtime($path);
382
		if ($statOwner) {
383
			$fstat = stat($path);
384
			$uid = $fstat['uid'];
385
			$gid = $fstat['gid'];
386
			$stat['perm'] = substr((string)decoct($fstat['mode']), -4);
387
			$stat = array_merge($stat, $this->getOwnerStat($uid, $gid));
388
		}
389
		
390
		$dir = is_dir($path);
391
		
392
		if (!isset($stat['mime'])) {
393
			$stat['mime'] = $dir ? 'directory' : $this->mimetype($path);
394
		}
395
		//logical rights first
396
		$stat['read'] = ($linkreadable || is_readable($path))? null : false;
397
		$stat['write'] = is_writable($path)? null : false;
398
399
		if (is_null($stat['read'])) {
400
			$stat['size'] = $dir ? 0 : $size;
401
		}
402
		
403
		return $stat;
404
	}
405
	
406
	/**
407
	 * Get stat `owner`, `group` and `isowner` by `uid` and `gid`
408
	 * Sub-fuction of _stat() and _scandir()
409
	 * 
410
	 * @param integer $uid
411
	 * @param integer $gid
412
	 * @return array  stat
413
	 */
414
	protected function getOwnerStat($uid, $gid) {
415
		static $names = null;
416
		static $phpuid = null;
417
		
418
		if (is_null($names)) {
419
			$names = array('uid' => array(), 'gid' =>array());
420
		}
421
		if (is_null($phpuid)) {
422
			if (is_callable('posix_getuid')) {
423
				$phpuid = posix_getuid();
424
			} else {
425
				$phpuid = 0;
426
			}
427
		}
428
		
429
		$stat = array();
430
		
431
		if ($uid) {
432
			$stat['isowner'] = ($phpuid == $uid);
433 View Code Duplication
			if (isset($names['uid'][$uid])) {
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...
434
				$stat['owner'] = $names['uid'][$uid];
435
			} else if (is_callable('posix_getpwuid')) {
436
				$pwuid = posix_getpwuid($uid);
437
				$stat['owner'] = $names['uid'][$uid] = $pwuid['name'];
438
			} else {
439
				$stat['owner'] = $names['uid'][$uid] = $uid;
440
			}
441
		}
442 View Code Duplication
		if ($gid) {
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...
443
			if (isset($names['gid'][$gid])) {
444
				$stat['group'] = $names['gid'][$gid];
445
			} else if (is_callable('posix_getgrgid')) {
446
				$grgid = posix_getgrgid($gid);
447
				$stat['group'] = $names['gid'][$gid] = $grgid['name'];
448
			} else {
449
				$stat['group'] = $names['gid'][$gid] = $gid;
450
			}
451
		}
452
		
453
		return $stat;
454
	}
455
456
	/**
457
	 * Return true if path is dir and has at least one childs directory
458
	 *
459
	 * @param  string  $path  dir path
460
	 * @return bool
461
	 * @author Dmitry (dio) Levashov
462
	 **/
463
	protected function _subdirs($path) {
464
465
		if (is_dir($path)) {
466
			$path = strtr($path, array('['  => '\\[', ']'  => '\\]', '*'  => '\\*', '?'  => '\\?'));
467
			return (bool)glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
468
		}
469
		return false;
470
	}
471
	
472
	/**
473
	 * Return object width and height
474
	 * Usualy used for images, but can be realize for video etc...
475
	 *
476
	 * @param  string  $path  file path
477
	 * @param  string  $mime  file mime type
478
	 * @return string
479
	 * @author Dmitry (dio) Levashov
480
	 **/
481
	protected function _dimensions($path, $mime) {
482
		clearstatcache();
483
		return strpos($mime, 'image') === 0 && ($s = @getimagesize($path)) !== false 
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression strpos($mime, 'image') =... . 'x' . $s[1] : false; of type string|false adds false to the return on line 483 which is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_dimensions of type string. It seems like you forgot to handle an error condition.
Loading history...
484
			? $s[0].'x'.$s[1] 
0 ignored issues
show
Bug introduced by
The variable $s does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
485
			: false;
486
	}
487
	/******************** file/dir content *********************/
488
	
489
	/**
490
	 * Return symlink target file
491
	 *
492
	 * @param  string  $path  link path
493
	 * @return string
494
	 * @author Dmitry (dio) Levashov
495
	 **/
496
	protected function readlink($path) {
497
		if (!($target = @readlink($path))) {
498
			return null;
499
		}
500
501
		if (strpos($target, $this->systemRoot) !== 0) {
502
			$target = $this->_joinPath(dirname($path), $target);
503
		}
504
505
		if (!file_exists($target)) {
506
			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 elFinderVolumeLocalFileSystem::readlink 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...
507
		}
508
		
509
		return $target;
510
	}
511
		
512
	/**
513
	 * Return files list in directory.
514
	 *
515
	 * @param  string  $path  dir path
516
	 * @return array
517
	 * @author Dmitry (dio) Levashov
518
	 **/
519
	protected function _scandir($path) {
520
		$files = array();
521
		$cache = array();
522
		$statOwner = (!empty($this->options['statOwner']));
523
		$dirItr = array();
524
		try {
525
			$dirItr = new DirectoryIterator($path);
526
		} catch (UnexpectedValueException $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
527
		
528
		foreach ($dirItr as $file) {
529
			try {
530
				if ($file->isDot()) { continue; }
531
				
532
				$files[] = $fpath = $file->getPathname();
533
				
534
				$br = false;
535
				$stat = array();
536
				
537
				$gid = $uid = 0;
538
				$stat['isowner'] = false;
539
				$linkreadable = false;
540
				if ($file->isLink()) {
541
					if (!($target = $this->readlink($fpath))
542
					|| $target == $fpath) {
543
						if (is_null($target)) {
544
							$stat = array();
545
							$br = true;
546
						} else {
547
							$_path = $fpath;
548
							$stat['mime']  = 'symlink-broken';
549
							$target = readlink($_path);
550
							$lstat = lstat($_path);
551
							$ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']);
552
							$linkreadable = !empty($ostat['isowner']);
553
							$dir = false;
554
							$stat['alias'] = $this->_path($target);
555
							$stat['target'] = $target;
556
						}
557
					} else {
558
						$dir = is_dir($target);
559
						$stat['alias'] = $this->_path($target);
560
						$stat['target'] = $target;
561
						$stat['mime'] = $dir ? 'directory' : $this->mimetype($stat['alias']);
562
					}
563
				} else {
564
					$dir = $file->isDir();
565
					$stat['mime'] = $dir ? 'directory' : $this->mimetype($fpath);
566
				}
567
				$size = sprintf('%u', $file->getSize());
568
				$stat['ts'] = $file->getMTime();
569
				if (!$br) {
570
					if ($statOwner && !$linkreadable) {
571
						$uid = $file->getOwner();
572
						$gid = $file->getGroup();
573
						$stat['perm'] = substr((string)decoct($file->getPerms()), -4);
574
						$stat = array_merge($stat, $this->getOwnerStat($uid, $gid));
575
					}
576
					
577
					//logical rights first
578
					$stat['read'] = ($linkreadable || $file->isReadable())? null : false;
579
					$stat['write'] = $file->isWritable()? null : false;
580
					
581
					if (is_null($stat['read'])) {
582
						$stat['size'] = $dir ? 0 : $size;
0 ignored issues
show
Bug introduced by
The variable $dir does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
583
					}
584
					
585
				}
586
				
587
				$cache[] = array($fpath, $stat);
588
			} catch (RuntimeException $e) {
589
				continue;
590
			}
591
		}
592
		
593
		if ($cache) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cache of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
594
			$cache = $this->convEncOut($cache, false);
595
			foreach($cache as $d) {
596
				$this->updateCache($d[0], $d[1]);
597
			}
598
		}
599
		
600
		return $files;
601
	}
602
		
603
	/**
604
	 * Open file and return file pointer
605
	 *
606
	 * @param  string  $path  file path
607
	 * @param  bool    $write open file for writing
0 ignored issues
show
Bug introduced by
There is no parameter named $write. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
608
	 * @return resource|false
609
	 * @author Dmitry (dio) Levashov
610
	 **/
611
	protected function _fopen($path, $mode='rb') {
612
		return @fopen($path, $mode);
613
	}
614
	
615
	/**
616
	 * Close opened file
617
	 *
618
	 * @param  resource  $fp  file pointer
619
	 * @return bool
620
	 * @author Dmitry (dio) Levashov
621
	 **/
622
	protected function _fclose($fp, $path='') {
623
		return @fclose($fp);
624
	}
625
	
626
	/********************  file/dir manipulations *************************/
627
	
628
	/**
629
	 * Create dir and return created dir path or false on failed
630
	 *
631
	 * @param  string  $path  parent dir path
632
	 * @param string  $name  new directory name
633
	 * @return string|bool
634
	 * @author Dmitry (dio) Levashov
635
	 **/
636 View Code Duplication
	protected function _mkdir($path, $name) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
637
		$path = $this->_joinPath($path, $name);
638
639
		if (@mkdir($path)) {
640
			@chmod($path, $this->options['dirMode']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
641
			clearstatcache();
642
			return $path;
643
		}
644
645
		return false;
646
	}
647
	
648
	/**
649
	 * Create file and return it's path or false on failed
650
	 *
651
	 * @param  string  $path  parent dir path
652
	 * @param string  $name  new file name
653
	 * @return string|bool
654
	 * @author Dmitry (dio) Levashov
655
	 **/
656 View Code Duplication
	protected function _mkfile($path, $name) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
657
		$path = $this->_joinPath($path, $name);
658
		
659
		if (($fp = @fopen($path, 'w'))) {
660
			@fclose($fp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
661
			@chmod($path, $this->options['fileMode']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
662
			clearstatcache();
663
			return $path;
664
		}
665
		return false;
666
	}
667
	
668
	/**
669
	 * Create symlink
670
	 *
671
	 * @param  string  $source     file to link to
672
	 * @param  string  $targetDir  folder to create link in
673
	 * @param  string  $name       symlink name
674
	 * @return bool
675
	 * @author Dmitry (dio) Levashov
676
	 **/
677
	protected function _symlink($source, $targetDir, $name) {
678
		return @symlink($source, $this->_joinPath($targetDir, $name));
679
	}
680
	
681
	/**
682
	 * Copy file into another file
683
	 *
684
	 * @param  string  $source     source file path
685
	 * @param  string  $targetDir  target directory path
686
	 * @param  string  $name       new file name
687
	 * @return bool
688
	 * @author Dmitry (dio) Levashov
689
	 **/
690
	protected function _copy($source, $targetDir, $name) {
691
		$ret = copy($source, $this->_joinPath($targetDir, $name));
692
		$ret && clearstatcache();
693
		return $ret;
694
	}
695
	
696
	/**
697
	 * Move file into another parent dir.
698
	 * Return new file path or false.
699
	 *
700
	 * @param  string  $source  source file path
701
	 * @param  string  $target  target dir path
0 ignored issues
show
Documentation introduced by
There is no parameter named $target. Did you maybe mean $targetDir?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
702
	 * @param  string  $name    file name
703
	 * @return string|bool
704
	 * @author Dmitry (dio) Levashov
705
	 **/
706
	protected function _move($source, $targetDir, $name) {
707
		$target = $this->_joinPath($targetDir, $name);
708
		$ret = @rename($source, $target) ? $target : false;
709
		$ret && clearstatcache();
0 ignored issues
show
Bug Best Practice introduced by
The expression $ret of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
710
		return $ret;
711
	}
712
		
713
	/**
714
	 * Remove file
715
	 *
716
	 * @param  string  $path  file path
717
	 * @return bool
718
	 * @author Dmitry (dio) Levashov
719
	 **/
720
	protected function _unlink($path) {
721
		$ret = @unlink($path);
722
		$ret && clearstatcache();
723
		return $ret;
724
	}
725
726
	/**
727
	 * Remove dir
728
	 *
729
	 * @param  string  $path  dir path
730
	 * @return bool
731
	 * @author Dmitry (dio) Levashov
732
	 **/
733
	protected function _rmdir($path) {
734
		$ret = @rmdir($path);
735
		$ret && clearstatcache();
736
		return $ret;
737
	}
738
	
739
	/**
740
	 * Create new file and write into it from file pointer.
741
	 * Return new file path or false on error.
742
	 *
743
	 * @param  resource  $fp   file pointer
744
	 * @param  string    $dir  target dir path
745
	 * @param  string    $name file name
746
	 * @param  array     $stat file stat (required by some virtual fs)
747
	 * @return bool|string
748
	 * @author Dmitry (dio) Levashov
749
	 **/
750
	protected function _save($fp, $dir, $name, $stat) {
751
		$path = $this->_joinPath($dir, $name);
752
753
		$meta = stream_get_meta_data($fp);
754
		$uri = isset($meta['uri'])? $meta['uri'] : '';
755
		if ($uri && @is_file($uri)) {
756
			fclose($fp);
757
			$isCmdPaste = ($this->ARGS['cmd'] === 'paste');
758
			$isCmdCopy = ($isCmdPaste && empty($this->ARGS['cut']));
759
			if (($isCmdCopy || !@rename($uri, $path)) && !@copy($uri, $path)) {
760
				return false;
761
			}
762
			// re-create the source file for remove processing of paste command
763
			$isCmdPaste && !$isCmdCopy && touch($uri);
764
		} else {
765
			if (@file_put_contents($path, $fp, LOCK_EX) === false) {
766
				return false;
767
			}
768
		}
769
770
		@chmod($path, $this->options['fileMode']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
771
		clearstatcache();
772
		return $path;
773
	}
774
	
775
	/**
776
	 * Get file contents
777
	 *
778
	 * @param  string  $path  file path
779
	 * @return string|false
780
	 * @author Dmitry (dio) Levashov
781
	 **/
782
	protected function _getContents($path) {
783
		return file_get_contents($path);
784
	}
785
	
786
	/**
787
	 * Write a string to a file
788
	 *
789
	 * @param  string  $path     file path
790
	 * @param  string  $content  new file content
791
	 * @return bool
792
	 * @author Dmitry (dio) Levashov
793
	 **/
794
	protected function _filePutContents($path, $content) {
795
		if (@file_put_contents($path, $content, LOCK_EX) !== false) {
796
			clearstatcache();
797
			return true;
798
		}
799
		return false;
800
	}
801
802
	/**
803
	 * Detect available archivers
804
	 *
805
	 * @return void
806
	 **/
807
	protected function _checkArchivers() {
808
		$this->archivers = $this->getArchivers();
809
		return;
810
	}
811
812
	/**
813
	 * chmod availability
814
	 *
815
	 * @return bool
816
	 **/
817
	protected function _chmod($path, $mode) {
818
		$modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o",$mode));
819
		$ret = @chmod($path, $modeOct);
820
		$ret && clearstatcache();
821
		return  $ret;
822
	}
823
824
	/**
825
	 * Recursive symlinks search
826
	 *
827
	 * @param  string  $path  file/dir path
828
	 * @return bool
829
	 * @author Dmitry (dio) Levashov
830
	 **/
831
	protected function _findSymlinks($path) {
832
		if (is_link($path)) {
833
			return true;
834
		}
835
		
836
		if (is_dir($path)) {
837
			foreach (scandir($path) as $name) {
838
				if ($name != '.' && $name != '..') {
839
					$p = $path.DIRECTORY_SEPARATOR.$name;
840
					if (is_link($p) || !$this->nameAccepted($name)
841
						||
842
					(($mimeByName = elFinderVolumeDriver::mimetypeInternalDetect($name)) && $mimeByName !== 'unknown' && !$this->allowPutMime($mimeByName))) {
843
						$this->setError(elFinder::ERROR_SAVE, $name);
844
						return true;
845
					}
846
					if (is_dir($p) && $this->_findSymlinks($p)) {
847
						return true;
848
					} elseif (is_file($p)) {
849
						$this->archiveSize += sprintf('%u', filesize($p));
850
					}
851
				}
852
			}
853
		} else {
854
			
855
			$this->archiveSize += sprintf('%u', filesize($path));
856
		}
857
		
858
		return false;
859
	}
860
861
	/**
862
	 * Extract files from archive
863
	 *
864
	 * @param  string  $path  archive path
865
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
866
	 * @return true
867
	 * @author Dmitry (dio) Levashov, 
868
	 * @author Alexey Sukhotin
869
	 **/
870
	protected function _extract($path, $arc) {
871
		
872
		if ($this->quarantine) {
873
874
			$dir     = $this->quarantine.DIRECTORY_SEPARATOR.md5(basename($path).mt_rand());
875
			$archive = $dir.DIRECTORY_SEPARATOR.basename($path);
876
			
877
			if (!@mkdir($dir)) {
878
				return false;
879
			}
880
			
881
			// insurance unexpected shutdown
882
			register_shutdown_function(array($this, 'rmdirRecursive'), realpath($dir));
883
			
884
			chmod($dir, 0777);
885
			
886
			// copy in quarantine
887
			if (!copy($path, $archive)) {
888
				return false;
889
			}
890
			
891
			// extract in quarantine
892
			$this->unpackArchive($archive, $arc);
893
			
894
			// get files list
895
			$ls = array();
896
			foreach (scandir($dir) as $i => $name) {
897
				if ($name != '.' && $name != '..') {
898
					$ls[] = $name;
899
				}
900
			}
901
			
902
			// no files - extract error ?
903
			if (empty($ls)) {
904
				return false;
905
			}
906
			
907
			$this->archiveSize = 0;
908
			
909
			// find symlinks
910
			$symlinks = $this->_findSymlinks($dir);
911
			
912 View Code Duplication
			if ($symlinks) {
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...
913
				$this->delTree($dir);
914
				return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS)));
915
			}
916
917
			// check max files size
918 View Code Duplication
			if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) {
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...
919
				$this->delTree($dir);
920
				return $this->setError(elFinder::ERROR_ARC_MAXSIZE);
921
			}
922
			
923
			$extractTo = $this->extractToNewdir; // 'auto', ture or false
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
924
			
925
			// archive contains one item - extract in archive dir
926
			$name = '';
927
			$src = $dir.DIRECTORY_SEPARATOR.$ls[0];
928
			if (($extractTo === 'auto' || !$extractTo) && count($ls) === 1 && is_file($src)) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $extractTo (integer) and 'auto' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
929
				$name = $ls[0];
930
			} else if ($extractTo === 'auto' || $extractTo) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $extractTo (integer) and 'auto' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
931
				// for several files - create new directory
932
				// create unique name for directory
933
				$src = $dir;
934
				$name = basename($path);
935 View Code Duplication
				if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) {
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...
936
					$name = substr($name, 0,  strlen($name)-strlen($m[0]));
937
				}
938
				$test = dirname($path).DIRECTORY_SEPARATOR.$name;
939
				if (file_exists($test) || is_link($test)) {
940
					$name = $this->uniqueName(dirname($path), $name, '-', false);
941
				}
942
			}
943
			
944
			if ($name !== '') {
945
				$result  = dirname($path).DIRECTORY_SEPARATOR.$name;
946
947
				if (! @rename($src, $result)) {
948
					$this->delTree($dir);
949
					return false;
950
				}
951
			} else {
952
				$dstDir = dirname($path);
953
				$res = false;
0 ignored issues
show
Unused Code introduced by
$res 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...
954
				$result = array();
955
				foreach($ls as $name) {
956
					$target = $dstDir.DIRECTORY_SEPARATOR.$name;
957
					if (is_dir($target)) {
958
						$this->delTree($target);
959
					}
960
					if (@rename($dir.DIRECTORY_SEPARATOR.$name, $target)) {
961
						$result[] = $target;
962
					}
963
				}
964
				if (!$result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
965
					$this->delTree($dir);
966
					return false;
967
				}
968
			}
969
			
970
			is_dir($dir) && $this->delTree($dir);
971
			
972
			return (is_array($result) || file_exists($result)) ? $result : false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return is_array($result)...ult) ? $result : false; (array|string|false) is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_extract of type boolean.

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...
973
		}
974
	}
975
	
976
	/**
977
	 * Create archive and return its path
978
	 *
979
	 * @param  string  $dir    target dir
980
	 * @param  array   $files  files names list
981
	 * @param  string  $name   archive name
982
	 * @param  array   $arc    archiver options
983
	 * @return string|bool
984
	 * @author Dmitry (dio) Levashov, 
985
	 * @author Alexey Sukhotin
986
	 **/
987
	protected function _archive($dir, $files, $name, $arc) {
988
		return $this->makeArchive($dir, $files, $name, $arc);
989
	}
990
	
991
	/******************** Over write functions *************************/
992
	
993
	/**
994
	 * File path of local server side work file path
995
	 *
996
	 * @param  string $path
997
	 * @return string
998
	 * @author Naoki Sawada
999
	 */
1000
	protected function getWorkFile($path) {
1001
		return $path;
1002
	}
1003
1004
	/**
1005
	 * Delete dirctory trees
1006
	 *
1007
	 * @param string $localpath path need convert encoding to server encoding
1008
	 * @return boolean
1009
	 * @author Naoki Sawada
1010
	 */
1011
	protected function delTree($localpath) {
1012
		return $this->rmdirRecursive($localpath);
1013
	}
1014
1015
	/******************** Over write (Optimized) functions *************************/
1016
	
1017
	/**
1018
	 * Recursive files search
1019
	 *
1020
	 * @param  string  $path   dir path
1021
	 * @param  string  $q      search string
1022
	 * @param  array   $mimes
1023
	 * @return array
1024
	 * @author Dmitry (dio) Levashov
1025
	 * @author Naoki Sawada
1026
	 **/
1027
	protected function doSearch($path, $q, $mimes) {
1028
		if ($this->encoding) {
1029
			// non UTF-8 has problem of glob() results
1030
			return parent::doSearch($path, $q, $mimes);
1031
		}
1032
		
1033
		static $escaper;
1034
		if (!$escaper) {
1035
			$escaper = array(
1036
				'['  => '\\[',
1037
				']'  => '\\]',
1038
				'*'  => '\\*',
1039
				'?'  => '\\?'
1040
			);
1041
		}
1042
		
1043
		$result = array();
1044
		
1045
		$path = strtr($path, $escaper);
1046
		$_q = strtr($q, $escaper);
1047
		$dirs = glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR);
1048
		$match = glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*'.$_q.'*', GLOB_NOSORT);
1049
		if ($match) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $match of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1050
			foreach($match as $p) {
1051
				$stat = $this->stat($p);
1052
		
1053
				if (!$stat) { // invalid links
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1054
					continue;
1055
				}
1056
		
1057
				if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) {
1058
					continue;
1059
				}
1060
					
1061
				$name = $stat['name'];
0 ignored issues
show
Unused Code introduced by
$name 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...
1062
		
1063
				if ((!$mimes || $stat['mime'] !== 'directory')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mimes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1064
					$stat['path'] = $this->path($stat['hash']);
1065
					if ($this->URL && !isset($stat['url'])) {
1066
						$path = str_replace(DIRECTORY_SEPARATOR, '/', substr($p, strlen($this->root) + 1));
1067
						$stat['url'] = $this->URL . $path;
1068
					}
1069
		
1070
					$result[] = $stat;
1071
				}
1072
			}
1073
		}
1074
		if ($dirs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $dirs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1075
			foreach($dirs as $dir) {
1076
				$stat = $this->stat($dir);
1077 View Code Duplication
				if ($stat['read'] && !isset($stat['alias'])) {
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...
1078
					@set_time_limit(30);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1079
					$result = array_merge($result, $this->doSearch($dir, $q, $mimes));
1080
				}
1081
			}
1082
		}
1083
	
1084
		return $result;
1085
	}
1086
	
1087
} // END class 
1088