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.

elFinderVolumeFTP   F
last analyzed

Complexity

Total Complexity 253

Size/Duplication

Total Lines 1400
Duplicated Lines 9.79 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
dl 137
loc 1400
rs 0.8
c 0
b 0
f 0
wmc 253
lcom 2
cbo 1

44 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 1
B init() 0 34 8
B configure() 0 26 8
B connect() 7 36 8
A umount() 0 3 2
C parseRaw() 0 61 14
D parsePermissions() 0 15 13
B cacheDir() 9 23 8
A ftpMode() 0 3 2
A _dirname() 0 3 1
A _basename() 0 3 1
A _joinPath() 0 3 1
C _normpath() 23 45 16
A _relpath() 0 3 2
A _abspath() 0 3 2
A _path() 0 3 2
A _inpath() 0 3 2
F _stat() 20 102 32
B _subdirs() 0 18 8
A _dimensions() 0 3 1
A _scandir() 0 11 3
A _fopen() 0 12 3
A _fclose() 0 6 2
A _mkdir() 0 9 3
A _mkfile() 0 10 4
A _symlink() 0 3 1
A _copy() 4 16 4
A _move() 0 4 2
A _unlink() 0 3 1
A _rmdir() 0 3 1
A _save() 0 6 2
A _getContents() 0 11 3
A _filePutContents() 0 17 5
A _checkArchivers() 0 4 1
A _unpack() 0 4 1
B _findSymlinks() 25 25 10
C _extract() 13 95 13
B _archive() 10 69 9
A tempDir() 0 19 4
B ftp_scan_dir() 0 35 6
B ftp_download_files() 0 35 10
B deleteDir() 0 29 8
B listFilesInDirectory() 0 34 9
C resize() 26 71 16

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

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

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

1
<?php
2
3
function chmodnum($chmod) {
4
    $trans = array('-' => '0', 'r' => '4', 'w' => '2', 'x' => '1');
5
    $chmod = substr(strtr($chmod, $trans), 1);
6
    $array = str_split($chmod, 3);
7
    return array_sum(str_split($array[0])) . array_sum(str_split($array[1])) . array_sum(str_split($array[2]));
8
}
9
10
elFinder::$netDrivers['ftp'] = 'FTP';
11
12
/**
13
 * Simple elFinder driver for FTP
14
 *
15
 * @author Dmitry (dio) Levashov
16
 * @author Cem (discofever)
17
 **/
18
class elFinderVolumeFTP extends elFinderVolumeDriver {
19
	
20
	/**
21
	 * Driver id
22
	 * Must be started from letter and contains [a-z0-9]
23
	 * Used as part of volume id
24
	 *
25
	 * @var string
26
	 **/
27
	protected $driverId = 'f';
28
	
29
	/**
30
	 * FTP Connection Instance
31
	 *
32
	 * @var ftp
33
	 **/
34
	protected $connect = null;
35
	
36
	/**
37
	 * Directory for tmp files
38
	 * If not set driver will try to use tmbDir as tmpDir
39
	 *
40
	 * @var string
41
	 **/
42
	protected $tmpPath = '';
43
	
44
	/**
45
	 * Last FTP error message
46
	 *
47
	 * @var string
48
	 **/
49
	protected $ftpError = '';
50
	
51
	/**
52
	 * FTP server output list as ftp on linux
53
	 *
54
	 * @var bool
55
	 **/
56
	protected $ftpOsUnix;
57
	
58
	/**
59
	 * Tmp folder path
60
	 *
61
	 * @var string
62
	 **/
63
	protected $tmp = '';
64
	
65
	/**
66
	 * Constructor
67
	 * Extend options with required fields
68
	 *
69
	 * @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...
70
	 * @author Dmitry (dio) Levashov
71
	 * @author Cem (DiscoFever)
72
	 **/
73
	public function __construct() {
74
		$opts = array(
75
			'host'          => 'localhost',
76
			'user'          => '',
77
			'pass'          => '',
78
			'port'          => 21,
79
			'mode'        	=> 'passive',
80
			'path'			=> '/',
81
			'timeout'		=> 20,
82
			'owner'         => true,
83
			'tmbPath'       => '',
84
			'tmpPath'       => '',
85
			'dirMode'       => 0755,
86
			'fileMode'      => 0644
87
		);
88
		$this->options = array_merge($this->options, $opts); 
89
		$this->options['mimeDetect'] = 'internal';
90
	}
91
	
92
	/*********************************************************************/
93
	/*                        INIT AND CONFIGURE                         */
94
	/*********************************************************************/
95
	
96
	/**
97
	 * Prepare FTP connection
98
	 * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn
99
	 *
100
	 * @return bool
101
	 * @author Dmitry (dio) Levashov
102
	 * @author Cem (DiscoFever)
103
	 **/
104
	protected function init() {
105
		if (!$this->options['host'] 
106
		||  !$this->options['user'] 
107
		||  !$this->options['pass'] 
108
		||  !$this->options['port']) {
109
			return $this->setError('Required options undefined.');
110
		}
111
		
112
		if (!function_exists('ftp_connect')) {
113
			return $this->setError('FTP extension not loaded.');
114
		}
115
116
		// remove protocol from host
117
		$scheme = parse_url($this->options['host'], PHP_URL_SCHEME);
118
119
		if ($scheme) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $scheme 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...
120
			$this->options['host'] = substr($this->options['host'], strlen($scheme)+3);
121
		}
122
123
		// normalize root path
124
		$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
125
		
126
		if (empty($this->options['alias'])) {
127
			$this->options['alias'] = $this->options['user'].'@'.$this->options['host'];
128
			// $num = elFinder::$volumesCnt-1;
129
			// $this->options['alias'] = $this->root == '/' || $this->root == '.' ? 'FTP folder '.$num : basename($this->root);
130
		}
131
132
		$this->rootName = $this->options['alias'];
133
		$this->options['separator'] = '/';
134
135
		return $this->connect();
136
		
137
	}
138
139
140
	/**
141
	 * Configure after successfull mount.
142
	 *
143
	 * @return void
144
	 * @author Dmitry (dio) Levashov
145
	 **/
146
	protected function configure() {
147
		parent::configure();
148
		
149
		if (!empty($this->options['tmpPath'])) {
150
			if ((is_dir($this->options['tmpPath']) || @mkdir($this->options['tmpPath'], 0755, true)) && is_writable($this->options['tmpPath'])) {
151
				$this->tmp = $this->options['tmpPath'];
152
			}
153
		}
154
		
155
		if (!$this->tmp && $this->tmbPath) {
156
			$this->tmp = $this->tmbPath;
157
		}
158
		
159
		if (!$this->tmp) {
160
			$this->disabled[] = 'mkfile';
161
			$this->disabled[] = 'paste';
162
			$this->disabled[] = 'duplicate';
163
			$this->disabled[] = 'upload';
164
			$this->disabled[] = 'edit';
165
			$this->disabled[] = 'archive';
166
			$this->disabled[] = 'extract';
167
		}
168
		
169
		// echo $this->tmp;
170
		
171
	}
172
	
173
	/**
174
	 * Connect to ftp server
175
	 *
176
	 * @return bool
177
	 * @author Dmitry (dio) Levashov
178
	 **/
179
	protected function connect() {
180 View Code Duplication
		if (!($this->connect = ftp_connect($this->options['host'], $this->options['port'], $this->options['timeout']))) {
0 ignored issues
show
Documentation Bug introduced by
It seems like ftp_connect($this->optio...is->options['timeout']) of type resource is incompatible with the declared type object<ftp> of property $connect.

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...
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...
181
			return $this->setError('Unable to connect to FTP server '.$this->options['host']);
182
		}
183 View Code Duplication
		if (!ftp_login($this->connect, $this->options['user'], $this->options['pass'])) {
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...
184
			$this->umount();
185
			return $this->setError('Unable to login into '.$this->options['host']);
186
		}
187
		
188
		// switch off extended passive mode - may be usefull for some servers
189
		@ftp_exec($this->connect, 'epsv4 off' );
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...
190
		// enter passive mode if required
191
		ftp_pasv($this->connect, $this->options['mode'] == 'passive');
192
193
		// enter root folder
194
		if (!ftp_chdir($this->connect, $this->root) 
195
		|| $this->root != ftp_pwd($this->connect)) {
196
			$this->umount();
197
			return $this->setError('Unable to open root folder.');
198
		}
199
		
200
		// check for MLST support
201
		$features = ftp_raw($this->connect, 'FEAT');
202
		if (!is_array($features)) {
203
			$this->umount();
204
			return $this->setError('Server does not support command FEAT.');
205
		}
206
207
		foreach ($features as $feat) {
208
			if (strpos(trim($feat), 'MLST') === 0) {
209
				return true;
210
			}
211
		}
212
		
213
		return $this->setError('Server does not support command MLST.');
214
	}
215
	
216
	/*********************************************************************/
217
	/*                               FS API                              */
218
	/*********************************************************************/
219
220
	/**
221
	 * Close opened connection
222
	 *
223
	 * @return void
224
	 * @author Dmitry (dio) Levashov
225
	 **/
226
	public function umount() {
227
		$this->connect && @ftp_close($this->connect);
228
	}
229
230
231
	/**
232
	 * Parse line from ftp_rawlist() output and return file stat (array)
233
	 *
234
	 * @param  string  $raw  line from ftp_rawlist() output
235
	 * @return array
236
	 * @author Dmitry Levashov
237
	 **/
238
	protected function parseRaw($raw) {
239
		$info = preg_split("/\s+/", $raw, 9);
240
		$stat = array();
241
242
		if (count($info) < 9 || $info[8] == '.' || $info[8] == '..') {
243
			return false;
244
		}
245
246
		if (!isset($this->ftpOsUnix)) {
247
			$this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1));
248
		}
249
		
250
		if ($this->ftpOsUnix) {
251
			
252
			$stat['ts'] = strtotime($info[5].' '.$info[6].' '.$info[7]);
253
			if (empty($stat['ts'])) {
254
				$stat['ts'] = strtotime($info[6].' '.$info[5].' '.$info[7]);
255
			}
256
			
257
			$name = $info[8];
258
			
259
			if (preg_match('|(.+)\-\>(.+)|', $name, $m)) {
260
				$name   = trim($m[1]);
261
				$target = trim($m[2]);
262
				if (substr($target, 0, 1) != '/') {
263
					$target = $this->root.'/'.$target;
264
				}
265
				$target = $this->_normpath($target);
266
				$stat['name']  = $name;
267
				if ($this->_inpath($target, $this->root) 
268
				&& ($tstat = $this->stat($target))) {
269
					$stat['size']  = $tstat['mime'] == 'directory' ? 0 : $info[4];
270
					$stat['alias'] = $this->_relpath($target);
271
					$stat['thash'] = $tstat['hash'];
272
					$stat['mime']  = $tstat['mime'];
273
					$stat['read']  = $tstat['read'];
274
					$stat['write']  = $tstat['write'];
275
				} else {
276
					
277
					$stat['mime']  = 'symlink-broken';
278
					$stat['read']  = false;
279
					$stat['write'] = false;
280
					$stat['size']  = 0;
281
					
282
				}
283
				return $stat;
284
			}
285
			
286
			$perm = $this->parsePermissions($info[0]);
287
			$stat['name']  = $name;
288
			$stat['mime']  = substr(strtolower($info[0]), 0, 1) == 'd' ? 'directory' : $this->mimetype($stat['name']);
289
			$stat['size']  = $stat['mime'] == 'directory' ? 0 : $info[4];
290
			$stat['read']  = $perm['read'];
291
			$stat['write'] = $perm['write'];
292
			$stat['perm']  = substr($info[0], 1);
293
		} else {
294
			die('Windows ftp servers not supported yet');
295
		}
296
297
		return $stat;
298
	}
299
	
300
	/**
301
	 * Parse permissions string. Return array(read => true/false, write => true/false)
302
	 *
303
	 * @param  string  $perm  permissions string
304
	 * @return string
305
	 * @author Dmitry (dio) Levashov
306
	 **/
307
	protected function parsePermissions($perm) {
308
		$res   = array();
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...
309
		$parts = array();
310
		$owner = $this->options['owner'];
311
		for ($i = 0, $l = strlen($perm); $i < $l; $i++) {
312
			$parts[] = substr($perm, $i, 1);
313
		}
314
315
		$read = ($owner && $parts[0] == 'r') || $parts[4] == 'r' || $parts[7] == 'r';
316
		
317
		return array(
318
			'read'  => $parts[0] == 'd' ? $read && (($owner && $parts[3] == 'x') || $parts[6] == 'x' || $parts[9] == 'x') : $read,
319
			'write' => ($owner && $parts[2] == 'w') || $parts[5] == 'w' || $parts[8] == 'w'
320
		);
321
	}
322
	
323
	/**
324
	 * Cache dir contents
325
	 *
326
	 * @param  string  $path  dir path
327
	 * @return void
328
	 * @author Dmitry Levashov
329
	 **/
330
	protected function cacheDir($path) {
331
		$this->dirsCache[$path] = array();
332
333 View Code Duplication
		if (preg_match('/\'|\"/', $path)) {
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...
334
			foreach (ftp_nlist($this->connect, $path) as $p) {
335
				if (($stat = $this->_stat($p)) &&empty($stat['hidden'])) {
336
					// $files[] = $stat;
337
					$this->dirsCache[$path][] = $p;
338
				}
339
			}
340
			return;
341
		}
342
		foreach (ftp_rawlist($this->connect, $path) as $raw) {
343
			if (($stat = $this->parseRaw($raw))) {
344
				$p    = $path.'/'.$stat['name'];
345
				$stat = $this->updateCache($p, $stat);
346
				if (empty($stat['hidden'])) {
347
					// $files[] = $stat;
348
					$this->dirsCache[$path][] = $p;
349
				}
350
			}
351
		}
352
	}
353
354
	/**
355
	 * Return ftp transfer mode for file
356
	 *
357
	 * @param  string  $path  file path
358
	 * @return string
359
	 * @author Dmitry (dio) Levashov
360
	 **/
361
	protected function ftpMode($path) {
362
		return strpos($this->mimetype($path), 'text/') === 0 ? FTP_ASCII : FTP_BINARY;
363
	}
364
365
	/*********************** paths/urls *************************/
366
	
367
	/**
368
	 * Return parent directory path
369
	 *
370
	 * @param  string  $path  file path
371
	 * @return string
372
	 * @author Dmitry (dio) Levashov
373
	 **/
374
	protected function _dirname($path) {
375
		return dirname($path);
376
	}
377
378
	/**
379
	 * Return file name
380
	 *
381
	 * @param  string  $path  file path
382
	 * @return string
383
	 * @author Dmitry (dio) Levashov
384
	 **/
385
	protected function _basename($path) {
386
		return basename($path);
387
	}
388
389
	/**
390
	 * Join dir name and file name and retur full path
391
	 *
392
	 * @param  string  $dir
393
	 * @param  string  $name
394
	 * @return string
395
	 * @author Dmitry (dio) Levashov
396
	 **/
397
	protected function _joinPath($dir, $name) {
398
		return $dir.DIRECTORY_SEPARATOR.$name;
399
	}
400
	
401
	/**
402
	 * Return normalized path, this works the same as os.path.normpath() in Python
403
	 *
404
	 * @param  string  $path  path
405
	 * @return string
406
	 * @author Troex Nevelin
407
	 **/
408
	protected function _normpath($path) {
409
		if (empty($path)) {
410
			$path = '.';
411
		}
412
		// path must be start with /
413
		$path = preg_replace('|^\.\/?|', '/', $path);
414
		$path = preg_replace('/^([^\/])/', "/$1", $path);
415
416 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...
417
			$initial_slashes = true;
418
		} else {
419
			$initial_slashes = false;
420
		}
421
			
422 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...
423
		&& (strpos($path, '//') === 0) 
424
		&& (strpos($path, '///') === false)) {
425
			$initial_slashes = 2;
426
		}
427
			
428
		$initial_slashes = (int) $initial_slashes;
429
430
		$comps = explode('/', $path);
431
		$new_comps = array();
432 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...
433
			if (in_array($comp, array('', '.'))) {
434
				continue;
435
			}
436
				
437
			if (($comp != '..') 
438
			|| (!$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...
439
			|| ($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...
440
				array_push($new_comps, $comp);
441
			} 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...
442
				array_pop($new_comps);
443
			}
444
		}
445
		$comps = $new_comps;
446
		$path = implode('/', $comps);
447
		if ($initial_slashes) {
448
			$path = str_repeat('/', $initial_slashes) . $path;
449
		}
450
		
451
		return $path ? $path : '.';
452
	}
453
	
454
	/**
455
	 * Return file path related to root dir
456
	 *
457
	 * @param  string  $path  file path
458
	 * @return string
459
	 * @author Dmitry (dio) Levashov
460
	 **/
461
	protected function _relpath($path) {
462
		return $path == $this->root ? '' : substr($path, strlen($this->root)+1);
463
	}
464
	
465
	/**
466
	 * Convert path related to root dir into real path
467
	 *
468
	 * @param  string  $path  file path
469
	 * @return string
470
	 * @author Dmitry (dio) Levashov
471
	 **/
472
	protected function _abspath($path) {
473
		return $path == $this->separator ? $this->root : $this->root.$this->separator.$path;
474
	}
475
	
476
	/**
477
	 * Return fake path started from root dir
478
	 *
479
	 * @param  string  $path  file path
480
	 * @return string
481
	 * @author Dmitry (dio) Levashov
482
	 **/
483
	protected function _path($path) {
484
		return $this->rootName.($path == $this->root ? '' : $this->separator.$this->_relpath($path));
485
	}
486
	
487
	/**
488
	 * Return true if $path is children of $parent
489
	 *
490
	 * @param  string  $path    path to check
491
	 * @param  string  $parent  parent path
492
	 * @return bool
493
	 * @author Dmitry (dio) Levashov
494
	 **/
495
	protected function _inpath($path, $parent) {
496
		return $path == $parent || strpos($path, $parent.'/') === 0;
497
	}
498
	
499
	/***************** file stat ********************/
500
	/**
501
	 * Return stat for given path.
502
	 * Stat contains following fields:
503
	 * - (int)    size    file size in b. required
504
	 * - (int)    ts      file modification time in unix time. required
505
	 * - (string) mime    mimetype. required for folders, others - optionally
506
	 * - (bool)   read    read permissions. required
507
	 * - (bool)   write   write permissions. required
508
	 * - (bool)   locked  is object locked. optionally
509
	 * - (bool)   hidden  is object hidden. optionally
510
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
511
	 * - (string) target  for symlinks - link target path. optionally
512
	 *
513
	 * If file does not exists - returns empty array or false.
514
	 *
515
	 * @param  string  $path    file path 
516
	 * @return array|false
517
	 * @author Dmitry (dio) Levashov
518
	 **/
519
	protected function _stat($path) {
520
		$raw = ftp_raw($this->connect, 'MLST '.$path);
521
522
		if (is_array($raw) && count($raw) > 1 && substr(trim($raw[0]), 0, 1) == 2) {
523
			$parts = explode(';', trim($raw[1]));
524
			array_pop($parts);
525
			$parts = array_map('strtolower', $parts);
526
			$stat  = array();
527
			// debug($parts);
528
			foreach ($parts as $part) {
529
530
				list($key, $val) = explode('=', $part);
531
532
				switch ($key) {
533
					case 'type':
534
						$stat['mime'] = strpos($val, 'dir') !== false ? 'directory' : $this->mimetype($path);
535
						break;
536
537
					case 'size':
538
						$stat['size'] = $val;
539
						break;
540
541
					case 'modify':
542
						$ts = mktime(intval(substr($val, 8, 2)), intval(substr($val, 10, 2)), intval(substr($val, 12, 2)), intval(substr($val, 4, 2)), intval(substr($val, 6, 2)), substr($val, 0, 4));
543
						$stat['ts'] = $ts;
544
						// $stat['date'] = $this->formatDate($ts);
545
						break;
546
547
					case 'unix.mode':
548
						$stat['chmod'] = $val;
549
						break;
550
551
					case 'perm':
552
						$val = strtolower($val);
553
						$stat['read']  = (int)preg_match('/e|l|r/', $val);
554
						$stat['write'] = (int)preg_match('/w|m|c/', $val);
555
						if (!preg_match('/f|d/', $val)) {
556
							$stat['locked'] = 1;
557
						}
558
						break;
559
				}
560
			}
561
			if (empty($stat['mime'])) {
562
				return array();
563
			}
564
			if ($stat['mime'] == 'directory') {
565
				$stat['size'] = 0;
566
			}
567
			
568
			if (isset($stat['chmod'])) {
569
				$stat['perm'] = '';
570
				if ($stat['chmod'][0] == 0) {
571
					$stat['chmod'] = substr($stat['chmod'], 1);
572
				}
573
574
				for ($i = 0; $i <= 2; $i++) {
575
					$perm[$i] = array(false, false, false);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$perm was never initialized. Although not strictly required by PHP, it is generally a good practice to add $perm = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
576
					$n = isset($stat['chmod'][$i]) ? $stat['chmod'][$i] : 0;
577
					
578 View Code Duplication
					if ($n - 4 >= 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...
579
						$perm[$i][0] = true;
0 ignored issues
show
Bug introduced by
The variable $perm 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...
580
						$n = $n - 4;
581
						$stat['perm'] .= 'r';
582
					} else {
583
						$stat['perm'] .= '-';
584
					}
585
					
586 View Code Duplication
					if ($n - 2 >= 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...
587
						$perm[$i][1] = true;
588
						$n = $n - 2;
589
						$stat['perm'] .= 'w';
590
					} else {
591
						$stat['perm'] .= '-';
592
					}
593
594 View Code Duplication
					if ($n - 1 == 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...
595
						$perm[$i][2] = true;
596
						$stat['perm'] .= 'x';
597
					} else {
598
						$stat['perm'] .= '-';
599
					}
600
					
601
					$stat['perm'] .= ' ';
602
				}
603
				
604
				$stat['perm'] = trim($stat['perm']);
605
606
				$owner = $this->options['owner'];
607
				$read = ($owner && $perm[0][0]) || $perm[1][0] || $perm[2][0];
608
609
				$stat['read']  = $stat['mime'] == 'directory' ? $read && (($owner && $perm[0][2]) || $perm[1][2] || $perm[2][2]) : $read;
610
				$stat['write'] = ($owner && $perm[0][1]) || $perm[1][1] || $perm[2][1];
611
				unset($stat['chmod']);
612
613
			}
614
			
615
			return $stat;
616
			
617
		}
618
		
619
		return array();
620
	}
621
	
622
	/**
623
	 * Return true if path is dir and has at least one childs directory
624
	 *
625
	 * @param  string  $path  dir path
626
	 * @return bool
627
	 * @author Dmitry (dio) Levashov
628
	 **/
629
	protected function _subdirs($path) {
630
		
631
		if (preg_match('/\s|\'|\"/', $path)) {
632
			foreach (ftp_nlist($this->connect, $path) as $p) {
633
				if (($stat = $this->stat($path.'/'.$p)) && $stat['mime'] == 'directory') {
634
					return true;
635
				}
636
			}
637
			return false;
638
		}
639
		
640
		foreach (ftp_rawlist($this->connect, $path) as $str) {
641
			if (($stat = $this->parseRaw($str)) && $stat['mime'] == 'directory') {
642
				return true;
643
			}
644
		}
645
		return false;
646
	}
647
	
648
	/**
649
	 * Return object width and height
650
	 * Ususaly used for images, but can be realize for video etc...
651
	 *
652
	 * @param  string  $path  file path
653
	 * @param  string  $mime  file mime type
654
	 * @return string
655
	 * @author Dmitry (dio) Levashov
656
	 **/
657
	protected function _dimensions($path, $mime) {
658
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_dimensions 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...
659
	}
660
	
661
	/******************** file/dir content *********************/
662
		
663
	/**
664
	 * Return files list in directory.
665
	 *
666
	 * @param  string  $path  dir path
667
	 * @return array
668
	 * @author Dmitry (dio) Levashov
669
	 * @author Cem (DiscoFever)
670
	 **/
671
	protected function _scandir($path) {
672
		$files = array();
673
674
		foreach (ftp_rawlist($this->connect, $path) as $str) {
675
			if (($stat = $this->parseRaw($str))) {
676
				$files[] = $path.DIRECTORY_SEPARATOR.$stat['name'];
677
			}
678
		}
679
680
		return $files;
681
	}
682
		
683
	/**
684
	 * Open file and return file pointer
685
	 *
686
	 * @param  string  $path  file path
687
	 * @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...
688
	 * @return resource|false
689
	 * @author Dmitry (dio) Levashov
690
	 **/
691
	protected function _fopen($path, $mode='rb') {
692
		
693
		if ($this->tmp) {
694
			$local = $this->tmp.DIRECTORY_SEPARATOR.md5($path);
695
696
			if (ftp_get($this->connect, $local, $path, FTP_BINARY)) {
697
				return @fopen($local, $mode);
698
			}
699
		}
700
		
701
		return false;
702
	}
703
	
704
	/**
705
	 * Close opened file
706
	 *
707
	 * @param  resource  $fp  file pointer
708
	 * @return bool
709
	 * @author Dmitry (dio) Levashov
710
	 **/
711
	protected function _fclose($fp, $path='') {
712
		@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...
713
		if ($path) {
714
			@unlink($this->tmp.DIRECTORY_SEPARATOR.md5($path));
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...
715
		}
716
	}
717
	
718
	/********************  file/dir manipulations *************************/
719
	
720
	/**
721
	 * Create dir and return created dir path or false on failed
722
	 *
723
	 * @param  string  $path  parent dir path
724
	 * @param string  $name  new directory name
725
	 * @return string|bool
726
	 * @author Dmitry (dio) Levashov
727
	 **/
728
	protected function _mkdir($path, $name) {
729
		$path = $path.'/'.$name;
730
		if (ftp_mkdir($this->connect, $path) === false) {
731
			return false;
732
		} 
733
		
734
		$this->options['dirMode'] && @ftp_chmod($this->connect, $this->options['dirMode'], $path);
735
		return $path;
736
	}
737
	
738
	/**
739
	 * Create file and return it's path or false on failed
740
	 *
741
	 * @param  string  $path  parent dir path
742
	 * @param string  $name  new file name
743
	 * @return string|bool
744
	 * @author Dmitry (dio) Levashov
745
	 **/
746
	protected function _mkfile($path, $name) {
747
		if ($this->tmp) {
748
			$path = $path.'/'.$name;
749
			$local = $this->tmp.DIRECTORY_SEPARATOR.md5($path);
750
			$res = touch($local) && ftp_put($this->connect, $path, $local, FTP_ASCII);
751
			@unlink($local);
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...
752
			return $res ? $path : false;
753
		}
754
		return false;
755
	}
756
	
757
	/**
758
	 * Create symlink. FTP driver does not support symlinks.
759
	 *
760
	 * @param  string  $target  link target
761
	 * @param  string  $path    symlink path
762
	 * @return bool
763
	 * @author Dmitry (dio) Levashov
764
	 **/
765
	protected function _symlink($target, $path, $name) {
766
		return false;
767
	}
768
	
769
	/**
770
	 * Copy file into another file
771
	 *
772
	 * @param  string  $source     source file path
773
	 * @param  string  $targetDir  target directory path
774
	 * @param  string  $name       new file name
775
	 * @return bool
776
	 * @author Dmitry (dio) Levashov
777
	 **/
778
	protected function _copy($source, $targetDir, $name) {
779
		$res = false;
780
		
781
		if ($this->tmp) {
782
			$local  = $this->tmp.DIRECTORY_SEPARATOR.md5($source);
783
			$target = $targetDir.DIRECTORY_SEPARATOR.$name;
0 ignored issues
show
Bug Compatibility introduced by
The expression $targetDir . DIRECTORY_SEPARATOR . $name; of type string adds the type string to the return on line 792 which is incompatible with the return type declared by the abstract method elFinderVolumeDriver::_copy of type boolean.
Loading history...
784
785 View Code Duplication
			if (ftp_get($this->connect, $local, $source, FTP_BINARY)
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...
786
			&& ftp_put($this->connect, $target, $local, $this->ftpMode($target))) {
787
				$res = $target;
788
			}
789
			@unlink($local);
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...
790
		}
791
		
792
		return $res;
793
	}
794
	
795
	/**
796
	 * Move file into another parent dir.
797
	 * Return new file path or false.
798
	 *
799
	 * @param  string  $source  source file path
800
	 * @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...
801
	 * @param  string  $name    file name
802
	 * @return string|bool
803
	 * @author Dmitry (dio) Levashov
804
	 **/
805
	protected function _move($source, $targetDir, $name) {
806
		$target = $targetDir.DIRECTORY_SEPARATOR.$name;
807
		return ftp_rename($this->connect, $source, $target) ? $target : false;
808
	}
809
		
810
	/**
811
	 * Remove file
812
	 *
813
	 * @param  string  $path  file path
814
	 * @return bool
815
	 * @author Dmitry (dio) Levashov
816
	 **/
817
	protected function _unlink($path) {
818
		return ftp_delete($this->connect, $path);
819
	}
820
821
	/**
822
	 * Remove dir
823
	 *
824
	 * @param  string  $path  dir path
825
	 * @return bool
826
	 * @author Dmitry (dio) Levashov
827
	 **/
828
	protected function _rmdir($path) {
829
		return ftp_rmdir($this->connect, $path);
830
	}
831
	
832
	/**
833
	 * Create new file and write into it from file pointer.
834
	 * Return new file path or false on error.
835
	 *
836
	 * @param  resource  $fp   file pointer
837
	 * @param  string    $dir  target dir path
838
	 * @param  string    $name file name
839
	 * @param  array     $stat file stat (required by some virtual fs)
840
	 * @return bool|string
841
	 * @author Dmitry (dio) Levashov
842
	 **/
843
	protected function _save($fp, $dir, $name, $stat) {
844
		$path = $dir.'/'.$name;
845
		return ftp_fput($this->connect, $path, $fp, $this->ftpMode($path))
846
			? $path
847
			: false;
848
	}
849
	
850
	/**
851
	 * Get file contents
852
	 *
853
	 * @param  string  $path  file path
854
	 * @return string|false
855
	 * @author Dmitry (dio) Levashov
856
	 **/
857
	protected function _getContents($path) {
858
		$contents = '';
859
		if (($fp = $this->_fopen($path))) {
860
			while (!feof($fp)) {
861
			  $contents .= fread($fp, 8192);
862
			}
863
			$this->_fclose($fp, $path);
864
			return $contents;
865
		}
866
		return false;
867
	}
868
	
869
	/**
870
	 * Write a string to a file
871
	 *
872
	 * @param  string  $path     file path
873
	 * @param  string  $content  new file content
874
	 * @return bool
875
	 * @author Dmitry (dio) Levashov
876
	 **/
877
	protected function _filePutContents($path, $content) {
878
		$res = false;
879
880
		if ($this->tmp) {
881
			$local = $this->tmp.DIRECTORY_SEPARATOR.md5($path).'.txt';
882
			
883
			if (@file_put_contents($local, $content, LOCK_EX) !== false
884
			&& ($fp = @fopen($local, 'rb'))) {
885
				clearstatcache();
886
				$res  = ftp_fput($this->connect, $path, $fp, $this->ftpMode($path));
887
				@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...
888
			}
889
			file_exists($local) && @unlink($local);
890
		}
891
892
		return $res;
893
	}
894
895
	/**
896
	 * Detect available archivers
897
	 *
898
	 * @return void
899
	 **/
900
	protected function _checkArchivers() {
901
		// die('Not yet implemented. (_checkArchivers)');
902
		return array();
903
	}
904
905
	/**
906
	 * Unpack archive
907
	 *
908
	 * @param  string  $path  archive path
909
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
910
	 * @return true
911
	 * @return void
912
	 * @author Dmitry (dio) Levashov
913
	 * @author Alexey Sukhotin
914
	 **/
915
	protected function _unpack($path, $arc) {
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $arc is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
916
		die('Not yet implemented. (_unpack)');
917
		return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

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

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

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

    return false;
}

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

Loading history...
918
	}
919
920
	/**
921
	 * Recursive symlinks search
922
	 *
923
	 * @param  string  $path  file/dir path
924
	 * @return bool
925
	 * @author Dmitry (dio) Levashov
926
	 **/
927 View Code Duplication
	protected function _findSymlinks($path) {
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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...
928
		die('Not yet implemented. (_findSymlinks)');
929
		if (is_link($path)) {
0 ignored issues
show
Unused Code introduced by
if (is_link($path)) { return true; } does not seem to be reachable.

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

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

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

    return false;
}

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

Loading history...
930
			return true;
931
		}
932
		if (is_dir($path)) {
933
			foreach (scandir($path) as $name) {
934
				if ($name != '.' && $name != '..') {
935
					$p = $path.DIRECTORY_SEPARATOR.$name;
936
					if (is_link($p)) {
937
						return true;
938
					}
939
					if (is_dir($p) && $this->_findSymlinks($p)) {
940
						return true;
941
					} elseif (is_file($p)) {
942
						$this->archiveSize += filesize($p);
0 ignored issues
show
Bug introduced by
The property archiveSize 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...
943
					}
944
				}
945
			}
946
		} else {
947
			$this->archiveSize += filesize($path);
948
		}
949
		
950
		return false;
951
	}
952
953
	/**
954
	 * Extract files from archive
955
	 *
956
	 * @param  string  $path  archive path
957
	 * @param  array   $arc   archiver command and arguments (same as in $this->archivers)
958
	 * @return true
959
	 * @author Dmitry (dio) Levashov,
960
	 * @author Alexey Sukhotin
961
	 **/
962
	protected function _extract($path, $arc)
963
	{
964
		// get current directory
965
		$cwd = getcwd();
966
967
		$tmpDir = $this->tempDir();
968
		if (!$tmpDir) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tmpDir of type false|string 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...
969
			return false;
970
		}
971
972
		$basename = $this->_basename($path);
973
		$localPath = $tmpDir . DIRECTORY_SEPARATOR . $basename;
974
975
		if (!ftp_get($this->connect, $localPath, $path, FTP_BINARY)) {
976
			//cleanup
977
			$this->deleteDir($tmpDir);
978
			return false;
979
		}
980
981
		$remoteDirectory = dirname($path);
982
		chdir($tmpDir);
983
		$command = escapeshellcmd($arc['cmd'] . ' ' . $arc['argc'] . ' "' . $basename . '"');
984
		$descriptorspec = array(
985
			0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
986
			1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
987
			2 => array("pipe", "w") // stderr is a file to write to
988
		);
989
990
			
991
		$process = proc_open($command, $descriptorspec, $pipes, $cwd);
992
993 View Code Duplication
		if (is_resource($process)) {
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...
994
			fclose($pipes[0]);
995
			fclose($pipes[1]);
996
			$return_value = proc_close($process);
0 ignored issues
show
Unused Code introduced by
$return_value 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...
997
		}
998
999
		unlink($basename);
1000
		$filesToProcess = elFinderVolumeFTP::listFilesInDirectory($tmpDir, true);
1001
		if(!$filesToProcess) {
1002
			$this->setError(elFinder::ERROR_EXTRACT_EXEC, $tmpDir." is not a directory");
1003
			$this->deleteDir($tmpDir); //cleanup
1004
			return false;
1005
		}
1006
		if (count($filesToProcess) > 1) {
1007
1008
			// for several files - create new directory
1009
			// create unique name for directory
1010
			$name = basename($path);
1011 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...
1012
				$name = substr($name, 0, strlen($name) - strlen($m[0]));
1013
			}
1014
1015
			$test = dirname($path) . DIRECTORY_SEPARATOR . $name;
1016
			if ($this->stat($test)) {
1017
				$name = $this->uniqueName(dirname($path), $name, '-', false);
1018
			}
1019
1020
			$newPath = dirname($path) . DIRECTORY_SEPARATOR . $name;
1021
1022
			$success = $this->_mkdir(dirname($path), $name);
1023
			foreach ($filesToProcess as $filename) {
1024
				if (!$success) {
1025
					break;
1026
				}
1027
				$targetPath = $newPath . DIRECTORY_SEPARATOR . $filename;
1028 View Code Duplication
				if (is_dir($filename)) {
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...
1029
					$success = $this->_mkdir($newPath, $filename);
1030
				} else {
1031
					$success = ftp_put($this->connect, $targetPath, $filename, FTP_BINARY);
1032
				}
1033
			}
1034
			unset($filename);
1035
1036
		} else {
1037
			$filename = $filesToProcess[0];
1038
			$newPath = $remoteDirectory . DIRECTORY_SEPARATOR . $filename;
1039
			$success = ftp_put($this->connect, $newPath, $filename, FTP_BINARY);
1040
		}
1041
1042
		// return to initial directory
1043
		chdir($cwd);
1044
1045
		//cleanup
1046
		if(!$this->deleteDir($tmpDir)) {
1047
			return false;
1048
		}
1049
		
1050
		if (!$success) {
1051
			$this->setError(elFinder::ERROR_FTP_UPLOAD_FILE, $newPath);
1052
			return false;
1053
		}
1054
		$this->clearcache();
1055
		return $newPath;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $newPath; (string) 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...
1056
	}
1057
1058
	/**
1059
	 * Create archive and return its path
1060
	 *
1061
	 * @param  string  $dir    target dir
1062
	 * @param  array   $files  files names list
1063
	 * @param  string  $name   archive name
1064
	 * @param  array   $arc    archiver options
1065
	 * @return string|bool
1066
	 * @author Dmitry (dio) Levashov,
1067
	 * @author Alexey Sukhotin
1068
	 **/
1069
	protected function _archive($dir, $files, $name, $arc)
1070
	{
1071
		// get current directory
1072
		$cwd = getcwd();
1073
1074
		$tmpDir = $this->tempDir();
1075
		if (!$tmpDir) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tmpDir of type false|string 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...
1076
			return false;
1077
		}
1078
1079
		//download data
1080
		if (!$this->ftp_download_files($dir, $files, $tmpDir)) {
1081
			//cleanup
1082
			$this->deleteDir($tmpDir);
1083
			return false;
1084
		}
1085
1086
		// go to the temporary directory
1087
		chdir($tmpDir);
1088
1089
		// path to local copy of archive
1090
		$path = $tmpDir . DIRECTORY_SEPARATOR . $name;
1091
1092
		$file_names_string = "";
1093
		foreach (scandir($tmpDir) as $filename) {
1094
			if ('.' == $filename) {
1095
				continue;
1096
			}
1097
			if ('..' == $filename) {
1098
				continue;
1099
			}
1100
			$file_names_string = $file_names_string . '"' . $filename . '" ';
1101
		}
1102
		$command = escapeshellcmd($arc['cmd'] . ' ' . $arc['argc'] . ' "' . $name . '" ' . $file_names_string);
1103
		
1104
		$descriptorspec = array(
1105
			0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
1106
			1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
1107
			2 => array("pipe", "w") // stderr is a file to write to
1108
		);
1109
1110
			
1111
		$process = proc_open($command, $descriptorspec, $pipes, $cwd);
1112
1113 View Code Duplication
		if (is_resource($process)) {
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...
1114
			fclose($pipes[0]);
1115
			fclose($pipes[1]);
1116
			$return_value = proc_close($process);
0 ignored issues
show
Unused Code introduced by
$return_value 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...
1117
		}
1118
1119
		$remoteArchiveFile = $dir . DIRECTORY_SEPARATOR . $name;
1120
1121
		// upload archive
1122 View Code Duplication
		if (!ftp_put($this->connect, $remoteArchiveFile, $path, FTP_BINARY)) {
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...
1123
			$this->setError(elFinder::ERROR_FTP_UPLOAD_FILE, $remoteArchiveFile);
1124
			$this->deleteDir($tmpDir); //cleanup
1125
			return false;
1126
		}
1127
1128
		// return to initial work directory
1129
		chdir($cwd);
1130
1131
		//cleanup
1132
		if(!$this->deleteDir($tmpDir)) {
1133
			return false;
1134
		}
1135
1136
		return $remoteArchiveFile;
1137
	}
1138
1139
	/**
1140
	 * Create writable temporary directory and return path to it.
1141
	 * @return string path to the new temporary directory or false in case of error.
1142
	 */
1143
	private function tempDir()
1144
	{
1145
		$tempPath = tempnam($this->tmp, 'elFinder');
1146
		if (!$tempPath) {
1147
			$this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp);
1148
			return false;
1149
		}
1150
		$success = unlink($tempPath);
1151
		if (!$success) {
1152
			$this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp);
1153
			return false;
1154
		}
1155
		$success = mkdir($tempPath, 0700, true);
1156
		if (!$success) {
1157
			$this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp);
1158
			return false;
1159
		}
1160
		return $tempPath;
1161
	}
1162
1163
	/**
1164
	 * Gets in a single FTP request an array of absolute remote FTP paths of files and
1165
	 * folders in $remote_directory omitting symbolic links.
1166
	 * @param $remote_directory string remote FTP path to scan for file and folders recursively
1167
	 * @return array of elements each of which is an array of two elements:
1168
	 * <ul>
1169
	 * <li>$item['path'] - absolute remote FTP path</li>
1170
	 * <li>$item['type'] - either 'f' for file or 'd' for directory</li>
1171
	 * </ul>
1172
	 */
1173
	protected function ftp_scan_dir($remote_directory)
1174
	{
1175
		$buff = ftp_rawlist($this->connect, $remote_directory, true);
1176
		$next_folder = false;
1177
		$items = array();
1178
		foreach ($buff as $str) {
1179
			if ('' == $str) {
1180
				$next_folder = true;
1181
				continue;
1182
			}
1183
			if ($next_folder) {
1184
				$remote_directory = preg_replace('/\:/', '', $str);
1185
				$next_folder = false;
1186
				$item = array();
1187
				$item['path'] = $remote_directory;
1188
				$item['type'] = 'd'; // directory
1189
				$items[] = $item;
1190
				continue;
1191
			}
1192
			$info = preg_split("/\s+/", $str, 9);
1193
			$type = substr($info[0], 0, 1);
1194
			switch ($type) {
1195
				case 'l' : //omit symbolic links
1196
				case 'd' :
1197
					break;
1198
				default:
1199
					$remote_file_path = $remote_directory . DIRECTORY_SEPARATOR . $info[8];
1200
					$item = array();
1201
					$item['path'] = $remote_file_path;
1202
					$item['type'] = 'f'; // normal file
1203
					$items[] = $item;
1204
			}
1205
		}
1206
		return $items;
1207
	}
1208
1209
	/**
1210
	 * Downloads specified files from remote directory
1211
	 * if there is a directory among files it is downloaded recursively (omitting symbolic links).
1212
	 * @param $remote_directory string remote FTP path to a source directory to download from.
1213
	 * @param array $files list of files to download from remote directory.
1214
	 * @param $dest_local_directory string destination folder to store downloaded files.
1215
	 * @return bool true on success and false on failure.
1216
	 */
1217
	private function ftp_download_files($remote_directory, array $files, $dest_local_directory)
1218
	{
1219
		$contents = $this->ftp_scan_dir($remote_directory);
1220
		if (!isset($contents)) {
1221
			$this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory);
1222
			return false;
1223
		}
1224
		foreach ($contents as $item) {
1225
			$drop = true;
1226
			foreach ($files as $file) {
1227
				if ($remote_directory . DIRECTORY_SEPARATOR . $file == $item['path'] || strstr($item['path'], $remote_directory . DIRECTORY_SEPARATOR . $file . DIRECTORY_SEPARATOR)) {
1228
					$drop = false;
1229
					break;
1230
				}
1231
			}
1232
			if ($drop) continue;
1233
			$relative_path = str_replace($remote_directory, '', $item['path']);
1234
			$local_path = $dest_local_directory . DIRECTORY_SEPARATOR . $relative_path;
1235
			switch ($item['type']) {
1236
				case 'd':
1237
					$success = mkdir($local_path);
1238
					break;
1239
				case 'f':
1240
					$success = ftp_get($this->connect, $local_path, $item['path'], FTP_BINARY);
1241
					break;
1242
				default:
1243
					$success = true;
1244
			}
1245
			if (!$success) {
1246
				$this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory);
1247
				return false;
1248
			}
1249
		}
1250
		return true;
1251
	}
1252
1253
	/**
1254
	 * Delete local directory recursively.
1255
	 * @param $dirPath string to directory to be erased.
1256
	 * @return bool true on success and false on failure.
1257
	 */
1258
	private function deleteDir($dirPath)
1259
	{
1260
		if (!is_dir($dirPath)) {
1261
			$success = unlink($dirPath);
1262
		} else {
1263
			$success = true;
1264
			foreach (array_reverse(elFinderVolumeFTP::listFilesInDirectory($dirPath, false)) as $path) {
1265
				$path = $dirPath . DIRECTORY_SEPARATOR . $path;
1266
				if(is_link($path)) {
1267
					unlink($path);
1268
				} else if (is_dir($path)) {
1269
					$success = rmdir($path);
1270
				} else {
1271
					$success = unlink($path);
1272
				}
1273
				if (!$success) {
1274
					break;
1275
				}
1276
			}
1277
			if($success) {
1278
				$success = rmdir($dirPath);
1279
			}
1280
		}
1281
		if(!$success) {
1282
			$this->setError(elFinder::ERROR_RM, $dirPath);
1283
			return false;
1284
		}
1285
		return $success;
1286
	}
1287
1288
	/**
1289
	 * Returns array of strings containing all files and folders in the specified local directory.
1290
	 * @param $dir
1291
	 * @param string $prefix
1292
	 * @internal param string $path path to directory to scan.
1293
	 * @return array array of files and folders names relative to the $path
1294
	 * or an empty array if the directory $path is empty,
1295
	 * <br />
1296
	 * false if $path is not a directory or does not exist.
1297
	 */
1298
	private static function listFilesInDirectory($dir, $omitSymlinks, $prefix = '')
1299
	{
1300
		if (!is_dir($dir)) {
1301
			return false;
1302
		}
1303
		$excludes = array(".","..");
1304
		$result = array();
1305
		$files = scandir($dir);
1306
		if(!$files) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $files 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...
1307
			return array();
1308
		}
1309
		foreach($files as $file) {
1310
			if(!in_array($file, $excludes)) {
1311
				$path = $dir.DIRECTORY_SEPARATOR.$file;
1312
				if(is_link($path)) {
1313
					if($omitSymlinks) {
1314
						continue;
1315
					} else {
1316
						$result[] = $prefix.$file;
1317
					}
1318
				} else if(is_dir($path)) {
1319
					$result[] = $prefix.$file.DIRECTORY_SEPARATOR;
1320
					$subs = elFinderVolumeFTP::listFilesInDirectory($path, $omitSymlinks, $prefix.$file.DIRECTORY_SEPARATOR);
1321
					if($subs) {
1322
						$result = array_merge($result, $subs);
1323
					}
1324
					
1325
				} else {
1326
					$result[] = $prefix.$file;
1327
				}
1328
			}
1329
		}
1330
		return $result;
1331
	}
1332
1333
/**
1334
	 * Resize image
1335
	 * @param string $hash
1336
	 * @param int $width
1337
	 * @param int $height
1338
	 * @param int $x
1339
	 * @param int $y
1340
	 * @param string $mode
1341
	 * @param string $bg
1342
	 * @param int $degree
1343
	 * @return array|bool|false
1344
	 */
1345
	public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0) {
1346
		if ($this->commandDisabled('resize')) {
1347
			return $this->setError(elFinder::ERROR_PERM_DENIED);
1348
		}
1349
1350
		if (($file = $this->file($hash)) == false) {
1351
			return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
1352
		}
1353
1354
		if (!$file['write'] || !$file['read']) {
1355
			return $this->setError(elFinder::ERROR_PERM_DENIED);
1356
		}
1357
1358
		$path = $this->decode($hash);
1359
1360
		$tmpDir = $this->tempDir();
1361
		if (!$tmpDir) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tmpDir of type false|string 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...
1362
			return false;
1363
		}
1364
		
1365
		$local_path = $tmpDir . DIRECTORY_SEPARATOR . basename($path);
1366
		$remote_directory = ftp_pwd($this->connect);
1367
		$success = ftp_get($this->connect, $local_path, $path, FTP_BINARY);
1368
		if (!$success) {
1369
			$this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory);
1370
			return false;
1371
		}
1372
1373
		if (!$this->canResize($path, $file)) {
0 ignored issues
show
Bug introduced by
It seems like $file defined by $this->file($hash) on line 1350 can also be of type boolean; however, elFinderVolumeDriver::canResize() does only seem to accept array, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
1374
			return $this->setError(elFinder::ERROR_UNSUPPORT_TYPE);
1375
		}
1376
1377 View Code Duplication
		switch($mode) {
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...
1378
1379
			case 'propresize':
1380
				$result = $this->imgResize($local_path, $width, $height, true, true);
1381
				break;
1382
1383
			case 'crop':
1384
				$result = $this->imgCrop($local_path, $width, $height, $x, $y);
0 ignored issues
show
Documentation introduced by
$x is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$y is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1385
				break;
1386
1387
			case 'fitsquare':
1388
				$result = $this->imgSquareFit($local_path, $width, $height, 'center', 'middle', ($bg ? $bg : $this->options['tmbBgColor']));
1389
				break;
1390
1391
			case 'rotate':
1392
				$result = $this->imgRotate($local_path, $degree, ($bg ? $bg : $this->options['tmbBgColor']));
1393
				break;
1394
1395
			default:
1396
				$result = $this->imgResize($local_path, $width, $height, false, true);
1397
				break;
1398
		}
1399
1400
		if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type false|string 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...
1401
			
1402
			// upload to FTP and clear temp local file
1403
1404 View Code Duplication
			if (!ftp_put($this->connect, $path, $local_path, FTP_BINARY)) {
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...
1405
				$this->setError(elFinder::ERROR_FTP_UPLOAD_FILE, $path);
1406
				$this->deleteDir($tmpDir); //cleanup
1407
			}
1408
			
1409
			$this->clearcache();
1410
			return $this->stat($path);
1411
		}
1412
1413
		$this->setError(elFinder::ERROR_UNKNOWN);
1414
		return false;
1415
	}
1416
1417
} // END class
1418
1419