Completed
Push — master ( 61c24d...075a0d )
by recca
07:28
created

elFinderVolumeDriver::getItemsInHand()   F

Complexity

Conditions 25
Paths 506

Size

Total Lines 74
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 51
nc 506
nop 3
dl 0
loc 74
rs 3.4377
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Base class for elFinder volume.
4
 * Provide 2 layers:
5
 *  1. Public API (commands)
6
 *  2. abstract fs API.
7
 *
8
 * All abstract methods begin with "_"
9
 *
10
 * @author Dmitry (dio) Levashov
11
 * @author Troex Nevelin
12
 * @author Alexey Sukhotin
13
 **/
14
abstract class elFinderVolumeDriver
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

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

namespace YourVendor;

class YourClass { }

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

Loading history...
15
{
16
    /**
17
	 * Net mount key.
18
	 *
19
	 * @var string
20
	 **/
21
	public $netMountKey = '';
22
23
	/**
24
	 * Request args
25
	 * $_POST or $_GET values.
26
	 *
27
	 * @var array
28
	 */
29
	protected $ARGS = [];
30
31
	/**
32
	 * Driver id
33
	 * Must be started from letter and contains [a-z0-9]
34
	 * Used as part of volume id.
35
	 *
36
	 * @var string
37
	 **/
38
	protected $driverId = 'a';
39
40
	/**
41
	 * Volume id - used as prefix for files hashes.
42
	 *
43
	 * @var string
44
	 **/
45
	protected $id = '';
46
47
	/**
48
	 * Flag - volume "mounted" and available.
49
	 *
50
	 * @var bool
51
	 **/
52
	protected $mounted = false;
53
54
	/**
55
	 * Root directory path.
56
	 *
57
	 * @var string
58
	 **/
59
	protected $root = '';
60
61
	/**
62
	 * Root basename | alias.
63
	 *
64
	 * @var string
65
	 **/
66
	protected $rootName = '';
67
68
	/**
69
	 * Default directory to open.
70
	 *
71
	 * @var string
72
	 **/
73
	protected $startPath = '';
74
75
	/**
76
	 * Base URL.
77
	 *
78
	 * @var string
79
	 **/
80
	protected $URL = '';
81
82
	/**
83
	 * A file save destination path when a temporary content URL is required
84
	 * on a network volume or the like
85
	 * If not specified, it tries to use "Connector Path/../files/.tmb".
86
	 *
87
	 * @var string
88
	 */
89
	protected $tmpLinkPath = '';
90
91
	/**
92
	 * A file save destination URL when a temporary content URL is required
93
	 * on a network volume or the like
94
	 * If not specified, it tries to use "Connector URL/../files/.tmb".
95
	 *
96
	 * @var string
97
	 */
98
	protected $tmpLinkUrl = '';
99
100
	/**
101
	 * Thumbnails dir path.
102
	 *
103
	 * @var string
104
	 **/
105
	protected $tmbPath = '';
106
107
	/**
108
	 * Is thumbnails dir writable.
109
	 *
110
	 * @var bool
111
	 **/
112
	protected $tmbPathWritable = false;
113
114
	/**
115
	 * Thumbnails base URL.
116
	 *
117
	 * @var string
118
	 **/
119
	protected $tmbURL = '';
120
121
	/**
122
	 * Thumbnails size in px.
123
	 *
124
	 * @var int
125
	 **/
126
	protected $tmbSize = 48;
127
128
	/**
129
	 * Image manipulation lib name
130
	 * auto|imagick|gd|convert.
131
	 *
132
	 * @var string
133
	 **/
134
	protected $imgLib = 'auto';
135
136
	/**
137
	 * Video to Image converter.
138
	 *
139
	 * @var array
140
	 */
141
	protected $imgConverter = [];
142
143
	/**
144
	 * Library to crypt files name.
145
	 *
146
	 * @var string
147
	 **/
148
	protected $cryptLib = '';
149
150
	/**
151
	 * Archivers config.
152
	 *
153
	 * @var array
154
	 **/
155
	protected $archivers = [
156
		'create' => [],
157
		'extract' => [],
158
	];
159
160
	/**
161
	 * Server character encoding.
162
	 *
163
	 * @var string or null
164
	 **/
165
	protected $encoding = null;
166
167
	/**
168
	 * How many subdirs levels return for tree.
169
	 *
170
	 * @var int
171
	 **/
172
	protected $treeDeep = 1;
173
174
	/**
175
	 * Errors from last failed action.
176
	 *
177
	 * @var array
178
	 **/
179
	protected $error = [];
180
181
	/**
182
	 * Today 24:00 timestamp.
183
	 *
184
	 * @var int
185
	 **/
186
	protected $today = 0;
187
188
	/**
189
	 * Yesterday 24:00 timestamp.
190
	 *
191
	 * @var int
192
	 **/
193
	protected $yesterday = 0;
194
195
	/**
196
	 * Force make dirctory on extract.
197
	 *
198
	 * @var int
199
	 **/
200
	protected $extractToNewdir = 'auto';
201
202
	/**
203
	 * Object configuration.
204
	 *
205
	 * @var array
206
	 **/
207
	protected $options = [
208
		// Driver ID (Prefix of volume ID), Normally, the value specified for each volume driver is used.
209
		'driverId' => '',
210
		// Id (Suffix of volume ID), Normally, the number incremented according to the specified number of volumes is used.
211
		'id' => '',
212
		// revision id of root directory that uses for caching control of root stat
213
		'rootRev' => '',
214
		// driver type it uses volume root's CSS class name. e.g. 'group' -> Adds 'elfinder-group' to CSS class name.
215
		'type' => '',
216
		// root directory path
217
		'path' => '',
218
		// Folder hash value on elFinder to be the parent of this volume
219
		'phash' => '',
220
		// Folder hash value on elFinder to trash bin of this volume, it require 'copyJoin' to true
221
		'trashHash' => '',
222
		// open this path on initial request instead of root path
223
		'startPath' => '',
224
		// how many subdirs levels return per request
225
		'treeDeep' => 1,
226
		// root url, not set to disable sending URL to client (replacement for old "fileURL" option)
227
		'URL' => '',
228
		// directory link url to own manager url with folder hash (`true`, `false` or default `'auto'`: URL is empty then `true` else `false`)
229
		'dirUrlOwn' => 'auto',
230
		// directory separator. required by client to show paths correctly
231
		'separator' => DIRECTORY_SEPARATOR,
232
		// Server character encoding (default is '': UTF-8)
233
		'encoding' => '',
234
		// for convert character encoding (default is '': Not change locale)
235
		'locale' => '',
236
		// URL of volume icon (16x16 pixel image file)
237
		'icon' => '',
238
		// CSS Class of volume root in tree
239
		'rootCssClass' => '',
240
		// Items to disable session caching
241
		'noSessionCache' => [],
242
		// enable i18n folder name that convert name to elFinderInstance.messages['folder_'+name]
243
		'i18nFolderName' => false,
244
		// Search timeout (sec)
245
		'searchTimeout' => 30,
246
		// Search exclusion directory regex pattern (require demiliter e.g. '#/path/to/exclude_directory#i')
247
		'searchExDirReg' => '',
248
		// library to crypt/uncrypt files names (not implemented)
249
		'cryptLib' => '',
250
		// how to detect files mimetypes. (auto/internal/finfo/mime_content_type)
251
		'mimeDetect' => 'auto',
252
		// mime.types file path (for mimeDetect==internal)
253
		'mimefile' => '',
254
		// Static extension/MIME of general server side scripts to security issues
255
		'staticMineMap' => [
256
			'php:*' => 'text/x-php',
257
			'php3:*' => 'text/x-php',
258
			'php4:*' => 'text/x-php',
259
			'php5:*' => 'text/x-php',
260
			'phtml:*' => 'text/x-php',
261
			'cgi:*' => 'text/x-httpd-cgi',
262
			'pl:*' => 'text/x-perl',
263
			'asp:*' => 'text/x-asap',
264
			'aspx:*' => 'text/x-asap',
265
			'py:*' => 'text/x-python',
266
			'rb:*' => 'text/x-ruby',
267
			'jsp:*' => 'text/x-jsp',
268
		],
269
		// mime type normalize map : Array '[ext]:[detected mime type]' => '[normalized mime]'
270
		'mimeMap' => [
271
			'md:application/x-genesis-rom' => 'text/x-markdown',
272
			'md:text/plain' => 'text/x-markdown',
273
			'markdown:text/plain' => 'text/x-markdown',
274
			'css:text/x-asm' => 'text/css',
275
			'ico:image/vnd.microsoft.icon' => 'image/x-icon',
276
			'csv:text/plain' => 'text/csv',
277
			'm4a:video/mp4' => 'audio/mp4',
278
			'oga:application/ogg' => 'audio/ogg',
279
			'ogv:application/ogg' => 'video/ogg',
280
			'zip:application/x-zip' => 'application/zip',
281
		],
282
		// An option to add MimeMap to the `mimeMap` option
283
		// Array '[ext]:[detected mime type]' => '[normalized mime]'
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
284
		'additionalMimeMap' => [],
285
		// MIME regex of send HTTP header "Content-Disposition: inline" or allow preview in quicklook
286
		// '.' is allow inline of all of MIME types
287
		// '$^' is not allow inline of all of MIME types
288
		'dispInlineRegex' => '^(?:(?:image|video|audio)|(?:text/plain|application/pdf)$)',
289
		// temporary content URL's base path
290
		'tmpLinkPath' => '',
291
		// temporary content URL's base URL
292
		'tmpLinkUrl' => '',
293
		// directory for thumbnails
294
		'tmbPath' => '.tmb',
295
		// mode to create thumbnails dir
296
		'tmbPathMode' => 0777,
297
		// thumbnails dir URL. Set it if store thumbnails outside root directory
298
		'tmbURL' => '',
299
		// thumbnails size (px)
300
		'tmbSize' => 48,
301
		// thumbnails crop (true - crop, false - scale image to fit thumbnail size)
302
		'tmbCrop' => true,
303
		// thumbnails background color (hex #rrggbb or 'transparent')
304
		'tmbBgColor' => 'transparent',
305
		// image rotate fallback background color (hex #rrggbb)
306
		'bgColorFb' => '#ffffff',
307
		// image manipulations library
308
		'imgLib' => 'auto',
309
		// Fallback self image to thumbnail (nothing imgLib)
310
		'tmbFbSelf' => true,
311
		// Video to Image converters ['TYPE or MIME' => ['func' => function($file){ /* Converts $file to Image */ return true; }, 'maxlen' => (int)TransferLength]]
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
312
		'imgConverter' => [],
313
		// Max length of transfer to image converter
314
		'tmbVideoConvLen' => 10000000,
315
		// Captre point seccond
316
		'tmbVideoConvSec' => 6,
317
		// Resource path of fallback icon images defailt: php/resouces
318
		'resourcePath' => '',
319
		// Jpeg image saveing quality
320
		'jpgQuality' => 100,
321
		// on paste file -  if true - old file will be replaced with new one, if false new file get name - original_name-number.ext
322
		'copyOverwrite' => true,
323
		// if true - join new and old directories content on paste
324
		'copyJoin' => true,
325
		// on upload -  if true - old file will be replaced with new one, if false new file get name - original_name-number.ext
326
		'uploadOverwrite' => true,
327
		// mimetypes allowed to upload
328
		'uploadAllow' => [],
329
		// mimetypes not allowed to upload
330
		'uploadDeny' => [],
331
		// order to proccess uploadAllow and uploadDeny options
332
		'uploadOrder' => ['deny', 'allow'],
333
		// maximum upload file size. NOTE - this is size for every uploaded files
334
		'uploadMaxSize' => 0,
335
		// maximum number of chunked upload connection. `-1` to disable chunked upload
336
		'uploadMaxConn' => 3,
337
		// maximum get file size. NOTE - Maximum value is 50% of PHP memory_limit
338
		'getMaxSize' => 0,
339
		// files dates format
340
		'dateFormat' => 'j M Y H:i',
341
		// files time format
342
		'timeFormat' => 'H:i',
343
		// if true - every folder will be check for children folders, -1 - every folder will be check asynchronously, false -  all folders will be marked as having subfolders
344
		'checkSubfolders' => true, // true, false or -1
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
345
		// allow to copy from this volume to other ones?
346
		'copyFrom' => true,
347
		// allow to copy from other volumes to this one?
348
		'copyTo' => true,
349
		// cmd duplicate suffix format e.g. '_%s_' to without spaces
350
		'duplicateSuffix' => ' %s ',
351
		// unique name numbar format e.g. '(%d)' to (1), (2)...
352
		'uniqueNumFormat' => '%d',
353
		// list of commands disabled on this root
354
		'disabled' => [],
355
		// enable file owner, group & mode info, `false` to inactivate "chmod" command.
356
		'statOwner' => false,
357
		// allow exec chmod of read-only files
358
		'allowChmodReadOnly' => false,
359
		// regexp or function name to validate new file name
360
		'acceptedName' => '/^[^\.].*/', // Notice: overwritten it in some volume drivers contractor
361
		// regexp or function name to validate new directory name
362
		'acceptedDirname' => '', // used `acceptedName` if empty value
363
			// function/class method to control files permissions
364
		'accessControl' => null,
365
		// some data required by access control
366
		'accessControlData' => null,
367
		// default permissions.
368
		'defaults' => [
369
			'read' => true,
370
			'write' => true,
371
			'locked' => false,
372
			'hidden' => false,
373
		],
374
		// files attributes
375
		'attributes' => [],
376
		// max allowed archive files size (0 - no limit)
377
		'maxArcFilesSize' => 0,
378
		// Allowed archive's mimetypes to create. Leave empty for all available types.
379
		'archiveMimes' => [],
380
		// Manual config for archivers. See example below. Leave empty for auto detect
381
		'archivers' => [],
382
		// plugin settings
383
		'plugin' => [],
384
		// Is support parent directory time stamp update on add|remove|rename item
385
		// Default `null` is auto detection that is LocalFileSystem, FTP or Dropbox are `true`
386
		'syncChkAsTs' => null,
387
		// Long pooling sync checker function for syncChkAsTs is true
388
		// Calls with args (TARGET DIRCTORY PATH, STAND-BY(sec), OLD TIMESTAMP, VOLUME DRIVER INSTANCE, ELFINDER INSTANCE)
389
		// This function must return the following values. Changed: New Timestamp or Same: Old Timestamp or Error: false
390
		// Default `null` is try use elFinderVolumeLocalFileSystem::localFileSystemInotify() on LocalFileSystem driver
391
		// another driver use elFinder stat() checker
392
		'syncCheckFunc' => null,
393
		// Long polling sync stand-by time (sec)
394
		'plStandby' => 30,
395
		// Sleep time (sec) for elFinder stat() checker (syncChkAsTs is true)
396
		'tsPlSleep' => 10,
397
		// Sleep time (sec) for elFinder ls() checker (syncChkAsTs is false)
398
		'lsPlSleep' => 30,
399
		// Client side sync interval minimum (ms)
400
		// Default `null` is auto set to ('tsPlSleep' or 'lsPlSleep') * 1000
401
		// `0` to disable auto sync
402
		'syncMinMs' => null,
403
		// required to fix bug on macos
404
		// However, we recommend to use the Normalizer plugin instead this option
405
		'utf8fix' => false,
406
		 //                           й                 ё              Й               Ё              Ø         Å
407
		'utf8patterns' => ["\u0438\u0306", "\u0435\u0308", "\u0418\u0306", "\u0415\u0308", "\u00d8A", "\u030a"],
408
		'utf8replace' => ["\u0439",        "\u0451",       "\u0419",       "\u0401",       "\u00d8", "\u00c5"],
409
	];
410
411
	/**
412
	 * Defaults permissions.
413
	 *
414
	 * @var array
415
	 **/
416
	protected $defaults = [
417
		'read' => true,
418
		'write' => true,
419
		'locked' => false,
420
		'hidden' => false,
421
	];
422
423
	/**
424
	 * Access control function/class.
425
	 *
426
	 * @var mixed
427
	 **/
428
	protected $attributes = [];
429
430
	/**
431
	 * Access control function/class.
432
	 *
433
	 * @var mixed
434
	 **/
435
	protected $access = null;
436
437
	/**
438
	 * Mime types allowed to upload.
439
	 *
440
	 * @var array
441
	 **/
442
	protected $uploadAllow = [];
443
444
	/**
445
	 * Mime types denied to upload.
446
	 *
447
	 * @var array
448
	 **/
449
	protected $uploadDeny = [];
450
451
	/**
452
	 * Order to validate uploadAllow and uploadDeny.
453
	 *
454
	 * @var array
455
	 **/
456
	protected $uploadOrder = [];
457
458
	/**
459
	 * Maximum allowed upload file size.
460
	 * Set as number or string with unit - "10M", "500K", "1G".
461
	 *
462
	 * @var int|string
463
	 **/
464
	protected $uploadMaxSize = 0;
465
466
	/**
467
	 * Run time setting of overwrite items on upload.
468
	 *
469
	 * @var string
470
	 */
471
	protected $uploadOverwrite = true;
472
473
	/**
474
	 * Maximum allowed get file size.
475
	 * Set as number or string with unit - "10M", "500K", "1G".
476
	 *
477
	 * @var int|string
478
	 **/
479
	protected $getMaxSize = -1;
480
481
	/**
482
	 * Mimetype detect method.
483
	 *
484
	 * @var string
485
	 **/
486
	protected $mimeDetect = 'auto';
487
488
	/**
489
	 * Finfo object for mimeDetect == 'finfo'.
490
	 *
491
	 * @var object
492
	 **/
493
	protected $finfo = null;
494
495
	/**
496
	 * List of disabled client's commands.
497
	 *
498
	 * @var array
499
	 **/
500
	protected $disabled = [];
501
502
	/**
503
	 * default extensions/mimetypes for mimeDetect == 'internal'.
504
	 *
505
	 * @var array
506
	 **/
507
	protected static $mimetypes = [
508
		// applications
509
		'ai' => 'application/postscript',
510
		'eps' => 'application/postscript',
511
		'exe' => 'application/x-executable',
512
		'doc' => 'application/msword',
513
		'dot' => 'application/msword',
514
		'xls' => 'application/vnd.ms-excel',
515
		'xlt' => 'application/vnd.ms-excel',
516
		'xla' => 'application/vnd.ms-excel',
517
		'ppt' => 'application/vnd.ms-powerpoint',
518
		'pps' => 'application/vnd.ms-powerpoint',
519
		'pdf' => 'application/pdf',
520
		'xml' => 'application/xml',
521
		'swf' => 'application/x-shockwave-flash',
522
		'torrent' => 'application/x-bittorrent',
523
		'jar' => 'application/x-jar',
524
		// open office (finfo detect as application/zip)
525
		'odt' => 'application/vnd.oasis.opendocument.text',
526
		'ott' => 'application/vnd.oasis.opendocument.text-template',
527
		'oth' => 'application/vnd.oasis.opendocument.text-web',
528
		'odm' => 'application/vnd.oasis.opendocument.text-master',
529
		'odg' => 'application/vnd.oasis.opendocument.graphics',
530
		'otg' => 'application/vnd.oasis.opendocument.graphics-template',
531
		'odp' => 'application/vnd.oasis.opendocument.presentation',
532
		'otp' => 'application/vnd.oasis.opendocument.presentation-template',
533
		'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
534
		'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
535
		'odc' => 'application/vnd.oasis.opendocument.chart',
536
		'odf' => 'application/vnd.oasis.opendocument.formula',
537
		'odb' => 'application/vnd.oasis.opendocument.database',
538
		'odi' => 'application/vnd.oasis.opendocument.image',
539
		'oxt' => 'application/vnd.openofficeorg.extension',
540
		// MS office 2007 (finfo detect as application/zip)
541
		'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
542
		'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
543
		'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
544
		'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
545
		'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
546
		'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
547
		'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
548
		'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
549
		'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
550
		'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
551
		'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
552
		'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
553
		'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
554
		'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
555
		'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
556
		'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
557
		'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
558
		'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
559
		'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
560
		// archives
561
		'gz' => 'application/x-gzip',
562
		'tgz' => 'application/x-gzip',
563
		'bz' => 'application/x-bzip2',
564
		'bz2' => 'application/x-bzip2',
565
		'tbz' => 'application/x-bzip2',
566
		'xz' => 'application/x-xz',
567
		'zip' => 'application/zip',
568
		'rar' => 'application/x-rar',
569
		'tar' => 'application/x-tar',
570
		'7z' => 'application/x-7z-compressed',
571
		// texts
572
		'txt' => 'text/plain',
573
		'php' => 'text/x-php',
574
		'html' => 'text/html',
575
		'htm' => 'text/html',
576
		'js' => 'text/javascript',
577
		'css' => 'text/css',
578
		'rtf' => 'text/rtf',
579
		'rtfd' => 'text/rtfd',
580
		'py' => 'text/x-python',
581
		'java' => 'text/x-java-source',
582
		'rb' => 'text/x-ruby',
583
		'sh' => 'text/x-shellscript',
584
		'pl' => 'text/x-perl',
585
		//'xml'   => 'text/xml',
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
586
		'sql' => 'text/x-sql',
587
		'c' => 'text/x-csrc',
588
		'h' => 'text/x-chdr',
589
		'cpp' => 'text/x-c++src',
590
		'hh' => 'text/x-c++hdr',
591
		'log' => 'text/plain',
592
		'csv' => 'text/csv',
593
		'md' => 'text/x-markdown',
594
		'markdown' => 'text/x-markdown',
595
		// images
596
		'bmp' => 'image/x-ms-bmp',
597
		'jpg' => 'image/jpeg',
598
		'jpeg' => 'image/jpeg',
599
		'gif' => 'image/gif',
600
		'png' => 'image/png',
601
		'tif' => 'image/tiff',
602
		'tiff' => 'image/tiff',
603
		'tga' => 'image/x-targa',
604
		'psd' => 'image/vnd.adobe.photoshop',
605
		//'ai'    => 'image/vnd.adobe.photoshop',
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
606
		'xbm' => 'image/xbm',
607
		'pxm' => 'image/pxm',
608
		//audio
609
		'mp3' => 'audio/mpeg',
610
		'mid' => 'audio/midi',
611
		'ogg' => 'audio/ogg',
612
		'oga' => 'audio/ogg',
613
		'm4a' => 'audio/mp4',
614
		'wav' => 'audio/wav',
615
		'wma' => 'audio/x-ms-wma',
616
		// video
617
		'avi' => 'video/x-msvideo',
618
		'dv' => 'video/x-dv',
619
		'mp4' => 'video/mp4',
620
		'mpeg' => 'video/mpeg',
621
		'mpg' => 'video/mpeg',
622
		'mov' => 'video/quicktime',
623
		'wm' => 'video/x-ms-wmv',
624
		'flv' => 'video/x-flv',
625
		'mkv' => 'video/x-matroska',
626
		'webm' => 'video/webm',
627
		'ogv' => 'video/ogg',
628
		'ogm' => 'video/ogg',
629
		];
630
631
	/**
632
	 * Directory separator - required by client.
633
	 *
634
	 * @var string
635
	 **/
636
	protected $separator = DIRECTORY_SEPARATOR;
637
638
	/**
639
	 * System Root path (Unix like: '/', Windows: '\', 'C:\' or 'D:\'...).
640
	 *
641
	 * @var string
642
	 **/
643
	protected $systemRoot = DIRECTORY_SEPARATOR;
644
645
	/**
646
	 * Mimetypes allowed to display.
647
	 *
648
	 * @var array
649
	 **/
650
	protected $onlyMimes = [];
651
652
	/**
653
	 * Store files moved or overwrited files info.
654
	 *
655
	 * @var array
656
	 **/
657
	protected $removed = [];
658
659
	/**
660
	 * Store files added files info.
661
	 *
662
	 * @var array
663
	 **/
664
	protected $added = [];
665
666
	/**
667
	 * Cache storage.
668
	 *
669
	 * @var array
670
	 **/
671
	protected $cache = [];
672
673
	/**
674
	 * Cache by folders.
675
	 *
676
	 * @var array
677
	 **/
678
	protected $dirsCache = [];
679
680
	/**
681
	 * You should use `$this->sessionCache['subdirs']` instead.
682
	 *
683
	 * @var array
684
	 * @deprecated
685
	 */
686
	protected $subdirsCache = [];
687
688
	/**
689
	 * This volume session cache.
690
	 *
691
	 * @var array
692
	 */
693
	protected $sessionCache;
694
695
	/**
696
	 * Session caching item list.
697
	 *
698
	 * @var array
699
	 */
700
	protected $sessionCaching = ['rootstat' => true, 'subdirs' => true];
701
702
	/**
703
	 * elFinder session wrapper object.
704
	 *
705
	 * @var elFinderSessionInterface
706
	 */
707
	protected $session;
708
709
	/**
710
	 * Search start time.
711
	 *
712
	 * @var int
713
	 */
714
	protected $searchStart;
715
716
	/**
717
	 * Current query word on doSearch.
718
	 *
719
	 * @var string
720
	 **/
721
	protected $doSearchCurrentQuery = [];
722
723
	/**
724
	 * Is root modified (for clear root stat cache).
725
	 *
726
	 * @var bool
727
	 */
728
	protected $rootModified = false;
729
730
	/**
731
	 * Is disable of command `url`.
732
	 *
733
	 * @var string
734
	 */
735
	protected $disabledGetUrl = false;
736
737
	/**
738
	 * Accepted filename validator.
739
	 *
740
	 * @var string | callable
741
	 */
742
	protected $nameValidator;
743
744
	/**
745
	 * Accepted dirname validator.
746
	 *
747
	 * @var string | callable
748
	 */
749
	protected $dirnameValidator;
750
751
	/**
752
	 * Flag - mimetypes from externail file was loaded.
753
	 *
754
	 * @var bool
755
	 **/
756
	private static $mimetypesLoaded = false;
757
758
	/*********************************************************************/
759
	/*                              PUBLIC API                           */
760
	/*********************************************************************/
761
762
	/**
763
	 * Return driver id. Used as a part of volume id.
764
	 *
765
	 * @return string
766
	 * @author Dmitry (dio) Levashov
767
	 **/
768
	public function driverId()
769
	{
770
	    return $this->driverId;
771
	}
772
773
	/**
774
	 * Return volume id.
775
	 *
776
	 * @return string
777
	 * @author Dmitry (dio) Levashov
778
	 **/
779
	public function id()
780
	{
781
	    return $this->id;
782
	}
783
784
	/**
785
	 * Assign elFinder session wrapper object.
786
	 *
787
	 * @param  $session  elFinderSessionInterface
788
	 */
789
	public function setSession($session)
790
	{
791
	    $this->session = $session;
792
	}
793
794
	/**
795
	 * Save session cache data
796
	 * Calls this function before umount this volume on elFinder::exec().
797
	 *
798
	 * @return void
799
	 */
800
	public function saveSessionCache()
801
	{
802
	    $this->session->set($this->id, $this->sessionCache);
803
	}
804
805
	/**
806
	 * Return debug info for client.
807
	 *
808
	 * @return array
809
	 * @author Dmitry (dio) Levashov
810
	 **/
811
	public function debug()
812
	{
813
	    return [
814
			'id' => $this->id(),
815
			'name' => strtolower(substr(get_class($this), strlen('elfinderdriver'))),
816
			'mimeDetect' => $this->mimeDetect,
817
			'imgLib' => $this->imgLib,
818
		];
819
	}
820
821
	/**
822
	 * chmod a file or folder.
823
	 *
824
	 * @param  string   $hash    file or folder hash to chmod
825
	 * @param  string   $mode    octal string representing new permissions
826
	 * @return array|false
827
	 * @author David Bartle
828
	 **/
829
	public function chmod($hash, $mode)
830
	{
831
	    if ($this->commandDisabled('chmod')) {
832
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
833
	    }
834
835
	    if (! ($file = $this->file($hash))) {
836
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
837
	    }
838
839 View Code Duplication
	    if (! $this->options['allowChmodReadOnly']) {
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...
840
	        if (! $this->attr($this->decode($hash), 'write', null, ($file['mime'] === 'directory'))) {
841
	            return $this->setError(elFinder::ERROR_PERM_DENIED, $file['name']);
842
	        }
843
	    }
844
845
	    $path = $this->decode($hash);
846
	    $write = $file['write'];
847
848 View Code Duplication
	    if ($this->convEncOut(! $this->_chmod($this->convEncIn($path), $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...
849
	        return $this->setError(elFinder::ERROR_PERM_DENIED, $file['name']);
850
	    }
851
852
	    $this->clearcache();
853
	    if ($path == $this->root) {
854
	        $this->rootModified = true;
855
	    }
856
857
	    if ($file = $this->stat($path)) {
858
	        $files = [$file];
859
	        if ($file['mime'] === 'directory' && $write !== $file['write']) {
860
	            foreach ($this->getScandir($path) as $stat) {
861
	                if ($this->mimeAccepted($stat['mime'])) {
862
	                    $files[] = $stat;
863
	                }
864
	            }
865
	        }
866
867
	        return $files;
868
	    } else {
869
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
870
	    }
871
	}
872
873
	/**
874
	 * stat a file or folder for elFinder cmd exec.
875
	 *
876
	 * @param  string   $hash    file or folder hash to chmod
877
	 * @return array
878
	 * @author Naoki Sawada
879
	 **/
880
	public function fstat($hash)
881
	{
882
	    $path = $this->decode($hash);
883
884
	    return $this->stat($path);
885
	}
886
887
	/**
888
	 * Clear PHP stat cache & all of inner stat caches.
889
	 */
890
	public function clearstatcache()
891
	{
892
	    clearstatcache();
893
	    $this->clearcache();
894
	}
895
896
	/**
897
	 * Clear inner stat caches for target hash.
898
	 *
899
	 * @param string $hash
900
	 */
901
	public function clearcaches($hash = null)
902
	{
903
	    if ($hash === null) {
904
	        $this->clearcache();
905
	    } else {
906
	        $path = $this->decode($hash);
907
	        unset($this->cache[$path], $this->dirsCache[$path]);
908
	    }
909
	}
910
911
	/**
912
	 * "Mount" volume.
913
	 * Return true if volume available for read or write,
914
	 * false - otherwise.
915
	 *
916
	 * @param array $opts
917
	 * @return bool
918
	 * @author Dmitry (dio) Levashov
919
	 * @author Alexey Sukhotin
920
	 */
921
	public function mount(array $opts)
0 ignored issues
show
Coding Style introduced by
mount uses the super-global variable $_SERVER which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
mount uses the super-global variable $_POST which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
mount uses the super-global variable $_GET which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
922
	{
923
	    $this->options = array_merge($this->options, $opts);
924
925 View Code Duplication
	    if (! isset($this->options['path']) || $this->options['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...
926
	        return $this->setError('Path undefined.');
927
	    }
928
929
	    if (! $this->session) {
930
	        return $this->setError('Session wrapper dose not set. Need to `$volume->setSession(elFinderSessionInterface);` before mount.');
931
	    }
932
	    if (! ($this->session instanceof elFinderSessionInterface)) {
933
	        return $this->setError('Session wrapper instance must be "elFinderSessionInterface".');
934
	    }
935
936
		// set driverId
937
		if (! empty($this->options['driverId'])) {
938
		    $this->driverId = $this->options['driverId'];
939
		}
940
941
	    $this->id = $this->driverId.(! empty($this->options['id']) ? $this->options['id'] : elFinder::$volumesCnt++).'_';
942
	    $this->root = $this->normpathCE($this->options['path']);
943
	    $this->separator = isset($this->options['separator']) ? $this->options['separator'] : DIRECTORY_SEPARATOR;
944
	    $this->systemRoot = isset($this->options['systemRoot']) ? $this->options['systemRoot'] : $this->separator;
945
946
		// set server encoding
947
		if (! empty($this->options['encoding']) && strtoupper($this->options['encoding']) !== 'UTF-8') {
948
		    $this->encoding = $this->options['encoding'];
949
		} else {
950
		    $this->encoding = null;
951
		}
952
953
		// set ARGS
954
		$this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
955
956
	    $argInit = ! empty($this->ARGS['init']);
957
958
		// session cache
959
		if ($argInit) {
960
		    $this->session->set($this->id, []);
961
		}
962
	    $this->sessionCache = $this->session->get($this->id, []);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->session->get($this->id, array()) of type * is incompatible with the declared type array of property $sessionCache.

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...
963
964
		// default file attribute
965
		$this->defaults = [
966
			'read' => isset($this->options['defaults']['read']) ? (bool) $this->options['defaults']['read'] : true,
967
			'write' => isset($this->options['defaults']['write']) ? (bool) $this->options['defaults']['write'] : true,
968
			'locked' => isset($this->options['defaults']['locked']) ? (bool) $this->options['defaults']['locked'] : false,
969
			'hidden' => isset($this->options['defaults']['hidden']) ? (bool) $this->options['defaults']['hidden'] : false,
970
		];
971
972
		// root attributes
973
		$this->attributes[] = [
974
			'pattern' => '~^'.preg_quote($this->separator).'$~',
975
			'locked' => true,
976
			'hidden' => false,
977
		];
978
		// set files attributes
979 View Code Duplication
		if (! empty($this->options['attributes']) && is_array($this->options['attributes'])) {
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...
980
		    foreach ($this->options['attributes'] as $a) {
981
		        // attributes must contain pattern and at least one rule
982
				if (! empty($a['pattern']) || count($a) > 1) {
983
				    $this->attributes[] = $a;
984
				}
985
		    }
986
		}
987
988
	    if (! empty($this->options['accessControl']) && is_callable($this->options['accessControl'])) {
989
	        $this->access = $this->options['accessControl'];
990
	    }
991
992
	    $this->today = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
993
	    $this->yesterday = $this->today - 86400;
994
995
	    if (! $this->init()) {
996
	        return false;
997
	    }
998
999
		// check some options is arrays
1000
		$this->uploadAllow = isset($this->options['uploadAllow']) && is_array($this->options['uploadAllow'])
1001
			? $this->options['uploadAllow']
1002
			: [];
1003
1004
	    $this->uploadDeny = isset($this->options['uploadDeny']) && is_array($this->options['uploadDeny'])
1005
			? $this->options['uploadDeny']
1006
			: [];
1007
1008
	    $this->options['uiCmdMap'] = (isset($this->options['uiCmdMap']) && is_array($this->options['uiCmdMap']))
1009
			? $this->options['uiCmdMap']
1010
			: [];
1011
1012
	    if (is_string($this->options['uploadOrder'])) { // telephat_mode on, compatibility with 1.x
1013
			$parts = explode(',', isset($this->options['uploadOrder']) ? $this->options['uploadOrder'] : 'deny,allow');
1014
	        $this->uploadOrder = [trim($parts[0]), trim($parts[1])];
1015
	    } else { // telephat_mode off
1016
			$this->uploadOrder = ! empty($this->options['uploadOrder']) ? $this->options['uploadOrder'] : ['deny', 'allow'];
1017
	    }
1018
1019
	    if (! empty($this->options['uploadMaxSize'])) {
1020
	        $this->uploadMaxSize = elFinder::getIniBytes('', $this->options['uploadMaxSize']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \elFinder::getIniBytes('...tions['uploadMaxSize']) can also be of type double. However, the property $uploadMaxSize is declared as type integer|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1021
	    }
1022
		// Set maximum to PHP_INT_MAX
1023
		if (! defined('PHP_INT_MAX')) {
1024
		    define('PHP_INT_MAX', 2147483647);
1025
		}
1026
	    if ($this->uploadMaxSize < 1 || $this->uploadMaxSize > PHP_INT_MAX) {
1027
	        $this->uploadMaxSize = PHP_INT_MAX;
1028
	    }
1029
1030
		// Set to get maximum size to 50% of memory_limit
1031
		$memLimit = elFinder::getIniBytes('memory_limit') / 2;
1032
	    if ($memLimit > 0) {
1033
	        $this->getMaxSize = empty($this->options['getMaxSize']) ? $memLimit : min($memLimit, elFinder::getIniBytes('', $this->options['getMaxSize']));
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($this->options['ge...options['getMaxSize'])) can also be of type double. However, the property $getMaxSize is declared as type integer|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1034
	    } else {
1035
	        $this->getMaxSize = -1;
1036
	    }
1037
1038
	    $this->disabled = isset($this->options['disabled']) && is_array($this->options['disabled'])
1039
			? array_values(array_diff($this->options['disabled'], ['open'])) // 'open' is required
1040
			: [];
1041
1042
	    $this->cryptLib = $this->options['cryptLib'];
1043
	    $this->mimeDetect = $this->options['mimeDetect'];
1044
1045
		// find available mimetype detect method
1046
		$type = strtolower($this->options['mimeDetect']);
1047
	    $type = preg_match('/^(finfo|mime_content_type|internal|auto)$/i', $type) ? $type : 'auto';
1048
	    $regexp = '/text\/x\-(php|c\+\+)/';
1049
1050
	    if (($type == 'finfo' || $type == 'auto')
1051
		&& class_exists('finfo', false)) {
1052
	        $tmpFileInfo = explode(';', finfo_file(finfo_open(FILEINFO_MIME), __FILE__));
1053
	    } else {
1054
	        $tmpFileInfo = false;
1055
	    }
1056
1057
	    $type = 'internal';
1058
	    if ($tmpFileInfo && preg_match($regexp, array_shift($tmpFileInfo))) {
1059
	        $type = 'finfo';
1060
	        $this->finfo = finfo_open(FILEINFO_MIME);
1061
	    } elseif (($type == 'mime_content_type' || $type == 'auto') && function_exists('mime_content_type')) {
1062
	        $_mimetypes = explode(';', mime_content_type(__FILE__));
1063
	        if (preg_match($regexp, array_shift($_mimetypes))) {
1064
	            $type = 'mime_content_type';
1065
	        }
1066
	    }
1067
	    $this->mimeDetect = $type;
1068
1069
		// load mimes from external file for mimeDetect == 'internal'
1070
		// based on Alexey Sukhotin idea and patch: http://elrte.org/redmine/issues/163
1071
		// file must be in file directory or in parent one
1072
		if ($this->mimeDetect == 'internal' && ! self::$mimetypesLoaded) {
1073
		    self::$mimetypesLoaded = true;
1074
		    $this->mimeDetect = 'internal';
1075
		    $file = false;
1076
		    if (! empty($this->options['mimefile']) && file_exists($this->options['mimefile'])) {
1077
		        $file = $this->options['mimefile'];
1078
		    } elseif (elFinder::$defaultMimefile && file_exists(elFinder::$defaultMimefile)) {
1079
		        $file = elFinder::$defaultMimefile;
1080
		    } elseif (file_exists(dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types')) {
1081
		        $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types';
1082
		    } elseif (file_exists(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types')) {
1083
		        $file = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types';
1084
		    }
1085
1086 View Code Duplication
		    if ($file && file_exists($file)) {
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...
1087
		        $mimecf = file($file);
1088
1089
		        foreach ($mimecf as $line_num => $line) {
1090
		            if (! preg_match('/^\s*#/', $line)) {
1091
		                $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
1092
		                for ($i = 1, $size = count($mime); $i < $size; $i++) {
1093
		                    if (! isset(self::$mimetypes[$mime[$i]])) {
1094
		                        self::$mimetypes[$mime[$i]] = $mime[0];
1095
		                    }
1096
		                }
1097
		            }
1098
		        }
1099
		    }
1100
		}
1101
1102
	    $this->rootName = empty($this->options['alias']) ? $this->basenameCE($this->root) : $this->options['alias'];
1103
1104
		// This get's triggered if $this->root == '/' and alias is empty.
1105
		// Maybe modify _basename instead?
1106
		if ($this->rootName === '') {
1107
		    $this->rootName = $this->separator;
1108
		}
1109
1110
	    $root = $this->stat($this->root);
1111
1112
	    if (! $root) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $root 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...
1113
	        return $this->setError('Root folder does not exist.');
1114
	    }
1115
	    if (! $root['read'] && ! $root['write']) {
1116
	        return $this->setError('Root folder has not read and write permissions.');
1117
	    }
1118
1119
	    if ($root['read']) {
1120
	        if ($argInit) {
1121
	            // check startPath - path to open by default instead of root
1122
				$startPath = $this->options['startPath'] ? $this->normpathCE($this->options['startPath']) : '';
1123
	            if ($startPath) {
1124
	                $start = $this->stat($startPath);
1125
	                if (! empty($start)
1126
					&& $start['mime'] == 'directory'
1127
					&& $start['read']
1128
					&& empty($start['hidden'])
1129
					&& $this->inpathCE($startPath, $this->root)) {
1130
	                    $this->startPath = $startPath;
1131
	                    if (substr($this->startPath, -1, 1) == $this->options['separator']) {
1132
	                        $this->startPath = substr($this->startPath, 0, -1);
1133
	                    }
1134
	                }
1135
	            }
1136
	        }
1137
	    } else {
1138
	        $this->options['URL'] = '';
1139
	        $this->options['tmbURL'] = '';
1140
	        $this->options['tmbPath'] = '';
1141
			// read only volume
1142
			array_unshift($this->attributes, [
1143
				'pattern' => '/.*/',
1144
				'read' => false,
1145
			]);
1146
	    }
1147
	    $this->treeDeep = $this->options['treeDeep'] > 0 ? (int) $this->options['treeDeep'] : 1;
1148
	    $this->tmbSize = $this->options['tmbSize'] > 0 ? (int) $this->options['tmbSize'] : 48;
1149
	    $this->URL = $this->options['URL'];
1150
	    if ($this->URL && preg_match('|[^/?&=]$|', $this->URL)) {
1151
	        $this->URL .= '/';
1152
	    }
1153
	    if (strtolower($this->options['dirUrlOwn']) === 'auto') {
1154
	        $this->options['dirUrlOwn'] = $this->URL ? false : true;
1155
	    } else {
1156
	        $this->options['dirUrlOwn'] = (bool) $this->options['dirUrlOwn'];
1157
	    }
1158
1159
	    $this->tmbURL = ! empty($this->options['tmbURL']) ? $this->options['tmbURL'] : '';
1160
	    if ($this->tmbURL && $this->tmbURL !== 'self' && preg_match('|[^/?&=]$|', $this->tmbURL)) {
1161
	        $this->tmbURL .= '/';
1162
	    }
1163
1164
	    $this->nameValidator = ! empty($this->options['acceptedName']) && (is_string($this->options['acceptedName']) || is_callable($this->options['acceptedName']))
0 ignored issues
show
Documentation Bug introduced by
It seems like !empty($this->options['a...ns['acceptedName'] : '' of type callable is incompatible with the declared type string of property $nameValidator.

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...
1165
			? $this->options['acceptedName']
1166
			: '';
1167
1168
	    $this->dirnameValidator = ! empty($this->options['acceptedDirname']) && (is_callable($this->options['acceptedDirname']) || (is_string($this->options['acceptedDirname']) && preg_match($this->options['acceptedDirname'], '') !== false))
0 ignored issues
show
Documentation Bug introduced by
It seems like !empty($this->options['a... : $this->nameValidator of type callable is incompatible with the declared type string of property $dirnameValidator.

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...
1169
			? $this->options['acceptedDirname']
1170
			: $this->nameValidator;
1171
1172
	    $this->_checkArchivers();
1173
		// manual control archive types to create
1174 View Code Duplication
		if (! empty($this->options['archiveMimes']) && is_array($this->options['archiveMimes'])) {
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...
1175
		    foreach ($this->archivers['create'] as $mime => $v) {
1176
		        if (! in_array($mime, $this->options['archiveMimes'])) {
1177
		            unset($this->archivers['create'][$mime]);
1178
		        }
1179
		    }
1180
		}
1181
1182
		// manualy add archivers
1183 View Code Duplication
		if (! empty($this->options['archivers']['create']) && is_array($this->options['archivers']['create'])) {
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...
1184
		    foreach ($this->options['archivers']['create'] as $mime => $conf) {
1185
		        if (strpos($mime, 'application/') === 0
1186
				&& ! empty($conf['cmd'])
1187
				&& isset($conf['argc'])
1188
				&& ! empty($conf['ext'])
1189
				&& ! isset($this->archivers['create'][$mime])) {
1190
		            $this->archivers['create'][$mime] = $conf;
1191
		        }
1192
		    }
1193
		}
1194
1195 View Code Duplication
	    if (! empty($this->options['archivers']['extract']) && is_array($this->options['archivers']['extract'])) {
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...
1196
	        foreach ($this->options['archivers']['extract'] as $mime => $conf) {
1197
	            if (strpos($mime, 'application/') === 0
1198
				&& ! empty($conf['cmd'])
1199
				&& isset($conf['argc'])
1200
				&& ! empty($conf['ext'])
1201
				&& ! isset($this->archivers['extract'][$mime])) {
1202
	                $this->archivers['extract'][$mime] = $conf;
1203
	            }
1204
	        }
1205
	    }
1206
1207
	    if (! empty($this->options['noSessionCache']) && is_array($this->options['noSessionCache'])) {
1208
	        foreach ($this->options['noSessionCache'] as $_key) {
1209
	            $this->sessionCaching[$_key] = false;
1210
	            unset($this->sessionCache[$_key]);
1211
	        }
1212
	    }
1213
	    if ($this->sessionCaching['subdirs']) {
1214
	        if (! isset($this->sessionCache['subdirs'])) {
1215
	            $this->sessionCache['subdirs'] = [];
1216
	        }
1217
	    }
1218
1219
	    $this->configure();
1220
1221
		// Normarize disabled (array_merge`for type array of JSON)
1222
		$this->disabled = array_values(array_unique($this->disabled));
1223
1224
		// fix sync interval
1225 View Code Duplication
		if ($this->options['syncMinMs'] !== 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...
1226
		    $this->options['syncMinMs'] = max($this->options[$this->options['syncChkAsTs'] ? 'tsPlSleep' : 'lsPlSleep'] * 1000, intval($this->options['syncMinMs']));
1227
		}
1228
1229
		// ` copyJoin` is required for the trash function
1230
		if ($this->options['trashHash'] && empty($this->options['copyJoin'])) {
1231
		    $this->options['trashHash'] = '';
1232
		}
1233
1234
		// set tmpLinkPath
1235
		if (elFinder::$tmpLinkPath && ! $this->options['tmpLinkPath']) {
1236
		    $this->options['tmpLinkPath'] = elFinder::$tmpLinkPath;
1237
		}
1238
	    if ($this->options['tmpLinkPath'] && is_writable($this->options['tmpLinkPath'])) {
1239
	        $this->tmpLinkPath = realpath($this->options['tmpLinkPath']);
1240
	    } elseif (! $this->options['URL'] && is_writable('../files/.tmb')) {
1241
	        $this->tmpLinkPath = realpath('../files/.tmb');
1242
	        $this->options['tmpLinkUrl'] = '';
1243
	        if (! elFinder::$tmpLinkPath) {
1244
	            elFinder::$tmpLinkPath = $this->tmpLinkPath;
1245
	            elFinder::$tmpLinkUrl = '';
1246
	        }
1247
	    }
1248
1249
		// set tmpLinkUrl
1250
		if (elFinder::$tmpLinkUrl && ! $this->options['tmpLinkUrl']) {
1251
		    $this->options['tmpLinkUrl'] = elFinder::$tmpLinkUrl;
1252
		}
1253
	    if ($this->options['tmpLinkUrl']) {
1254
	        $this->tmpLinkUrl = $this->options['tmpLinkUrl'];
1255
	    }
1256
	    if ($this->tmpLinkPath && ! $this->tmpLinkUrl) {
1257
	        $cur = realpath('./');
1258
	        $i = 0;
1259
	        while ($cur !== $this->systemRoot && strpos($this->tmpLinkPath, $cur) !== 0) {
1260
	            $i++;
1261
	            $cur = dirname($cur);
1262
	        }
1263
	        list($req) = explode('?', $_SERVER['REQUEST_URI']);
1264
	        $reqs = explode('/', dirname($req));
1265
	        $uri = implode('/', array_slice($reqs, 0, count($reqs) - 1)).substr($this->tmpLinkPath, strlen($cur));
1266
	        $https = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off');
1267
	        $this->tmpLinkUrl = ($https ? 'https://' : 'http://')
1268
				.$_SERVER['SERVER_NAME'] // host
1269
				.(((! $https && $_SERVER['SERVER_PORT'] == 80) || ($https && $_SERVER['SERVER_PORT'] == 443)) ? '' : (':'.$_SERVER['SERVER_PORT']))  // port
1270
				.$uri;
1271
	        if (! elFinder::$tmpLinkUrl) {
1272
	            elFinder::$tmpLinkUrl = $this->tmpLinkUrl;
1273
	        }
1274
	    }
1275
1276
		// remove last '/'
1277
		if ($this->tmpLinkPath) {
1278
		    $this->tmpLinkPath = rtrim($this->tmpLinkPath, '/');
1279
		}
1280
	    if ($this->tmpLinkUrl) {
1281
	        $this->tmpLinkUrl = rtrim($this->tmpLinkUrl, '/');
1282
	    }
1283
1284
		// to update options cache
1285
		$this->updateCache($this->root, $root);
1286
1287
	    return $this->mounted = true;
1288
	}
1289
1290
	/**
1291
	 * Some "unmount" stuffs - may be required by virtual fs.
1292
	 *
1293
	 * @return void
1294
	 * @author Dmitry (dio) Levashov
1295
	 **/
1296
	public function umount()
1297
	{
1298
	}
1299
1300
	/**
1301
	 * Remove session cache of this volume.
1302
	 */
1303
	public function clearSessionCache()
1304
	{
1305
	    $this->sessionCache = [];
1306
	}
1307
1308
	/**
1309
	 * Return error message from last failed action.
1310
	 *
1311
	 * @return array
1312
	 * @author Dmitry (dio) Levashov
1313
	 **/
1314
	public function error()
1315
	{
1316
	    return $this->error;
1317
	}
1318
1319
	/**
1320
	 * Return is uploadable that given file name.
1321
	 *
1322
	 * @param  string  $name  file name
1323
	 * @param  bool    $allowUnknown
1324
	 * @return bool
1325
	 * @author Naoki Sawada
1326
	 **/
1327
	public function isUploadableByName($name, $allowUnknown = false)
1328
	{
1329
	    $mimeByName = $this->mimetype($name, true);
1330
1331
	    return ($allowUnknown && $mimeByName === 'unknown') || $this->allowPutMime($mimeByName);
1332
	}
1333
1334
	/**
1335
	 * Return Extention/MIME Table (elFinderVolumeDriver::$mimetypes).
1336
	 *
1337
	 * @return array
1338
	 * @author Naoki Sawada
1339
	 */
1340
	public function getMimeTable()
1341
	{
1342
	    // load mime.types
1343
		! self::$mimetypesLoaded && self::mimetypeInternalDetect();
1344
1345
	    return self::$mimetypes;
1346
	}
1347
1348
	/**
1349
	 * Return file extention detected by MIME type.
1350
	 *
1351
	 * @param  string  $mime    MIME type
1352
	 * @param  string  $suffix  Additional suffix
1353
	 * @return string
1354
	 * @author Naoki Sawada
1355
	 */
1356
	public function getExtentionByMime($mime, $suffix = '')
1357
	{
1358
	    static $extTable = null;
1359
1360
	    if (is_null($extTable)) {
1361
	        $extTable = array_flip(array_unique($this->getMimeTable()));
1362
	        foreach (array_keys($this->options['mimeMap']) as $pair) {
1363
	            list($ext, $_mime) = explode(':', $pair);
1364
	            if ($_mime !== '*' && ! isset($extTable[$_mime])) {
1365
	                $extTable[$_mime] = $ext;
1366
	            }
1367
	        }
1368
	    }
1369
1370
	    if ($mime && isset($extTable[$mime])) {
1371
	        return $suffix ? ($extTable[$mime].$suffix) : $extTable[$mime];
1372
	    }
1373
1374
	    return '';
1375
	}
1376
1377
	/**
1378
	 * Set mimetypes allowed to display to client.
1379
	 *
1380
	 * @param  array  $mimes
1381
	 * @return void
1382
	 * @author Dmitry (dio) Levashov
1383
	 **/
1384
	public function setMimesFilter($mimes)
1385
	{
1386
	    if (is_array($mimes)) {
1387
	        $this->onlyMimes = $mimes;
1388
	    }
1389
	}
1390
1391
	/**
1392
	 * Return root folder hash.
1393
	 *
1394
	 * @return string
1395
	 * @author Dmitry (dio) Levashov
1396
	 **/
1397
	public function root()
1398
	{
1399
	    return $this->encode($this->root);
1400
	}
1401
1402
	/**
1403
	 * Return target path hash.
1404
	 *
1405
	 * @param  string $path
1406
	 * @param  string $name
1407
	 * @author Naoki Sawada
1408
	 * @return string
1409
	 */
1410
	public function getHash($path, $name = '')
1411
	{
1412
	    if ($name !== '') {
1413
	        $path = $this->joinPathCE($path, $name);
1414
	    }
1415
1416
	    return $this->encode($path);
1417
	}
1418
1419
	/**
1420
	 * Return decoded path of target hash
1421
	 * This method do not check the stat of target
1422
	 * Use method `realpath()` to do check of the stat of target.
1423
	 *
1424
	 * @param  string $hash
1425
	 * @author Naoki Sawada
1426
	 * @return string
1427
	 */
1428
	public function getPath($hash)
1429
	{
1430
	    return $this->decode($hash);
1431
	}
1432
1433
	/**
1434
	 * Return root or startPath hash.
1435
	 *
1436
	 * @return string
1437
	 * @author Dmitry (dio) Levashov
1438
	 **/
1439
	public function defaultPath()
1440
	{
1441
	    return $this->encode($this->startPath ? $this->startPath : $this->root);
1442
	}
1443
1444
	/**
1445
	 * Return volume options required by client:.
1446
	 *
1447
	 * @param $hash
1448
	 * @return array
1449
	 * @author Dmitry (dio) Levashov
1450
	 */
1451
	public function options($hash)
1452
	{
1453
	    $create = $createext = [];
1454
	    if (isset($this->archivers['create']) && is_array($this->archivers['create'])) {
1455
	        foreach ($this->archivers['create'] as $m => $v) {
1456
	            $create[] = $m;
1457
	            $createext[$m] = $v['ext'];
1458
	        }
1459
	    }
1460
	    $opts = [
1461
			'path' => $hash ? $this->path($hash) : '',
1462
			'url' => $this->URL,
1463
			'tmbUrl' => (! $this->imgLib && $this->options['tmbFbSelf']) ? 'self' : $this->tmbURL,
1464
			'disabled' => $this->disabled,
1465
			'separator' => $this->separator,
1466
			'copyOverwrite' => intval($this->options['copyOverwrite']),
1467
			'uploadOverwrite' => intval($this->options['uploadOverwrite']),
1468
			'uploadMaxSize' => intval($this->uploadMaxSize),
1469
			'uploadMaxConn' => intval($this->options['uploadMaxConn']),
1470
			'uploadMime' => [
1471
				'firstOrder' => isset($this->uploadOrder[0]) ? $this->uploadOrder[0] : 'deny',
1472
				'allow' => $this->uploadAllow,
1473
				'deny' => $this->uploadDeny,
1474
			],
1475
			'dispInlineRegex' => $this->options['dispInlineRegex'],
1476
			'jpgQuality' => intval($this->options['jpgQuality']),
1477
			'archivers' => [
1478
				'create' => $create,
1479
				'extract' => isset($this->archivers['extract']) && is_array($this->archivers['extract']) ? array_keys($this->archivers['extract']) : [],
1480
				'createext' => $createext,
1481
			],
1482
			'uiCmdMap' => (isset($this->options['uiCmdMap']) && is_array($this->options['uiCmdMap'])) ? $this->options['uiCmdMap'] : [],
1483
			'syncChkAsTs' => intval($this->options['syncChkAsTs']),
1484
			'syncMinMs' => intval($this->options['syncMinMs']),
1485
			'i18nFolderName' => intval($this->options['i18nFolderName']),
1486
			'tmbCrop' => intval($this->options['tmbCrop']),
1487
		];
1488
	    if (! empty($this->options['trashHash'])) {
1489
	        $opts['trashHash'] = $this->options['trashHash'];
1490
	    }
1491
	    if ($hash === null) {
1492
	        // call from getRootStatExtra()
1493
			if (! empty($this->options['icon'])) {
1494
			    $opts['icon'] = $this->options['icon'];
1495
			}
1496
	        if (! empty($this->options['rootCssClass'])) {
1497
	            $opts['csscls'] = $this->options['rootCssClass'];
1498
	        }
1499
	        if (isset($this->options['netkey'])) {
1500
	            $opts['netkey'] = $this->options['netkey'];
1501
	        }
1502
	    }
1503
1504
	    return $opts;
1505
	}
1506
1507
	/**
1508
	 * Get option value of this volume.
1509
	 *
1510
	 * @param string $name  target option name
1511
	 * @return null|mixed   target option value
1512
	 * @author Naoki Sawada
1513
	 */
1514
	public function getOption($name)
1515
	{
1516
	    return isset($this->options[$name]) ? $this->options[$name] : null;
1517
	}
1518
1519
	/**
1520
	 * Get plugin values of this options.
1521
	 *
1522
	 * @param string $name  Plugin name
1523
	 * @return null|array   Plugin values
1524
	 * @author Naoki Sawada
1525
	 */
1526
	public function getOptionsPlugin($name = '')
1527
	{
1528
	    if ($name) {
1529
	        return isset($this->options['plugin'][$name]) ? $this->options['plugin'][$name] : [];
1530
	    } else {
1531
	        return $this->options['plugin'];
1532
	    }
1533
	}
1534
1535
	/**
1536
	 * Return true if command disabled in options.
1537
	 *
1538
	 * @param  string  $cmd  command name
1539
	 * @return bool
1540
	 * @author Dmitry (dio) Levashov
1541
	 **/
1542
	public function commandDisabled($cmd)
1543
	{
1544
	    return in_array($cmd, $this->disabled);
1545
	}
1546
1547
	/**
1548
	 * Return true if mime is required mimes list.
1549
	 *
1550
	 * @param  string     $mime   mime type to check
1551
	 * @param  array      $mimes  allowed mime types list or not set to use client mimes list
1552
	 * @param  bool|null  $empty  what to return on empty list
1553
	 * @return bool|null
1554
	 * @author Dmitry (dio) Levashov
1555
	 * @author Troex Nevelin
1556
	 **/
1557
	public function mimeAccepted($mime, $mimes = null, $empty = true)
1558
	{
1559
	    $mimes = is_array($mimes) ? $mimes : $this->onlyMimes;
1560
	    if (empty($mimes)) {
1561
	        return $empty;
1562
	    }
1563
1564
	    return $mime == 'directory'
1565
			|| in_array('all', $mimes)
1566
			|| in_array('All', $mimes)
1567
			|| in_array($mime, $mimes)
1568
			|| in_array(substr($mime, 0, strpos($mime, '/')), $mimes);
1569
	}
1570
1571
	/**
1572
	 * Return true if voume is readable.
1573
	 *
1574
	 * @return bool
1575
	 * @author Dmitry (dio) Levashov
1576
	 **/
1577
	public function isReadable()
1578
	{
1579
	    $stat = $this->stat($this->root);
1580
1581
	    return $stat['read'];
1582
	}
1583
1584
	/**
1585
	 * Return true if copy from this volume allowed.
1586
	 *
1587
	 * @return bool
1588
	 * @author Dmitry (dio) Levashov
1589
	 **/
1590
	public function copyFromAllowed()
1591
	{
1592
	    return (bool) $this->options['copyFrom'];
1593
	}
1594
1595
	/**
1596
	 * Return file path related to root with convert encoging.
1597
	 *
1598
	 * @param  string   $hash  file hash
1599
	 * @return string
1600
	 * @author Dmitry (dio) Levashov
1601
	 **/
1602
	public function path($hash)
1603
	{
1604
	    return $this->convEncOut($this->_path($this->convEncIn($this->decode($hash))));
1605
	}
1606
1607
	/**
1608
	 * Return file real path if file exists.
1609
	 *
1610
	 * @param  string  $hash  file hash
1611
	 * @return string | false
1612
	 * @author Dmitry (dio) Levashov
1613
	 **/
1614
	public function realpath($hash)
1615
	{
1616
	    $path = $this->decode($hash);
1617
1618
	    return $this->stat($path) ? $path : false;
1619
	}
1620
1621
	/**
1622
	 * Return list of moved/overwrited files.
1623
	 *
1624
	 * @return array
1625
	 * @author Dmitry (dio) Levashov
1626
	 **/
1627
	public function removed()
1628
	{
1629
	    if ($this->removed) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->removed 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...
1630
	        $unsetSubdir = isset($this->sessionCache['subdirs']) ? true : false;
1631
	        foreach ($this->removed as $item) {
1632
	            if ($item['mime'] === 'directory') {
1633
	                $path = $this->decode($item['hash']);
1634
	                if ($unsetSubdir) {
1635
	                    unset($this->sessionCache['subdirs'][$path]);
1636
	                }
1637
	                if ($item['phash'] !== '') {
1638
	                    $parent = $this->decode($item['phash']);
1639
	                    unset($this->cache[$parent]);
1640
	                    if ($unsetSubdir) {
1641
	                        unset($this->sessionCache['subdirs'][$parent]);
1642
	                    }
1643
	                }
1644
	            }
1645
	        }
1646
	    }
1647
1648
	    return $this->removed;
1649
	}
1650
1651
	/**
1652
	 * Return list of added files.
1653
	 *
1654
	 * @deprecated
1655
	 * @return array
1656
	 * @author Naoki Sawada
1657
	 **/
1658
	public function added()
1659
	{
1660
	    return $this->added;
1661
	}
1662
1663
	/**
1664
	 * Clean removed files list.
1665
	 *
1666
	 * @return void
1667
	 * @author Dmitry (dio) Levashov
1668
	 **/
1669
	public function resetRemoved()
1670
	{
1671
	    $this->resetResultStat();
1672
	}
1673
1674
	/**
1675
	 * Clean added/removed files list.
1676
	 *
1677
	 * @return void
1678
	 **/
1679
	public function resetResultStat()
1680
	{
1681
	    $this->removed = [];
1682
	    $this->added = [];
1683
	}
1684
1685
	/**
1686
	 * Return file/dir hash or first founded child hash with required attr == $val.
1687
	 *
1688
	 * @param  string   $hash  file hash
1689
	 * @param  string   $attr  attribute name
1690
	 * @param  bool     $val   attribute value
1691
	 * @return string|false
1692
	 * @author Dmitry (dio) Levashov
1693
	 **/
1694
	public function closest($hash, $attr, $val)
1695
	{
1696
	    return ($path = $this->closestByAttr($this->decode($hash), $attr, $val)) ? $this->encode($path) : false;
1697
	}
1698
1699
	/**
1700
	 * Return file info or false on error.
1701
	 *
1702
	 * @param  string $hash file hash
1703
	 * @return array|false
1704
	 * @internal param bool $realpath add realpath field to file info
1705
	 * @author Dmitry (dio) Levashov
1706
	 */
1707
	public function file($hash)
1708
	{
1709
	    $file = $this->stat($this->decode($hash));
1710
1711
	    return ($file) ? $file : $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
1712
	}
1713
1714
	/**
1715
	 * Return folder info.
1716
	 *
1717
	 * @param  string $hash folder hash
1718
	 * @param bool $resolveLink
1719
	 * @return array|false
1720
	 * @internal param bool $hidden return hidden file info
1721
	 * @author Dmitry (dio) Levashov
1722
	 */
1723
	public function dir($hash, $resolveLink = false)
1724
	{
1725
	    if (($dir = $this->file($hash)) == false) {
1726
	        return $this->setError(elFinder::ERROR_DIR_NOT_FOUND);
1727
	    }
1728
1729
	    if ($resolveLink && ! empty($dir['thash'])) {
1730
	        $dir = $this->file($dir['thash']);
1731
	    }
1732
1733
	    return $dir && $dir['mime'] == 'directory' && empty($dir['hidden'])
1734
			? $dir
1735
			: $this->setError(elFinder::ERROR_NOT_DIR);
1736
	}
1737
1738
	/**
1739
	 * Return directory content or false on error.
1740
	 *
1741
	 * @param  string   $hash   file hash
1742
	 * @return array|false
1743
	 * @author Dmitry (dio) Levashov
1744
	 **/
1745
	public function scandir($hash)
1746
	{
1747
	    if (($dir = $this->dir($hash)) == false) {
1748
	        return false;
1749
	    }
1750
1751
	    $path = $this->decode($hash);
1752
	    if ($res = $dir['read']
1753
			? $this->getScandir($path)
1754
			: $this->setError(elFinder::ERROR_PERM_DENIED)) {
1755
	        $dirs = null;
1756 View Code Duplication
	        if ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$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...
1757
	            $dirs = $this->sessionCache['subdirs'][$path];
1758
	        }
1759
	        if ($dirs !== null || (isset($dir['dirs']) && $dir['dirs'] != 1)) {
1760
	            $_dir = $dir;
1761
	            if ($dirs || $this->subdirs($hash)) {
1762
	                $dir['dirs'] = 1;
1763
	            } else {
1764
	                unset($dir['dirs']);
1765
	            }
1766
	            if ($dir !== $_dir) {
1767
	                $this->updateCache($path, $dir);
0 ignored issues
show
Bug introduced by
It seems like $dir defined by $this->dir($hash) on line 1747 can also be of type boolean; however, elFinderVolumeDriver::updateCache() 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...
1768
	            }
1769
	        }
1770
	    }
1771
1772
	    return $res;
1773
	}
1774
1775
	/**
1776
	 * Return dir files names list.
1777
	 *
1778
	 * @param  string $hash file hash
1779
	 * @param null $intersect
1780
	 * @return array
1781
	 * @author Dmitry (dio) Levashov
1782
	 */
1783
	public function ls($hash, $intersect = null)
1784
	{
1785
	    if (($dir = $this->dir($hash)) == false || ! $dir['read']) {
1786
	        return false;
1787
	    }
1788
1789
	    $list = [];
1790
	    $path = $this->decode($hash);
1791
1792
	    $check = [];
1793
	    if ($intersect) {
1794
	        $check = array_flip($intersect);
1795
	    }
1796
1797
	    foreach ($this->getScandir($path) as $stat) {
1798
	        if (empty($stat['hidden']) && (! $check || isset($check[$stat['name']])) && $this->mimeAccepted($stat['mime'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $check 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...
1799
	            $list[$stat['hash']] = $stat['name'];
1800
	        }
1801
	    }
1802
1803
	    return $list;
1804
	}
1805
1806
	/**
1807
	 * Return subfolders for required folder or false on error.
1808
	 *
1809
	 * @param  string   $hash  folder hash or empty string to get tree from root folder
1810
	 * @param  int      $deep  subdir deep
1811
	 * @param  string   $exclude  dir hash which subfolders must be exluded from result, required to not get stat twice on cwd subfolders
1812
	 * @return array|false
1813
	 * @author Dmitry (dio) Levashov
1814
	 **/
1815
	public function tree($hash = '', $deep = 0, $exclude = '')
1816
	{
1817
	    $path = $hash ? $this->decode($hash) : $this->root;
1818
1819 View Code Duplication
	    if (($dir = $this->stat($path)) == false || $dir['mime'] != 'directory') {
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...
1820
	        return false;
1821
	    }
1822
1823
	    $dirs = $this->gettree($path, $deep > 0 ? $deep - 1 : $this->treeDeep - 1, $exclude ? $this->decode($exclude) : null);
1824
	    array_unshift($dirs, $dir);
1825
1826
	    return $dirs;
1827
	}
1828
1829
	/**
1830
	 * Return part of dirs tree from required dir up to root dir.
1831
	 *
1832
	 * @param  string    $hash   directory hash
1833
	 * @param  bool|null $lineal only lineal parents
1834
	 * @param  string    $until  hash that is enough to that extent >= 2.1.24
0 ignored issues
show
Bug introduced by
There is no parameter named $until. 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...
1835
	 * @return array
1836
	 * @author Dmitry (dio) Levashov
1837
	 **/
1838
	public function parents($hash, $lineal = false)
1839
	{
1840
	    if (($current = $this->dir($hash)) == false) {
1841
	        return false;
1842
	    }
1843
1844
	    $args = func_get_args();
1845
		// checks 3rd param `$until` (elFinder >= 2.1.24)
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1846
		$until = '';
1847
	    if (isset($args[2])) {
1848
	        $until = $args[2];
1849
	    }
1850
1851
	    $path = $this->decode($hash);
1852
	    $tree = [];
1853
1854
	    while ($path && $path != $this->root) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $path of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
1855
	        elFinder::extendTimeLimit();
1856
	        $path = $this->dirnameCE($path);
1857
	        if (! ($stat = $this->stat($path)) || ! empty($stat['hidden']) || ! $stat['read']) {
1858
	            return false;
1859
	        }
1860
1861
	        array_unshift($tree, $stat);
1862
	        if (! $lineal) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lineal of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
1863
	            foreach ($this->gettree($path, 0) as $dir) {
1864
	                elFinder::extendTimeLimit();
1865
	                if (! isset($tree[$dir['hash']])) {
1866
	                    $tree[$dir['hash']] = $dir;
1867
	                }
1868
	            }
1869
	        }
1870
1871
	        if ($until && $until === $this->encode($path)) {
1872
	            break;
1873
	        }
1874
	    }
1875
1876
	    return $tree ? array_values($tree) : [$current];
1877
	}
1878
1879
	/**
1880
	 * Create thumbnail for required file and return its name of false on failed.
1881
	 *
1882
	 * @param $hash
1883
	 * @return false|string
1884
	 * @author Dmitry (dio) Levashov
1885
	 */
1886
	public function tmb($hash)
1887
	{
1888
	    $path = $this->decode($hash);
1889
	    $stat = $this->stat($path);
1890
1891
	    if (isset($stat['tmb'])) {
1892
	        $res = $stat['tmb'] == '1' ? $this->createTmb($path, $stat) : $stat['tmb'];
1893
	        if (! $res) {
1894
	            list($type) = explode('/', $stat['mime']);
1895
	            $fallback = $this->options['resourcePath'].DIRECTORY_SEPARATOR.strtolower($type).'.png';
1896
	            if (is_file($fallback)) {
1897
	                $res = $this->tmbname($stat);
1898
	                if (! copy($fallback, $this->tmbPath.DIRECTORY_SEPARATOR.$res)) {
1899
	                    $res = false;
1900
	                }
1901
	            }
1902
	        }
1903
1904
	        return $res;
1905
	    }
1906
1907
	    return false;
1908
	}
1909
1910
	/**
1911
	 * Return file size / total directory size.
1912
	 *
1913
	 * @param  string   file hash
1914
	 * @return int
1915
	 * @author Dmitry (dio) Levashov
1916
	 **/
1917
	public function size($hash)
1918
	{
1919
	    return $this->countSize($this->decode($hash));
1920
	}
1921
1922
	/**
1923
	 * Open file for reading and return file pointer.
1924
	 *
1925
	 * @param  string   file hash
1926
	 * @return resource
1927
	 * @author Dmitry (dio) Levashov
1928
	 **/
1929
	public function open($hash)
1930
	{
1931 View Code Duplication
	    if (($file = $this->file($hash)) == false
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...
1932
		|| $file['mime'] == 'directory') {
1933
	        return false;
1934
	    }
1935
1936
	    return $this->fopenCE($this->decode($hash), 'rb');
1937
	}
1938
1939
	/**
1940
	 * Close file pointer.
1941
	 *
1942
	 * @param  resource  $fp   file pointer
1943
	 * @param  string    $hash file hash
1944
	 * @return void
1945
	 * @author Dmitry (dio) Levashov
1946
	 **/
1947
	public function close($fp, $hash)
1948
	{
1949
	    $this->fcloseCE($fp, $this->decode($hash));
1950
	}
1951
1952
	/**
1953
	 * Create directory and return dir info.
1954
	 *
1955
	 * @param  string   $dsthash  destination directory hash
1956
	 * @param  string   $name directory name
1957
	 * @return array|false
1958
	 * @author Dmitry (dio) Levashov
1959
	 **/
1960
	public function mkdir($dsthash, $name)
1961
	{
1962
	    if ($this->commandDisabled('mkdir')) {
1963
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
1964
	    }
1965
1966
	    if (! $this->nameAccepted($name, true)) {
1967
	        return $this->setError(elFinder::ERROR_INVALID_DIRNAME);
1968
	    }
1969
1970
	    if (($dir = $this->dir($dsthash)) == false) {
1971
	        return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dsthash);
1972
	    }
1973
1974
	    $path = $this->decode($dsthash);
1975
1976
	    if (! $dir['write'] || ! $this->allowCreate($path, $name, true)) {
1977
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
1978
	    }
1979
1980
	    $dst = $this->joinPathCE($path, $name);
1981
	    $stat = $this->isNameExists($dst);
1982
	    if (! empty($stat)) {
1983
	        return $this->setError(elFinder::ERROR_EXISTS, $name);
1984
	    }
1985
	    $this->clearcache();
1986
1987
	    $mkpath = $this->convEncOut($this->_mkdir($this->convEncIn($path), $this->convEncIn($name)));
1988
	    if ($mkpath) {
1989
	        $this->updateSubdirsCache($path, true);
1990
	        $this->updateSubdirsCache($mkpath, false);
1991
	    }
1992
1993
	    return $mkpath ? $this->stat($mkpath) : false;
1994
	}
1995
1996
	/**
1997
	 * Create empty file and return its info.
1998
	 *
1999
	 * @param  string   $dst  destination directory
2000
	 * @param  string   $name file name
2001
	 * @return array|false
2002
	 * @author Dmitry (dio) Levashov
2003
	 **/
2004
	public function mkfile($dst, $name)
2005
	{
2006
	    if ($this->commandDisabled('mkfile')) {
2007
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2008
	    }
2009
2010
	    if (! $this->nameAccepted($name, false)) {
2011
	        return $this->setError(elFinder::ERROR_INVALID_NAME);
2012
	    }
2013
2014
	    $mimeByName = $this->mimetype($name, true);
2015
	    if ($mimeByName && ! $this->allowPutMime($mimeByName)) {
2016
	        return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $name);
2017
	    }
2018
2019 View Code Duplication
	    if (($dir = $this->dir($dst)) == false) {
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...
2020
	        return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst);
2021
	    }
2022
2023
	    $path = $this->decode($dst);
2024
2025
	    if (! $dir['write'] || ! $this->allowCreate($path, $name, false)) {
2026
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2027
	    }
2028
2029
	    if ($this->isNameExists($this->joinPathCE($path, $name))) {
2030
	        return $this->setError(elFinder::ERROR_EXISTS, $name);
2031
	    }
2032
2033
	    $this->clearcache();
2034
2035
	    return ($path = $this->convEncOut($this->_mkfile($this->convEncIn($path), $this->convEncIn($name)))) ? $this->stat($path) : false;
2036
	}
2037
2038
	/**
2039
	 * Rename file and return file info.
2040
	 *
2041
	 * @param  string  $hash  file hash
2042
	 * @param  string  $name  new file name
2043
	 * @return array|false
2044
	 * @author Dmitry (dio) Levashov
2045
	 **/
2046
	public function rename($hash, $name)
2047
	{
2048
	    if ($this->commandDisabled('rename')) {
2049
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2050
	    }
2051
2052
	    if (! ($file = $this->file($hash))) {
2053
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
2054
	    }
2055
2056
	    if ($name === $file['name']) {
2057
	        return $file;
2058
	    }
2059
2060
	    if (! empty($file['locked'])) {
2061
	        return $this->setError(elFinder::ERROR_LOCKED, $file['name']);
2062
	    }
2063
2064
	    $isDir = ($file['mime'] === 'directory');
2065
2066
	    if (! $this->nameAccepted($name, $isDir)) {
2067
	        return $this->setError(elFinder::ERROR_INVALID_DIRNAME);
2068
	    }
2069
2070
	    if (! $isDir) {
2071
	        $mimeByName = $this->mimetype($name, true);
2072
	        if ($mimeByName && ! $this->allowPutMime($mimeByName)) {
2073
	            return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $name);
2074
	        }
2075
	    }
2076
2077
	    $path = $this->decode($hash);
2078
	    $dir = $this->dirnameCE($path);
2079
	    $stat = $this->isNameExists($this->joinPathCE($dir, $name));
2080
	    if ($stat) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2081
	        return $this->setError(elFinder::ERROR_EXISTS, $name);
2082
	    }
2083
2084
	    if (! $this->allowCreate($dir, $name, ($file['mime'] === 'directory'))) {
2085
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2086
	    }
2087
2088
	    $this->rmTmb($file); // remove old name tmbs, we cannot do this after dir move
0 ignored issues
show
Documentation introduced by
$file is of type array|boolean, but the function expects a string.

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...
2089
2090
		if ($path = $this->convEncOut($this->_move($this->convEncIn($path), $this->convEncIn($dir), $this->convEncIn($name)))) {
2091
		    $this->clearcache();
2092
2093
		    return $this->stat($path);
2094
		}
2095
2096
	    return false;
2097
	}
2098
2099
	/**
2100
	 * Create file copy with suffix "copy number" and return its info.
2101
	 *
2102
	 * @param  string   $hash    file hash
2103
	 * @param  string   $suffix  suffix to add to file name
2104
	 * @return array|false
2105
	 * @author Dmitry (dio) Levashov
2106
	 **/
2107
	public function duplicate($hash, $suffix = 'copy')
2108
	{
2109
	    if ($this->commandDisabled('duplicate')) {
2110
	        return $this->setError(elFinder::ERROR_COPY, '#'.$hash, elFinder::ERROR_PERM_DENIED);
2111
	    }
2112
2113
	    if (($file = $this->file($hash)) == false) {
2114
	        return $this->setError(elFinder::ERROR_COPY, elFinder::ERROR_FILE_NOT_FOUND);
2115
	    }
2116
2117
	    $path = $this->decode($hash);
2118
	    $dir = $this->dirnameCE($path);
2119
	    $name = $this->uniqueName($dir, $file['name'], sprintf($this->options['duplicateSuffix'], $suffix));
2120
2121
	    if (! $this->allowCreate($dir, $name, ($file['mime'] === 'directory'))) {
2122
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2123
	    }
2124
2125
	    return ($path = $this->copy($path, $dir, $name)) == false
2126
			? false
2127
			: $this->stat($path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->copy($path, $dir, $name) on line 2125 can also be of type boolean or null; however, elFinderVolumeDriver::stat() does only seem to accept string, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
2128
	}
2129
2130
	/**
2131
	 * Save uploaded file.
2132
	 * On success return array with new file stat and with removed file hash (if existed file was replaced).
2133
	 *
2134
	 * @param  resource $fp file pointer
2135
	 * @param  string $dst destination folder hash
2136
	 * @param $name
2137
	 * @param  string $tmpname file tmp name - required to detect mime type
2138
	 * @param  array $hashes exists files hash array with filename as key
2139
	 * @return array|false
2140
	 * @internal param string $src file name
2141
	 * @author Dmitry (dio) Levashov
2142
	 */
2143
	public function upload($fp, $dst, $name, $tmpname, $hashes = [])
2144
	{
2145
	    if ($this->commandDisabled('upload')) {
2146
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2147
	    }
2148
2149 View Code Duplication
	    if (($dir = $this->dir($dst)) == false) {
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...
2150
	        return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst);
2151
	    }
2152
2153
	    if (empty($dir['write'])) {
2154
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2155
	    }
2156
2157
	    if (! $this->nameAccepted($name, false)) {
2158
	        return $this->setError(elFinder::ERROR_INVALID_NAME);
2159
	    }
2160
2161
	    $mimeByName = '';
2162
	    if ($this->mimeDetect === 'internal') {
2163
	        $mime = $this->mimetype($name, true);
2164
	    } else {
2165
	        $mime = $this->mimetype($tmpname, $name);
2166
	        $mimeByName = $this->mimetype($name, true);
2167
	        if ($mime === 'unknown') {
2168
	            $mime = $mimeByName;
2169
	        }
2170
	    }
2171
2172 View Code Duplication
	    if (! $this->allowPutMime($mime) || ($mimeByName && ! $this->allowPutMime($mimeByName))) {
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...
2173
	        return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME);
2174
	    }
2175
2176
	    $tmpsize = sprintf('%u', filesize($tmpname));
2177
	    if ($this->uploadMaxSize > 0 && $tmpsize > $this->uploadMaxSize) {
2178
	        return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE);
2179
	    }
2180
2181
	    $dstpath = $this->decode($dst);
2182 View Code Duplication
	    if (isset($hashes[$name])) {
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...
2183
	        $test = $this->decode($hashes[$name]);
2184
	        $file = $this->stat($test);
2185
	    } else {
2186
	        $test = $this->joinPathCE($dstpath, $name);
2187
	        $file = $this->isNameExists($test);
2188
	    }
2189
2190
	    $this->clearcache();
2191
2192
	    if ($file && $file['name'] === $name) { // file exists and check filename for item ID based filesystem
0 ignored issues
show
Bug Best Practice introduced by
The expression $file 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...
2193
			if ($this->uploadOverwrite) {
2194 View Code Duplication
			    if (! $file['write']) {
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...
2195
			        return $this->setError(elFinder::ERROR_PERM_DENIED);
2196
			    } elseif ($file['mime'] == 'directory') {
2197
			        return $this->setError(elFinder::ERROR_NOT_REPLACE, $name);
2198
			    }
2199
			    $this->remove($test);
2200
			} else {
2201
			    $name = $this->uniqueName($dstpath, $name, '-', false);
2202
			}
2203
	    }
2204
2205
	    $stat = [
2206
			'mime' => $mime,
2207
			'width' => 0,
2208
			'height' => 0,
2209
			'size' => $tmpsize, ];
2210
2211
		// $w = $h = 0;
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2212
		if (strpos($mime, 'image') === 0 && ($s = getimagesize($tmpname))) {
2213
		    $stat['width'] = $s[0];
2214
		    $stat['height'] = $s[1];
2215
		}
2216
		// $this->clearcache();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2217
		if (($path = $this->saveCE($fp, $dstpath, $name, $stat)) == false) {
2218
		    return false;
2219
		}
2220
2221
	    $stat = $this->stat($path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->saveCE($fp, $dstpath, $name, $stat) on line 2217 can also be of type boolean; however, elFinderVolumeDriver::stat() does only seem to accept string, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
2222
		// Try get URL
2223
		if (empty($stat['url']) && ($url = $this->getContentUrl($stat['hash']))) {
2224
		    $stat['url'] = $url;
2225
		}
2226
2227
	    return $stat;
2228
	}
2229
2230
	/**
2231
	 * Paste files.
2232
	 *
2233
	 * @param  object $volume source volume
2234
	 * @param $src
2235
	 * @param  string $dst destination dir hash
2236
	 * @param  bool $rmSrc remove source after copy?
2237
	 * @param array $hashes
2238
	 * @return array|false
2239
	 * @internal param string $source file hash
2240
	 * @author Dmitry (dio) Levashov
2241
	 */
2242
	public function paste($volume, $src, $dst, $rmSrc = false, $hashes = [])
2243
	{
2244
	    $err = $rmSrc ? elFinder::ERROR_MOVE : elFinder::ERROR_COPY;
2245
2246
	    if ($this->commandDisabled('paste')) {
2247
	        return $this->setError($err, '#'.$src, elFinder::ERROR_PERM_DENIED);
2248
	    }
2249
2250
	    if (($file = $volume->file($src, $rmSrc)) == false) {
2251
	        return $this->setError($err, '#'.$src, elFinder::ERROR_FILE_NOT_FOUND);
2252
	    }
2253
2254
	    $name = $file['name'];
2255
	    $errpath = $volume->path($file['hash']);
2256
2257 View Code Duplication
	    if (($dir = $this->dir($dst)) == false) {
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...
2258
	        return $this->setError($err, $errpath, elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst);
2259
	    }
2260
2261
	    if (! $dir['write'] || ! $file['read']) {
2262
	        return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED);
2263
	    }
2264
2265
	    $destination = $this->decode($dst);
2266
2267
	    if (($test = $volume->closest($src, $rmSrc ? 'locked' : 'read', $rmSrc))) {
2268
	        return $rmSrc
2269
				? $this->setError($err, $errpath, elFinder::ERROR_LOCKED, $volume->path($test))
2270
				: $this->setError($err, $errpath, empty($file['thash']) ? elFinder::ERROR_PERM_DENIED : elFinder::ERROR_MKOUTLINK);
2271
	    }
2272
2273 View Code Duplication
	    if (isset($hashes[$name])) {
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...
2274
	        $test = $this->decode($hashes[$name]);
2275
	        $stat = $this->stat($test);
2276
	    } else {
2277
	        $test = $this->joinPathCE($destination, $name);
2278
	        $stat = $this->isNameExists($test);
2279
	    }
2280
	    $this->clearcache();
2281
	    $dstDirExists = false;
2282
	    if ($stat && $stat['name'] === $name) { // file exists and check filename for item ID based filesystem
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2283
			if ($this->options['copyOverwrite']) {
2284
			    // do not replace file with dir or dir with file
2285
				if (! $this->isSameType($file['mime'], $stat['mime'])) {
2286
				    return $this->setError(elFinder::ERROR_NOT_REPLACE, $this->path($stat['hash']));
2287
				}
2288
				// existed file is not writable
2289
				if (! $stat['write']) {
2290
				    return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED);
2291
				}
2292
			    if ($this->options['copyJoin']) {
2293
			        if ($stat['locked']) {
2294
			            return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash']));
2295
			        }
2296
			    } else {
2297
			        // existed file locked or has locked child
2298
					if (($locked = $this->closestByAttr($test, 'locked', true))) {
2299
					    $stat = $this->stat($locked);
2300
2301
					    return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash']));
2302
					}
2303
			    }
2304
				// target is entity file of alias
2305
				if ($volume === $this && ((isset($file['target']) && $test == $file['target']) || $test == $this->decode($src))) {
2306
				    return $this->setError(elFinder::ERROR_REPLACE, $errpath);
2307
				}
2308
				// remove existed file
2309
				if (! $this->options['copyJoin'] || $stat['mime'] !== 'directory') {
2310
				    if (! $this->remove($test)) {
2311
				        return $this->setError(elFinder::ERROR_REPLACE, $this->path($stat['hash']));
2312
				    }
2313
				} elseif ($stat['mime'] === 'directory') {
2314
				    $dstDirExists = true;
2315
				}
2316
			} else {
2317
			    $name = $this->uniqueName($destination, $name, ' ', false);
2318
			}
2319
	    }
2320
2321
		// copy/move inside current volume
2322
		if ($volume === $this) { //  changing == operand to === fixes issue #1285 - Paul Canning 24/03/2016
2323
			$source = $this->decode($src);
2324
			// do not copy into itself
2325
			if ($this->inpathCE($destination, $source)) {
2326
			    return $this->setError(elFinder::ERROR_COPY_INTO_ITSELF, $errpath);
2327
			}
2328
		    $rmDir = false;
2329
		    if ($rmSrc) {
2330
		        if ($dstDirExists) {
2331
		            $rmDir = true;
2332
		            $method = 'copy';
2333
		        } else {
2334
		            $method = 'move';
2335
		        }
2336
		    } else {
2337
		        $method = 'copy';
2338
		    }
2339
		    $this->clearcache();
2340
		    if ($res = ($path = $this->$method($source, $destination, $name)) ? $this->stat($path) : false) {
2341
		        if ($rmDir) {
2342
		            $this->remove($source);
2343
		        }
2344
		    } else {
2345
		        return false;
2346
		    }
2347
		} else {
2348
		    // copy/move from another volume
2349
			if (! $this->options['copyTo'] || ! $volume->copyFromAllowed()) {
2350
			    return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED);
2351
			}
2352
2353
		    if (($path = $this->copyFrom($volume, $src, $destination, $name)) == false) {
2354
		        return false;
2355
		    }
2356
2357
		    if ($rmSrc) {
2358
		        if (! $volume->rm($src)) {
2359
		            return $this->setError(elFinder::ERROR_MOVE, $errpath, elFinder::ERROR_RM_SRC);
2360
		        }
2361
		    }
2362
		    $res = $this->stat($path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->copyFrom($volume,...c, $destination, $name) on line 2353 can also be of type boolean or null; however, elFinderVolumeDriver::stat() does only seem to accept string, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
2363
		}
2364
2365
	    return $res;
2366
	}
2367
2368
	/**
2369
	 * Return path to archive of target items.
2370
	 *
2371
	 * @param  array  $hashes
2372
	 * @return string archive path
2373
	 * @author Naoki Sawada
2374
	 */
2375
	public function zipdl($hashes)
2376
	{
2377
	    if ($this->commandDisabled('zipdl')) {
2378
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2379
	    }
2380
2381
	    $archivers = $this->getArchivers();
2382
	    $cmd = null;
2383
	    if (! $archivers || empty($archivers['create'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $archivers 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...
2384
	        return false;
2385
	    }
2386
	    $archivers = $archivers['create'];
2387
	    foreach (['zip', 'tgz'] as $ext) {
2388
	        $mime = self::$mimetypes[$ext];
2389
	        if (isset($archivers[$mime])) {
2390
	            $cmd = $archivers[$mime];
2391
	            break;
2392
	        }
2393
	    }
2394
	    if (! $cmd) {
2395
	        $cmd = $archivers[0];
2396
	        $ext = $cmd['ext'];
2397
	        $mime = $this->mimetype('file.'.$ext, true);
2398
	    }
2399
	    $res = false;
2400
	    $mixed = false;
2401
	    $hashes = array_values($hashes);
2402
	    $dirname = dirname(str_replace($this->separator, DIRECTORY_SEPARATOR, $this->path($hashes[0])));
2403
	    $cnt = count($hashes);
2404
	    if ($cnt > 1) {
2405
	        for ($i = 1; $i < $cnt; $i++) {
2406
	            if ($dirname !== dirname(str_replace($this->separator, DIRECTORY_SEPARATOR, $this->path($hashes[$i])))) {
2407
	                $mixed = true;
2408
	                break;
2409
	            }
2410
	        }
2411
	    }
2412
	    if ($mixed || $this->root == $this->dirnameCE($this->decode($hashes[0]))) {
2413
	        $prefix = $this->rootName;
2414
	    } else {
2415
	        $prefix = basename($dirname);
2416
	    }
2417
	    if ($dir = $this->getItemsInHand($hashes)) {
2418
	        $tmppre = (substr(PHP_OS, 0, 3) === 'WIN') ? 'zdl' : 'elfzdl';
2419
	        $pdir = dirname($dir);
2420
			// garbage collection
2421
			$ttl = 7200; // expire 2h
2422
			$time = time();
2423
	        foreach (glob($pdir.DIRECTORY_SEPARATOR.$tmppre.'*') as $_file) {
2424
	            if (filemtime($_file) + $ttl < $time) {
2425
	                unlink($_file);
2426
	            }
2427
	        }
2428
	        $files = self::localScandir($dir);
2429
	        if ($files && ($arc = tempnam($dir, $tmppre))) {
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...
2430
	            unlink($arc);
2431
	            $arc = $arc.'.'.$ext;
0 ignored issues
show
Bug introduced by
The variable $ext 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...
2432
	            $name = basename($arc);
2433
	            if ($arc = $this->makeArchive($dir, $files, $name, $cmd)) {
2434
	                $file = tempnam($pdir, $tmppre);
2435
	                unlink($file);
2436
	                $res = rename($arc, $file);
2437
	                $this->rmdirRecursive($dir);
2438
	            }
2439
	        }
2440
	    }
2441
2442
	    return $res ? ['path' => $file, 'ext' => $ext, 'mime' => $mime, 'prefix' => $prefix] : false;
0 ignored issues
show
Bug introduced by
The variable $file 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...
Bug introduced by
The variable $mime 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...
2443
	}
2444
2445
	/**
2446
	 * Return file contents.
2447
	 *
2448
	 * @param  string  $hash  file hash
2449
	 * @return string|false
2450
	 * @author Dmitry (dio) Levashov
2451
	 **/
2452
	public function getContents($hash)
2453
	{
2454
	    $file = $this->file($hash);
2455
2456
	    if (! $file) {
2457
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
2458
	    }
2459
2460
	    if ($file['mime'] == 'directory') {
2461
	        return $this->setError(elFinder::ERROR_NOT_FILE);
2462
	    }
2463
2464
	    if (! $file['read']) {
2465
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2466
	    }
2467
2468
	    if ($this->getMaxSize > 0 && $file['size'] > $this->getMaxSize) {
2469
	        return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE);
2470
	    }
2471
2472
	    return $this->_getContents($this->convEncIn($this->decode($hash), true));
2473
	}
2474
2475
	/**
2476
	 * Put content in text file and return file info.
2477
	 *
2478
	 * @param  string  $hash     file hash
2479
	 * @param  string  $content  new file content
2480
	 * @return array
2481
	 * @author Dmitry (dio) Levashov
2482
	 **/
2483
	public function putContents($hash, $content)
2484
	{
2485
	    if ($this->commandDisabled('edit')) {
2486
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2487
	    }
2488
2489
	    $path = $this->decode($hash);
2490
2491
	    if (! ($file = $this->file($hash))) {
2492
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
2493
	    }
2494
2495
	    if (! $file['write']) {
2496
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2497
	    }
2498
2499
		// check data cheme
2500
		if (preg_match('~^data:(.+?/.+?);base64,~', $content, $m)) {
2501
		    $dMime = $m[1];
2502
		    if ($file['size'] > 0 && $dMime !== $file['mime']) {
2503
		        return $this->setError(elFinder::ERROR_PERM_DENIED);
2504
		    }
2505
		    $content = base64_decode(substr($content, strlen($m[0])));
2506
		}
2507
2508
		// check MIME
2509
		$name = $this->basenameCE($path);
2510
	    $mime = '';
2511
	    $mimeByName = $this->mimetype($name, true);
2512
	    if ($this->mimeDetect !== 'internal') {
2513
	        if ($tp = tmpfile()) {
2514
	            fwrite($tp, $content);
2515
	            $info = stream_get_meta_data($tp);
2516
	            $filepath = $info['uri'];
2517
	            $mime = $this->mimetype($filepath, $name);
2518
	            fclose($tp);
2519
	        }
2520
	    }
2521 View Code Duplication
	    if (! $this->allowPutMime($mimeByName) || ($mime && ! $this->allowPutMime($mime))) {
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...
2522
	        return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME);
2523
	    }
2524
2525
	    $this->clearcache();
2526
2527
	    return $this->convEncOut($this->_filePutContents($this->convEncIn($path), $content)) ? $this->stat($path) : false;
2528
	}
2529
2530
	/**
2531
	 * Extract files from archive.
2532
	 *
2533
	 * @param  string $hash archive hash
2534
	 * @param null $makedir
2535
	 * @return array|bool
2536
	 * @author Dmitry (dio) Levashov,
2537
	 * @author Alexey Sukhotin
2538
	 */
2539
	public function extract($hash, $makedir = null)
2540
	{
2541
	    if ($this->commandDisabled('extract')) {
2542
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2543
	    }
2544
2545
	    if (($file = $this->file($hash)) == false) {
2546
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
2547
	    }
2548
2549
	    $archiver = isset($this->archivers['extract'][$file['mime']])
2550
			? $this->archivers['extract'][$file['mime']]
2551
			: false;
2552
2553
	    if (! $archiver) {
2554
	        return $this->setError(elFinder::ERROR_NOT_ARCHIVE);
2555
	    }
2556
2557
	    $path = $this->decode($hash);
2558
	    $parent = $this->stat($this->dirnameCE($path));
2559
2560
	    if (! $file['read'] || ! $parent['write']) {
2561
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2562
	    }
2563
	    $this->clearcache();
2564
	    $this->extractToNewdir = is_null($makedir) ? 'auto' : (bool) $makedir;
0 ignored issues
show
Documentation Bug introduced by
It seems like is_null($makedir) ? 'auto' : (bool) $makedir of type string or boolean is incompatible with the declared type integer of property $extractToNewdir.

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...
2565
2566
	    if ($path = $this->convEncOut($this->_extract($this->convEncIn($path), $archiver))) {
2567
	        if (is_array($path)) {
2568
	            foreach ($path as $_k => $_p) {
2569
	                $path[$_k] = $this->stat($_p);
2570
	            }
2571
	        } else {
2572
	            $path = $this->stat($path);
2573
	        }
2574
2575
	        return $path;
2576
	    } else {
2577
	        return false;
2578
	    }
2579
	}
2580
2581
	/**
2582
	 * Add files to archive.
2583
	 *
2584
	 * @param $hashes
2585
	 * @param $mime
2586
	 * @param string $name
2587
	 * @return array|bool
2588
	 */
2589
	public function archive($hashes, $mime, $name = '')
2590
	{
2591
	    if ($this->commandDisabled('archive')) {
2592
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2593
	    }
2594
2595
	    if ($name !== '' && ! $this->nameAccepted($name, false)) {
2596
	        return $this->setError(elFinder::ERROR_INVALID_NAME);
2597
	    }
2598
2599
	    $archiver = isset($this->archivers['create'][$mime])
2600
			? $this->archivers['create'][$mime]
2601
			: false;
2602
2603
	    if (! $archiver) {
2604
	        return $this->setError(elFinder::ERROR_ARCHIVE_TYPE);
2605
	    }
2606
2607
	    $files = [];
2608
2609
	    foreach ($hashes as $hash) {
2610 View Code Duplication
	        if (($file = $this->file($hash)) == false) {
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...
2611
	            return $this->setError(elFinder::ERROR_FILE_NOT_FOUND, '#' + $hash);
2612
	        }
2613
	        if (! $file['read']) {
2614
	            return $this->setError(elFinder::ERROR_PERM_DENIED);
2615
	        }
2616
	        $path = $this->decode($hash);
2617
	        if (! isset($dir)) {
2618
	            $dir = $this->dirnameCE($path);
2619
	            $stat = $this->stat($dir);
2620
	            if (! $stat['write']) {
2621
	                return $this->setError(elFinder::ERROR_PERM_DENIED);
2622
	            }
2623
	        }
2624
2625
	        $files[] = $this->basenameCE($path);
2626
	    }
2627
2628
	    if ($name === '') {
2629
	        $name = count($files) == 1 ? $files[0] : 'Archive';
2630
	    } else {
2631
	        $name = str_replace(['/', '\\'], '_', preg_replace('/\.'.preg_quote($archiver['ext'], '/').'$/i', '', $name));
2632
	    }
2633
	    $name .= '.'.$archiver['ext'];
2634
	    $name = $this->uniqueName($dir, $name, '');
0 ignored issues
show
Bug introduced by
The variable $dir does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2635
	    $this->clearcache();
2636
2637
	    return ($path = $this->convEncOut($this->_archive($this->convEncIn($dir), $this->convEncIn($files), $this->convEncIn($name), $archiver))) ? $this->stat($path) : false;
2638
	}
2639
2640
	/**
2641
	 * Resize image.
2642
	 *
2643
	 * @param  string   $hash    image file
2644
	 * @param  int      $width   new width
2645
	 * @param  int      $height  new height
2646
	 * @param  int      $x       X start poistion for crop
2647
	 * @param  int      $y       Y start poistion for crop
2648
	 * @param  string   $mode    action how to mainpulate image
2649
	 * @param  string   $bg      background color
2650
	 * @param  int      $degree  rotete degree
2651
	 * @param  int      $jpgQuality  JEPG quality (1-100)
2652
	 * @return array|false
2653
	 * @author Dmitry (dio) Levashov
2654
	 * @author Alexey Sukhotin
2655
	 * @author nao-pon
2656
	 * @author Troex Nevelin
2657
	 **/
2658
	public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0, $jpgQuality = null)
2659
	{
2660
	    if ($this->commandDisabled('resize')) {
2661
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2662
	    }
2663
2664
	    if (($file = $this->file($hash)) == false) {
2665
	        return $this->setError(elFinder::ERROR_FILE_NOT_FOUND);
2666
	    }
2667
2668
	    if (! $file['write'] || ! $file['read']) {
2669
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2670
	    }
2671
2672
	    $path = $this->decode($hash);
2673
2674
	    $work_path = $this->getWorkFile($this->encoding ? $this->convEncIn($path, true) : $path);
2675
2676
	    if (! $work_path || ! is_writable($work_path)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $work_path 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...
2677
	        if ($work_path && $path !== $work_path && is_file($work_path)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $work_path 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...
2678
	            unlink($work_path);
2679
	        }
2680
2681
	        return $this->setError(elFinder::ERROR_PERM_DENIED);
2682
	    }
2683
2684
	    if ($this->imgLib !== 'imagick' && $this->imgLib !== 'convert') {
2685
	        if (elFinder::isAnimationGif($work_path)) {
2686
	            return $this->setError(elFinder::ERROR_UNSUPPORT_TYPE);
2687
	        }
2688
	    }
2689
2690
	    switch ($mode) {
2691
2692 View Code Duplication
			case 'propresize':
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...
2693
				$result = $this->imgResize($work_path, $width, $height, true, true, null, $jpgQuality);
2694
				break;
2695
2696
			case 'crop':
2697
				$result = $this->imgCrop($work_path, $width, $height, $x, $y, null, $jpgQuality);
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...
2698
				break;
2699
2700
			case 'fitsquare':
2701
				$result = $this->imgSquareFit($work_path, $width, $height, 'center', 'middle', ($bg ? $bg : $this->options['tmbBgColor']), null, $jpgQuality);
2702
				break;
2703
2704
			case 'rotate':
2705
				$result = $this->imgRotate($work_path, $degree, ($bg ? $bg : $this->options['bgColorFb']), null, $jpgQuality);
2706
				break;
2707
2708 View Code Duplication
			default:
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...
2709
				$result = $this->imgResize($work_path, $width, $height, false, true, null, $jpgQuality);
2710
				break;
2711
		}
2712
2713
	    $ret = false;
2714
	    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...
2715
	        $this->rmTmb($file);
0 ignored issues
show
Documentation introduced by
$file is of type array|boolean, but the function expects a string.

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...
2716
	        $this->clearstatcache();
2717
	        $stat = $this->stat($path);
2718
	        $fstat = stat($work_path);
2719
	        $stat['size'] = $fstat['size'];
2720
	        $stat['ts'] = $fstat['mtime'];
2721
	        if ($imgsize = getimagesize($work_path)) {
2722
	            $stat['width'] = $imgsize[0];
2723
	            $stat['height'] = $imgsize[1];
2724
	            $stat['mime'] = $imgsize['mime'];
2725
	        }
2726
	        if ($path !== $work_path) {
2727
	            if ($fp = fopen($work_path, 'rb')) {
2728
	                $ret = $this->saveCE($fp, $this->dirnameCE($path), $this->basenameCE($path), $stat);
2729
	                fclose($fp);
2730
	            }
2731
	        } else {
2732
	            $ret = true;
2733
	        }
2734
	        if ($ret) {
2735
	            $this->clearcache();
2736
	            $ret = $this->stat($path);
2737
	            $ret['width'] = $stat['width'];
2738
	            $ret['height'] = $stat['height'];
2739
	        }
2740
	    }
2741
	    if ($path !== $work_path) {
2742
	        is_file($work_path) && unlink($work_path);
2743
	    }
2744
2745
	    return $ret;
2746
	}
2747
2748
	/**
2749
	 * Remove file/dir.
2750
	 *
2751
	 * @param  string  $hash  file hash
2752
	 * @return bool
2753
	 * @author Dmitry (dio) Levashov
2754
	 **/
2755
	public function rm($hash)
2756
	{
2757
	    return $this->commandDisabled('rm')
2758
			? $this->setError(elFinder::ERROR_PERM_DENIED)
2759
			: $this->remove($this->decode($hash));
2760
	}
2761
2762
	/**
2763
	 * Search files.
2764
	 *
2765
	 * @param  string $q search string
2766
	 * @param  array $mimes
2767
	 * @param null $hash
2768
	 * @return array
2769
	 * @author Dmitry (dio) Levashov
2770
	 */
2771
	public function search($q, $mimes, $hash = null)
2772
	{
2773
	    $dir = null;
2774
	    if ($hash) {
2775
	        $dir = $this->decode($hash);
2776
	        $stat = $this->stat($dir);
2777
	        if (! $stat || $stat['mime'] !== 'directory' || ! $stat['read']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2778
	            $q = '';
2779
	        }
2780
	    }
2781
	    if ($mimes && $this->onlyMimes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mimes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
Bug Best Practice introduced by
The expression $this->onlyMimes 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...
2782
	        $mimes = array_intersect($mimes, $this->onlyMimes);
2783
	        if (! $mimes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mimes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2784
	            $q = '';
2785
	        }
2786
	    }
2787
	    $this->searchStart = time();
2788
2789
	    $qs = preg_split('/"([^"]+)"| +/', $q, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
2790
	    $query = $excludes = [];
2791
	    foreach ($qs as $_q) {
2792
	        $_q = trim($_q);
2793
	        if ($_q !== '') {
2794
	            if ($_q[0] === '-') {
2795
	                if (isset($_q[1])) {
2796
	                    $excludes[] = substr($_q, 1);
2797
	                }
2798
	            } else {
2799
	                $query[] = $_q;
2800
	            }
2801
	        }
2802
	    }
2803
	    if (! $query) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $query 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...
2804
	        $q = '';
2805
	    } else {
2806
	        $q = implode(' ', $query);
2807
	        $this->doSearchCurrentQuery = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array('q' => $q, 'excludes' => $excludes) of type array<string,string|arra...g","excludes":"array"}> is incompatible with the declared type string of property $doSearchCurrentQuery.

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...
2808
				'q' => $q,
2809
				'excludes' => $excludes,
2810
			];
2811
	    }
2812
2813
		// valided regex $this->options['searchExDirReg']
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2814 View Code Duplication
		if ($this->options['searchExDirReg']) {
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...
2815
		    if (false === preg_match($this->options['searchExDirReg'], '')) {
2816
		        $this->options['searchExDirReg'] = '';
2817
		    }
2818
		}
2819
2820
	    return ($q === '' || $this->commandDisabled('search'))
2821
			? []
2822
			: $this->doSearch(is_null($dir) ? $this->root : $dir, $q, $mimes);
2823
	}
2824
2825
	/**
2826
	 * Return image dimensions.
2827
	 *
2828
	 * @param  string  $hash  file hash
2829
	 * @return array
2830
	 * @author Dmitry (dio) Levashov
2831
	 **/
2832
	public function dimensions($hash)
2833
	{
2834
	    if (($file = $this->file($hash)) == false) {
2835
	        return false;
2836
	    }
2837
2838
	    return $this->convEncOut($this->_dimensions($this->convEncIn($this->decode($hash)), $file['mime']));
2839
	}
2840
2841
	/**
2842
	 * Return has subdirs.
2843
	 *
2844
	 * @param  string  $hash  file hash
2845
	 * @return bool
2846
	 * @author Naoki Sawada
2847
	 **/
2848
	public function subdirs($hash)
2849
	{
2850
	    return (bool) $this->subdirsCE($this->decode($hash));
2851
	}
2852
2853
	/**
2854
	 * Return content URL (for netmout volume driver)
2855
	 * If file.url == 1 requests from JavaScript client with XHR.
2856
	 *
2857
	 * @param string $hash  file hash
2858
	 * @param array $options  options array
2859
	 * @return bool|string
2860
	 * @author Naoki Sawada
2861
	 */
2862
	public function getContentUrl($hash, $options = [])
2863
	{
2864
	    if (($file = $this->file($hash)) === false) {
2865
	        return false;
2866
	    }
2867
	    if (empty($file['url'])) {
2868
	        if ($this->URL) {
2869
	            $path = str_replace($this->separator, '/', substr($this->decode($hash), strlen($this->root) + 1));
2870
	            if ($this->encoding) {
2871
	                $path = $this->convEncIn($path, true);
2872
	            }
2873
	            $path = str_replace('%2F', '/', rawurlencode($path));
2874
2875
	            return $this->URL.$path;
2876
	        }
2877
2878
	        return false;
2879
	    } else {
2880
	        if ($file['url'] != 1) {
2881
	            return $file['url'];
2882
	        } elseif (! empty($options['temporary']) && $this->tmpLinkPath) {
2883
	            $name = 'temp_'.md5($hash);
2884
	            $path = $this->tmpLinkPath.DIRECTORY_SEPARATOR.$name;
2885
	            $contents = $this->getContents($hash);
0 ignored issues
show
Unused Code introduced by
$contents 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...
2886
	            $gc = create_function('$p,$t', 'foreach(glob($p) as $f) { (filemtime($f) < (time() - $t)) && unlink($f); }');
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
2887
				/*$gc = function($p,$t) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
61% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2888
					foreach(glob($p) as $f) {
2889
						(filemtime($f) < (time() - $t)) && unlink($f);
2890
					}
2891
				};*/
2892
				register_shutdown_function($gc, $this->tmpLinkPath.DIRECTORY_SEPARATOR.'temp_*', elFinder::$tmpLinkLifeTime);
2893
	            if (file_put_contents($path, $this->getContents($hash))) {
2894
	                return $this->tmpLinkUrl.'/'.$name;
2895
	            }
2896
	        }
2897
2898
	        return false;
2899
	    }
2900
	}
2901
2902
	/**
2903
	 * Return temp path.
2904
	 *
2905
	 * @return string
2906
	 * @author Naoki Sawada
2907
	 */
2908
	public function getTempPath()
2909
	{
2910
	    $tempPath = null;
2911
	    if (isset($this->tmpPath) && $this->tmpPath && is_writable($this->tmpPath)) {
2912
	        $tempPath = $this->tmpPath;
0 ignored issues
show
Bug introduced by
The property tmpPath 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...
2913
	    } elseif (isset($this->tmp) && $this->tmp && is_writable($this->tmp)) {
0 ignored issues
show
Bug introduced by
The property tmp does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2914
	        $tempPath = $this->tmp;
2915
	    } elseif (function_exists('sys_get_temp_dir')) {
2916
	        $tempPath = sys_get_temp_dir();
2917
	    } elseif ($this->tmbPathWritable) {
2918
	        $tempPath = $this->tmbPath;
2919
	    }
2920
	    if ($tempPath && DIRECTORY_SEPARATOR !== '/') {
2921
	        $tempPath = str_replace('/', DIRECTORY_SEPARATOR, $tempPath);
2922
	    }
2923
2924
	    return $tempPath;
2925
	}
2926
2927
	/**
2928
	 * (Make &) Get upload taget dirctory hash.
2929
	 *
2930
	 * @param string $baseTargetHash
2931
	 * @param string $path
2932
	 * @param array  $result
2933
	 * @return bool|string
2934
	 * @author Naoki Sawada
2935
	 */
2936
	public function getUploadTaget($baseTargetHash, $path, &$result)
2937
	{
2938
	    $base = $this->decode($baseTargetHash);
2939
	    $targetHash = $baseTargetHash;
2940
	    $path = ltrim($path, $this->separator);
2941
	    $dirs = explode($this->separator, $path);
2942
	    array_pop($dirs);
2943
	    foreach ($dirs as $dir) {
2944
	        $targetPath = $this->joinPathCE($base, $dir);
2945
	        if (! $_realpath = $this->realpath($this->encode($targetPath))) {
2946
	            if ($stat = $this->mkdir($targetHash, $dir)) {
2947
	                $result['added'][] = $stat;
2948
	                $targetHash = $stat['hash'];
2949
	                $base = $this->decode($targetHash);
2950
	            } else {
2951
	                return false;
2952
	            }
2953
	        } else {
2954
	            $targetHash = $this->encode($_realpath);
2955
	            if ($this->dir($targetHash)) {
2956
	                $base = $this->decode($targetHash);
2957
	            } else {
2958
	                return false;
2959
	            }
2960
	        }
2961
	    }
2962
2963
	    return $targetHash;
2964
	}
2965
2966
	/**
2967
	 * Return this uploadMaxSize value.
2968
	 *
2969
	 * @return int
2970
	 * @author Naoki Sawada
2971
	 */
2972
	public function getUploadMaxSize()
2973
	{
2974
	    return $this->uploadMaxSize;
2975
	}
2976
2977
    public function setUploadOverwrite($var)
2978
    {
2979
        $this->uploadOverwrite = (bool) $var;
0 ignored issues
show
Documentation Bug introduced by
The property $uploadOverwrite was declared of type string, but (bool) $var is of type boolean. Maybe add a type cast?

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

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

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
2980
    }
2981
2982
	/**
2983
	 * Image file utility.
2984
	 *
2985
	 * @param string $mode     'resize', 'rotate', 'propresize', 'crop', 'fitsquare'
2986
	 * @param string $src      Image file local path
2987
	 * @param array  $options  excute options
2988
	 * @return bool
2989
	 * @author Naoki Sawada
2990
	 */
2991
	public function imageUtil($mode, $src, $options = [])
2992
	{
2993
	    if (! isset($options['jpgQuality'])) {
2994
	        $options['jpgQuality'] = intval($this->options['jpgQuality']);
2995
	    }
2996
	    if (! isset($options['bgcolor'])) {
2997
	        $options['bgcolor'] = '#ffffff';
2998
	    }
2999
	    if (! isset($options['bgColorFb'])) {
3000
	        $options['bgColorFb'] = $this->options['bgColorFb'];
3001
	    }
3002
3003
		// check 'width' ,'height'
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
3004
		if (in_array($mode, ['resize', 'propresize', 'crop', 'fitsquare'])) {
3005
		    if (empty($options['width']) || empty($options['height'])) {
3006
		        return false;
3007
		    }
3008
		}
3009
3010
	    switch ($mode) {
3011
			case 'rotate':
3012
				if (empty($options['degree'])) {
3013
				    return true;
3014
				}
3015
3016
				return (bool) $this->imgRotate($src, $options['degree'], $options['bgColorFb'], null, $options['jpgQuality']);
3017
3018 View Code Duplication
			case 'resize':
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...
3019
				return (bool) $this->imgResize($src, $options['width'], $options['height'], false, true, null, $options['jpgQuality'], $options);
3020
3021 View Code Duplication
			case 'propresize':
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...
3022
				return (bool) $this->imgResize($src, $options['width'], $options['height'], true, true, null, $options['jpgQuality'], $options);
3023
3024
			case 'crop':
3025
				if (isset($options['x']) && isset($options['y'])) {
3026
				    return (bool) $this->imgCrop($src, $options['width'], $options['height'], $options['x'], $options['y'], null, $options['jpgQuality']);
3027
				}
3028
				break;
3029
3030
			case 'fitsquare':
3031
				return (bool) $this->imgSquareFit($src, $options['width'], $options['height'], 'center', 'middle', $options['bgcolor'], null, $options['jpgQuality']);
3032
3033
		}
3034
3035
	    return false;
3036
	}
3037
3038
	/**
3039
	 * Convert Video To Image by ffmpeg.
3040
	 *
3041
	 * @param  $file video source file path
3042
	 * @param  $stat file stat array
3043
	 * @return bool
3044
	 * @author Naoki Sawada
3045
	 */
3046
	public function ffmpegToImg($file, $stat)
0 ignored issues
show
Coding Style introduced by
ffmpegToImg uses the super-global variable $GLOBALS which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3047
	{
3048
	    $name = basename($file);
3049
	    $path = dirname($file);
3050
	    $tmp = $path.DIRECTORY_SEPARATOR.md5($name);
3051
	    $GLOBALS['elFinderTempFiles'][] = $tmp; // regist to remove at the end
3052
		if (rename($file, $tmp)) {
3053
		    // specific start time by file name (xxx^[sec].[extention] - video^3.mp4)
3054
			if (preg_match('/\^(\d+(?:\.\d+)?)\.[^.]+$/', $stat['name'], $_m)) {
3055
			    $ss = $_m[1];
3056
			} else {
3057
			    $ss = $this->options['tmbVideoConvSec'];
3058
			}
3059
		    $cmd = sprintf('ffmpeg -i %s -ss 00:00:%.3f -vframes 1 -f image2 %s', escapeshellarg($tmp), $ss, escapeshellarg($file));
3060
		    $r = $this->procExec($cmd);
3061
		    unlink($tmp);
3062
3063
		    return $r === 0;
3064
		}
3065
3066
	    return false;
3067
	}
3068
3069
	/**
3070
	 * Return new unique name based on file name and suffix.
3071
	 *
3072
	 * @param $dir
3073
	 * @param $name
3074
	 * @param  string $suffix suffix append to name
3075
	 * @param bool $checkNum
3076
	 * @param int $start
3077
	 * @return string
3078
	 * @internal param string $path file path
3079
	 * @author Dmitry (dio) Levashov
3080
	 */
3081
	public function uniqueName($dir, $name, $suffix = ' copy', $checkNum = true, $start = 1)
3082
	{
3083
	    $ext = '';
3084
3085
	    if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) {
3086
	        $ext = '.'.$m[1];
3087
	        $name = substr($name, 0, strlen($name) - strlen($m[0]));
3088
	    }
3089
3090
	    if ($checkNum && preg_match('/('.preg_quote($suffix, '/').')(\d*)$/i', $name, $m)) {
3091
	        $i = (int) $m[2];
3092
	        $name = substr($name, 0, strlen($name) - strlen($m[2]));
3093
	    } else {
3094
	        $i = $start;
3095
	        $name .= $suffix;
3096
	    }
3097
	    $max = $i + 100000;
3098
3099
	    while ($i <= $max) {
3100
	        $n = $name.($i > 0 ? sprintf($this->options['uniqueNumFormat'], $i) : '').$ext;
3101
3102
	        if (! $this->isNameExists($this->joinPathCE($dir, $n))) {
3103
	            $this->clearcache();
3104
3105
	            return $n;
3106
	        }
3107
	        $i++;
3108
	    }
3109
3110
	    return $name.md5($dir).$ext;
3111
	}
3112
3113
	/**
3114
	 * Converts character encoding from UTF-8 to server's one.
3115
	 *
3116
	 * @param  mixed  $var           target string or array var
3117
	 * @param  bool   $restoreLocale do retore global locale, default is false
3118
	 * @param  string $unknown       replaces character for unknown
3119
	 * @return mixed
3120
	 * @author Naoki Sawada
3121
	 */
3122
	public function convEncIn($var = null, $restoreLocale = false, $unknown = '_')
3123
	{
3124
	    return (! $this->encoding) ? $var : $this->convEnc($var, 'UTF-8', $this->encoding, $this->options['locale'], $restoreLocale, $unknown);
3125
	}
3126
3127
	/**
3128
	 * Converts character encoding from server's one to UTF-8.
3129
	 *
3130
	 * @param  mixed  $var           target string or array var
3131
	 * @param  bool   $restoreLocale do retore global locale, default is true
3132
	 * @param  string $unknown       replaces character for unknown
3133
	 * @return mixed
3134
	 * @author Naoki Sawada
3135
	 */
3136
	public function convEncOut($var = null, $restoreLocale = true, $unknown = '_')
3137
	{
3138
	    return (! $this->encoding) ? $var : $this->convEnc($var, $this->encoding, 'UTF-8', $this->options['locale'], $restoreLocale, $unknown);
3139
	}
3140
3141
	/**
3142
	 * Get image size array with `dimensions`.
3143
	 *
3144
	 * @param string $path path need convert encoding to server encoding
3145
	 * @param string $mime file mime type
3146
	 * @return array|false
3147
	 */
3148
	public function getImageSize($path, $mime = '')
3149
	{
3150
	    $size = false;
3151
	    if ($mime === '' || strtolower(substr($mime, 0, 5)) === 'image') {
3152
	        if ($work = $this->getWorkFile($path)) {
3153
	            if ($size = getimagesize($work)) {
3154
	                $size['dimensions'] = $size[0].'x'.$size[1];
3155
	            }
3156
	        }
3157
	        is_file($work) && unlink($work);
3158
	    }
3159
3160
	    return $size;
3161
	}
3162
3163
	/**
3164
	 * Remove directory recursive on local file system.
3165
	 *
3166
	 * @param string $dir Target dirctory path
3167
	 * @return bool
3168
	 * @author Naoki Sawada
3169
	 */
3170
	public function rmdirRecursive($dir)
3171
	{
3172
	    return self::localRmdirRecursive($dir);
3173
	}
3174
3175
	/*********************************************************************/
3176
	/*                            INITIALIZATION                         */
3177
	/*********************************************************************/
3178
3179
	/**
3180
	 * Prepare driver before mount volume.
3181
	 * Return true if volume is ready.
3182
	 *
3183
	 * @return bool
3184
	 * @author Dmitry (dio) Levashov
3185
	 **/
3186
	protected function init()
3187
	{
3188
	    return true;
3189
	}
3190
3191
	/**
3192
	 * Configure after successfull mount.
3193
	 * By default set thumbnails path and image manipulation library.
3194
	 *
3195
	 * @return void
3196
	 * @author Dmitry (dio) Levashov
3197
	 **/
3198
	protected function configure()
3199
	{
3200
	    // set thumbnails path
3201
		$path = $this->options['tmbPath'];
3202
	    if ($path) {
3203 View Code Duplication
	        if (! file_exists($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...
3204
	            if (mkdir($path)) {
3205
	                chmod($path, $this->options['tmbPathMode']);
3206
	            } else {
3207
	                $path = '';
3208
	            }
3209
	        }
3210
3211
	        if (is_dir($path) && is_readable($path)) {
3212
	            $this->tmbPath = $path;
3213
	            $this->tmbPathWritable = is_writable($path);
3214
	        }
3215
	    }
3216
		// set resouce path
3217
		if (! is_dir($this->options['resourcePath'])) {
3218
		    $this->options['resourcePath'] = dirname(__FILE__).DIRECTORY_SEPARATOR.'resources';
3219
		}
3220
3221
		// set image manipulation library
3222
		$type = preg_match('/^(imagick|gd|convert|auto)$/i', $this->options['imgLib'])
3223
			? strtolower($this->options['imgLib'])
3224
			: 'auto';
3225
3226
	    $imgLibFallback = extension_loaded('imagick') ? 'imagick' : (function_exists('gd_info') ? 'gd' : '');
0 ignored issues
show
Unused Code introduced by
$imgLibFallback 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...
3227
	    if (($type === 'imagick' || $type === 'auto') && extension_loaded('imagick')) {
3228
	        $this->imgLib = 'imagick';
3229
	    } elseif (($type === 'gd' || $type === 'auto') && function_exists('gd_info')) {
3230
	        $this->imgLib = 'gd';
3231
	    } else {
3232
	        $convertCache = 'imgLibConvert';
3233
	        if (($convertCmd = $this->session->get($convertCache, false)) !== false) {
3234
	            $this->imgLib = $convertCmd;
3235
	        } else {
3236
	            $this->imgLib = ($this->procExec('convert -version') === 0) ? 'convert' : '';
3237
	            $this->session->set($convertCache, $this->imgLib);
3238
	        }
3239
	    }
3240
	    if ($type !== 'auto' && $this->imgLib === '') {
3241
	        // fallback
3242
			$this->imgLib = extension_loaded('imagick') ? 'imagick' : (function_exists('gd_info') ? 'gd' : '');
3243
	    }
3244
3245
		// check video to img converter
3246 View Code Duplication
		if (! empty($this->options['imgConverter']) && is_array($this->options['imgConverter'])) {
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...
3247
		    foreach ($this->options['imgConverter'] as $_type => $_converter) {
3248
		        if (isset($_converter['func'])) {
3249
		            $this->imgConverter[strtolower($_type)] = $_converter;
3250
		        }
3251
		    }
3252
		}
3253
	    if (! isset($this->imgConverter['video'])) {
3254
	        $videoLibCache = 'videoLib';
3255
	        if (($videoLibCmd = $this->session->get($videoLibCache, false)) === false) {
3256
	            $videoLibCmd = ($this->procExec('ffmpeg -version') === 0) ? 'ffmpeg' : '';
3257
	            $this->session->set($videoLibCache, $videoLibCmd);
3258
	        }
3259
	        if ($videoLibCmd) {
3260
	            $this->imgConverter['video'] = [
3261
					'func' => [$this, $videoLibCmd.'ToImg'],
3262
					'maxlen' => $this->options['tmbVideoConvLen'],
3263
				];
3264
	        }
3265
	    }
3266
3267
		// check archivers
3268
		if (empty($this->archivers['create'])) {
3269
		    $this->disabled[] = 'archive';
3270
		}
3271
	    if (empty($this->archivers['extract'])) {
3272
	        $this->disabled[] = 'extract';
3273
	    }
3274
	    $_arc = $this->getArchivers();
3275
	    if (empty($_arc['create'])) {
3276
	        $this->disabled[] = 'zipdl';
3277
	    }
3278
3279
		// check 'statOwner' for command `chmod`
3280
		if (empty($this->options['statOwner'])) {
3281
		    $this->disabled[] = 'chmod';
3282
		}
3283
3284
		// check 'mimeMap'
3285
		if (! is_array($this->options['mimeMap'])) {
3286
		    $this->options['mimeMap'] = [];
3287
		}
3288 View Code Duplication
	    if (is_array($this->options['staticMineMap']) && $this->options['staticMineMap']) {
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...
3289
	        $this->options['mimeMap'] = array_merge($this->options['mimeMap'], $this->options['staticMineMap']);
3290
	    }
3291 View Code Duplication
	    if (is_array($this->options['additionalMimeMap']) && $this->options['additionalMimeMap']) {
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...
3292
	        $this->options['mimeMap'] = array_merge($this->options['mimeMap'], $this->options['additionalMimeMap']);
3293
	    }
3294
3295
		// check 'url' in disabled commands
3296
		if (in_array('url', $this->disabled)) {
3297
		    $this->disabledGetUrl = true;
0 ignored issues
show
Documentation Bug introduced by
The property $disabledGetUrl was declared of type string, but true is of type boolean. Maybe add a type cast?

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

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

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
3298
		}
3299
3300
		// set run time setting uploadOverwrite
3301
		$this->uploadOverwrite = $this->options['uploadOverwrite'];
3302
	}
3303
3304
	/**
3305
	 * @deprecated
3306
	 */
3307
	protected function sessionRestart()
3308
	{
3309
	    $this->sessionCache = $this->session->start()->get($this->id, []);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->session->start()->get($this->id, array()) of type * is incompatible with the declared type array of property $sessionCache.

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...
3310
3311
	    return true;
3312
	}
3313
3314
	/**
3315
	 * Save error message.
3316
	 *
3317
	 * @param  array  error
3318
	 * @return false
3319
	 * @author Naoki Sawada
3320
	 **/
3321
	protected function setError()
3322
	{
3323
	    $this->error = [];
3324
	    $this->addError(func_get_args());
3325
3326
	    return false;
3327
	}
3328
3329
	/**
3330
	 * Add error message.
3331
	 *
3332
	 * @param  array  error
3333
	 * @return false
3334
	 * @author Dmitry(dio) Levashov
3335
	 **/
3336
	protected function addError()
3337
	{
3338
	    foreach (func_get_args() as $err) {
3339
	        if (is_array($err)) {
3340
	            $this->error = array_merge($this->error, $err);
3341
	        } else {
3342
	            $this->error[] = $err;
3343
	        }
3344
	    }
3345
3346
	    return false;
3347
	}
3348
3349
	/*********************************************************************/
3350
	/*                               FS API                              */
3351
	/*********************************************************************/
3352
3353
	/***************** server encoding support *******************/
3354
3355
	/**
3356
	 * Return parent directory path (with convert encoding).
3357
	 *
3358
	 * @param  string  $path  file path
3359
	 * @return string
3360
	 * @author Naoki Sawada
3361
	 **/
3362
	protected function dirnameCE($path)
3363
	{
3364
	    $dirname = (! $this->encoding) ? $this->_dirname($path) : $this->convEncOut($this->_dirname($this->convEncIn($path)));
3365
		// check to infinite loop prevention
3366
		return ($dirname != $path) ? $dirname : '';
3367
	}
3368
3369
	/**
3370
	 * Return file name (with convert encoding).
3371
	 *
3372
	 * @param  string  $path  file path
3373
	 * @return string
3374
	 * @author Naoki Sawada
3375
	 **/
3376
	protected function basenameCE($path)
3377
	{
3378
	    return (! $this->encoding) ? $this->_basename($path) : $this->convEncOut($this->_basename($this->convEncIn($path)));
3379
	}
3380
3381
	/**
3382
	 * Join dir name and file name and return full path. (with convert encoding)
3383
	 * Some drivers (db) use int as path - so we give to concat path to driver itself.
3384
	 *
3385
	 * @param  string  $dir   dir path
3386
	 * @param  string  $name  file name
3387
	 * @return string
3388
	 * @author Naoki Sawada
3389
	 **/
3390
	protected function joinPathCE($dir, $name)
3391
	{
3392
	    return (! $this->encoding) ? $this->_joinPath($dir, $name) : $this->convEncOut($this->_joinPath($this->convEncIn($dir), $this->convEncIn($name)));
3393
	}
3394
3395
	/**
3396
	 * Return normalized path (with convert encoding).
3397
	 *
3398
	 * @param  string  $path  file path
3399
	 * @return string
3400
	 * @author Naoki Sawada
3401
	 **/
3402
	protected function normpathCE($path)
3403
	{
3404
	    return (! $this->encoding) ? $this->_normpath($path) : $this->convEncOut($this->_normpath($this->convEncIn($path)));
3405
	}
3406
3407
	/**
3408
	 * Return file path related to root dir (with convert encoding).
3409
	 *
3410
	 * @param  string  $path  file path
3411
	 * @return string
3412
	 * @author Naoki Sawada
3413
	 **/
3414
	protected function relpathCE($path)
3415
	{
3416
	    return (! $this->encoding) ? $this->_relpath($path) : $this->convEncOut($this->_relpath($this->convEncIn($path)));
3417
	}
3418
3419
	/**
3420
	 * Convert path related to root dir into real path (with convert encoding).
3421
	 *
3422
	 * @param  string  $path  rel file path
3423
	 * @return string
3424
	 * @author Naoki Sawada
3425
	 **/
3426
	protected function abspathCE($path)
3427
	{
3428
	    return (! $this->encoding) ? $this->_abspath($path) : $this->convEncOut($this->_abspath($this->convEncIn($path)));
3429
	}
3430
3431
	/**
3432
	 * Return true if $path is children of $parent (with convert encoding).
3433
	 *
3434
	 * @param  string  $path    path to check
3435
	 * @param  string  $parent  parent path
3436
	 * @return bool
3437
	 * @author Naoki Sawada
3438
	 **/
3439
	protected function inpathCE($path, $parent)
3440
	{
3441
	    return (! $this->encoding) ? $this->_inpath($path, $parent) : $this->convEncOut($this->_inpath($this->convEncIn($path), $this->convEncIn($parent)));
3442
	}
3443
3444
	/**
3445
	 * Open file and return file pointer (with convert encoding).
3446
	 *
3447
	 * @param  string $path file path
3448
	 * @param string $mode
3449
	 * @return false|resource
3450
	 * @internal param bool $write open file for writing
3451
	 * @author Naoki Sawada
3452
	 */
3453
	protected function fopenCE($path, $mode = 'rb')
3454
	{
3455
	    return (! $this->encoding) ? $this->_fopen($path, $mode) : $this->convEncOut($this->_fopen($this->convEncIn($path), $mode));
3456
	}
3457
3458
	/**
3459
	 * Close opened file (with convert encoding).
3460
	 *
3461
	 * @param  resource  $fp    file pointer
3462
	 * @param  string    $path  file path
3463
	 * @return bool
3464
	 * @author Naoki Sawada
3465
	 **/
3466
	protected function fcloseCE($fp, $path = '')
3467
	{
3468
	    return (! $this->encoding) ? $this->_fclose($fp, $path) : $this->convEncOut($this->_fclose($fp, $this->convEncIn($path)));
3469
	}
3470
3471
	/**
3472
	 * Create new file and write into it from file pointer. (with convert encoding)
3473
	 * Return new file path or false on error.
3474
	 *
3475
	 * @param  resource  $fp   file pointer
3476
	 * @param  string    $dir  target dir path
3477
	 * @param  string    $name file name
3478
	 * @param  array     $stat file stat (required by some virtual fs)
3479
	 * @return bool|string
3480
	 * @author Naoki Sawada
3481
	 **/
3482
	protected function saveCE($fp, $dir, $name, $stat)
3483
	{
3484
	    return (! $this->encoding) ? $this->_save($fp, $dir, $name, $stat) : $this->convEncOut($this->_save($fp, $this->convEncIn($dir), $this->convEncIn($name), $this->convEncIn($stat)));
3485
	}
3486
3487
	/**
3488
	 * Return true if path is dir and has at least one childs directory (with convert encoding).
3489
	 *
3490
	 * @param  string  $path  dir path
3491
	 * @return bool
3492
	 * @author Naoki Sawada
3493
	 **/
3494
	protected function subdirsCE($path)
3495
	{
3496 View Code Duplication
	    if ($this->sessionCaching['subdirs']) {
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...
3497
	        if (isset($this->sessionCache['subdirs'][$path]) && ! $this->isMyReload()) {
3498
	            return $this->sessionCache['subdirs'][$path];
3499
	        }
3500
	    }
3501
	    $hasdir = (bool) ((! $this->encoding) ? $this->_subdirs($path) : $this->convEncOut($this->_subdirs($this->convEncIn($path))));
3502
	    $this->updateSubdirsCache($path, $hasdir);
3503
3504
	    return $hasdir;
3505
	}
3506
3507
	/**
3508
	 * Return files list in directory (with convert encoding).
3509
	 *
3510
	 * @param  string  $path  dir path
3511
	 * @return array
3512
	 * @author Naoki Sawada
3513
	 **/
3514
	protected function scandirCE($path)
3515
	{
3516
	    return (! $this->encoding) ? $this->_scandir($path) : $this->convEncOut($this->_scandir($this->convEncIn($path)));
3517
	}
3518
3519
	/**
3520
	 * Create symlink (with convert encoding).
3521
	 *
3522
	 * @param  string  $source     file to link to
3523
	 * @param  string  $targetDir  folder to create link in
3524
	 * @param  string  $name       symlink name
3525
	 * @return bool
3526
	 * @author Naoki Sawada
3527
	 **/
3528
	protected function symlinkCE($source, $targetDir, $name)
3529
	{
3530
	    return (! $this->encoding) ? $this->_symlink($source, $targetDir, $name) : $this->convEncOut($this->_symlink($this->convEncIn($source), $this->convEncIn($targetDir), $this->convEncIn($name)));
3531
	}
3532
3533
	/***************** paths *******************/
3534
3535
	/**
3536
	 * Encode path into hash.
3537
	 *
3538
	 * @param  string  file path
3539
	 * @return string
3540
	 * @author Dmitry (dio) Levashov
3541
	 * @author Troex Nevelin
3542
	 **/
3543
	protected function encode($path)
3544
	{
3545
	    if ($path !== '') {
3546
3547
			// cut ROOT from $path for security reason, even if hacker decodes the path he will not know the root
3548
			$p = $this->relpathCE($path);
3549
			// if reqesting root dir $path will be empty, then assign '/' as we cannot leave it blank for crypt
3550
			if ($p === '') {
3551
			    $p = $this->separator;
3552
			}
3553
3554
			// TODO crypt path and return hash
3555
			$hash = $this->crypt($p);
3556
			// hash is used as id in HTML that means it must contain vaild chars
3557
			// make base64 html safe and append prefix in begining
3558
			$hash = strtr(base64_encode($hash), '+/=', '-_.');
3559
			// remove dots '.' at the end, before it was '=' in base64
3560
			$hash = rtrim($hash, '.');
3561
			// append volume id to make hash unique
3562
			return $this->id.$hash;
3563
	    }
3564
	    //TODO: Add return statement here
3565
	}
3566
3567
	/**
3568
	 * Decode path from hash.
3569
	 *
3570
	 * @param  string  file hash
3571
	 * @return string
3572
	 * @author Dmitry (dio) Levashov
3573
	 * @author Troex Nevelin
3574
	 **/
3575
	protected function decode($hash)
3576
	{
3577
	    if (strpos($hash, $this->id) === 0) {
3578
	        // cut volume id after it was prepended in encode
3579
			$h = substr($hash, strlen($this->id));
3580
			// replace HTML safe base64 to normal
3581
			$h = base64_decode(strtr($h, '-_.', '+/='));
3582
			// TODO uncrypt hash and return path
3583
			$path = $this->uncrypt($h);
3584
			// append ROOT to path after it was cut in encode
3585
			return $this->abspathCE($path); //$this->root.($path === $this->separator ? '' : $this->separator.$path);
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
3586
	    }
3587
	    //TODO: Add return statement here
3588
	}
3589
3590
	/**
3591
	 * Return crypted path
3592
	 * Not implemented.
3593
	 *
3594
	 * @param  string  path
3595
	 * @return mixed
3596
	 * @author Dmitry (dio) Levashov
3597
	 **/
3598
	protected function crypt($path)
3599
	{
3600
	    return $path;
3601
	}
3602
3603
	/**
3604
	 * Return uncrypted path
3605
	 * Not implemented.
3606
	 *
3607
	 * @param  mixed  hash
3608
	 * @return mixed
3609
	 * @author Dmitry (dio) Levashov
3610
	 **/
3611
	protected function uncrypt($hash)
3612
	{
3613
	    return $hash;
3614
	}
3615
3616
	/**
3617
	 * Validate file name based on $this->options['acceptedName'] regexp or function.
3618
	 *
3619
	 * @param  string  $name  file name
3620
	 * @return bool
3621
	 * @author Dmitry (dio) Levashov
3622
	 **/
3623
	protected function nameAccepted($name, $isDir = false)
3624
	{
3625
	    if (json_encode($name) === false) {
3626
	        return false;
3627
	    }
3628
	    $nameValidator = $isDir ? $this->dirnameValidator : $this->nameValidator;
3629
	    if ($nameValidator) {
3630
	        if (is_callable($nameValidator)) {
3631
	            $res = call_user_func($nameValidator, $name);
3632
3633
	            return $res;
3634
	        }
3635
	        if (preg_match($nameValidator, '') !== false) {
3636
	            return preg_match($nameValidator, $name);
3637
	        }
3638
	    }
3639
3640
	    return true;
3641
	}
3642
3643
	/**
3644
	 * Return session rootstat cache key.
3645
	 *
3646
	 * @return string
3647
	 */
3648
	protected function getRootstatCachekey()
3649
	{
3650
	    return md5($this->root.(isset($this->options['alias']) ? $this->options['alias'] : ''));
3651
	}
3652
3653
	/**
3654
	 * Converts character encoding (base function).
3655
	 *
3656
	 * @param  mixed $var target string or array var
3657
	 * @param  string $from from character encoding
3658
	 * @param  string $to to character encoding
3659
	 * @param  string $locale local locale
3660
	 * @param $restoreLocale
3661
	 * @param  string $unknown replaces character for unknown
3662
	 * @return mixed
3663
	 */
3664
	protected function convEnc($var, $from, $to, $locale, $restoreLocale, $unknown = '_')
3665
	{
3666
	    if (strtoupper($from) !== strtoupper($to)) {
3667
	        if ($locale) {
3668
	            setlocale(LC_ALL, $locale);
3669
	        }
3670
	        if (is_array($var)) {
3671
	            $_ret = [];
3672
	            foreach ($var as $_k => $_v) {
3673
	                $_ret[$_k] = $this->convEnc($_v, $from, $to, '', false, $unknown = '_');
3674
	            }
3675
	            $var = $_ret;
3676
	        } else {
3677
	            $_var = false;
3678
	            if (is_string($var)) {
3679
	                $_var = $var;
3680
	                if (false !== ($_var = iconv($from, $to.'//TRANSLIT', $_var))) {
3681
	                    $_var = str_replace('?', $unknown, $_var);
3682
	                }
3683
	            }
3684
	            if ($_var !== false) {
3685
	                $var = $_var;
3686
	            }
3687
	        }
3688
	        if ($restoreLocale) {
3689
	            setlocale(LC_ALL, elFinder::$locale);
3690
	        }
3691
	    }
3692
3693
	    return $var;
3694
	}
3695
3696
	/*********************** util mainly for inheritance class *********************/
3697
3698
	/**
3699
	 * Get temporary filename. Tempfile will be removed when after script execution finishes or exit() is called.
3700
	 * When needing the unique file to a path, give $path to parameter.
3701
	 *
3702
	 * @param  string       $path for get unique file to a path
3703
	 * @return string|false
3704
	 * @author Naoki Sawada
3705
	 */
3706
	protected function getTempFile($path = '')
3707
	{
3708
	    static $cache = [];
3709
	    static $rmfunc;
3710
3711
	    $key = '';
3712
	    if ($path !== '') {
3713
	        $key = $this->id.'#'.$path;
3714
	        if (isset($cache[$key])) {
3715
	            return $cache[$key];
3716
	        }
3717
	    }
3718
3719
	    if ($tmpdir = $this->getTempPath()) {
3720
	        if (! $rmfunc) {
3721
	            $rmfunc = create_function('$f', 'is_file($f) && unlink($f);');
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
3722
	        }
3723
	        $name = tempnam($tmpdir, 'ELF');
3724
	        if ($key) {
3725
	            $cache[$key] = $name;
3726
	        }
3727
	        register_shutdown_function($rmfunc, $name);
3728
3729
	        return $name;
3730
	    }
3731
3732
	    return false;
3733
	}
3734
3735
	/**
3736
	 * File path of local server side work file path.
3737
	 *
3738
	 * @param  string $path path need convert encoding to server encoding
3739
	 * @return string
3740
	 * @author Naoki Sawada
3741
	 */
3742
	protected function getWorkFile($path)
3743
	{
3744
	    if ($work = $this->getTempFile()) {
3745
	        if ($wfp = fopen($work, 'wb')) {
3746
	            if ($fp = $this->_fopen($path)) {
3747
	                while (! feof($fp)) {
3748
	                    fwrite($wfp, fread($fp, 8192));
3749
	                }
3750
	                $this->_fclose($fp, $path);
3751
	                fclose($wfp);
3752
3753
	                return $work;
3754
	            }
3755
	        }
3756
	    }
3757
3758
	    return false;
3759
	}
3760
3761
	/**
3762
	 * Delete dirctory trees.
3763
	 *
3764
	 * @param string $localpath path need convert encoding to server encoding
3765
	 * @return bool
3766
	 * @author Naoki Sawada
3767
	 */
3768
	protected function delTree($localpath)
3769
	{
3770
	    foreach ($this->_scandir($localpath) as $p) {
3771
	        elFinder::extendTimeLimit();
3772
	        $stat = $this->stat($this->convEncOut($p));
3773
	        $this->convEncIn();
3774
	        ($stat['mime'] === 'directory') ? $this->delTree($p) : $this->_unlink($p);
3775
	    }
3776
3777
	    return $this->_rmdir($localpath);
3778
	}
3779
3780
	/**
3781
	 * Copy items to a new temporary directory on the local server.
3782
	 *
3783
	 * @param  array  $hashes  target hashes
3784
	 * @param  string $dir     destination directory (for recurcive)
3785
	 * @param  string $canLink it can use link() (for recurcive)
3786
	 * @return string|false    saved path name
3787
	 * @author Naoki Sawada
3788
	 */
3789
	protected function getItemsInHand($hashes, $dir = null, $canLink = null)
3790
	{
3791
	    static $totalSize = 0;
3792
	    if (is_null($dir)) {
3793
	        $totalSize = 0;
3794
	        if (! $tmpDir = $this->getTempPath()) {
3795
	            return false;
3796
	        }
3797
	        $dir = tempnam($tmpDir, 'elf');
3798
	        if (! unlink($dir) || ! mkdir($dir, 0700, true)) {
3799
	            return false;
3800
	        }
3801
	        register_shutdown_function([$this, 'rmdirRecursive'], $dir);
3802
	    }
3803
	    if (is_null($canLink)) {
3804
	        $canLink = ($this instanceof elFinderVolumeLocalFileSystem);
3805
	    }
3806
	    elFinder::extendTimeLimit();
3807
	    $res = true;
3808
	    $files = [];
3809
	    foreach ($hashes as $hash) {
3810
	        if (($file = $this->file($hash)) == false) {
3811
	            continue;
3812
	        }
3813
	        if (! $file['read']) {
3814
	            continue;
3815
	        }
3816
3817
	        $name = $file['name'];
3818
			// for call from search results
3819
			if (isset($files[$name])) {
3820
			    $name = preg_replace('/^(.*?)(\..*)?$/', '$1_'.$files[$name]++.'$2', $name);
3821
			} else {
3822
			    $files[$name] = 1;
3823
			}
3824
	        $target = $dir.DIRECTORY_SEPARATOR.$name;
3825
3826
	        if ($file['mime'] === 'directory') {
3827
	            $chashes = [];
3828
	            $_files = $this->scandir($hash);
3829
	            foreach ($_files as $_file) {
0 ignored issues
show
Bug introduced by
The expression $_files of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

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

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

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

Loading history...
3830
	                if ($file['read']) {
3831
	                    $chashes[] = $_file['hash'];
3832
	                }
3833
	            }
3834
	            if (($res = mkdir($target, 0700, true)) && $chashes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $chashes 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...
3835
	                $res = $this->getItemsInHand($chashes, $target, $canLink);
0 ignored issues
show
Bug introduced by
It seems like $canLink can also be of type boolean; however, elFinderVolumeDriver::getItemsInHand() does only seem to accept string|null, 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...
3836
	            }
3837
	            if (! $res) {
3838
	                break;
3839
	            }
3840
	            ! empty($file['ts']) && touch($target, $file['ts']);
3841
	        } else {
3842
	            $path = $this->decode($hash);
3843
	            if (! $canLink || ! ($canLink = link($path, $target))) {
3844
	                if ($fp = $this->fopenCE($path)) {
3845
	                    if ($tfp = fopen($target, 'wb')) {
3846
	                        $totalSize += stream_copy_to_stream($fp, $tfp);
3847
	                        fclose($tfp);
3848
	                    }
3849
	                    ! empty($file['ts']) && touch($target, $file['ts']);
3850
	                    $this->fcloseCE($fp, $path);
3851
	                }
3852
	            } else {
3853
	                $totalSize += filesize($path);
3854
	            }
3855
	            if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $totalSize) {
3856
	                $res = $this->setError(elFinder::ERROR_ARC_MAXSIZE);
3857
	            }
3858
	        }
3859
	    }
3860
3861
	    return $res ? $dir : false;
3862
	}
3863
3864
	/*********************** file stat *********************/
3865
3866
	/**
3867
	 * Check file attribute.
3868
	 *
3869
	 * @param  string  $path  file path
3870
	 * @param  string  $name  attribute name (read|write|locked|hidden)
3871
	 * @param  bool    $val   attribute value returned by file system
3872
	 * @param  bool    $isDir path is directory (true: directory, false: file)
3873
	 * @return bool
3874
	 * @author Dmitry (dio) Levashov
3875
	 **/
3876
	protected function attr($path, $name, $val = null, $isDir = null)
3877
	{
3878
	    if (! isset($this->defaults[$name])) {
3879
	        return false;
3880
	    }
3881
3882
	    $relpath = $this->relpathCE($path);
3883
	    if ($this->separator !== '/') {
3884
	        $relpath = str_replace($this->separator, '/', $relpath);
3885
	    }
3886
	    $relpath = '/'.$relpath;
3887
3888
	    $perm = null;
3889
3890
	    if ($this->access) {
3891
	        $perm = call_user_func($this->access, $name, $path, $this->options['accessControlData'], $this, $isDir, $relpath);
3892
	        if ($perm !== null) {
3893
	            return (bool) $perm;
3894
	        }
3895
	    }
3896
3897
	    for ($i = 0, $c = count($this->attributes); $i < $c; $i++) {
3898
	        $attrs = $this->attributes[$i];
3899
3900
	        if (isset($attrs[$name]) && isset($attrs['pattern']) && preg_match($attrs['pattern'], $relpath)) {
3901
	            $perm = $attrs[$name];
3902
	        }
3903
	    }
3904
3905
	    return $perm === null ? (is_null($val) ? $this->defaults[$name] : $val) : (bool) $perm;
3906
	}
3907
3908
	/**
3909
	 * Return true if file with given name can be created in given folder.
3910
	 *
3911
	 * @param string $dir parent dir path
3912
	 * @param string $name new file name
3913
	 * @param null $isDir
3914
	 * @return bool
3915
	 * @author Dmitry (dio) Levashov
3916
	 */
3917
	protected function allowCreate($dir, $name, $isDir = null)
3918
	{
3919
	    return $this->attr($this->joinPathCE($dir, $name), 'write', true, $isDir);
3920
	}
3921
3922
	/**
3923
	 * Return true if file MIME type can save with check uploadOrder config.
3924
	 *
3925
	 * @param string $mime
3926
	 * @return bool
3927
	 */
3928
	protected function allowPutMime($mime)
3929
	{
3930
	    // logic based on http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order
3931
		$allow = $this->mimeAccepted($mime, $this->uploadAllow, null);
3932
	    $deny = $this->mimeAccepted($mime, $this->uploadDeny, null);
3933
	    $res = true; // default to allow
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...
3934
		if (strtolower($this->uploadOrder[0]) == 'allow') { // array('allow', 'deny'), default is to 'deny'
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
3935
			$res = false; // default is deny
3936
			if (! $deny && ($allow === true)) { // match only allow
0 ignored issues
show
Bug Best Practice introduced by
The expression $deny of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
3937
				$res = true;
3938
			}// else (both match | no match | match only deny) { deny }
3939
		} else { // array('deny', 'allow'), default is to 'allow' - this is the default rule
3940
			$res = true; // default is allow
3941
			if (($deny === true) && ! $allow) { // match only deny
0 ignored issues
show
Bug Best Practice introduced by
The expression $allow of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
3942
				$res = false;
3943
			} // else (both match | no match | match only allow) { allow }
3944
		}
3945
3946
	    return $res;
3947
	}
3948
3949
	/**
3950
	 * Return fileinfo.
3951
	 *
3952
	 * @param  string  $path  file cache
3953
	 * @return array
3954
	 * @author Dmitry (dio) Levashov
3955
	 **/
3956
	protected function stat($path)
3957
	{
3958
	    if ($path === false || is_null($path)) {
3959
	        return false;
3960
	    }
3961
	    $is_root = ($path == $this->root);
3962
	    if ($is_root) {
3963
	        $rootKey = $this->getRootstatCachekey();
3964
	        if ($this->sessionCaching['rootstat'] && ! isset($this->sessionCache['rootstat'])) {
3965
	            $this->sessionCache['rootstat'] = [];
3966
	        }
3967
	        if (! isset($this->cache[$path]) && ! $this->isMyReload()) {
3968
	            // need $path as key for netmount/netunmount
3969
				if ($this->sessionCaching['rootstat'] && isset($this->sessionCache['rootstat'][$rootKey])) {
3970
				    if ($ret = $this->sessionCache['rootstat'][$rootKey]) {
3971
				        if ($this->options['rootRev'] === $ret['rootRev']) {
3972 View Code Duplication
				            if (isset($this->options['phash'])) {
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...
3973
				                $ret['isroot'] = 1;
3974
				                $ret['phash'] = $this->options['phash'];
3975
				            }
3976
3977
				            return $ret;
3978
				        }
3979
				    }
3980
				}
3981
	        }
3982
	    }
3983
	    $ret = isset($this->cache[$path])
3984
			? $this->cache[$path]
3985
			: $this->updateCache($path, $this->convEncOut($this->_stat($this->convEncIn($path))));
3986
	    if ($is_root && $this->sessionCaching['rootstat']) {
3987
	        if ($ret) {
3988
	            $this->rootModified = false;
3989
	            $this->sessionCache['rootstat'][$rootKey] = $ret;
0 ignored issues
show
Bug introduced by
The variable $rootKey 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...
3990 View Code Duplication
	            if (isset($this->options['phash'])) {
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...
3991
	                $ret['isroot'] = 1;
3992
	                $ret['phash'] = $this->options['phash'];
3993
	            }
3994
	        } else {
3995
	            unset($this->sessionCache['rootstat'][$rootKey]);
3996
	        }
3997
	    }
3998
3999
	    return $ret;
4000
	}
4001
4002
	/**
4003
	 * Get root stat extra key values.
4004
	 *
4005
	 * @return array stat extras
4006
	 * @author Naoki Sawada
4007
	 */
4008
	protected function getRootStatExtra()
4009
	{
4010
	    $stat = [];
4011
	    if ($this->rootName) {
4012
	        $stat['name'] = $this->rootName;
4013
	    }
4014
	    $stat['rootRev'] = $this->options['rootRev'];
4015
	    $stat['options'] = $this->options(null);
4016
4017
	    return $stat;
4018
	}
4019
4020
	/**
4021
	 * Return fileinfo based on filename
4022
	 * For item ID based path file system
4023
	 * Please override if needed on each drivers.
4024
	 *
4025
	 * @param  string  $path  file cache
4026
	 * @return array
4027
	 */
4028
	protected function isNameExists($path)
4029
	{
4030
	    return $this->stat($path);
4031
	}
4032
4033
	/**
4034
	 * Put file stat in cache and return it.
4035
	 *
4036
	 * @param  string  $path   file path
4037
	 * @param  array   $stat   file stat
4038
	 * @return array
4039
	 * @author Dmitry (dio) Levashov
4040
	 **/
4041
	protected function updateCache($path, $stat)
4042
	{
4043
	    if (empty($stat) || ! is_array($stat)) {
4044
	        return $this->cache[$path] = [];
4045
	    }
4046
4047
	    $stat['hash'] = $this->encode($path);
4048
4049
	    $root = $path == $this->root;
4050
	    $parent = '';
4051
4052
	    if ($root) {
4053
	        $stat = array_merge($stat, $this->getRootStatExtra());
4054
	    } else {
4055
	        if (! isset($stat['name']) || $stat['name'] === '') {
4056
	            $stat['name'] = $this->basenameCE($path);
4057
	        }
4058
	        if (empty($stat['phash'])) {
4059
	            $parent = $this->dirnameCE($path);
4060
	            $stat['phash'] = $this->encode($parent);
4061
	        } else {
4062
	            $parent = $this->decode($stat['phash']);
4063
	        }
4064
	    }
4065
4066
		// name check
4067
		if (! $jeName = json_encode($stat['name'])) {
4068
		    return $this->cache[$path] = [];
4069
		}
4070
		// fix name if required
4071
		if ($this->options['utf8fix'] && $this->options['utf8patterns'] && $this->options['utf8replace']) {
4072
		    $stat['name'] = json_decode(str_replace($this->options['utf8patterns'], $this->options['utf8replace'], $jeName));
4073
		}
4074
4075
	    if (empty($stat['mime'])) {
4076
	        $stat['mime'] = $this->mimetype($stat['name'], true);
4077
	    }
4078
4079
		// @todo move dateformat to client
4080
		// $stat['date'] = isset($stat['ts'])
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
4081
		// 	? $this->formatDate($stat['ts'])
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
4082
		// 	: 'unknown';
4083
4084
		if (! isset($stat['size'])) {
4085
		    $stat['size'] = 'unknown';
4086
		}
4087
4088
	    if ($isDir = ($stat['mime'] === 'directory')) {
4089
	        $stat['volumeid'] = $this->id;
4090
	    }
4091
4092
	    $stat['read'] = intval($this->attr($path, 'read', isset($stat['read']) ? (bool) $stat['read'] : null, $isDir));
4093
	    $stat['write'] = intval($this->attr($path, 'write', isset($stat['write']) ? (bool) $stat['write'] : null, $isDir));
4094
	    if ($root) {
4095
	        $stat['locked'] = 1;
4096
	        if ($this->options['type'] !== '') {
4097
	            $stat['type'] = $this->options['type'];
4098
	        }
4099
	    } else {
4100
	        // lock when parent directory is not writable
4101
			if (! isset($stat['locked'])) {
4102
			    $pstat = $this->stat($parent);
4103
			    if (isset($pstat['write']) && ! $pstat['write']) {
4104
			        $stat['locked'] = true;
4105
			    }
4106
			}
4107
	        if ($this->attr($path, 'locked', isset($stat['locked']) ? (bool) $stat['locked'] : null, $isDir)) {
4108
	            $stat['locked'] = 1;
4109
	        } else {
4110
	            unset($stat['locked']);
4111
	        }
4112
	    }
4113
4114
	    if ($root) {
4115
	        unset($stat['hidden']);
4116
	    } elseif ($this->attr($path, 'hidden', isset($stat['hidden']) ? (bool) $stat['hidden'] : null, $isDir)
4117
		|| ! $this->mimeAccepted($stat['mime'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->mimeAccepted($stat['mime']) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
4118
	        $stat['hidden'] = 1;
4119
	    } else {
4120
	        unset($stat['hidden']);
4121
	    }
4122
4123
	    if ($stat['read'] && empty($stat['hidden'])) {
4124
	        if ($isDir) {
4125
	            // caching parent's subdirs
4126
				if ($parent) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
4127
				    $this->updateSubdirsCache($parent, true);
4128
				}
4129
				// for dir - check for subdirs
4130
				if ($this->options['checkSubfolders']) {
4131
				    if (! isset($stat['dirs']) && intval($this->options['checkSubfolders']) === -1) {
4132
				        $stat['dirs'] = -1;
4133
				    }
4134
				    if (isset($stat['dirs'])) {
4135
				        if ($stat['dirs']) {
4136
				            if ($stat['dirs'] == -1) {
4137
				                $stat['dirs'] = ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$path])) ? (int) $this->sessionCache['subdirs'][$path] : -1;
4138
				            } else {
4139
				                $stat['dirs'] = 1;
4140
				            }
4141
				        } else {
4142
				            unset($stat['dirs']);
4143
				        }
4144
				    } elseif (! empty($stat['alias']) && ! empty($stat['target'])) {
4145
				        $stat['dirs'] = isset($this->cache[$stat['target']])
4146
							? intval(isset($this->cache[$stat['target']]['dirs']))
4147
							: $this->subdirsCE($stat['target']);
4148
				    } elseif ($this->subdirsCE($path)) {
4149
				        $stat['dirs'] = 1;
4150
				    }
4151
				} else {
4152
				    $stat['dirs'] = 1;
4153
				}
4154
	            if ($this->options['dirUrlOwn'] === true) {
4155
	                $stat['url'] = '#elf_'.$stat['hash'];
4156
	            }
4157
	        } else {
4158
	            // for files - check for thumbnails
4159
				$p = isset($stat['target']) ? $stat['target'] : $path;
4160
	            if ($this->tmbURL && ! isset($stat['tmb']) && $this->canCreateTmb($p, $stat)) {
4161
	                $tmb = $this->gettmb($p, $stat);
4162
	                $stat['tmb'] = $tmb ? $tmb : 1;
4163
	            }
4164
	        }
4165
	        if (! isset($stat['url']) && $this->URL && $this->encoding) {
4166
	            $_path = str_replace($this->separator, '/', substr($path, strlen($this->root) + 1));
4167
	            $stat['url'] = rtrim($this->URL, '/').'/'.str_replace('%2F', '/', rawurlencode((substr(PHP_OS, 0, 3) === 'WIN') ? $_path : $this->convEncIn($_path, true)));
4168
	        }
4169
	    } else {
4170
	        if ($isDir) {
4171
	            unset($stat['dirs']);
4172
	        }
4173
	    }
4174
4175
	    if (! empty($stat['alias']) && ! empty($stat['target'])) {
4176
	        $stat['thash'] = $this->encode($stat['target']);
4177
			//$this->cache[$stat['target']] = $stat;
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
4178
			unset($stat['target']);
4179
	    }
4180
4181
	    $this->cache[$path] = $stat;
4182
4183
	    if ($root && $this->sessionCaching['rootstat']) {
4184
	        // to update session cache
4185
			$this->stat($path);
4186
	    }
4187
4188
	    return $stat;
4189
	}
4190
4191
	/**
4192
	 * Get stat for folder content and put in cache.
4193
	 *
4194
	 * @param  string  $path
4195
	 * @return void
4196
	 * @author Dmitry (dio) Levashov
4197
	 **/
4198
	protected function cacheDir($path)
4199
	{
4200
	    $this->dirsCache[$path] = [];
4201
	    $hasDir = false;
4202
4203
	    foreach ($this->scandirCE($path) as $p) {
4204
	        if (($stat = $this->stat($p)) && empty($stat['hidden'])) {
4205
	            if (! $hasDir && $stat['mime'] === 'directory') {
4206
	                $hasDir = true;
4207
	            }
4208
	            $this->dirsCache[$path][] = $p;
4209
	        }
4210
	    }
4211
4212
	    $this->updateSubdirsCache($path, $hasDir);
4213
	}
4214
4215
	/**
4216
	 * Clean cache.
4217
	 *
4218
	 * @return void
4219
	 * @author Dmitry (dio) Levashov
4220
	 **/
4221
	protected function clearcache()
4222
	{
4223
	    $this->cache = $this->dirsCache = [];
4224
	}
4225
4226
	/**
4227
	 * Return file mimetype.
4228
	 *
4229
	 * @param  string      $path file path
4230
	 * @param  string|bool $name
4231
	 * @return string
4232
	 * @author Dmitry (dio) Levashov
4233
	 */
4234
	protected function mimetype($path, $name = '')
4235
	{
4236
	    $type = '';
4237
	    $nameCheck = false;
4238
4239
	    if ($name === '') {
4240
	        $name = $path;
4241
	    } elseif ($name === true) {
4242
	        $name = $path;
4243
	        $nameCheck = true;
4244
	    }
4245
	    $ext = (false === $pos = strrpos($name, '.')) ? '' : substr($name, $pos + 1);
4246
	    if (! $nameCheck && is_readable($path)) {
4247
	        if (filesize($path) > 0) {
4248
	            if ($this->mimeDetect == 'finfo') {
4249
	                if ($type = finfo_file($this->finfo, $path)) {
4250
	                    if ($ext && preg_match('~^application/(?:octet-stream|(?:x-)?zip)~', $type)) {
4251
	                        if (isset(self::$mimetypes[$ext])) {
4252
	                            $type = self::$mimetypes[$ext];
4253
	                        }
4254
	                    } elseif ($ext === 'js' && preg_match('~^text/~', $type)) {
4255
	                        $type = 'text/javascript';
4256
	                    }
4257
	                } else {
4258
	                    $type = 'unknown';
4259
	                }
4260
	            } elseif ($this->mimeDetect == 'mime_content_type') {
4261
	                $type = mime_content_type($path);
4262
	            }
4263
	        } else {
4264
	            $type = 'text/plain';
4265
	        }
4266
	    }
4267
	    if (! $type) {
4268
	        $type = self::mimetypeInternalDetect($path);
4269
	    }
4270
4271
	    if ($type === 'unknown' && $this->mimeDetect != 'internal') {
4272
	        $type = self::mimetypeInternalDetect($path);
4273
	    }
4274
4275
	    $type = explode(';', $type);
4276
	    $type = trim($type[0]);
4277
4278
	    if (in_array($type, ['application/x-empty', 'inode/x-empty'])) {
4279
	        // finfo return this mime for empty files
4280
			$type = 'text/plain';
4281
	    }
4282
4283
		// mime type normalization
4284
		$_checkKey = strtolower($ext.':'.$type);
4285
	    if (isset($this->options['mimeMap'][$_checkKey])) {
4286
	        $type = $this->options['mimeMap'][$_checkKey];
4287
	    } else {
4288
	        $_checkKey = strtolower($ext.':*');
4289
	        if (isset($this->options['mimeMap'][$_checkKey])) {
4290
	            $type = $this->options['mimeMap'][$_checkKey];
4291
	        }
4292
	    }
4293
4294
	    return $type;
4295
	}
4296
4297
	/**
4298
	 * Detect file mimetype using "internal" method or Loading mime.types with $path = ''.
4299
	 *
4300
	 * @param  string  $path  file path
4301
	 * @return string
4302
	 * @author Dmitry (dio) Levashov
4303
	 **/
4304
	protected static function mimetypeInternalDetect($path = '')
4305
	{
4306
	    // load default MIME table file "mime.types"
4307
		if (! self::$mimetypesLoaded) {
4308
		    self::$mimetypesLoaded = true;
4309
		    $file = elFinder::$defaultMimefile;
4310
		    if ($file === '' || ! is_readable($file)) {
4311
		        $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types';
4312
		    }
4313 View Code Duplication
		    if (is_readable($file)) {
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...
4314
		        $mimecf = file($file);
4315
		        foreach ($mimecf as $line_num => $line) {
4316
		            if (! preg_match('/^\s*#/', $line)) {
4317
		                $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
4318
		                for ($i = 1, $size = count($mime); $i < $size; $i++) {
4319
		                    if (! isset(self::$mimetypes[$mime[$i]])) {
4320
		                        self::$mimetypes[$mime[$i]] = $mime[0];
4321
		                    }
4322
		                }
4323
		            }
4324
		        }
4325
		    }
4326
		}
4327
	    $ext = '';
4328
	    if ($path) {
4329
	        $pinfo = pathinfo($path);
4330
	        $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : '';
4331
	    }
4332
4333
	    return ($ext && isset(self::$mimetypes[$ext])) ? self::$mimetypes[$ext] : 'unknown';
4334
	}
4335
4336
	/**
4337
	 * Return file/total directory size.
4338
	 *
4339
	 * @param  string  $path  file path
4340
	 * @return int
4341
	 * @author Dmitry (dio) Levashov
4342
	 **/
4343
	protected function countSize($path)
4344
	{
4345
	    elFinder::extendTimeLimit();
4346
4347
	    $result = ['size' => 0, 'files' => 0, 'dirs' => 0];
4348
	    $stat = $this->stat($path);
4349
4350
	    if (empty($stat) || ! $stat['read'] || ! empty($stat['hidden'])) {
4351
	        $result['size'] = 'unknown';
4352
4353
	        return $result;
4354
	    }
4355
4356
	    if ($stat['mime'] != 'directory') {
4357
	        $result['size'] = intval($stat['size']);
4358
	        $result['files'] = 1;
4359
4360
	        return $result;
4361
	    }
4362
4363
	    $subdirs = $this->options['checkSubfolders'];
4364
	    $this->options['checkSubfolders'] = true;
4365
	    foreach ($this->getScandir($path) as $stat) {
4366
	        if ($isDir = ($stat['mime'] === 'directory' && $stat['read'])) {
4367
	            ++$result['dirs'];
4368
	        } else {
4369
	            ++$result['files'];
4370
	        }
4371
	        $res = $isDir
4372
				? $this->countSize($this->decode($stat['hash']))
4373
				: (isset($stat['size']) ? ['size' => intval($stat['size'])] : []);
4374 View Code Duplication
	        if (! empty($res['size']) && is_numeric($res['size'])) {
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...
4375
	            $result['size'] += $res['size'];
4376
	        }
4377 View Code Duplication
	        if (! empty($res['files']) && is_numeric($res['files'])) {
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...
4378
	            $result['files'] += $res['files'];
4379
	        }
4380 View Code Duplication
	        if (! empty($res['dirs']) && is_numeric($res['dirs'])) {
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...
4381
	            $result['dirs'] += $res['dirs'];
4382
	        }
4383
	    }
4384
	    $this->options['checkSubfolders'] = $subdirs;
4385
4386
	    return $result;
4387
	}
4388
4389
	/**
4390
	 * Return true if all mimes is directory or files.
4391
	 *
4392
	 * @param  string  $mime1  mimetype
4393
	 * @param  string  $mime2  mimetype
4394
	 * @return bool
4395
	 * @author Dmitry (dio) Levashov
4396
	 **/
4397
	protected function isSameType($mime1, $mime2)
4398
	{
4399
	    return ($mime1 == 'directory' && $mime1 == $mime2) || ($mime1 != 'directory' && $mime2 != 'directory');
4400
	}
4401
4402
	/**
4403
	 * If file has required attr == $val - return file path,
4404
	 * If dir has child with has required attr == $val - return child path.
4405
	 *
4406
	 * @param  string   $path  file path
4407
	 * @param  string   $attr  attribute name
4408
	 * @param  bool     $val   attribute value
4409
	 * @return string|false
4410
	 * @author Dmitry (dio) Levashov
4411
	 **/
4412
	protected function closestByAttr($path, $attr, $val)
4413
	{
4414
	    $stat = $this->stat($path);
4415
4416
	    if (empty($stat)) {
4417
	        return false;
4418
	    }
4419
4420
	    $v = isset($stat[$attr]) ? $stat[$attr] : false;
4421
4422
	    if ($v == $val) {
4423
	        return $path;
4424
	    }
4425
4426
	    return $stat['mime'] == 'directory'
4427
			? $this->childsByAttr($path, $attr, $val)
4428
			: false;
4429
	}
4430
4431
	/**
4432
	 * Return first found children with required attr == $val.
4433
	 *
4434
	 * @param  string   $path  file path
4435
	 * @param  string   $attr  attribute name
4436
	 * @param  bool     $val   attribute value
4437
	 * @return string|false
4438
	 * @author Dmitry (dio) Levashov
4439
	 **/
4440
	protected function childsByAttr($path, $attr, $val)
4441
	{
4442
	    foreach ($this->scandirCE($path) as $p) {
4443
	        if (($_p = $this->closestByAttr($p, $attr, $val)) != false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $_p = $this->closestByAttr($p, $attr, $val) of type string|false against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
4444
	            return $_p;
4445
	        }
4446
	    }
4447
4448
	    return false;
4449
	}
4450
4451
    protected function isMyReload($target = '', $ARGtarget = '')
4452
    {
4453
        if ($this->rootModified || (! empty($this->ARGS['cmd']) && $this->ARGS['cmd'] === 'parents')) {
4454
            return true;
4455
        }
4456
        if (! empty($this->ARGS['reload'])) {
4457
            if ($ARGtarget === '') {
4458
                $ARGtarget = isset($this->ARGS['target']) ? $this->ARGS['target']
4459
					: ((isset($this->ARGS['targets']) && is_array($this->ARGS['targets']) && count($this->ARGS['targets']) === 1) ?
4460
						$this->ARGS['targets'][0] : '');
4461
            }
4462
            if ($ARGtarget !== '') {
4463
                $ARGtarget = strval($ARGtarget);
4464
                if ($target === '') {
4465
                    return strpos($ARGtarget, $this->id) === 0;
4466
                } else {
4467
                    $target = strval($target);
4468
4469
                    return $target === $ARGtarget;
4470
                }
4471
            }
4472
        }
4473
4474
        return false;
4475
    }
4476
4477
	/**
4478
	 * Update subdirs cache data.
4479
	 *
4480
	 * @param string $path
4481
	 * @param bool   $subdirs
4482
	 *
4483
	 * @returnv void
4484
	 */
4485
	protected function updateSubdirsCache($path, $subdirs)
4486
	{
4487
	    if (isset($this->cache[$path])) {
4488
	        if ($subdirs) {
4489
	            $this->cache[$path]['dirs'] = 1;
4490
	        } else {
4491
	            unset($this->cache[$path]['dirs']);
4492
	        }
4493
	    }
4494
	    if ($this->sessionCaching['subdirs']) {
4495
	        $this->sessionCache['subdirs'][$path] = $subdirs;
4496
	    }
4497
	    if ($this->sessionCaching['rootstat'] && $path == $this->root) {
4498
	        unset($this->sessionCache['rootstat'][$this->getRootstatCachekey()]);
4499
	    }
4500
	}
4501
4502
	/*****************  get content *******************/
4503
4504
	/**
4505
	 * Return required dir's files info.
4506
	 * If onlyMimes is set - return only dirs and files of required mimes.
4507
	 *
4508
	 * @param  string  $path  dir path
4509
	 * @return array
4510
	 * @author Dmitry (dio) Levashov
4511
	 **/
4512
	protected function getScandir($path)
4513
	{
4514
	    $files = [];
4515
4516
	    ! isset($this->dirsCache[$path]) && $this->cacheDir($path);
4517
4518
	    foreach ($this->dirsCache[$path] as $p) {
4519
	        if (($stat = $this->stat($p)) && empty($stat['hidden'])) {
4520
	            $files[] = $stat;
4521
	        }
4522
	    }
4523
4524
	    return $files;
4525
	}
4526
4527
	/**
4528
	 * Return subdirs tree.
4529
	 *
4530
	 * @param  string $path parent dir path
4531
	 * @param  int $deep tree deep
4532
	 * @param string $exclude
4533
	 * @return array
4534
	 * @author Dmitry (dio) Levashov
4535
	 */
4536
	protected function gettree($path, $deep, $exclude = '')
4537
	{
4538
	    $dirs = [];
4539
4540
	    ! isset($this->dirsCache[$path]) && $this->cacheDir($path);
4541
4542
	    foreach ($this->dirsCache[$path] as $p) {
4543
	        $stat = $this->stat($p);
4544
4545
	        if ($stat && empty($stat['hidden']) && $p != $exclude && $stat['mime'] == 'directory') {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
4546
	            $dirs[] = $stat;
4547
	            if ($deep > 0 && ! empty($stat['dirs'])) {
4548
	                $dirs = array_merge($dirs, $this->gettree($p, $deep - 1));
4549
	            }
4550
	        }
4551
	    }
4552
4553
	    return $dirs;
4554
	}
4555
4556
	/**
4557
	 * Recursive files search.
4558
	 *
4559
	 * @param  string  $path   dir path
4560
	 * @param  string  $q      search string
4561
	 * @param  array   $mimes
4562
	 * @return array
4563
	 * @author Dmitry (dio) Levashov
4564
	 **/
4565
	protected function doSearch($path, $q, $mimes)
4566
	{
4567
	    $result = [];
4568
4569
	    $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0;
4570 View Code Duplication
	    if ($timeout && $timeout < time()) {
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...
4571
	        $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
4572
4573
	        return $result;
4574
	    }
4575
4576
	    foreach ($this->scandirCE($path) as $p) {
4577
	        elFinder::extendTimeLimit($this->options['searchTimeout'] + 30);
4578
4579 View Code Duplication
	        if ($timeout && ($this->error || $timeout < time())) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->error 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...
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...
4580
	            ! $this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path)));
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->error 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...
4581
	            break;
4582
	        }
4583
4584
	        $stat = $this->stat($p);
4585
4586
	        if (! $stat) { // invalid links
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
4587
				continue;
4588
	        }
4589
4590
	        if (! empty($stat['hidden']) || ! $this->mimeAccepted($stat['mime'], $mimes)) {
4591
	            continue;
4592
	        }
4593
4594
	        $name = $stat['name'];
4595
4596 View Code Duplication
	        if ($this->doSearchCurrentQuery['excludes']) {
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...
4597
	            foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) {
0 ignored issues
show
Bug introduced by
The expression $this->doSearchCurrentQuery['excludes'] of type string is not traversable.
Loading history...
4598
	                if ($this->stripos($name, $exclude) !== false) {
4599
	                    continue 2;
4600
	                }
4601
	            }
4602
	        }
4603
4604
	        if ((! $mimes || $stat['mime'] !== 'directory') && $this->stripos($name, $q) !== false) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $mimes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
4605
	            $stat['path'] = $this->path($stat['hash']);
4606
	            if ($this->URL && ! isset($stat['url'])) {
4607
	                $path = str_replace($this->separator, '/', substr($p, strlen($this->root) + 1));
4608
	                if ($this->encoding) {
4609
	                    $path = str_replace('%2F', '/', rawurlencode($this->convEncIn($path, true)));
4610
	                } else {
4611
	                    $path = str_replace('%2F', '/', rawurlencode($path));
4612
	                }
4613
	                $stat['url'] = $this->URL.$path;
4614
	            }
4615
4616
	            $result[] = $stat;
4617
	        }
4618
	        if ($stat['mime'] == 'directory' && $stat['read'] && ! isset($stat['alias'])) {
4619
	            if (! $this->options['searchExDirReg'] || ! preg_match($this->options['searchExDirReg'], $p)) {
4620
	                $result = array_merge($result, $this->doSearch($p, $q, $mimes));
4621
	            }
4622
	        }
4623
	    }
4624
4625
	    return $result;
4626
	}
4627
4628
	/**********************  manuipulations  ******************/
4629
4630
	/**
4631
	 * Copy file/recursive copy dir only in current volume.
4632
	 * Return new file path or false.
4633
	 *
4634
	 * @param  string  $src   source path
4635
	 * @param  string  $dst   destination dir path
4636
	 * @param  string  $name  new file name (optionaly)
4637
	 * @return string|false
4638
	 * @author Dmitry (dio) Levashov
4639
	 **/
4640
	protected function copy($src, $dst, $name)
4641
	{
4642
	    elFinder::extendTimeLimit();
4643
4644
	    $srcStat = $this->stat($src);
4645
4646
	    if (! empty($srcStat['thash'])) {
4647
	        $target = $this->decode($srcStat['thash']);
4648
	        if (! $this->inpathCE($target, $this->root)) {
4649
	            return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']), elFinder::ERROR_MKOUTLINK);
4650
	        }
4651
	        $stat = $this->stat($target);
4652
	        $this->clearcache();
4653
4654
	        return $stat && $this->symlinkCE($target, $dst, $name)
0 ignored issues
show
Bug Best Practice introduced by
The expression $stat of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
4655
				? $this->joinPathCE($dst, $name)
4656
				: $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']));
4657
	    }
4658
4659
	    if ($srcStat['mime'] === 'directory') {
4660
	        $testStat = $this->isNameExists($this->joinPathCE($dst, $name));
4661
	        $this->clearcache();
4662
4663 View Code Duplication
	        if (($testStat && $testStat['mime'] !== 'directory') || (! $testStat && ! $testStat = $this->mkdir($this->encode($dst), $name))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $testStat 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...
Bug Best Practice introduced by
The expression $testStat 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...
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...
4664
	            return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']));
4665
	        }
4666
4667
	        $dst = $this->decode($testStat['hash']);
4668
4669
	        foreach ($this->getScandir($src) as $stat) {
4670
	            if (empty($stat['hidden'])) {
4671
	                $name = $stat['name'];
4672
	                $_src = $this->decode($stat['hash']);
4673
	                if (! $this->copy($_src, $dst, $name)) {
4674
	                    $this->remove($dst, true); // fall back
4675
						return $this->setError($this->error, elFinder::ERROR_COPY, $this->_path($src));
4676
	                }
4677
	            }
4678
	        }
4679
4680
	        $this->added[] = $testStat;
4681
4682
	        return $dst;
4683
	    }
4684
4685 View Code Duplication
	    if ($this->options['copyJoin']) {
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...
4686
	        $test = $this->joinPathCE($dst, $name);
4687
	        if ($testStat = $this->isNameExists($test)) {
0 ignored issues
show
Unused Code introduced by
$testStat 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...
4688
	            $this->remove($test);
4689
	        }
4690
	    } else {
4691
	        $testStat = false;
0 ignored issues
show
Unused Code introduced by
$testStat 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...
4692
	    }
4693
	    if ($res = $this->convEncOut($this->_copy($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)))) {
4694
	        $path = is_string($res) ? $res : $this->joinPathCE($dst, $name);
4695
	        $this->clearcache();
4696
	        if ($this->ARGS['cmd'] !== 'duplicate') {
4697
	            $this->added[] = $this->stat($path);
4698
	        }
4699
4700
	        return $path;
4701
	    }
4702
4703
	    return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']));
4704
	}
4705
4706
	/**
4707
	 * Move file
4708
	 * Return new file path or false.
4709
	 *
4710
	 * @param  string  $src   source path
4711
	 * @param  string  $dst   destination dir path
4712
	 * @param  string  $name  new file name
4713
	 * @return string|false
4714
	 * @author Dmitry (dio) Levashov
4715
	 **/
4716
	protected function move($src, $dst, $name)
4717
	{
4718
	    $stat = $this->stat($src);
4719
	    $stat['realpath'] = $src;
4720
	    $this->rmTmb($stat); // can not do rmTmb() after _move()
0 ignored issues
show
Documentation introduced by
$stat is of type array<string,string,{"realpath":"string"}>, but the function expects a string.

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...
4721
		$this->clearcache();
4722
4723
	    if ($res = $this->convEncOut($this->_move($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)))) {
4724
	        $this->removed[] = $stat;
4725
	        if ($stat['mime'] === 'directory') {
4726
	            $this->updateSubdirsCache($dst, true);
4727
	        }
4728
4729
	        return is_string($res) ? $res : $this->joinPathCE($dst, $name);
4730
	    }
4731
4732
	    return $this->setError(elFinder::ERROR_MOVE, $this->path($stat['hash']));
4733
	}
4734
4735
	/**
4736
	 * Copy file from another volume.
4737
	 * Return new file path or false.
4738
	 *
4739
	 * @param  object  $volume       source volume
4740
	 * @param  string  $src          source file hash
4741
	 * @param  string  $destination  destination dir path
4742
	 * @param  string  $name         file name
4743
	 * @return string|false
4744
	 * @author Dmitry (dio) Levashov
4745
	 **/
4746
	protected function copyFrom($volume, $src, $destination, $name)
4747
	{
4748
	    elFinder::extendTimeLimit();
4749
4750
	    if (($source = $volume->file($src)) == false) {
4751
	        return $this->setError(elFinder::ERROR_COPY, '#'.$src, $volume->error());
4752
	    }
4753
4754
	    $srcIsDir = ($source['mime'] === 'directory');
4755
4756
	    $errpath = $volume->path($source['hash']);
4757
4758
	    if (! $this->nameAccepted($source['name'], $srcIsDir)) {
4759
	        return $this->setError(elFinder::ERROR_COPY, $errpath, $srcIsDir ? elFinder::ERROR_INVALID_DIRNAME : elFinder::ERROR_INVALID_NAME);
4760
	    }
4761
4762
	    if (! $source['read']) {
4763
	        return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED);
4764
	    }
4765
4766
	    if ($srcIsDir) {
4767
	        $test = $this->isNameExists($this->joinPathCE($destination, $name));
4768
	        $this->clearcache();
4769
4770 View Code Duplication
	        if (($test && $test['mime'] != 'directory') || (! $test && ! $test = $this->mkdir($this->encode($destination), $name))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $test 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...
Bug Best Practice introduced by
The expression $test 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...
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...
4771
	            return $this->setError(elFinder::ERROR_COPY, $errpath);
4772
	        }
4773
4774
			//$path = $this->joinPathCE($destination, $name);
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
4775
			$path = $this->decode($test['hash']);
4776
4777
	        foreach ($volume->scandir($src) as $entr) {
4778
	            if (! $this->copyFrom($volume, $entr['hash'], $path, $entr['name'])) {
4779
	                $this->remove($path, true); // fall back
4780
					return $this->setError($this->error, elFinder::ERROR_COPY, $errpath);
4781
	            }
4782
	        }
4783
4784
	        $this->added[] = $test;
4785
	    } else {
4786
	        // MIME check
4787
			$mimeByName = $this->mimetype($source['name'], true);
4788
	        if ($source['mime'] === $mimeByName) {
4789
	            $mimeByName = '';
4790
	        }
4791 View Code Duplication
	        if (! $this->allowPutMime($source['mime']) || ($mimeByName && ! $this->allowPutMime($mimeByName))) {
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...
4792
	            return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $errpath);
4793
	        }
4794
4795
	        if (strpos($source['mime'], 'image') === 0 && ($dim = $volume->dimensions($src))) {
4796
	            $s = explode('x', $dim);
4797
	            $source['width'] = $s[0];
4798
	            $source['height'] = $s[1];
4799
	        }
4800
4801
	        if (($fp = $volume->open($src)) == false
4802
			|| ($path = $this->saveCE($fp, $destination, $name, $source)) == false) {
4803
	            $fp && $volume->close($fp, $src);
4804
4805
	            return $this->setError(elFinder::ERROR_COPY, $errpath);
4806
	        }
4807
	        $volume->close($fp, $src);
4808
4809
	        $this->added[] = $this->stat($path);
0 ignored issues
show
Bug introduced by
It seems like $path defined by $this->saveCE($fp, $destination, $name, $source) on line 4802 can also be of type boolean; however, elFinderVolumeDriver::stat() does only seem to accept string, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
4810
	    }
4811
4812
	    return $path;
4813
	}
4814
4815
	/**
4816
	 * Remove file/ recursive remove dir.
4817
	 *
4818
	 * @param  string  $path   file path
4819
	 * @param  bool    $force  try to remove even if file locked
4820
	 * @return bool
4821
	 * @author Dmitry (dio) Levashov
4822
	 **/
4823
	protected function remove($path, $force = false)
4824
	{
4825
	    $stat = $this->stat($path);
4826
4827
	    if (empty($stat)) {
4828
	        return $this->setError(elFinder::ERROR_RM, $path, elFinder::ERROR_FILE_NOT_FOUND);
4829
	    }
4830
4831
	    $stat['realpath'] = $path;
4832
	    $this->rmTmb($stat);
0 ignored issues
show
Documentation introduced by
$stat is of type array<string,string,{"realpath":"string"}>, but the function expects a string.

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...
4833
	    $this->clearcache();
4834
4835
	    if (! $force && ! empty($stat['locked'])) {
4836
	        return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash']));
4837
	    }
4838
4839
	    if ($stat['mime'] == 'directory' && empty($stat['thash'])) {
4840
	        $ret = $this->delTree($this->convEncIn($path));
4841
	        $this->convEncOut();
4842
	        if (! $ret) {
4843
	            return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash']));
4844
	        }
4845 View Code Duplication
	    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4846
	        if ($this->convEncOut(! $this->_unlink($this->convEncIn($path)))) {
4847
	            return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash']));
4848
	        }
4849
	    }
4850
4851
	    $this->removed[] = $stat;
4852
4853
	    return true;
4854
	}
4855
4856
	/************************* thumbnails **************************/
4857
4858
	/**
4859
	 * Return thumbnail file name for required file.
4860
	 *
4861
	 * @param  array  $stat  file stat
4862
	 * @return string
4863
	 * @author Dmitry (dio) Levashov
4864
	 **/
4865
	protected function tmbname($stat)
4866
	{
4867
	    return $stat['hash'].$stat['ts'].'.png';
4868
	}
4869
4870
	/**
4871
	 * Return thumnbnail name if exists.
4872
	 *
4873
	 * @param  string  $path file path
4874
	 * @param  array   $stat file stat
4875
	 * @return string|false
4876
	 * @author Dmitry (dio) Levashov
4877
	 **/
4878
	protected function gettmb($path, $stat)
4879
	{
4880
	    if ($this->tmbURL && $this->tmbPath) {
4881
	        // file itself thumnbnail
4882
			if (strpos($path, $this->tmbPath) === 0) {
4883
			    return basename($path);
4884
			}
4885
4886
	        $name = $this->tmbname($stat);
4887
	        if (file_exists($this->tmbPath.DIRECTORY_SEPARATOR.$name)) {
4888
	            return $name;
4889
	        }
4890
	    }
4891
4892
	    return false;
4893
	}
4894
4895
	/**
4896
	 * Return true if thumnbnail for required file can be created.
4897
	 *
4898
	 * @param  string  $path  thumnbnail path
4899
	 * @param  array   $stat  file stat
4900
	 * @param  bool    $checkTmbPath
4901
	 * @return string|bool
4902
	 * @author Dmitry (dio) Levashov
4903
	 **/
4904
	protected function canCreateTmb($path, $stat, $checkTmbPath = true)
4905
	{
4906
	    if ((! $checkTmbPath || $this->tmbPathWritable)
4907
			&& (! $this->tmbPath || strpos($path, $this->tmbPath) === false) // do not create thumnbnail for thumnbnail
4908
		) {
4909
	        $mime = strtolower($stat['mime']);
4910
	        list($type) = explode('/', $mime);
4911
	        if (! empty($this->imgConverter)) {
4912
	            if (isset($this->imgConverter[$mime])) {
4913
	                return true;
4914
	            }
4915
	            if (isset($this->imgConverter[$type])) {
4916
	                return true;
4917
	            }
4918
	        }
4919
4920
	        return $this->imgLib
4921
				&& ($type === 'image')
4922
				&& ($this->imgLib == 'gd' ? in_array($stat['mime'], ['image/jpeg', 'image/png', 'image/gif', 'image/x-ms-bmp']) : true);
4923
	    }
4924
4925
	    return false;
4926
	}
4927
4928
	/**
4929
	 * Return true if required file can be resized.
4930
	 * By default - the same as canCreateTmb.
4931
	 *
4932
	 * @param  string  $path  thumnbnail path
4933
	 * @param  array   $stat  file stat
4934
	 * @return string|bool
4935
	 * @author Dmitry (dio) Levashov
4936
	 **/
4937
	protected function canResize($path, $stat)
4938
	{
4939
	    return $this->canCreateTmb($path, $stat, false);
4940
	}
4941
4942
	/**
4943
	 * Create thumnbnail and return it's URL on success.
4944
	 *
4945
	 * @param  string $path file path
4946
	 * @param $stat
4947
	 * @return false|string
4948
	 * @internal param string $mime file mime type
4949
	 * @author Dmitry (dio) Levashov
4950
	 */
4951
	protected function createTmb($path, $stat)
4952
	{
4953
	    if (! $stat || ! $this->canCreateTmb($path, $stat)) {
4954
	        return false;
4955
	    }
4956
4957
	    $name = $this->tmbname($stat);
4958
	    $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name;
4959
4960
	    $maxlength = -1;
4961
	    $imgConverter = null;
4962
4963
		// check imgConverter
4964
		$mime = strtolower($stat['mime']);
4965
	    list($type) = explode('/', $mime);
4966
	    if (isset($this->imgConverter[$mime])) {
4967
	        $imgConverter = $this->imgConverter[$mime]['func'];
4968 View Code Duplication
	        if (! empty($this->imgConverter[$mime]['maxlen'])) {
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...
4969
	            $maxlength = intval($this->imgConverter[$mime]['maxlen']);
4970
	        }
4971
	    } elseif (isset($this->imgConverter[$type])) {
4972
	        $imgConverter = $this->imgConverter[$type]['func'];
4973 View Code Duplication
	        if (! empty($this->imgConverter[$type]['maxlen'])) {
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...
4974
	            $maxlength = intval($this->imgConverter[$type]['maxlen']);
4975
	        }
4976
	    }
4977
	    if ($imgConverter && ! is_callable($imgConverter)) {
4978
	        return false;
4979
	    }
4980
4981
		// copy image into tmbPath so some drivers does not store files on local fs
4982
		if (($src = $this->fopenCE($path, 'rb')) == false) {
4983
		    return false;
4984
		}
4985
4986
	    if (($trg = fopen($tmb, 'wb')) == false) {
4987
	        $this->fcloseCE($src, $path);
4988
4989
	        return false;
4990
	    }
4991
4992
	    stream_copy_to_stream($src, $trg, $maxlength);
4993
4994
	    $this->fcloseCE($src, $path);
4995
	    fclose($trg);
4996
4997
		// call imgConverter
4998
		if ($imgConverter) {
4999
		    if (! call_user_func_array($imgConverter, [$tmb, $stat, $this])) {
5000
		        file_exists($tmb) && unlink($tmb);
5001
5002
		        return false;
5003
		    }
5004
		}
5005
5006
	    $result = false;
5007
5008
	    $tmbSize = $this->tmbSize;
5009
5010
	    if ($this->imgLib === 'imagick') {
5011
	        try {
5012
	            $imagickTest = new imagick($tmb);
5013
	            $imagickTest->clear();
5014
	            $imagickTest = true;
5015
	        } catch (Exception $e) {
5016
	            $imagickTest = false;
5017
	        }
5018
	    }
5019
5020
	    if (($this->imgLib === 'imagick' && ! $imagickTest) || ($s = getimagesize($tmb)) === false) {
0 ignored issues
show
Bug introduced by
The variable $imagickTest 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...
5021
	        if ($this->imgLib === 'imagick') {
5022
	            $bgcolor = $this->options['tmbBgColor'];
5023
	            if ($bgcolor === 'transparent') {
5024
	                $bgcolor = 'rgba(255, 255, 255, 0.0)';
5025
	            }
5026
	            try {
5027
	                $imagick = new imagick();
5028
	                $imagick->setBackgroundColor(new ImagickPixel($bgcolor));
5029
	                $imagick->readImage($this->getExtentionByMime($stat['mime'], ':').$tmb);
5030
	                $imagick->setImageFormat('png');
5031
	                $imagick->writeImage($tmb);
5032
	                $imagick->clear();
5033
	                if (($s = getimagesize($tmb)) !== false) {
5034
	                    $result = true;
5035
	                }
5036
	            } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
5037
	            }
5038
	        }
5039
	        if (! $result) {
5040
	            file_exists($tmb) && unlink($tmb);
5041
5042
	            return false;
5043
	        }
5044
	        $result = false;
0 ignored issues
show
Unused Code introduced by
$result 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...
5045
	    }
5046
5047
		/* If image smaller or equal thumbnail size - just fitting to thumbnail square */
5048
		if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) {
5049
		    $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
5050
		} else {
5051
		    if ($this->options['tmbCrop']) {
5052
		        $result = $tmb;
5053
				/* Resize and crop if image bigger than thumbnail */
5054
				if (! (($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) {
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...
5055
				    $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png');
5056
				}
5057
5058
		        if ($result && ($s = getimagesize($tmb)) != false) {
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...
5059
		            $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0;
5060
		            $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0;
5061
		            $result = $this->imgCrop($result, $tmbSize, $tmbSize, $x, $y, 'png');
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...
5062
		        } else {
5063
		            $result = false;
5064
		        }
5065
		    } else {
5066
		        $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png');
5067
		    }
5068
5069
		    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...
5070
		        if ($s = getimagesize($tmb)) {
5071
		            if ($s[0] !== $tmbSize || $s[1] !== $tmbSize) {
5072
		                $result = $this->imgSquareFit($result, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png');
5073
		            }
5074
		        }
5075
		    }
5076
		}
5077
5078
	    if (! $result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result 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...
5079
	        unlink($tmb);
5080
5081
	        return false;
5082
	    }
5083
5084
	    return $name;
5085
	}
5086
5087
	/**
5088
	 * Resize image.
5089
	 *
5090
	 * @param  string   $path               image file
5091
	 * @param  int      $width              new width
5092
	 * @param  int      $height             new height
5093
	 * @param  bool	    $keepProportions    crop image
5094
	 * @param  bool	    $resizeByBiggerSide resize image based on bigger side if true
5095
	 * @param  string   $destformat         image destination format
5096
	 * @param  int      $jpgQuality         JEPG quality (1-100)
5097
	 * @param  array    $options            Other extra options
5098
	 * @return string|false
5099
	 * @author Dmitry (dio) Levashov
5100
	 * @author Alexey Sukhotin
5101
	 **/
5102
	protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null, $jpgQuality = null, $options = [])
5103
	{
5104
	    if (($s = getimagesize($path)) == false) {
5105
	        return false;
5106
	    }
5107
5108
	    $result = false;
0 ignored issues
show
Unused Code introduced by
$result 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...
5109
5110
	    if (! $jpgQuality) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $jpgQuality of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5111
	        $jpgQuality = $this->options['jpgQuality'];
5112
	    }
5113
5114
	    list($orig_w, $orig_h) = [$s[0], $s[1]];
5115
	    list($size_w, $size_h) = [$width, $height];
5116
5117
	    if (empty($options['unenlarge']) || $orig_w > $size_w || $orig_h > $size_h) {
5118
	        if ($keepProportions == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
5119
	            /* Resizing by biggest side */
5120
				if ($resizeByBiggerSide) {
5121 View Code Duplication
				    if ($orig_w > $orig_h) {
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...
5122
				        $size_h = round($orig_h * $width / $orig_w);
5123
				        $size_w = $width;
5124
				    } else {
5125
				        $size_w = round($orig_w * $height / $orig_h);
5126
				        $size_h = $height;
5127
				    }
5128 View Code Duplication
				} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5129
				    if ($orig_w > $orig_h) {
5130
				        $size_w = round($orig_w * $height / $orig_h);
5131
				        $size_h = $height;
5132
				    } else {
5133
				        $size_h = round($orig_h * $width / $orig_w);
5134
				        $size_w = $width;
5135
				    }
5136
				}
5137
	        }
5138
	    } else {
5139
	        $size_w = $orig_w;
5140
	        $size_h = $orig_h;
5141
	    }
5142
5143
	    elFinder::extendTimeLimit(300);
5144
	    switch ($this->imgLib) {
5145
			case 'imagick':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5146
5147
				try {
5148
				    $img = new imagick($path);
5149
				} catch (Exception $e) {
5150
				    return false;
5151
				}
5152
5153
				// Imagick::FILTER_BOX faster than FILTER_LANCZOS so use for createTmb
5154
				// resize bench: http://app-mgng.rhcloud.com/9
5155
				// resize sample: http://www.dylanbeattie.net/magick/filters/result.html
5156
				$filter = ($destformat === 'png' /* createTmb */) ? Imagick::FILTER_BOX : Imagick::FILTER_LANCZOS;
5157
5158
				$ani = ($img->getNumberImages() > 1);
5159
				if ($ani && is_null($destformat)) {
5160
				    $img = $img->coalesceImages();
5161
				    do {
5162
				        $img->resizeImage($size_w, $size_h, $filter, 1);
5163
				    } while ($img->nextImage());
5164
				    $img = $img->optimizeImageLayers();
5165
				    $result = $img->writeImages($path, true);
0 ignored issues
show
Bug introduced by
The method writeImages cannot be called on $img (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5166
				} else {
5167
				    if ($ani) {
5168
				        $img->setFirstIterator();
5169
				    }
5170
				    if (strtoupper($img->getImageFormat()) === 'JPEG') {
5171
				        $img->setImageCompression(imagick::COMPRESSION_JPEG);
5172
				        $img->setImageCompressionQuality($jpgQuality);
5173
				        if (isset($options['preserveExif']) && ! $options['preserveExif']) {
5174
				            try {
5175
				                $orientation = $img->getImageOrientation();
5176
				            } catch (ImagickException $e) {
5177
				                $orientation = 0;
5178
				            }
5179
				            $img->stripImage();
5180
				            if ($orientation) {
5181
				                $img->setImageOrientation($orientation);
5182
				            }
5183
				        }
5184
				    }
5185
				    $img->resizeImage($size_w, $size_h, $filter, true);
5186
				    if ($destformat) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $destformat of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
5187
				        $result = $this->imagickImage($img, $path, $destformat, $jpgQuality);
0 ignored issues
show
Documentation introduced by
$img is of type object<Imagick>, but the function expects a resource.

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...
5188
				    } else {
5189
				        $result = $img->writeImage($path);
5190
				    }
5191
				}
5192
5193
				$img->clear();
5194
5195
				return $result ? $path : false;
5196
5197
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5198
5199
			case 'convert':
5200
				extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s));
0 ignored issues
show
Bug introduced by
$this->imageMagickConver...ormat, $jpgQuality, $s) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
5201
				$filter = ($destformat === 'png' /* createTmb */) ? '-filter Box' : '-filter Lanczos';
5202
				$strip = (isset($options['preserveExif']) && ! $options['preserveExif']) ? ' -strip' : '';
0 ignored issues
show
Unused Code introduced by
$strip 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...
5203
				//$cmd = sprintf('convert%s%s +repage %s -resize %dx%d +repage%s %s %s', $coalesce, $jpgQuality, $filter, $size_w, $size_h, $deconstruct, $quotedPath, $quotedDstPath);
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5204
				$cmd = sprintf('convert %s%s%s %s -geometry %dx%d! %s %s', $quotedPath, $coalesce, $jpgQuality, $filter, $size_w, $size_h, $deconstruct, $quotedDstPath);
5205
5206
				$result = false;
5207
				if ($this->procExec($cmd) === 0) {
5208
				    $result = true;
5209
				}
5210
5211
				return $result ? $path : false;
5212
5213
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5214
5215
			case 'gd':
5216
				$img = $this->gdImageCreate($path, $s['mime']);
5217
5218
				if ($img && false != ($tmp = imagecreatetruecolor($size_w, $size_h))) {
5219
				    $bgNum = false;
5220 View Code Duplication
				    if ($s[2] === IMAGETYPE_GIF && (! $destformat || $destformat === 'gif')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $destformat of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
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...
5221
				        $bgIdx = imagecolortransparent($img);
5222
				        if ($bgIdx !== -1) {
5223
				            $c = imagecolorsforindex($img, $bgIdx);
5224
				            $bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']);
5225
				            imagefill($tmp, 0, 0, $bgNum);
5226
				            imagecolortransparent($tmp, $bgNum);
5227
				        }
5228
				    }
5229
				    if ($bgNum === false) {
5230
				        $this->gdImageBackground($tmp, 'transparent');
5231
				    }
5232
5233
				    if (! imagecopyresampled($tmp, $img, 0, 0, 0, 0, $size_w, $size_h, $s[0], $s[1])) {
5234
				        return false;
5235
				    }
5236
5237
				    $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality);
5238
5239
				    imagedestroy($img);
5240
				    imagedestroy($tmp);
5241
5242
				    return $result ? $path : false;
5243
				}
5244
				break;
5245
		}
5246
5247
	    return false;
5248
	}
5249
5250
  	/**
5251
  	 * Crop image.
5252
  	 *
5253
  	 * @param  string   $path               image file
5254
  	 * @param  int      $width              crop width
5255
  	 * @param  int      $height             crop height
5256
  	 * @param  bool	    $x                  crop left offset
5257
  	 * @param  bool	    $y                  crop top offset
5258
  	 * @param  string   $destformat         image destination format
5259
  	 * @param  int      $jpgQuality         JEPG quality (1-100)
5260
  	 * @return string|false
5261
  	 * @author Dmitry (dio) Levashov
5262
  	 * @author Alexey Sukhotin
5263
  	 **/
5264
  	protected function imgCrop($path, $width, $height, $x, $y, $destformat = null, $jpgQuality = null)
5265
  	{
5266
  	    if (($s = getimagesize($path)) == false) {
5267
  	        return false;
5268
  	    }
5269
5270
  	    $result = false;
0 ignored issues
show
Unused Code introduced by
$result 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...
5271
5272
  	    if (! $jpgQuality) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $jpgQuality of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5273
  	        $jpgQuality = $this->options['jpgQuality'];
5274
  	    }
5275
5276
  	    elFinder::extendTimeLimit(300);
5277
  	    switch ($this->imgLib) {
5278
			case 'imagick':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5279
5280
				try {
5281
				    $img = new imagick($path);
5282
				} catch (Exception $e) {
5283
				    return false;
5284
				}
5285
5286
				$ani = ($img->getNumberImages() > 1);
5287
				if ($ani && is_null($destformat)) {
5288
				    $img = $img->coalesceImages();
5289
				    do {
5290
				        $img->setImagePage($s[0], $s[1], 0, 0);
5291
				        $img->cropImage($width, $height, $x, $y);
5292
				        $img->setImagePage($width, $height, 0, 0);
5293
				    } while ($img->nextImage());
5294
				    $img = $img->optimizeImageLayers();
5295
				    $result = $img->writeImages($path, true);
0 ignored issues
show
Bug introduced by
The method writeImages cannot be called on $img (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5296
				} else {
5297
				    if ($ani) {
5298
				        $img->setFirstIterator();
5299
				    }
5300
				    $img->setImagePage($s[0], $s[1], 0, 0);
5301
				    $img->cropImage($width, $height, $x, $y);
5302
				    $img->setImagePage($width, $height, 0, 0);
5303
				    $result = $this->imagickImage($img, $path, $destformat, $jpgQuality);
0 ignored issues
show
Documentation introduced by
$img is of type object<Imagick>, but the function expects a resource.

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...
5304
				}
5305
5306
				$img->clear();
5307
5308
				return $result ? $path : false;
5309
5310
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5311
5312
			case 'convert':
5313
				extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s));
0 ignored issues
show
Bug introduced by
$this->imageMagickConver...ormat, $jpgQuality, $s) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
5314
				$cmd = sprintf('convert %s%s%s -crop %dx%d+%d+%d%s %s', $quotedPath, $coalesce, $jpgQuality, $width, $height, $x, $y, $deconstruct, $quotedDstPath);
5315
5316
				$result = false;
5317
				if ($this->procExec($cmd) === 0) {
5318
				    $result = true;
5319
				}
5320
5321
				return $result ? $path : false;
5322
5323
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5324
5325
			case 'gd':
5326
				$img = $this->gdImageCreate($path, $s['mime']);
5327
5328
				if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) {
5329
				    $bgNum = false;
5330 View Code Duplication
				    if ($s[2] === IMAGETYPE_GIF && (! $destformat || $destformat === 'gif')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $destformat of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
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...
5331
				        $bgIdx = imagecolortransparent($img);
5332
				        if ($bgIdx !== -1) {
5333
				            $c = imagecolorsforindex($img, $bgIdx);
5334
				            $bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']);
5335
				            imagefill($tmp, 0, 0, $bgNum);
5336
				            imagecolortransparent($tmp, $bgNum);
5337
				        }
5338
				    }
5339
				    if ($bgNum === false) {
5340
				        $this->gdImageBackground($tmp, 'transparent');
5341
				    }
5342
5343
				    $size_w = $width;
5344
				    $size_h = $height;
5345
5346
				    if ($s[0] < $width || $s[1] < $height) {
5347
				        $size_w = $s[0];
5348
				        $size_h = $s[1];
5349
				    }
5350
5351
				    if (! imagecopy($tmp, $img, 0, 0, $x, $y, $size_w, $size_h)) {
5352
				        return false;
5353
				    }
5354
5355
				    $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality);
5356
5357
				    imagedestroy($img);
5358
				    imagedestroy($tmp);
5359
5360
				    return $result ? $path : false;
5361
				}
5362
				break;
5363
		}
5364
5365
  	    return false;
5366
  	}
5367
5368
	/**
5369
	 * Put image to square.
5370
	 *
5371
	 * @param  string $path image file
5372
	 * @param  int $width square width
5373
	 * @param  int $height square height
5374
	 * @param int|string $align reserved
5375
	 * @param int|string $valign reserved
5376
	 * @param  string $bgcolor square background color in #rrggbb format
5377
	 * @param  string $destformat image destination format
5378
	 * @param  int $jpgQuality JEPG quality (1-100)
5379
	 * @return false|string
5380
	 * @author Dmitry (dio) Levashov
5381
	 * @author Alexey Sukhotin
5382
	 */
5383
	protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null, $jpgQuality = null)
0 ignored issues
show
Unused Code introduced by
The parameter $align 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 $valign 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...
5384
	{
5385
	    if (($s = getimagesize($path)) == false) {
5386
	        return false;
5387
	    }
5388
5389
	    $result = false;
0 ignored issues
show
Unused Code introduced by
$result 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...
5390
5391
		/* Coordinates for image over square aligning */
5392
		$y = ceil(abs($height - $s[1]) / 2);
5393
	    $x = ceil(abs($width - $s[0]) / 2);
5394
5395
	    if (! $jpgQuality) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $jpgQuality of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5396
	        $jpgQuality = $this->options['jpgQuality'];
5397
	    }
5398
5399
	    elFinder::extendTimeLimit(300);
5400
	    switch ($this->imgLib) {
5401
			case 'imagick':
5402
				try {
5403
				    $img = new imagick($path);
5404
				} catch (Exception $e) {
5405
				    return false;
5406
				}
5407
5408
				if ($bgcolor === 'transparent') {
5409
				    $bgcolor = 'rgba(255, 255, 255, 0.0)';
5410
				}
5411
				$ani = ($img->getNumberImages() > 1);
5412
				if ($ani && is_null($destformat)) {
5413
				    $img1 = new Imagick();
5414
				    $img1->setFormat('gif');
5415
				    $img = $img->coalesceImages();
5416
				    do {
5417
				        $gif = new Imagick();
5418
				        $gif->newImage($width, $height, new ImagickPixel($bgcolor));
5419
				        $gif->setImageColorspace($img->getImageColorspace());
5420
				        $gif->setImageFormat('gif');
5421
				        $gif->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y);
5422
				        $gif->setImageDelay($img->getImageDelay());
5423
				        $gif->setImageIterations($img->getImageIterations());
5424
				        $img1->addImage($gif);
5425
				        $gif->clear();
5426
				    } while ($img->nextImage());
5427
				    $img1 = $img1->optimizeImageLayers();
5428
				    $result = $img1->writeImages($path, true);
0 ignored issues
show
Bug introduced by
The method writeImages cannot be called on $img1 (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5429
				} else {
5430
				    if ($ani) {
5431
				        $img->setFirstIterator();
5432
				    }
5433
				    $img1 = new Imagick();
5434
				    $img1->newImage($width, $height, new ImagickPixel($bgcolor));
5435
				    $img1->setImageColorspace($img->getImageColorspace());
5436
				    $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y);
5437
				    $result = $this->imagickImage($img1, $path, $destformat, $jpgQuality);
0 ignored issues
show
Documentation introduced by
$img1 is of type object<Imagick>, but the function expects a resource.

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...
5438
				}
5439
5440
				$img1->clear();
5441
				$img->clear();
5442
5443
				return $result ? $path : false;
5444
5445
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5446
5447
			case 'convert':
5448
				extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s));
0 ignored issues
show
Bug introduced by
$this->imageMagickConver...ormat, $jpgQuality, $s) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
5449
				if ($bgcolor === 'transparent') {
5450
				    $bgcolor = 'rgba(255, 255, 255, 0.0)';
5451
				}
5452
				$cmd = sprintf('convert -size %dx%d "xc:%s" png:- | convert%s%s png:-  %s -geometry +%d+%d -compose over -composite%s %s', $width, $height, $bgcolor, $coalesce, $jpgQuality, $quotedPath, $x, $y, $deconstruct, $quotedDstPath);
5453
5454
				$result = false;
5455
				if ($this->procExec($cmd) === 0) {
5456
				    $result = true;
5457
				}
5458
5459
				return $result ? $path : false;
5460
5461
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5462
5463
			case 'gd':
5464
				$img = $this->gdImageCreate($path, $s['mime']);
5465
5466
				if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) {
5467
				    $this->gdImageBackground($tmp, $bgcolor);
5468
				    if ($bgcolor === 'transparent' && ($destformat === 'png' || $s[2] === IMAGETYPE_PNG)) {
5469
				        $bgNum = imagecolorallocatealpha($tmp, 255, 255, 255, 127);
5470
				        imagefill($tmp, 0, 0, $bgNum);
5471
				    }
5472
5473
				    if (! imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) {
5474
				        return false;
5475
				    }
5476
5477
				    $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality);
5478
5479
				    imagedestroy($img);
5480
				    imagedestroy($tmp);
5481
5482
				    return $result ? $path : false;
5483
				}
5484
				break;
5485
		}
5486
5487
	    return false;
5488
	}
5489
5490
	/**
5491
	 * Rotate image.
5492
	 *
5493
	 * @param  string   $path               image file
5494
	 * @param  int      $degree             rotete degrees
5495
	 * @param  string   $bgcolor            square background color in #rrggbb format
5496
	 * @param  string   $destformat         image destination format
5497
	 * @param  int      $jpgQuality         JEPG quality (1-100)
5498
	 * @return string|false
5499
	 * @author nao-pon
5500
	 * @author Troex Nevelin
5501
	 **/
5502
	protected function imgRotate($path, $degree, $bgcolor = '#ffffff', $destformat = null, $jpgQuality = null)
5503
	{
5504
	    if (($s = getimagesize($path)) == false || $degree % 360 === 0) {
5505
	        return false;
5506
	    }
5507
5508
	    $result = false;
5509
5510
		// try lossless rotate
5511
		if ($degree % 90 === 0 && in_array($s[2], [IMAGETYPE_JPEG, IMAGETYPE_JPEG2000])) {
5512
		    $count = ($degree / 90) % 4;
5513
		    $exiftran = [
5514
				1 => '-9',
5515
				2 => '-1',
5516
				3 => '-2',
5517
			];
5518
		    $jpegtran = [
5519
				1 => '90',
5520
				2 => '180',
5521
				3 => '270',
5522
			];
5523
		    $quotedPath = escapeshellarg($path);
5524
		    $cmds = [];
5525
		    if ($this->procExec('exiftran -h') === 0) {
5526
		        $cmds[] = 'exiftran -i '.$exiftran[$count].' '.$path;
5527
		    }
5528
		    if ($this->procExec('jpegtran -version') === 0) {
5529
		        $cmds[] = 'jpegtran -rotate '.$jpegtran[$count].' -copy all -outfile '.$quotedPath.' '.$quotedPath;
5530
		    }
5531
		    foreach ($cmds as $cmd) {
5532
		        if ($this->procExec($cmd) === 0) {
5533
		            $result = true;
5534
		            break;
5535
		        }
5536
		    }
5537
		    if ($result) {
5538
		        return $path;
5539
		    }
5540
		}
5541
5542
	    if (! $jpgQuality) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $jpgQuality of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5543
	        $jpgQuality = $this->options['jpgQuality'];
5544
	    }
5545
5546
	    elFinder::extendTimeLimit(300);
5547
	    switch ($this->imgLib) {
5548
			case 'imagick':
5549
				try {
5550
				    $img = new imagick($path);
5551
				} catch (Exception $e) {
5552
				    return false;
5553
				}
5554
5555 View Code Duplication
				if ($s[2] === IMAGETYPE_GIF || $s[2] === IMAGETYPE_PNG) {
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...
5556
				    $bgcolor = 'rgba(255, 255, 255, 0.0)';
5557
				}
5558
				if ($img->getNumberImages() > 1) {
5559
				    $img = $img->coalesceImages();
5560
				    do {
5561
				        $img->rotateImage(new ImagickPixel($bgcolor), $degree);
5562
				    } while ($img->nextImage());
5563
				    $img = $img->optimizeImageLayers();
5564
				    $result = $img->writeImages($path, true);
0 ignored issues
show
Bug introduced by
The method writeImages cannot be called on $img (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5565
				} else {
5566
				    $img->rotateImage(new ImagickPixel($bgcolor), $degree);
5567
				    $result = $this->imagickImage($img, $path, $destformat, $jpgQuality);
0 ignored issues
show
Documentation introduced by
$img is of type object<Imagick>, but the function expects a resource.

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...
5568
				}
5569
				$img->clear();
5570
5571
				return $result ? $path : false;
5572
5573
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5574
5575
			case 'convert':
5576
				extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s));
0 ignored issues
show
Bug introduced by
$this->imageMagickConver...ormat, $jpgQuality, $s) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
5577 View Code Duplication
				if ($s[2] === IMAGETYPE_GIF || $s[2] === IMAGETYPE_PNG) {
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...
5578
				    $bgcolor = 'rgba(255, 255, 255, 0.0)';
5579
				}
5580
				$cmd = sprintf('convert %s%s%s -background "%s" -rotate %d%s %s', $quotedPath, $coalesce, $jpgQuality, $bgcolor, $degree, $deconstruct, $quotedDstPath);
5581
5582
				$result = false;
5583
				if ($this->procExec($cmd) === 0) {
5584
				    $result = true;
5585
				}
5586
5587
				return $result ? $path : false;
5588
5589
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5590
5591
			case 'gd':
5592
				$img = $this->gdImageCreate($path, $s['mime']);
5593
5594
				$degree = 360 - $degree;
5595
5596
				$bgNum = -1;
5597
				$bgIdx = false;
5598
				if ($s[2] === IMAGETYPE_GIF) {
5599
				    $bgIdx = imagecolortransparent($img);
5600
				    if ($bgIdx !== -1) {
5601
				        $c = imagecolorsforindex($img, $bgIdx);
5602
				        $w = imagesx($img);
5603
				        $h = imagesy($img);
5604
				        $newImg = imagecreatetruecolor($w, $h);
5605
				        imagepalettecopy($newImg, $img);
5606
				        $bgNum = imagecolorallocate($newImg, $c['red'], $c['green'], $c['blue']);
5607
				        imagefill($newImg, 0, 0, $bgNum);
5608
				        imagecolortransparent($newImg, $bgNum);
5609
				        imagecopy($newImg, $img, 0, 0, 0, 0, $w, $h);
5610
				        imagedestroy($img);
5611
				        $img = $newImg;
5612
				        $newImg = null;
0 ignored issues
show
Unused Code introduced by
$newImg 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...
5613
				    }
5614
				} elseif ($s[2] === IMAGETYPE_PNG) {
5615
				    $bgNum = imagecolorallocatealpha($img, 255, 255, 255, 127);
5616
				}
5617 View Code Duplication
				if ($bgNum === -1) {
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...
5618
				    list($r, $g, $b) = sscanf($bgcolor, '#%02x%02x%02x');
5619
				    $bgNum = imagecolorallocate($img, $r, $g, $b);
5620
				}
5621
5622
				$tmp = imagerotate($img, $degree, $bgNum);
5623
				if ($bgIdx !== -1) {
5624
				    imagecolortransparent($tmp, $bgNum);
5625
				}
5626
5627
				$result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality);
5628
5629
				imagedestroy($img);
5630
				imagedestroy($tmp);
5631
5632
				return $result ? $path : false;
5633
5634
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
5635
		}
5636
5637
	    return false;
5638
	}
5639
5640
	/**
5641
	 * Execute shell command.
5642
	 *
5643
	 * @param  string $command command line
5644
	 * @param  array $output stdout strings
5645
	 * @param array|int $return_var process exit code
5646
	 * @param  array $error_output stderr strings
5647
	 * @return int exit code
5648
	 * @author Alexey Sukhotin
5649
	 */
5650
	protected function procExec($command, array &$output = null, &$return_var = -1, array &$error_output = null)
5651
	{
5652
	    static $allowed = null;
5653
5654
	    if ($allowed === null) {
5655
	        if ($allowed = function_exists('proc_open')) {
5656
	            if ($disabled = ini_get('disable_functions')) {
5657
	                $funcs = array_map('trim', explode(',', $disabled));
5658
	                $allowed = ! in_array('proc_open', $funcs);
5659
	            }
5660
	        }
5661
	    }
5662
5663
	    if (! $allowed) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $allowed of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
5664
	        $return_var = -1;
5665
5666
	        return $return_var;
5667
	    }
5668
5669
	    if (! $command) {
5670
	        $return_var = 0;
5671
5672
	        return $return_var;
5673
	    }
5674
5675
	    $descriptorspec = [
5676
			0 => ['pipe', 'r'],  // stdin
5677
			1 => ['pipe', 'w'],  // stdout
5678
			2 => ['pipe', 'w'],   // stderr
5679
		];
5680
5681
	    $process = proc_open($command, $descriptorspec, $pipes, null, null);
5682
5683
	    if (is_resource($process)) {
5684
	        fclose($pipes[0]);
5685
5686
	        $tmpout = '';
0 ignored issues
show
Unused Code introduced by
$tmpout 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...
5687
	        $tmperr = '';
0 ignored issues
show
Unused Code introduced by
$tmperr 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...
5688
5689
	        $output = stream_get_contents($pipes[1]);
5690
	        $error_output = stream_get_contents($pipes[2]);
5691
5692
	        fclose($pipes[1]);
5693
	        fclose($pipes[2]);
5694
	        $return_var = proc_close($process);
5695
	    } else {
5696
	        $return_var = -1;
5697
	    }
5698
5699
	    return $return_var;
5700
	}
5701
5702
	/**
5703
	 * Remove thumbnail, also remove recursively if stat is directory.
5704
	 *
5705
	 * @param  string  $stat  file stat
5706
	 * @return void
5707
	 * @author Dmitry (dio) Levashov
5708
	 * @author Naoki Sawada
5709
	 * @author Troex Nevelin
5710
	 **/
5711
	protected function rmTmb($stat)
5712
	{
5713
	    if ($stat['mime'] === 'directory') {
5714
	        foreach ($this->scandirCE($this->decode($stat['hash'])) as $p) {
5715
	            elFinder::extendTimeLimit(30);
5716
	            $name = $this->basenameCE($p);
5717
	            $name != '.' && $name != '..' && $this->rmTmb($this->stat($p));
0 ignored issues
show
Documentation introduced by
$this->stat($p) is of type array, but the function expects a string.

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...
5718
	        }
5719
	    } elseif (! empty($stat['tmb']) && $stat['tmb'] != '1') {
5720
	        $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$stat['tmb'];
5721
	        file_exists($tmb) && unlink($tmb);
5722
	        clearstatcache();
5723
	    }
5724
	}
5725
5726
	/**
5727
	 * Create an gd image according to the specified mime type.
5728
	 *
5729
	 * @param string $path image file
5730
	 * @param string $mime
5731
	 * @return gd image resource identifier
5732
	 */
5733
	protected function gdImageCreate($path, $mime)
5734
	{
5735
	    switch ($mime) {
5736
			case 'image/jpeg':
5737
			return imagecreatefromjpeg($path);
5738
5739
			case 'image/png':
5740
			return imagecreatefrompng($path);
5741
5742
			case 'image/gif':
5743
			return imagecreatefromgif($path);
5744
5745
			case 'image/x-ms-bmp':
5746
			if (! function_exists('imagecreatefrombmp')) {
5747
			    include_once dirname(__FILE__).'/libs/GdBmp.php';
5748
			}
5749
5750
			return imagecreatefrombmp($path);
5751
5752
			case 'image/xbm':
5753
			return imagecreatefromxbm($path);
5754
5755
			case 'image/xpm':
5756
			return imagecreatefromxpm($path);
5757
		}
5758
5759
	    return false;
5760
	}
5761
5762
	/**
5763
	 * Output gd image to file.
5764
	 *
5765
	 * @param resource $image gd image resource
5766
	 * @param string $filename The path to save the file to.
5767
	 * @param string $destformat The Image type to use for $filename
5768
	 * @param string $mime The original image mime type
5769
	 * @param int $jpgQuality JEPG quality (1-100)
5770
	 * @return bool
5771
	 */
5772
	protected function gdImage($image, $filename, $destformat, $mime, $jpgQuality = null)
5773
	{
5774
	    if (! $jpgQuality) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $jpgQuality of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5775
	        $jpgQuality = $this->options['jpgQuality'];
5776
	    }
5777
	    if ($destformat) {
5778
	        switch ($destformat) {
5779
				case 'jpg':
5780
					$mime = 'image/jpeg';
5781
					break;
5782
				case 'gif':
5783
					$mime = 'image/gif';
5784
					break;
5785
				case 'png':
5786
				default:
5787
					$mime = 'image/png';
5788
					break;
5789
			}
5790
	    }
5791
	    switch ($mime) {
5792
			case 'image/gif':
5793
				return imagegif($image, $filename);
5794
			case 'image/jpeg':
5795
				return imagejpeg($image, $filename, $jpgQuality);
5796
			case 'image/wbmp':
5797
				return imagewbmp($image, $filename);
5798
			case 'image/png':
5799
			default:
5800
				return imagepng($image, $filename);
5801
		}
5802
	}
5803
5804
	/**
5805
	 * Output imagick image to file.
5806
	 *
5807
	 * @param resource $img imagick image resource
5808
	 * @param string $filename The path to save the file to.
5809
	 * @param string $destformat The Image type to use for $filename
5810
	 * @param int $jpgQuality JEPG quality (1-100)
5811
	 * @return bool
5812
	 */
5813
	protected function imagickImage($img, $filename, $destformat, $jpgQuality = null)
5814
	{
5815
	    if (! $jpgQuality) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $jpgQuality of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5816
	        $jpgQuality = $this->options['jpgQuality'];
5817
	    }
5818
5819
	    try {
5820
	        if ($destformat) {
5821
	            if ($destformat === 'gif') {
5822
	                $img->setImageFormat('gif');
0 ignored issues
show
Bug introduced by
The method setImageFormat cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5823
	            } elseif ($destformat === 'png') {
5824
	                $img->setImageFormat('png');
0 ignored issues
show
Bug introduced by
The method setImageFormat cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5825
	            } elseif ($destformat === 'jpg') {
5826
	                $img->setImageFormat('jpeg');
0 ignored issues
show
Bug introduced by
The method setImageFormat cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5827
	            }
5828
	        }
5829
	        if (strtoupper($img->getImageFormat()) === 'JPEG') {
0 ignored issues
show
Bug introduced by
The method getImageFormat cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5830
	            $img->setImageCompression(imagick::COMPRESSION_JPEG);
0 ignored issues
show
Bug introduced by
The method setImageCompression cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5831
	            $img->setImageCompressionQuality($jpgQuality);
0 ignored issues
show
Bug introduced by
The method setImageCompressionQuality cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5832
	            try {
5833
	                $orientation = $img->getImageOrientation();
0 ignored issues
show
Bug introduced by
The method getImageOrientation cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5834
	            } catch (ImagickException $e) {
5835
	                $orientation = 0;
5836
	            }
5837
	            $img->stripImage();
0 ignored issues
show
Bug introduced by
The method stripImage cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5838
	            if ($orientation) {
5839
	                $img->setImageOrientation($orientation);
0 ignored issues
show
Bug introduced by
The method setImageOrientation cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5840
	            }
5841
	        }
5842
	        $result = $img->writeImage($filename);
0 ignored issues
show
Bug introduced by
The method writeImage cannot be called on $img (of type resource).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
5843
	    } catch (Exception $e) {
5844
	        $result = false;
5845
	    }
5846
5847
	    return $result;
5848
	}
5849
5850
	/**
5851
	 * Assign the proper background to a gd image.
5852
	 *
5853
	 * @param resource $image gd image resource
5854
	 * @param string $bgcolor background color in #rrggbb format
5855
	 */
5856
	protected function gdImageBackground($image, $bgcolor)
5857
	{
5858
	    if ($bgcolor === 'transparent') {
5859
	        imagealphablending($image, false);
5860
	        imagesavealpha($image, true);
5861 View Code Duplication
	    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5862
	        list($r, $g, $b) = sscanf($bgcolor, '#%02x%02x%02x');
5863
	        $bgcolor1 = imagecolorallocate($image, $r, $g, $b);
5864
	        imagefill($image, 0, 0, $bgcolor1);
5865
	    }
5866
	}
5867
5868
	/**
5869
	 * Prepare variables for exec convert of ImageMagick.
5870
	 *
5871
	 * @param  string  $path
5872
	 * @param  string  $destformat
5873
	 * @param  int     $jpgQuality
5874
	 * @param  array   $imageSize
5875
	 * @return array
5876
	 */
5877
	protected function imageMagickConvertPrepare($path, $destformat, $jpgQuality, $imageSize = null)
5878
	{
5879
	    if (is_null($imageSize)) {
5880
	        $imageSize = getimagesize($path);
5881
	    }
5882
	    if (! $imageSize) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $imageSize 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...
5883
	        return [];
5884
	    }
5885
	    $srcType = $this->getExtentionByMime($imageSize['mime'], ':');
5886
	    $ani = false;
5887
	    $cmd = 'identify '.escapeshellarg($srcType.$path);
5888
	    if ($this->procExec($cmd, $o) === 0) {
5889
	        $ani = preg_split('/(?:\r\n|\n|\r)/', trim($o));
5890
	        if (count($ani) < 2) {
5891
	            $ani = false;
5892
	        }
5893
	    }
5894
	    $coalesce = $index = '';
5895
	    $deconstruct = ' +repage';
5896
	    if ($ani) {
5897
	        if (is_null($destformat)) {
5898
	            $coalesce = ' -coalesce -repage 0x0';
5899
	            $deconstruct = ' +repage -deconstruct -layers optimize';
5900
	        } else {
5901
	            $index = '[0]';
5902
	            if ($srcType === 'ico:') {
5903
	                foreach ($ani as $_i => $_info) {
5904
	                    if (preg_match('/ (\d+)x(\d+) /', $_info, $m)) {
5905
	                        if ($m[1] == $imageSize[0] && $m[2] == $imageSize[1]) {
5906
	                            $index = '['.$_i.']';
5907
	                            break;
5908
	                        }
5909
	                    }
5910
	                }
5911
	            }
5912
	        }
5913
	    }
5914
	    if ($imageSize[2] === IMAGETYPE_JPEG || $imageSize[2] === IMAGETYPE_JPEG2000) {
5915
	        $jpgQuality = ' -quality '.$jpgQuality;
5916
	    } else {
5917
	        $jpgQuality = '';
5918
	    }
5919
	    $quotedPath = escapeshellarg($srcType.$path.$index);
5920
	    $quotedDstPath = escapeshellarg(($destformat ? ($destformat.':') : $srcType).$path);
5921
5922
	    return compact('ani', 'index', 'coalesce', 'deconstruct', 'jpgQuality', 'quotedPath', 'quotedDstPath');
5923
	}
5924
5925
	/*********************** misc *************************/
5926
5927
	/**
5928
	 * Return smart formatted date.
5929
	 *
5930
	 * @param  int     $ts  file timestamp
5931
	 * @return string
5932
	 * @author Dmitry (dio) Levashov
5933
	 **/
5934
	// protected function formatDate($ts) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5935
	// 	if ($ts > $this->today) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5936
	// 		return 'Today '.date($this->options['timeFormat'], $ts);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5937
	// 	}
5938
	//
5939
	// 	if ($ts > $this->yesterday) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5940
	// 		return 'Yesterday '.date($this->options['timeFormat'], $ts);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5941
	// 	}
5942
	//
5943
	// 	return date($this->options['dateFormat'], $ts);
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
5944
	// }
5945
5946
	/**
5947
	 * Find position of first occurrence of string in a string with multibyte support.
5948
	 *
5949
	 * @param  string  $haystack  The string being checked.
5950
	 * @param  string  $needle    The string to find in haystack.
5951
	 * @param  int     $offset    The search offset. If it is not specified, 0 is used.
5952
	 * @return int|bool
5953
	 * @author Alexey Sukhotin
5954
	 **/
5955
	protected function stripos($haystack, $needle, $offset = 0)
5956
	{
5957
	    if (function_exists('mb_stripos')) {
5958
	        return mb_stripos($haystack, $needle, $offset, 'UTF-8');
5959
	    } elseif (function_exists('mb_strtolower') && function_exists('mb_strpos')) {
5960
	        return mb_strpos(mb_strtolower($haystack, 'UTF-8'), mb_strtolower($needle, 'UTF-8'), $offset);
5961
	    }
5962
5963
	    return stripos($haystack, $needle, $offset);
5964
	}
5965
5966
	/**
5967
	 * Get server side available archivers.
5968
	 *
5969
	 * @param bool $use_cache
5970
	 * @return array
5971
	 */
5972
	protected function getArchivers($use_cache = true)
5973
	{
5974
	    $sessionKey = 'ARCHIVERS_CACHE';
5975
	    if ($use_cache && isset($this->sessionCache[$sessionKey]) && is_array($this->sessionCache[$sessionKey])) {
5976
	        return $this->sessionCache[$sessionKey];
5977
	    }
5978
5979
	    $arcs = [
5980
			'create' => [],
5981
			'extract' => [],
5982
		];
5983
5984
	    if ($this->procExec('') === 0) {
5985
	        $this->procExec('tar --version', $o, $ctar);
5986
5987
	        if ($ctar == 0) {
5988
	            $arcs['create']['application/x-tar'] = ['cmd' => 'tar', 'argc' => '-cf', 'ext' => 'tar'];
5989
	            $arcs['extract']['application/x-tar'] = ['cmd' => 'tar', 'argc' => '-xf', 'ext' => 'tar', 'toSpec' => '-C '];
5990
	            unset($o);
5991
	            $this->procExec('gzip --version', $o, $c);
5992 View Code Duplication
	            if ($c == 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...
5993
	                $arcs['create']['application/x-gzip'] = ['cmd' => 'tar', 'argc' => '-czf', 'ext' => 'tgz'];
5994
	                $arcs['extract']['application/x-gzip'] = ['cmd' => 'tar', 'argc' => '-xzf', 'ext' => 'tgz', 'toSpec' => '-C '];
5995
	            }
5996
	            unset($o);
5997
	            $this->procExec('bzip2 --version', $o, $c);
5998 View Code Duplication
	            if ($c == 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...
5999
	                $arcs['create']['application/x-bzip2'] = ['cmd' => 'tar', 'argc' => '-cjf', 'ext' => 'tbz'];
6000
	                $arcs['extract']['application/x-bzip2'] = ['cmd' => 'tar', 'argc' => '-xjf', 'ext' => 'tbz', 'toSpec' => '-C '];
6001
	            }
6002
	            unset($o);
6003
	            $this->procExec('xz --version', $o, $c);
6004 View Code Duplication
	            if ($c == 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...
6005
	                $arcs['create']['application/x-xz'] = ['cmd' => 'tar', 'argc' => '-cJf', 'ext' => 'xz'];
6006
	                $arcs['extract']['application/x-xz'] = ['cmd' => 'tar', 'argc' => '-xJf', 'ext' => 'xz', 'toSpec' => '-C '];
6007
	            }
6008
	        }
6009
	        unset($o);
6010
	        $this->procExec('zip -v', $o, $c);
6011 View Code Duplication
	        if ($c == 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...
6012
	            $arcs['create']['application/zip'] = ['cmd' => 'zip', 'argc' => '-r9', 'ext' => 'zip'];
6013
	        }
6014
	        unset($o);
6015
	        $this->procExec('unzip --help', $o, $c);
6016 View Code Duplication
	        if ($c == 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...
6017
	            $arcs['extract']['application/zip'] = ['cmd' => 'unzip', 'argc' => '',  'ext' => 'zip', 'toSpec' => '-d '];
6018
	        }
6019
	        unset($o);
6020
	        $this->procExec('rar --version', $o, $c);
6021 View Code Duplication
	        if ($c == 0 || $c == 7) {
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...
6022
	            $arcs['create']['application/x-rar'] = ['cmd' => 'rar', 'argc' => 'a -inul', 'ext' => 'rar'];
6023
	        }
6024
	        unset($o);
6025
	        $this->procExec('unrar', $o, $c);
6026 View Code Duplication
	        if ($c == 0 || $c == 7) {
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...
6027
	            $arcs['extract']['application/x-rar'] = ['cmd' => 'unrar', 'argc' => 'x -y', 'ext' => 'rar', 'toSpec' => ''];
6028
	        }
6029
	        unset($o);
6030
	        $this->procExec('7za --help', $o, $c);
6031
	        if ($c == 0) {
6032
	            $arcs['create']['application/x-7z-compressed'] = ['cmd' => '7za', 'argc' => 'a', 'ext' => '7z'];
6033
	            $arcs['extract']['application/x-7z-compressed'] = ['cmd' => '7za', 'argc' => 'x -y', 'ext' => '7z', 'toSpec' => '-o'];
6034
6035
	            if (empty($arcs['create']['application/zip'])) {
6036
	                $arcs['create']['application/zip'] = ['cmd' => '7za', 'argc' => 'a -tzip', 'ext' => 'zip'];
6037
	            }
6038 View Code Duplication
	            if (empty($arcs['extract']['application/zip'])) {
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...
6039
	                $arcs['extract']['application/zip'] = ['cmd' => '7za', 'argc' => 'x -tzip -y', 'ext' => 'zip', 'toSpec' => '-o'];
6040
	            }
6041
	            if (empty($arcs['create']['application/x-tar'])) {
6042
	                $arcs['create']['application/x-tar'] = ['cmd' => '7za', 'argc' => 'a -ttar', 'ext' => 'tar'];
6043
	            }
6044 View Code Duplication
	            if (empty($arcs['extract']['application/x-tar'])) {
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...
6045
	                $arcs['extract']['application/x-tar'] = ['cmd' => '7za', 'argc' => 'x -ttar -y', 'ext' => 'tar', 'toSpec' => '-o'];
6046
	            }
6047
	        } elseif (substr(PHP_OS, 0, 3) === 'WIN') {
6048
	            // check `7z` for Windows server.
6049
				unset($o);
6050
	            $this->procExec('7z', $o, $c);
6051
	            if ($c == 0) {
6052
	                $arcs['create']['application/x-7z-compressed'] = ['cmd' => '7z', 'argc' => 'a', 'ext' => '7z'];
6053
	                $arcs['extract']['application/x-7z-compressed'] = ['cmd' => '7z', 'argc' => 'x -y', 'ext' => '7z', 'toSpec' => '-o'];
6054
6055
	                if (empty($arcs['create']['application/zip'])) {
6056
	                    $arcs['create']['application/zip'] = ['cmd' => '7z', 'argc' => 'a -tzip', 'ext' => 'zip'];
6057
	                }
6058 View Code Duplication
	                if (empty($arcs['extract']['application/zip'])) {
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...
6059
	                    $arcs['extract']['application/zip'] = ['cmd' => '7z', 'argc' => 'x -tzip -y', 'ext' => 'zip', 'toSpec' => '-o'];
6060
	                }
6061
	                if (empty($arcs['create']['application/x-tar'])) {
6062
	                    $arcs['create']['application/x-tar'] = ['cmd' => '7z', 'argc' => 'a -ttar', 'ext' => 'tar'];
6063
	                }
6064 View Code Duplication
	                if (empty($arcs['extract']['application/x-tar'])) {
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...
6065
	                    $arcs['extract']['application/x-tar'] = ['cmd' => '7z', 'argc' => 'x -ttar -y', 'ext' => 'tar', 'toSpec' => '-o'];
6066
	                }
6067 View Code Duplication
	                if (empty($arcs['extract']['application/x-rar'])) {
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...
6068
	                    $arcs['extract']['application/x-rar'] = ['cmd' => '7z', 'argc' => 'x -trar -y', 'ext' => 'rar', 'toSpec' => '-o'];
6069
	                }
6070
	            }
6071
	        }
6072
	    }
6073
6074
		// Use PHP ZipArchive Class
6075
		if (class_exists('ZipArchive', false)) {
6076
		    if (empty($arcs['create']['application/zip'])) {
6077
		        $arcs['create']['application/zip'] = ['cmd' => 'phpfunction', 'argc' => ['self', 'zipArchiveZip'], 'ext' => 'zip'];
6078
		    }
6079
		    if (empty($arcs['extract']['application/zip'])) {
6080
		        $arcs['extract']['application/zip'] = ['cmd' => 'phpfunction', 'argc' => ['self', 'zipArchiveUnzip'], 'ext' => 'zip'];
6081
		    }
6082
		}
6083
6084
	    $this->sessionCache[$sessionKey] = $arcs;
6085
6086
	    return $arcs;
6087
	}
6088
6089
	/**
6090
	 * Resolve relative / (Unix-like)absolute path.
6091
	 *
6092
	 * @param string $path  target path
6093
	 * @param string $base  base path
6094
	 * @return string
6095
	 */
6096
	protected function getFullPath($path, $base)
6097
	{
6098
	    $separator = $this->separator;
6099
	    $systemroot = $this->systemRoot;
6100
6101
	    if ($base[0] === $separator && strpos($base, 0, strlen($systemroot)) !== $systemroot) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of strpos($base, 0, strlen($systemroot)) (integer) and $systemroot (string) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
6102
	        $base = $systemroot.substr($base, 1);
6103
	    }
6104
6105
		// 'Here'
6106
		if ($path === '' || $path === '.'.$separator) {
6107
		    return $base;
6108
		}
6109
6110
	    $sepquoted = preg_quote($separator, '#');
6111
6112
	    if (substr($path, 0, 3) === '..'.$separator) {
6113
	        $path = $base.$separator.$path;
6114
	    }
6115
		// normalize `/../`
6116
		$normreg = '#('.$sepquoted.')[^'.$sepquoted.']+'.$sepquoted.'\.\.'.$sepquoted.'#'; // '#(/)[^\/]+/\.\./#'
6117
		while (preg_match($normreg, $path)) {
6118
		    $path = preg_replace($normreg, '$1', $path, 1);
6119
		}
6120
6121
		// Absolute path
6122
		if ($path[0] === $separator || strpos($path, $systemroot) === 0) {
6123
		    return $path;
6124
		}
6125
6126
	    $preg_separator = '#'.$sepquoted.'#';
6127
6128
		// Relative path from 'Here'
6129
		if (substr($path, 0, 2) === '.'.$separator || $path[0] !== '.') {
6130
		    $arrn = preg_split($preg_separator, $path, -1, PREG_SPLIT_NO_EMPTY);
6131
		    if ($arrn[0] !== '.') {
6132
		        array_unshift($arrn, '.');
6133
		    }
6134
		    $arrn[0] = $base;
6135
6136
		    return implode($separator, $arrn);
6137
		}
6138
6139
	    return $path;
6140
	}
6141
6142
	/**
6143
	 * Create archive and return its path.
6144
	 *
6145
	 * @param  string  $dir    target dir
6146
	 * @param  array   $files  files names list
6147
	 * @param  string  $name   archive name
6148
	 * @param  array   $arc    archiver options
6149
	 * @return string|bool
6150
	 * @author Dmitry (dio) Levashov,
6151
	 * @author Alexey Sukhotin
6152
	 * @author Naoki Sawada
6153
	 **/
6154
	protected function makeArchive($dir, $files, $name, $arc)
6155
	{
6156
	    if ($arc['cmd'] === 'phpfunction') {
6157 View Code Duplication
	        if (is_callable($arc['argc'])) {
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...
6158
	            call_user_func_array($arc['argc'], [$dir, $files, $name]);
6159
	        }
6160
	    } else {
6161
	        $cwd = getcwd();
6162
	        if (chdir($dir)) {
6163
	            foreach ($files as $i => $file) {
6164
	                $files[$i] = '.'.DIRECTORY_SEPARATOR.$file;
6165
	            }
6166
	            $files = array_map('escapeshellarg', $files);
6167
6168
	            $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($name).' '.implode(' ', $files);
6169
	            $this->procExec($cmd, $o, $c);
6170
	            chdir($cwd);
6171
	        } else {
6172
	            return false;
6173
	        }
6174
	    }
6175
	    $path = $dir.DIRECTORY_SEPARATOR.$name;
6176
6177
	    return file_exists($path) ? $path : false;
6178
	}
6179
6180
	/**
6181
	 * Unpack archive.
6182
	 *
6183
	 * @param  string      $path  archive path
6184
	 * @param  array       $arc   archiver command and arguments (same as in $this->archivers)
6185
	 * @param  bool|string $mode  bool: remove archive ( unlink($path) ) | string: extract to directory
6186
	 * @return void
6187
	 * @author Dmitry (dio) Levashov
6188
	 * @author Alexey Sukhotin
6189
	 * @author Naoki Sawada
6190
	 **/
6191
	protected function unpackArchive($path, $arc, $mode = true)
6192
	{
6193
	    if (is_string($mode)) {
6194
	        $dir = $mode;
6195
	        $chdir = null;
6196
	        $remove = false;
6197
	    } else {
6198
	        $dir = dirname($path);
6199
	        $chdir = $dir;
6200
	        $remove = $mode;
6201
	    }
6202
	    $dir = realpath($dir);
6203
	    $path = realpath($path);
6204
	    if ($arc['cmd'] === 'phpfunction') {
6205 View Code Duplication
	        if (is_callable($arc['argc'])) {
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...
6206
	            call_user_func_array($arc['argc'], [$path, $dir]);
6207
	        }
6208
	    } else {
6209
	        $cwd = getcwd();
6210
	        if (! $chdir || chdir($dir)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $chdir of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
6211
	            if ($chdir) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $chdir of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
6212
	                $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg(basename($path));
6213
	            } else {
6214
	                $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($path).' '.$arc['toSpec'].escapeshellarg($dir);
6215
	            }
6216
	            $this->procExec($cmd, $o, $c);
6217
	            $chdir && chdir($cwd);
0 ignored issues
show
Bug Best Practice introduced by
The expression $chdir of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
6218
	        }
6219
	    }
6220
	    $remove && unlink($path);
6221
	}
6222
6223
	/**
6224
	 * Check and filter the extracted items.
6225
	 *
6226
	 * @param  string $path    target local path
6227
	 * @param  array  $checks  types to check default: ['symlink', 'name', 'writable', 'mime']
6228
	 * @return array  ['symlinks' => [], 'names' => [], 'writables' => [], 'mimes' => [], 'rmNames' => [], 'totalSize' => 0]
6229
	 * @author Naoki Sawada
6230
	 */
6231
	protected function checkExtractItems($path, $checks = null)
6232
	{
6233
	    if (is_null($checks) || ! is_array($checks)) {
6234
	        $checks = ['symlink', 'name', 'writable', 'mime'];
6235
	    }
6236
	    $chkSymlink = in_array('symlink', $checks);
6237
	    $chkName = in_array('name', $checks);
6238
	    $chkWritable = in_array('writable', $checks);
6239
	    $chkMime = in_array('mime', $checks);
6240
6241
	    $res = [
6242
			'symlinks' => [],
6243
			'names' => [],
6244
			'writables' => [],
6245
			'mimes' => [],
6246
			'rmNames' => [],
6247
			'totalSize' => 0,
6248
		];
6249
6250
	    if (is_dir($path)) {
6251
	        foreach (self::localScandir($path) as $name) {
6252
	            $p = $path.DIRECTORY_SEPARATOR.$name;
6253
	            if ($chkSymlink && is_link($p)) {
6254
	                self::localRmdirRecursive($p);
6255
	                $res['symlinks'][] = $p;
6256
	                $res['rmNames'][] = $name;
6257
	                continue;
6258
	            }
6259
	            $isDir = is_dir($p);
6260
	            if ($chkName && ! $this->nameAccepted($name, $isDir)) {
6261
	                self::localRmdirRecursive($p);
6262
	                $res['names'][] = $p;
6263
	                $res['rmNames'][] = $name;
6264
	                continue;
6265
	            }
6266
	            if ($chkWritable && ! $this->attr($p, 'write', null, $isDir)) {
6267
	                self::localRmdirRecursive($p);
6268
	                $res['writables'][] = $p;
6269
	                $res['rmNames'][] = $name;
6270
	                continue;
6271
	            }
6272 View Code Duplication
	            if ($chkMime && ($mimeByName = self::mimetypeInternalDetect($name)) && $mimeByName !== 'unknown' && ! $this->allowPutMime($mimeByName)) {
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...
6273
	                self::localRmdirRecursive($p);
6274
	                $res['mimes'][] = $p;
6275
	                $res['rmNames'][] = $name;
6276
	                continue;
6277
	            }
6278
	            if ($isDir) {
6279
	                $cRes = $this->checkExtractItems($p, $checks);
6280
	                foreach ($cRes as $k => $v) {
6281
	                    if (is_array($v)) {
6282
	                        $res[$k] = array_merge($res[$k], $cRes[$k]);
6283
	                    } else {
6284
	                        $res[$k] += $cRes[$k];
6285
	                    }
6286
	                }
6287
	            } else {
6288
	                $res['totalSize'] += sprintf('%u', filesize($p));
6289
	            }
6290
	        }
6291
	        $res['rmNames'] = array_unique($res['rmNames']);
6292
	    } else {
6293
	        if ($chkSymlink && is_link($path)) {
6294
	            unlink($path);
6295
	            $res['symlinks'][] = $path;
6296
	            $res['rmNames'][] = basename($path);
6297
	        } elseif ($chkName && ! $this->nameAccepted($name, false)) {
0 ignored issues
show
Bug introduced by
The variable $name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
6298
	            unlink($path);
6299
	            $res['names'][] = $path;
6300
	            $res['rmNames'][] = $name;
0 ignored issues
show
Bug introduced by
The variable $name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
6301
	        } elseif ($chkWritable && ! $this->attr($path, 'write', null, $isDir)) {
0 ignored issues
show
Bug introduced by
The variable $isDir seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
6302
	            unlink($path);
6303
	            $res['writables'][] = $path;
6304
	            $res['rmNames'][] = $name;
0 ignored issues
show
Bug introduced by
The variable $name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
6305 View Code Duplication
	        } elseif ($chkMime && ($mimeByName = self::mimetypeInternalDetect($name)) && $mimeByName !== 'unknown' && ! $this->allowPutMime($mimeByName)) {
0 ignored issues
show
Bug introduced by
The variable $name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

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...
6306
	            unlink($path);
6307
	            $res['mimes'][] = $path;
6308
	            $res['rmNames'][] = $name;
0 ignored issues
show
Bug introduced by
The variable $name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
6309
	        } else {
6310
	            $res['totalSize'] += sprintf('%u', filesize($path));
6311
	        }
6312
	    }
6313
6314
	    return $res;
6315
	}
6316
6317
	/**
6318
	 * Return files of target directory that is dotfiles excludes.
6319
	 *
6320
	 * @param  string $dir target directory path
6321
	 * @return array
6322
	 * @throws Exception
6323
	 * @author Naoki Sawada
6324
	 */
6325
	protected static function localScandir($dir)
6326
	{
6327
	    // PHP function scandir() is not work well in specific environment. I dont know why.
6328
		// ref. https://github.com/Studio-42/elFinder/issues/1248
6329
		$files = [];
6330
	    if ($dh = opendir($dir)) {
6331
	        while (false !== ($file = readdir($dh))) {
6332
	            if ($file !== '.' && $file !== '..') {
6333
	                $files[] = $file;
6334
	            }
6335
	        }
6336
	        closedir($dh);
6337
	    } else {
6338
	        throw new Exception('Can not open local directory.');
6339
	    }
6340
6341
	    return $files;
6342
	}
6343
6344
	/**
6345
	 * Remove directory recursive on local file system.
6346
	 *
6347
	 * @param string $dir Target dirctory path
6348
	 * @return bool
6349
	 * @author Naoki Sawada
6350
	 */
6351
	protected static function localRmdirRecursive($dir)
6352
	{
6353
	    if (! is_link($dir) && is_dir($dir)) {
6354
	        chmod($dir, 0777);
6355
	        if ($handle = opendir($dir)) {
6356
	            while (false !== ($file = readdir($handle))) {
6357
	                if ($file === '.' || $file === '..') {
6358
	                    continue;
6359
	                }
6360
	                elFinder::extendTimeLimit(30);
6361
	                $path = $dir.DIRECTORY_SEPARATOR.$file;
6362
	                if (! is_link($dir) && is_dir($path)) {
6363
	                    self::localRmdirRecursive($path);
6364
	                } else {
6365
	                    chmod($path, 0666);
6366
	                    unlink($path);
6367
	                }
6368
	            }
6369
	            closedir($handle);
6370
	        }
6371
6372
	        return rmdir($dir);
6373
	    } elseif (is_file($dir) || is_link($dir)) {
6374
	        chmod($dir, 0666);
6375
6376
	        return unlink($dir);
6377
	    }
6378
6379
	    return false;
6380
	}
6381
6382
	/**
6383
	 * Move item recursive on local file system.
6384
	 *
6385
	 * @param string $src
6386
	 * @param string $target
6387
	 * @param string $overWrite
6388
	 * @param string $copyJoin
6389
	 * @return bool
6390
	 * @author Naoki Sawada
6391
	 */
6392
	protected static function localMoveRecursive($src, $target, $overWrite = true, $copyJoin = true)
6393
	{
6394
	    $res = false;
6395
	    if (! file_exists($target)) {
6396
	        return rename($src, $target);
6397
	    }
6398
	    if (! $copyJoin || ! is_dir($target)) {
6399
	        if ($overWrite) {
6400
	            if (is_dir($target)) {
6401
	                $del = self::localRmdirRecursive($target);
6402
	            } else {
6403
	                $del = unlink($target);
6404
	            }
6405
	            if ($del) {
6406
	                return rename($src, $target);
6407
	            }
6408
	        }
6409
	    } else {
6410
	        foreach (self::localScandir($src) as $item) {
6411
	            $res |= self::localMoveRecursive($src.DIRECTORY_SEPARATOR.$item, $target.DIRECTORY_SEPARATOR.$item, $overWrite, $copyJoin);
6412
	        }
6413
	    }
6414
6415
	    return (bool) $res;
6416
	}
6417
6418
	/**
6419
	 * Create Zip archive using PHP class ZipArchive.
6420
	 *
6421
	 * @param  string        $dir      target dir
6422
	 * @param  array         $files    files names list
6423
	 * @param  string|object $zipPath  Zip archive name
6424
	 * @return bool
6425
	 * @author Naoki Sawada
6426
	 */
6427
	protected static function zipArchiveZip($dir, $files, $zipPath)
6428
	{
6429
	    try {
6430
	        if ($start = is_string($zipPath)) {
6431
	            $zip = new ZipArchive();
6432
	            if ($zip->open($dir.DIRECTORY_SEPARATOR.$zipPath, ZipArchive::CREATE) !== true) {
6433
	                $zip = false;
6434
	            }
6435
	        } else {
6436
	            $zip = $zipPath;
6437
	        }
6438
	        if ($zip) {
6439
	            foreach ($files as $file) {
6440
	                $path = $dir.DIRECTORY_SEPARATOR.$file;
6441
	                if (is_dir($path)) {
6442
	                    $zip->addEmptyDir($file);
6443
	                    $_files = [];
6444
	                    if ($handle = opendir($path)) {
6445
	                        while (false !== ($entry = readdir($handle))) {
6446
	                            if ($entry !== '.' && $entry !== '..') {
6447
	                                $_files[] = $file.DIRECTORY_SEPARATOR.$entry;
6448
	                            }
6449
	                        }
6450
	                        closedir($handle);
6451
	                    }
6452
	                    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...
6453
	                        self::zipArchiveZip($dir, $_files, $zip);
6454
	                    }
6455
	                } else {
6456
	                    $zip->addFile($path, $file);
6457
	                }
6458
	            }
6459
	            $start && $zip->close();
6460
	        }
6461
	    } catch (Exception $e) {
6462
	        return false;
6463
	    }
6464
6465
	    return true;
6466
	}
6467
6468
	/**
6469
	 * Unpack Zip archive using PHP class ZipArchive.
6470
	 *
6471
	 * @param  string $zipPath  Zip archive name
6472
	 * @param  string $toDir    Extract to path
6473
	 * @return bool
6474
	 * @author Naoki Sawada
6475
	 */
6476
	protected static function zipArchiveUnzip($zipPath, $toDir)
6477
	{
6478
	    try {
6479
	        $zip = new ZipArchive();
6480
	        if ($zip->open($zipPath) === true) {
6481
	            $zip->extractTo($toDir);
6482
	            $zip->close();
6483
	        }
6484
	    } catch (Exception $e) {
6485
	        return false;
6486
	    }
6487
6488
	    return true;
6489
	}
6490
6491
	/**
6492
	 * Recursive symlinks search.
6493
	 *
6494
	 * @param  string  $path  file/dir path
6495
	 * @return bool
6496
	 * @author Dmitry (dio) Levashov
6497
	 **/
6498
	protected static function localFindSymlinks($path)
6499
	{
6500
	    if (is_link($path)) {
6501
	        return true;
6502
	    }
6503
6504
	    if (is_dir($path)) {
6505
	        foreach (self::localScandir($path) as $name) {
6506
	            $p = $path.DIRECTORY_SEPARATOR.$name;
6507
	            if (is_link($p)) {
6508
	                return true;
6509
	            }
6510
	            if (is_dir($p) && $this->_findSymlinks($p)) {
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

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

Loading history...
6511
	                return true;
6512
	            }
6513
	        }
6514
	    }
6515
6516
	    return false;
6517
	}
6518
6519
	/**==================================* abstract methods *====================================**/
6520
6521
	/*********************** paths/urls *************************/
6522
6523
	/**
6524
	 * Return parent directory path.
6525
	 *
6526
	 * @param  string  $path  file path
6527
	 * @return string
6528
	 * @author Dmitry (dio) Levashov
6529
	 **/
6530
	abstract protected function _dirname($path);
6531
6532
	/**
6533
	 * Return file name.
6534
	 *
6535
	 * @param  string  $path  file path
6536
	 * @return string
6537
	 * @author Dmitry (dio) Levashov
6538
	 **/
6539
	abstract protected function _basename($path);
6540
6541
	/**
6542
	 * Join dir name and file name and return full path.
6543
	 * Some drivers (db) use int as path - so we give to concat path to driver itself.
6544
	 *
6545
	 * @param  string  $dir   dir path
6546
	 * @param  string  $name  file name
6547
	 * @return string
6548
	 * @author Dmitry (dio) Levashov
6549
	 **/
6550
	abstract protected function _joinPath($dir, $name);
6551
6552
	/**
6553
	 * Return normalized path.
6554
	 *
6555
	 * @param  string  $path  file path
6556
	 * @return string
6557
	 * @author Dmitry (dio) Levashov
6558
	 **/
6559
	abstract protected function _normpath($path);
6560
6561
	/**
6562
	 * Return file path related to root dir.
6563
	 *
6564
	 * @param  string  $path  file path
6565
	 * @return string
6566
	 * @author Dmitry (dio) Levashov
6567
	 **/
6568
	abstract protected function _relpath($path);
6569
6570
	/**
6571
	 * Convert path related to root dir into real path.
6572
	 *
6573
	 * @param  string  $path  rel file path
6574
	 * @return string
6575
	 * @author Dmitry (dio) Levashov
6576
	 **/
6577
	abstract protected function _abspath($path);
6578
6579
	/**
6580
	 * Return fake path started from root dir.
6581
	 * Required to show path on client side.
6582
	 *
6583
	 * @param  string  $path  file path
6584
	 * @return string
6585
	 * @author Dmitry (dio) Levashov
6586
	 **/
6587
	abstract protected function _path($path);
6588
6589
	/**
6590
	 * Return true if $path is children of $parent.
6591
	 *
6592
	 * @param  string  $path    path to check
6593
	 * @param  string  $parent  parent path
6594
	 * @return bool
6595
	 * @author Dmitry (dio) Levashov
6596
	 **/
6597
	abstract protected function _inpath($path, $parent);
6598
6599
	/**
6600
	 * Return stat for given path.
6601
	 * Stat contains following fields:
6602
	 * - (int)    size    file size in b. required
6603
	 * - (int)    ts      file modification time in unix time. required
6604
	 * - (string) mime    mimetype. required for folders, others - optionally
6605
	 * - (bool)   read    read permissions. required
6606
	 * - (bool)   write   write permissions. required
6607
	 * - (bool)   locked  is object locked. optionally
6608
	 * - (bool)   hidden  is object hidden. optionally
6609
	 * - (string) alias   for symlinks - link target path relative to root path. optionally
6610
	 * - (string) target  for symlinks - link target path. optionally.
6611
	 *
6612
	 * If file does not exists - returns empty array or false.
6613
	 *
6614
	 * @param  string  $path    file path
6615
	 * @return array|false
6616
	 * @author Dmitry (dio) Levashov
6617
	 **/
6618
	abstract protected function _stat($path);
6619
6620
	/***************** file stat ********************/
6621
6622
	/**
6623
	 * Return true if path is dir and has at least one childs directory.
6624
	 *
6625
	 * @param  string  $path  dir path
6626
	 * @return bool
6627
	 * @author Dmitry (dio) Levashov
6628
	 **/
6629
	abstract protected function _subdirs($path);
6630
6631
	/**
6632
	 * Return object width and height
6633
	 * Ususaly used for images, but can be realize for video etc...
6634
	 *
6635
	 * @param  string  $path  file path
6636
	 * @param  string  $mime  file mime type
6637
	 * @return string
6638
	 * @author Dmitry (dio) Levashov
6639
	 **/
6640
	abstract protected function _dimensions($path, $mime);
6641
6642
	/******************** file/dir content *********************/
6643
6644
	/**
6645
	 * Return files list in directory.
6646
	 *
6647
	 * @param  string  $path  dir path
6648
	 * @return array
6649
	 * @author Dmitry (dio) Levashov
6650
	 **/
6651
	abstract protected function _scandir($path);
6652
6653
	/**
6654
	 * Open file and return file pointer.
6655
	 *
6656
	 * @param  string $path file path
6657
	 * @param  string $mode open mode
6658
	 * @return resource|false
6659
	 * @author Dmitry (dio) Levashov
6660
	 **/
6661
	abstract protected function _fopen($path, $mode = 'rb');
6662
6663
	/**
6664
	 * Close opened file.
6665
	 *
6666
	 * @param  resource  $fp    file pointer
6667
	 * @param  string    $path  file path
6668
	 * @return bool
6669
	 * @author Dmitry (dio) Levashov
6670
	 **/
6671
	abstract protected function _fclose($fp, $path = '');
6672
6673
	/********************  file/dir manipulations *************************/
6674
6675
	/**
6676
	 * Create dir and return created dir path or false on failed.
6677
	 *
6678
	 * @param  string  $path  parent dir path
6679
	 * @param string  $name  new directory name
6680
	 * @return string|bool
6681
	 * @author Dmitry (dio) Levashov
6682
	 **/
6683
	abstract protected function _mkdir($path, $name);
6684
6685
	/**
6686
	 * Create file and return it's path or false on failed.
6687
	 *
6688
	 * @param  string  $path  parent dir path
6689
	 * @param string  $name  new file name
6690
	 * @return string|bool
6691
	 * @author Dmitry (dio) Levashov
6692
	 **/
6693
	abstract protected function _mkfile($path, $name);
6694
6695
	/**
6696
	 * Create symlink.
6697
	 *
6698
	 * @param  string  $source     file to link to
6699
	 * @param  string  $targetDir  folder to create link in
6700
	 * @param  string  $name       symlink name
6701
	 * @return bool
6702
	 * @author Dmitry (dio) Levashov
6703
	 **/
6704
	abstract protected function _symlink($source, $targetDir, $name);
6705
6706
	/**
6707
	 * Copy file into another file (only inside one volume).
6708
	 *
6709
	 * @param  string $source source file path
6710
	 * @param $targetDir
6711
	 * @param  string $name file name
6712
	 * @return bool|string
6713
	 * @internal param string $target target dir path
6714
	 * @author Dmitry (dio) Levashov
6715
	 */
6716
	abstract protected function _copy($source, $targetDir, $name);
6717
6718
	/**
6719
	 * Move file into another parent dir.
6720
	 * Return new file path or false.
6721
	 *
6722
	 * @param  string $source source file path
6723
	 * @param $targetDir
6724
	 * @param  string $name file name
6725
	 * @return bool|string
6726
	 * @internal param string $target target dir path
6727
	 * @author Dmitry (dio) Levashov
6728
	 */
6729
	abstract protected function _move($source, $targetDir, $name);
6730
6731
	/**
6732
	 * Remove file.
6733
	 *
6734
	 * @param  string  $path  file path
6735
	 * @return bool
6736
	 * @author Dmitry (dio) Levashov
6737
	 **/
6738
	abstract protected function _unlink($path);
6739
6740
	/**
6741
	 * Remove dir.
6742
	 *
6743
	 * @param  string  $path  dir path
6744
	 * @return bool
6745
	 * @author Dmitry (dio) Levashov
6746
	 **/
6747
	abstract protected function _rmdir($path);
6748
6749
	/**
6750
	 * Create new file and write into it from file pointer.
6751
	 * Return new file path or false on error.
6752
	 *
6753
	 * @param  resource  $fp   file pointer
6754
	 * @param  string    $dir  target dir path
6755
	 * @param  string    $name file name
6756
	 * @param  array     $stat file stat (required by some virtual fs)
6757
	 * @return bool|string
6758
	 * @author Dmitry (dio) Levashov
6759
	 **/
6760
	abstract protected function _save($fp, $dir, $name, $stat);
6761
6762
	/**
6763
	 * Get file contents.
6764
	 *
6765
	 * @param  string  $path  file path
6766
	 * @return string|false
6767
	 * @author Dmitry (dio) Levashov
6768
	 **/
6769
	abstract protected function _getContents($path);
6770
6771
	/**
6772
	 * Write a string to a file.
6773
	 *
6774
	 * @param  string  $path     file path
6775
	 * @param  string  $content  new file content
6776
	 * @return bool
6777
	 * @author Dmitry (dio) Levashov
6778
	 **/
6779
	abstract protected function _filePutContents($path, $content);
6780
6781
	/**
6782
	 * Extract files from archive.
6783
	 *
6784
	 * @param  string  $path file path
6785
	 * @param  array   $arc  archiver options
6786
	 * @return bool
6787
	 * @author Dmitry (dio) Levashov,
6788
	 * @author Alexey Sukhotin
6789
	 **/
6790
	abstract protected function _extract($path, $arc);
6791
6792
	/**
6793
	 * Create archive and return its path.
6794
	 *
6795
	 * @param  string  $dir    target dir
6796
	 * @param  array   $files  files names list
6797
	 * @param  string  $name   archive name
6798
	 * @param  array   $arc    archiver options
6799
	 * @return string|bool
6800
	 * @author Dmitry (dio) Levashov,
6801
	 * @author Alexey Sukhotin
6802
	 **/
6803
	abstract protected function _archive($dir, $files, $name, $arc);
6804
6805
	/**
6806
	 * Detect available archivers.
6807
	 *
6808
	 * @return void
6809
	 * @author Dmitry (dio) Levashov,
6810
	 * @author Alexey Sukhotin
6811
	 **/
6812
	abstract protected function _checkArchivers();
6813
6814
	/**
6815
	 * Change file mode (chmod).
6816
	 *
6817
	 * @param  string  $path  file path
6818
	 * @param  string  $mode  octal string such as '0755'
6819
	 * @return bool
6820
	 * @author David Bartle,
6821
	 **/
6822
	abstract protected function _chmod($path, $mode);
6823
} // END class
6824