GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

elFinderVolumeLocalFileSystem::_abspath()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * elFinder driver for local filesystem.
5
 *
6
 * @author Dmitry (dio) Levashov
7
 * @author Troex Nevelin
8
 **/
9
class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver {
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
	 * Canonicalized absolute pathname of $root
29
	 * 
30
	 * @var strung
31
	 */
32
	protected $aroot;
33
	
34
	/**
35
	 * Constructor
36
	 * Extend options with required fields
37
	 *
38
	 * @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...
39
	 * @author Dmitry (dio) Levashov
40
	 **/
41
	public function __construct() {
42
		$this->options['alias']    = '';              // alias to replace root dir name
43
		$this->options['dirMode']  = 0755;            // new dirs mode
44
		$this->options['fileMode'] = 0644;            // new files mode
45
		$this->options['quarantine'] = '.quarantine';  // quarantine folder name - required to check archive (must be hidden)
46
		$this->options['maxArcFilesSize'] = 0;        // max allowed archive files size (0 - no limit)
47
	}
48
	
49
	/*********************************************************************/
50
	/*                        INIT AND CONFIGURE                         */
51
	/*********************************************************************/
52
	
53
	/**
54
	 * Configure after successfull mount.
55
	 *
56
	 * @return void
57
	 * @author Dmitry (dio) Levashov
58
	 **/
59
	protected function configure() {
60
		$this->aroot = realpath($this->root);
0 ignored issues
show
Documentation Bug introduced by
It seems like realpath($this->root) of type string is incompatible with the declared type object<strung> of property $aroot.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
61
		$root = $this->stat($this->root);
62
		
63
		if ($this->options['quarantine']) {
64
			$this->attributes[] = array(
65
				'pattern' => '~^'.preg_quote(DIRECTORY_SEPARATOR.$this->options['quarantine']).'$~',
66
				'read'    => false,
67
				'write'   => false,
68
				'locked'  => true,
69
				'hidden'  => true
70
			);
71
		}
72
		
73
		// chek thumbnails path
74
		if ($this->options['tmbPath']) {
75
			$this->options['tmbPath'] = strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false
76
				// tmb path set as dirname under root dir
77
				? $this->root.DIRECTORY_SEPARATOR.$this->options['tmbPath']
78
				// tmb path as full path
79
				: $this->_normpath($this->options['tmbPath']);
80
		}
81
82
		parent::configure();
83
		
84
		// if no thumbnails url - try detect it
85
		if ($root['read'] && !$this->tmbURL && $this->URL) {
86
			if (strpos($this->tmbPath, $this->root) === 0) {
87
				$this->tmbURL = $this->URL.str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root)+1));
88
				if (preg_match("|[^/?&=]$|", $this->tmbURL)) {
89
					$this->tmbURL .= '/';
90
				}
91
			}
92
		}
93
94
		// check quarantine dir
95
		if (!empty($this->options['quarantine'])) {
96
			$this->quarantine = $this->root.DIRECTORY_SEPARATOR.$this->options['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...
97
			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...
98
				$this->archivers['extract'] = array();
99
				$this->disabled[] = 'extract';
100
			}
101
		} else {
102
			$this->archivers['extract'] = array();
103
			$this->disabled[] = 'extract';
104
		}
105
		
106
	}
107
	
108
	/*********************************************************************/
109
	/*                               FS API                              */
110
	/*********************************************************************/
111
112
	/*********************** paths/urls *************************/
113
	
114
	/**
115
	 * Return parent directory path
116
	 *
117
	 * @param  string  $path  file path
118
	 * @return string
119
	 * @author Dmitry (dio) Levashov
120
	 **/
121
	protected function _dirname($path) {
122
		return dirname($path);
123
	}
124
125
	/**
126
	 * Return file name
127
	 *
128
	 * @param  string  $path  file path
129
	 * @return string
130
	 * @author Dmitry (dio) Levashov
131
	 **/
132
	protected function _basename($path) {
133
		return basename($path);
134
	}
135
136
	/**
137
	 * Join dir name and file name and retur full path
138
	 *
139
	 * @param  string  $dir
140
	 * @param  string  $name
141
	 * @return string
142
	 * @author Dmitry (dio) Levashov
143
	 **/
144
	protected function _joinPath($dir, $name) {
145
		return $dir.DIRECTORY_SEPARATOR.$name;
146
	}
147
	
148
	/**
149
	 * Return normalized path, this works the same as os.path.normpath() in Python
150
	 *
151
	 * @param  string  $path  path
152
	 * @return string
153
	 * @author Troex Nevelin
154
	 **/
155
	protected function _normpath($path) {
156
		if (empty($path)) {
157
			return '.';
158
		}
159
160 View Code Duplication
		if (strpos($path, '/') === 0) {
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...
161
			$initial_slashes = true;
162
		} else {
163
			$initial_slashes = false;
164
		}
165
			
166 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...
167
		&& (strpos($path, '//') === 0) 
168
		&& (strpos($path, '///') === false)) {
169
			$initial_slashes = 2;
170
		}
171
			
172
		$initial_slashes = (int) $initial_slashes;
173
174
		$comps = explode('/', $path);
175
		$new_comps = array();
176 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...
177
			if (in_array($comp, array('', '.'))) {
178
				continue;
179
			}
180
				
181
			if (($comp != '..') 
182
			|| (!$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...
183
			|| ($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...
184
				array_push($new_comps, $comp);
185
			} 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...
186
				array_pop($new_comps);
187
			}
188
		}
189
		$comps = $new_comps;
190
		$path = implode('/', $comps);
191
		if ($initial_slashes) {
192
			$path = str_repeat('/', $initial_slashes) . $path;
193
		}
194
		
195
		return $path ? $path : '.';
196
	}
197
	
198
	/**
199
	 * Return file path related to root dir
200
	 *
201
	 * @param  string  $path  file path
202
	 * @return string
203
	 * @author Dmitry (dio) Levashov
204
	 **/
205
	protected function _relpath($path) {
206
		return $path == $this->root ? '' : substr($path, strlen($this->root)+1);
207
	}
208
	
209
	/**
210
	 * Convert path related to root dir into real path
211
	 *
212
	 * @param  string  $path  file path
213
	 * @return string
214
	 * @author Dmitry (dio) Levashov
215
	 **/
216
	protected function _abspath($path) {
217
		return $path == DIRECTORY_SEPARATOR ? $this->root : $this->root.DIRECTORY_SEPARATOR.$path;
218
	}
219
	
220
	/**
221
	 * Return fake path started from root dir
222
	 *
223
	 * @param  string  $path  file path
224
	 * @return string
225
	 * @author Dmitry (dio) Levashov
226
	 **/
227
	protected function _path($path) {
228
		return $this->rootName.($path == $this->root ? '' : $this->separator.$this->_relpath($path));
229
	}
230
	
231
	/**
232
	 * Return true if $path is children of $parent
233
	 *
234
	 * @param  string  $path    path to check
235
	 * @param  string  $parent  parent path
236
	 * @return bool
237
	 * @author Dmitry (dio) Levashov
238
	 **/
239
	protected function _inpath($path, $parent) {
240
		$real_path = realpath($path);
241
		$real_parent = realpath($parent);
242
		if ($real_path && $real_parent) {
243
			return $real_path === $real_parent || strpos($real_path, $real_parent.DIRECTORY_SEPARATOR) === 0;
244
		}
245
		return false;
246
	}
247
	
248
	
249
	
250
	/***************** file stat ********************/
251
252
	/**
253
	 * Return stat for given path.
254
	 * Stat contains following fields:
255
	 * - (int)    size    file size in b. required
256
	 * - (int)    ts      file modification time in unix time. required
257
	 * - (string) mime    mimetype. required for folders, others - optionally
258
	 * - (bool)   read    read permissions. required
259
	 * - (bool)   write   write permissions. required
260
	 * - (bool)   locked  is object locked. optionally
261
	 * - (bool)   hidden  is object hidden. optionally
262
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
263
	 * - (string) target  for symlinks - link target path. optionally
264
	 *
265
	 * If file does not exists - returns empty array or false.
266
	 *
267
	 * @param  string  $path    file path 
268
	 * @return array|false
269
	 * @author Dmitry (dio) Levashov
270
	 **/
271
	protected function _stat($path) {
272
		$stat = array();
273
274
		if (!file_exists($path)) {
275
			return $stat;
276
		}
277
278
		//Verifies the given path is the root or is inside the root. Prevents directory traveral.
279
		if (!$this->aroot) {
280
			// for Inheritance class ( not calling parent::configure() )
281
			$this->aroot = realpath($this->root);
0 ignored issues
show
Documentation Bug introduced by
It seems like realpath($this->root) of type string is incompatible with the declared type object<strung> of property $aroot.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
282
		}
283
		if (!$this->_inpath($path, $this->aroot)) {
284
			return $stat;
285
		}
286
287
		if ($path != $this->root && is_link($path)) {
288
			if (($target = $this->readlink($path)) == false 
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $target = $this->readlink($path) of type false|string against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
289
			|| $target == $path) {
290
				$stat['mime']  = 'symlink-broken';
291
				$stat['read']  = false;
292
				$stat['write'] = false;
293
				$stat['size']  = 0;
294
				return $stat;
295
			}
296
			$stat['alias']  = $this->_path($target);
297
			$stat['target'] = $target;
298
			$path  = $target;
299
			$lstat = lstat($path);
300
			$size  = $lstat['size'];
301
		} else {
302
			$size = @filesize($path);
303
		}
304
		
305
		$dir = is_dir($path);
306
		
307
		$stat['mime']  = $dir ? 'directory' : $this->mimetype($path);
308
		$stat['ts']    = filemtime($path);
309
		$stat['read']  = is_readable($path);
310
		$stat['write'] = is_writable($path);
311
		if ($stat['read']) {
312
			$stat['size'] = $dir ? 0 : $size;
313
		}
314
		
315
		return $stat;
316
	}
317
	
318
319
	/**
320
	 * Return true if path is dir and has at least one childs directory
321
	 *
322
	 * @param  string  $path  dir path
323
	 * @return bool
324
	 * @author Dmitry (dio) Levashov
325
	 **/
326
	protected function _subdirs($path) {
327
328
		if (($dir = dir($path))) {
0 ignored issues
show
Unused Code introduced by
$dir 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...
329
			$dir = dir($path);
330
			while (($entry = $dir->read()) !== false) {
331
				$p = $dir->path.DIRECTORY_SEPARATOR.$entry;
0 ignored issues
show
Bug introduced by
The property path does not seem to exist in Directory.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
332
				if ($entry != '.' && $entry != '..' && is_dir($p) && !$this->attr($p, 'hidden')) {
333
					$dir->close();
334
					return true;
335
				}
336
			}
337
			$dir->close();
338
		}
339
		return false;
340
	}
341
	
342
	/**
343
	 * Return object width and height
344
	 * Usualy used for images, but can be realize for video etc...
345
	 *
346
	 * @param  string  $path  file path
347
	 * @param  string  $mime  file mime type
348
	 * @return string
349
	 * @author Dmitry (dio) Levashov
350
	 **/
351
	protected function _dimensions($path, $mime) {
352
		clearstatcache();
353
		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 353 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...
354
			? $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...
355
			: false;
356
	}
357
	/******************** file/dir content *********************/
358
	
359
	/**
360
	 * Return symlink target file
361
	 *
362
	 * @param  string  $path  link path
363
	 * @return string
364
	 * @author Dmitry (dio) Levashov
365
	 **/
366
	protected function readlink($path) {
367
		if (!($target = @readlink($path))) {
368
			return false;
369
		}
370
		
371
		if (substr($target, 0, 1) != DIRECTORY_SEPARATOR) {
372
			$target = dirname($path).DIRECTORY_SEPARATOR.$target;
373
		}
374
		
375
		if ($this->_inpath($target, $this->aroot)) {
376
			$atarget = realpath($target);
377
			return $this->_normpath($this->root.DIRECTORY_SEPARATOR.substr($atarget, strlen($this->aroot)+1));
378
		}
379
380
		return false;
381
	}
382
		
383
	/**
384
	 * Return files list in directory.
385
	 *
386
	 * @param  string  $path  dir path
387
	 * @return array
388
	 * @author Dmitry (dio) Levashov
389
	 **/
390
	protected function _scandir($path) {
391
		$files = array();
392
		
393
		foreach (scandir($path) as $name) {
394
			if ($name != '.' && $name != '..') {
395
				$files[] = $path.DIRECTORY_SEPARATOR.$name;
396
			}
397
		}
398
		return $files;
399
	}
400
		
401
	/**
402
	 * Open file and return file pointer
403
	 *
404
	 * @param  string  $path  file path
405
	 * @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...
406
	 * @return resource|false
407
	 * @author Dmitry (dio) Levashov
408
	 **/
409
	protected function _fopen($path, $mode='rb') {
410
		return @fopen($path, 'r');
411
	}
412
	
413
	/**
414
	 * Close opened file
415
	 *
416
	 * @param  resource  $fp  file pointer
417
	 * @return bool
418
	 * @author Dmitry (dio) Levashov
419
	 **/
420
	protected function _fclose($fp, $path='') {
421
		return @fclose($fp);
422
	}
423
	
424
	/********************  file/dir manipulations *************************/
425
	
426
	/**
427
	 * Create dir and return created dir path or false on failed
428
	 *
429
	 * @param  string  $path  parent dir path
430
	 * @param string  $name  new directory name
431
	 * @return string|bool
432
	 * @author Dmitry (dio) Levashov
433
	 **/
434 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...
435
		$path = $path.DIRECTORY_SEPARATOR.$name;
436
437
		if (@mkdir($path)) {
438
			@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...
439
			return $path;
440
		}
441
442
		return false;
443
	}
444
	
445
	/**
446
	 * Create file and return it's path or false on failed
447
	 *
448
	 * @param  string  $path  parent dir path
449
	 * @param string  $name  new file name
450
	 * @return string|bool
451
	 * @author Dmitry (dio) Levashov
452
	 **/
453 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...
454
		$path = $path.DIRECTORY_SEPARATOR.$name;
455
		
456
		if (($fp = @fopen($path, 'w'))) {
457
			@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...
458
			@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...
459
			return $path;
460
		}
461
		return false;
462
	}
463
	
464
	/**
465
	 * Create symlink
466
	 *
467
	 * @param  string  $source     file to link to
468
	 * @param  string  $targetDir  folder to create link in
469
	 * @param  string  $name       symlink name
470
	 * @return bool
471
	 * @author Dmitry (dio) Levashov
472
	 **/
473
	protected function _symlink($source, $targetDir, $name) {
474
		return @symlink($source, $targetDir.DIRECTORY_SEPARATOR.$name);
475
	}
476
	
477
	/**
478
	 * Copy file into another file
479
	 *
480
	 * @param  string  $source     source file path
481
	 * @param  string  $targetDir  target directory path
482
	 * @param  string  $name       new file name
483
	 * @return bool
484
	 * @author Dmitry (dio) Levashov
485
	 **/
486
	protected function _copy($source, $targetDir, $name) {
487
		return copy($source, $targetDir.DIRECTORY_SEPARATOR.$name);
488
	}
489
	
490
	/**
491
	 * Move file into another parent dir.
492
	 * Return new file path or false.
493
	 *
494
	 * @param  string  $source  source file path
495
	 * @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...
496
	 * @param  string  $name    file name
497
	 * @return string|bool
498
	 * @author Dmitry (dio) Levashov
499
	 **/
500
	protected function _move($source, $targetDir, $name) {
501
		$target = $targetDir.DIRECTORY_SEPARATOR.$name;
502
		return @rename($source, $target) ? $target : false;
503
	}
504
		
505
	/**
506
	 * Remove file
507
	 *
508
	 * @param  string  $path  file path
509
	 * @return bool
510
	 * @author Dmitry (dio) Levashov
511
	 **/
512
	protected function _unlink($path) {
513
		return @unlink($path);
514
	}
515
516
	/**
517
	 * Remove dir
518
	 *
519
	 * @param  string  $path  dir path
520
	 * @return bool
521
	 * @author Dmitry (dio) Levashov
522
	 **/
523
	protected function _rmdir($path) {
524
		return @rmdir($path);
525
	}
526
	
527
	/**
528
	 * Create new file and write into it from file pointer.
529
	 * Return new file path or false on error.
530
	 *
531
	 * @param  resource  $fp   file pointer
532
	 * @param  string    $dir  target dir path
533
	 * @param  string    $name file name
534
	 * @param  array     $stat file stat (required by some virtual fs)
535
	 * @return bool|string
536
	 * @author Dmitry (dio) Levashov
537
	 **/
538
	protected function _save($fp, $dir, $name, $stat) {
539
		$path = $dir.DIRECTORY_SEPARATOR.$name;
540
541
		if (!($target = @fopen($path, 'wb'))) {
542
			return false;
543
		}
544
545
		while (!feof($fp)) {
546
			fwrite($target, fread($fp, 8192));
547
		}
548
		fclose($target);
549
		@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...
550
		clearstatcache();
551
		return $path;
552
	}
553
	
554
	/**
555
	 * Get file contents
556
	 *
557
	 * @param  string  $path  file path
558
	 * @return string|false
559
	 * @author Dmitry (dio) Levashov
560
	 **/
561
	protected function _getContents($path) {
562
		return file_get_contents($path);
563
	}
564
	
565
	/**
566
	 * Write a string to a file
567
	 *
568
	 * @param  string  $path     file path
569
	 * @param  string  $content  new file content
570
	 * @return bool
571
	 * @author Dmitry (dio) Levashov
572
	 **/
573
	protected function _filePutContents($path, $content) {
574
		if (@file_put_contents($path, $content, LOCK_EX) !== false) {
575
			clearstatcache();
576
			return true;
577
		}
578
		return false;
579
	}
580
581
	/**
582
	 * Detect available archivers
583
	 *
584
	 * @return void
585
	 **/
586
	protected function _checkArchivers() {
587
		$this->archivers = $this->getArchivers();
588
		return;
589
	}
590
591
	/**
592
	 * Unpack archive
593
	 *
594
	 * @param  string  $path  archive path
595
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
596
	 * @return void
597
	 * @author Dmitry (dio) Levashov
598
	 * @author Alexey Sukhotin
599
	 **/
600
	protected function _unpack($path, $arc) {
601
		$cwd = getcwd();
602
		$dir = $this->_dirname($path);
603
		chdir($dir);
604
		$cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($this->_basename($path));
605
		$this->procExec($cmd, $o, $c);
606
		chdir($cwd);
607
	}
608
609
	/**
610
	 * Recursive symlinks search
611
	 *
612
	 * @param  string  $path  file/dir path
613
	 * @return bool
614
	 * @author Dmitry (dio) Levashov
615
	 **/
616 View Code Duplication
	protected function _findSymlinks($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...
617
		if (is_link($path)) {
618
			return true;
619
		}
620
		
621
		if (is_dir($path)) {
622
			foreach (scandir($path) as $name) {
623
				if ($name != '.' && $name != '..') {
624
					$p = $path.DIRECTORY_SEPARATOR.$name;
625
					if (is_link($p) || !$this->nameAccepted($name)) {
626
						return true;
627
					}
628
					if (is_dir($p) && $this->_findSymlinks($p)) {
629
						return true;
630
					} elseif (is_file($p)) {
631
						$this->archiveSize += filesize($p);
632
					}
633
				}
634
			}
635
		} else {
636
			
637
			$this->archiveSize += filesize($path);
638
		}
639
		
640
		return false;
641
	}
642
643
	/**
644
	 * Extract files from archive
645
	 *
646
	 * @param  string  $path  archive path
647
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
648
	 * @return true
649
	 * @author Dmitry (dio) Levashov, 
650
	 * @author Alexey Sukhotin
651
	 **/
652
	protected function _extract($path, $arc) {
653
		
654
		if ($this->quarantine) {
655
			$dir     = $this->quarantine.DIRECTORY_SEPARATOR.str_replace(' ', '_', microtime()).basename($path);
656
			$archive = $dir.DIRECTORY_SEPARATOR.basename($path);
657
			
658
			if (!@mkdir($dir)) {
659
				return false;
660
			}
661
			
662
			chmod($dir, 0777);
663
			
664
			// copy in quarantine
665
			if (!copy($path, $archive)) {
666
				return false;
667
			}
668
			
669
			// extract in quarantine
670
			$this->_unpack($archive, $arc);
671
			unlink($archive);
672
			
673
			// get files list
674
			$ls = array();
675
			foreach (scandir($dir) as $i => $name) {
676
				if ($name != '.' && $name != '..') {
677
					$ls[] = $name;
678
				}
679
			}
680
			
681
			// no files - extract error ?
682
			if (empty($ls)) {
683
				return false;
684
			}
685
			
686
			$this->archiveSize = 0;
687
			
688
			// find symlinks
689
			$symlinks = $this->_findSymlinks($dir);
690
			// remove arc copy
691
			$this->remove($dir);
692
			
693
			if ($symlinks) {
694
				return $this->setError(elFinder::ERROR_ARC_SYMLINKS);
695
			}
696
697
			// check max files size
698
			if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) {
699
				return $this->setError(elFinder::ERROR_ARC_MAXSIZE);
700
			}
701
			
702
			
703
			
704
			// archive contains one item - extract in archive dir
705
			if (count($ls) == 1) {
706
				$this->_unpack($path, $arc);
707
				$result = dirname($path).DIRECTORY_SEPARATOR.$ls[0];
708
				
709
710
			} else {
711
				// for several files - create new directory
712
				// create unique name for directory
713
				$name = basename($path);
714 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...
715
					$name = substr($name, 0,  strlen($name)-strlen($m[0]));
716
				}
717
				$test = dirname($path).DIRECTORY_SEPARATOR.$name;
718
				if (file_exists($test) || is_link($test)) {
719
					$name = $this->uniqueName(dirname($path), $name, '-', false);
720
				}
721
				
722
				$result  = dirname($path).DIRECTORY_SEPARATOR.$name;
723
				$archive = $result.DIRECTORY_SEPARATOR.basename($path);
724
725
				if (!$this->_mkdir(dirname($path), $name) || !copy($path, $archive)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_mkdir(dirname($path), $name) 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...
726
					return false;
727
				}
728
				
729
				$this->_unpack($archive, $arc);
730
				@unlink($archive);
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...
731
			}
732
			
733
			return file_exists($result) ? $result : false;
0 ignored issues
show
Bug Compatibility introduced by
The expression file_exists($result) ? $result : false; of type string|false adds the type string to the return on line 733 which is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_extract of type boolean.
Loading history...
734
		}
735
	}
736
	
737
	/**
738
	 * Create archive and return its path
739
	 *
740
	 * @param  string  $dir    target dir
741
	 * @param  array   $files  files names list
742
	 * @param  string  $name   archive name
743
	 * @param  array   $arc    archiver options
744
	 * @return string|bool
745
	 * @author Dmitry (dio) Levashov, 
746
	 * @author Alexey Sukhotin
747
	 **/
748
	protected function _archive($dir, $files, $name, $arc) {
749
		$cwd = getcwd();
750
		chdir($dir);
751
		
752
		$files = array_map('escapeshellarg', $files);
753
		
754
		$cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($name).' '.implode(' ', $files);
755
		$this->procExec($cmd, $o, $c);
756
		chdir($cwd);
757
758
		$path = $dir.DIRECTORY_SEPARATOR.$name;
759
		return file_exists($path) ? $path : false;
760
	}
761
	
762
} // END class 
763