XoopsMediaUploader::getErrors()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 14
rs 9.9332
c 0
b 0
f 0
cc 4
nc 3
nop 1
1
<?php
2
/**
3
 * XOOPS file uploader
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2025 XOOPS Project (https://xoops.org)
13
 * @license             GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             kernel
15
 * @since               2.0.0
16
 * @author              Kazumi Ono (http://www.myweb.ne.jp/, http://jp.xoops.org/)
17
 * @author              Taiwen Jiang <[email protected]>
18
 */
19
20
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
21
22
use Xmf\Request;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Request. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
23
24
/**
25
 * Upload Media files
26
 *
27
 * Example of usage (single file):
28
 * <code>
29
 * include_once __DIR__ . '/uploader.php';
30
 * $allowed_mimetypes = array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png');
31
 * $maxfilesize = 50000;
32
 * $maxfilewidth = 120;
33
 * $maxfileheight = 120;
34
 * $randomFilename = true;
35
 * $uploader = new XoopsMediaUploader('/home/xoops/uploads', $allowed_mimetypes, $maxfilesize, $maxfilewidth, $maxfileheight, $randomFilename);
36
 * if ($uploader->fetchMedia('single_file_name')) {
37
 *     if (!$uploader->upload()) {
38
 *         echo $uploader->getErrors();
39
 *     } else {
40
 *         echo '<h4>File uploaded successfully!</h4>'
41
 *         echo 'Saved as: ' . $uploader->getSavedFileName() . '<br>';
42
 *         echo 'Full path: ' . $uploader->getSavedDestination();
43
 *     }
44
 * } else {
45
 *        echo $uploader->getErrors();
46
 * }
47
 * </code>
48
 *
49
 * Example of usage (multiple file):
50
 * <code>
51
 * include_once __DIR__ . '/uploader.php';
52
 * $allowed_mimetypes = array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/webp');
53
 * $maxfilesize = 50000;
54
 * $maxfilewidth = 120;
55
 * $maxfileheight = 120;
56
 * $randomFilename = true;
57
 * $uploader = new XoopsMediaUploader('/home/xoops/uploads', $allowed_mimetypes, $maxfilesize, $maxfilewidth, $maxfileheight, $randomFilename);
58
 * for ($i = 0; $i < $uploader->countMedia('multiple_file_name'); $i++) {
59
 *     if ($uploader->fetchMedia('multiple_file_name')) {
60
 *        if (!$uploader->upload()) {
61
 *           echo $uploader->getErrors();
62
 *        } else {
63
 *           echo '<h4>File uploaded successfully!</h4>'
64
 *           echo 'Saved as: ' . $uploader->getSavedFileName() . '<br>';
65
 *           echo 'Full path: ' . $uploader->getSavedDestination();
66
 *        }
67
 *     } else {
68
 *        echo $uploader->getErrors();
69
 *     }
70
 * }
71
 * </code>
72
 *
73
 */
74
class XoopsMediaUploader
75
{
76
    /**
77
     * Flag indicating if unrecognized mimetypes should be allowed (use with precaution ! may lead to security issues )
78
     */
79
80
    public $allowUnknownTypes       = false;
81
    public $mediaName;
82
    public $mediaType;
83
    public $mediaSize;
84
    public $mediaTmpName;
85
    public $mediaError;
86
    public $mediaRealType           = '';
87
    public $uploadDir               = '';
88
    public $allowedMimeTypes        = [];
89
    public $deniedMimeTypes         = [
90
        'application/x-httpd-php',
91
    ];
92
    public $maxFileSize             = 0;
93
    public $maxWidth;
94
    public $maxHeight;
95
    public $targetFileName;
96
    public $prefix;
97
    public $errors                  = [];
98
    public $savedDestination;
99
    public $savedFileName;
100
    public $extensionToMime         = [];
101
    public $checkImageType          = true;
102
    public $extensionsToBeSanitized = [
103
        'php',
104
        'phtml',
105
        'phtm',
106
        'php3',
107
        'php4',
108
        'cgi',
109
        'pl',
110
        'asp',
111
        'php5',
112
        'php7',
113
    ];
114
    // extensions needed image check (anti-IE Content-Type XSS)
115
    public $imageExtensions = [
116
        1  => 'gif',
117
        2  => 'jpg',
118
        3  => 'png',
119
        4  => 'swf',
120
        5  => 'psd',
121
        6  => 'bmp',
122
        7  => 'tif',
123
        8  => 'tif',
124
        9  => 'jpc',
125
        10 => 'jp2',
126
        11 => 'jpx',
127
        12 => 'jb2',
128
        13 => 'swc',
129
        14 => 'iff',
130
        15 => 'wbmp',
131
        16 => 'xbm',
132
        17 => 'webp',
133
    ];
134
    public $randomFilename  = false;
135
136
    /**
137
     * Constructor
138
     *
139
     * @param string $uploadDir
140
     * @param array  $allowedMimeTypes
141
     * @param int    $maxFileSize
142
     * @param int    $maxWidth
143
     * @param int    $maxHeight
144
     * @param bool   $randomFilename
145
     */
146
147
    public function __construct($uploadDir, $allowedMimeTypes, $maxFileSize = 0, $maxWidth = null, $maxHeight = null, $randomFilename = false)
148
    {
149
        $this->extensionToMime = include $GLOBALS['xoops']->path('include/mimetypes.inc.php');
150
        if (!is_array($this->extensionToMime)) {
151
            $this->extensionToMime = [];
152
153
            return false;
154
        }
155
        if (is_array($allowedMimeTypes)) {
0 ignored issues
show
introduced by
The condition is_array($allowedMimeTypes) is always true.
Loading history...
156
            $this->allowedMimeTypes = & $allowedMimeTypes;
157
        }
158
        $this->uploadDir = $uploadDir;
159
160
        $limits = [];
161
        $limits = $this->arrayPushIfPositive($limits, $maxFileSize);
162
        $limits = $this->arrayPushIfPositive($limits, $this->return_bytes(ini_get('upload_max_filesize')));
163
        $limits = $this->arrayPushIfPositive($limits, $this->return_bytes(ini_get('post_max_size')));
164
        $limits = $this->arrayPushIfPositive($limits, $this->return_bytes(ini_get('memory_limit')));
165
        $this->maxFileSize = min($limits);
166
167
        if (isset($maxWidth)) {
168
            $this->maxWidth = (int) $maxWidth;
169
        }
170
        if (isset($maxHeight)) {
171
            $this->maxHeight = (int) $maxHeight;
172
        }
173
        if (isset($randomFilename)) {
174
            $this->randomFilename = $randomFilename;
175
        }
176
        if (!include_once $GLOBALS['xoops']->path('language/' . $GLOBALS['xoopsConfig']['language'] . '/uploader.php')) {
177
            include_once $GLOBALS['xoops']->path('language/english/uploader.php');
178
        }
179
    }
180
181
    /**
182
     * converts memory/file sizes as defined in php.ini to bytes
183
     *
184
     * @param $size_str
185
     *
186
     * @return int
187
     */
188
    public function return_bytes($size_str)
189
    {
190
        switch (substr($size_str, -1)) {
191
            case 'K':
192
            case 'k':
193
                return (int) $size_str * 1024;
194
            case 'M':
195
            case 'm':
196
                return (int) $size_str * 1048576;
197
            case 'G':
198
            case 'g':
199
                return (int) $size_str * 1073741824;
200
            default:
201
                return $size_str;
202
        }
203
    }
204
205
    /**
206
     * Count the uploaded files (in case of multiple upload)
207
     *
208
     * @param  string $media_name Name of the file field
209
     * @return int|false
210
     */
211
    public function countMedia($media_name)
212
    {
213
        if (!Request::hasVar($media_name, 'FILES')) {
214
            $this->setErrors(_ER_UP_FILENOTFOUND);
215
            return false;
216
        }
217
        $files = Request::getArray($media_name, [], 'FILES');
218
        return count($files['name']);
219
    }
220
221
    /**
222
     * Fetch the uploaded file
223
     *
224
     * @param  string $media_name Name of the file field
225
     * @param  int    $index      Index of the file (if more than one uploaded under that name)
226
     * @return bool
227
     */
228
    public function fetchMedia($media_name, $index = null)
229
    {
230
        if (empty($this->extensionToMime)) {
231
            $this->setErrors(_ER_UP_MIMETYPELOAD);
232
233
            return false;
234
        }
235
236
        if (!Request::hasVar($media_name, 'FILES')) {
237
            $this->setErrors(_ER_UP_FILENOTFOUND);
238
            return false;
239
        }
240
241
        $files = Request::getArray($media_name, [], 'FILES');
242
243
        if (is_array($files['name']) && isset($index)) {
244
            $index = (int) $index;
245
            $this->mediaName = $files['name'][$index];
246
            if ($this->randomFilename) {
247
                $unique = uniqid();
248
                $this->targetFileName = $unique . '--' . $this->mediaName;
249
            }
250
            $this->mediaType    = $files['type'][$index];
251
            $this->mediaSize    = $files['size'][$index];
252
            $this->mediaTmpName = $files['tmp_name'][$index];
253
            $this->mediaError   = !empty($files['error'][$index]) ? $files['error'][$index] : 0;
254
        } elseif (is_array($files['name']) && !isset($index)) {
255
            $this->setErrors(_ER_UP_INDEXNOTSET);
256
            return false;
257
        } else {
258
            $file = $files;
259
            $this->mediaName = $file['name'];
260
            if ($this->randomFilename) {
261
                $unique = uniqid();
262
                $this->targetFileName = $unique . '--' . $this->mediaName;
263
            }
264
            $this->mediaType    = $file['type'];
265
            $this->mediaSize    = $file['size'];
266
            $this->mediaTmpName = $file['tmp_name'];
267
            $this->mediaError   = !empty($file['error']) ? $file['error'] : 0;
268
        }
269
270
        if (($ext = strrpos($this->mediaName, '.')) !== false) {
271
            $ext = strtolower(substr($this->mediaName, $ext + 1));
272
            if (isset($this->extensionToMime[$ext])) {
273
                $this->mediaRealType = $this->extensionToMime[$ext];
274
            }
275
        }
276
        $this->errors = [];
277
        if ($this->mediaError > 0) {
278
            switch($this->mediaError) {
279
                case UPLOAD_ERR_INI_SIZE:
280
                    $this->setErrors(_ER_UP_INISIZE);
281
                    return false;
282
                    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...
283
                case UPLOAD_ERR_FORM_SIZE:
284
                    $this->setErrors(_ER_UP_FORMSIZE);
285
                    return false;
286
                    break;
287
                case UPLOAD_ERR_PARTIAL:
288
                    $this->setErrors(_ER_UP_PARTIAL);
289
                    return false;
290
                    break;
291
                case UPLOAD_ERR_NO_FILE:
292
                    $this->setErrors(_ER_UP_NOFILE);
293
                    return false;
294
                    break;
295
                case UPLOAD_ERR_NO_TMP_DIR:
296
                    $this->setErrors(_ER_UP_NOTMPDIR);
297
                    return false;
298
                    break;
299
                case UPLOAD_ERR_CANT_WRITE:
300
                    $this->setErrors(_ER_UP_CANTWRITE);
301
                    return false;
302
                    break;
303
                case UPLOAD_ERR_EXTENSION:
304
                    $this->setErrors(_ER_UP_EXTENSION);
305
                    return false;
306
                    break;
307
                default:
308
                    $this->setErrors(_ER_UP_UNKNOWN);
309
                    return false;
310
                    break;
311
            }
312
        }
313
314
        if ((int) $this->mediaSize < 0) {
315
            $this->setErrors(_ER_UP_INVALIDFILESIZE);
316
317
            return false;
318
        }
319
        if ($this->mediaName == '') {
320
            $this->setErrors(_ER_UP_FILENAMEEMPTY);
321
322
            return false;
323
        }
324
        if ($this->mediaTmpName === 'none' || !is_uploaded_file($this->mediaTmpName)) {
325
            $this->setErrors(_ER_UP_NOFILEUPLOADED);
326
327
            return false;
328
        }
329
330
        return true;
331
    }
332
333
    /**
334
     * Set the target filename
335
     *
336
     * @param string $value
337
     */
338
    public function setTargetFileName($value)
339
    {
340
        $this->targetFileName = (string) trim($value);
341
    }
342
343
    /**
344
     * Set the prefix
345
     *
346
     * @param string $value
347
     */
348
    public function setPrefix($value)
349
    {
350
        $this->prefix = (string) trim($value);
351
    }
352
353
    /**
354
     * Get the uploaded filename
355
     *
356
     * @return string
357
     */
358
    public function getMediaName()
359
    {
360
        return $this->mediaName;
361
    }
362
363
    /**
364
     * Get the type of the uploaded file
365
     *
366
     * @return string
367
     */
368
    public function getMediaType()
369
    {
370
        return $this->mediaType;
371
    }
372
373
    /**
374
     * Get the size of the uploaded file
375
     *
376
     * @return int
377
     */
378
    public function getMediaSize()
379
    {
380
        return $this->mediaSize;
381
    }
382
383
    /**
384
     * Get the temporary name that the uploaded file was stored under
385
     *
386
     * @return string
387
     */
388
    public function getMediaTmpName()
389
    {
390
        return $this->mediaTmpName;
391
    }
392
393
    /**
394
     * Get the saved filename
395
     *
396
     * @return string
397
     */
398
    public function getSavedFileName()
399
    {
400
        return $this->savedFileName;
401
    }
402
403
    /**
404
     * Get the destination the file is saved to
405
     *
406
     * @return string
407
     */
408
    public function getSavedDestination()
409
    {
410
        return $this->savedDestination;
411
    }
412
413
    /**
414
     * Check the file and copy it to the destination
415
     *
416
     * @param  int $chmod
417
     * @return bool
418
     */
419
    public function upload($chmod = 0644)
420
    {
421
        if ($this->uploadDir == '') {
422
            $this->setErrors(_ER_UP_UPLOADDIRNOTSET);
423
424
            return false;
425
        }
426
        if (!is_dir($this->uploadDir)) {
427
            $this->setErrors(sprintf(_ER_UP_FAILEDOPENDIR, $this->uploadDir));
428
429
            return false;
430
        }
431
        if (!is_writable($this->uploadDir)) {
432
            $this->setErrors(sprintf(_ER_UP_FAILEDOPENDIRWRITE, $this->uploadDir));
433
434
            return false;
435
        }
436
        $this->sanitizeMultipleExtensions();
437
438
        if (!$this->checkMaxFileSize()) {
439
            return false;
440
        }
441
        if (!$this->checkMaxWidth()) {
442
            return false;
443
        }
444
        if (!$this->checkMaxHeight()) {
445
            return false;
446
        }
447
        if (!$this->checkMimeType()) {
448
            return false;
449
        }
450
        if (!$this->checkImageType()) {
451
            return false;
452
        }
453
        if (count($this->errors) > 0) {
454
            return false;
455
        }
456
457
        return $this->_copyFile($chmod);
458
    }
459
460
    /**
461
     * Copy the file to its destination
462
     *
463
     * @param int $chmod
464
     * @return bool
465
     */
466
    public function _copyFile($chmod)
467
    {
468
        $matched = [];
469
        if (!preg_match("/\.([a-zA-Z0-9]+)$/", $this->mediaName, $matched)) {
470
            $this->setErrors(_ER_UP_INVALIDFILENAME);
471
            return false;
472
        }
473
474
        if (isset($this->targetFileName)) {
475
            $this->savedFileName = $this->targetFileName;
476
        } elseif (isset($this->prefix)) {
477
            $this->savedFileName = uniqid($this->prefix, false) . '.' . strtolower($matched[1]); //TODO: for true, need to increase size of image_name field in image table
478
        } else {
479
            $this->savedFileName = strtolower($this->mediaName);
480
        }
481
482
        $this->savedFileName = iconv('UTF-8', 'ASCII//TRANSLIT', $this->savedFileName);
483
        $this->savedFileName = preg_replace('!\s+!', '_', $this->savedFileName);
484
        $this->savedFileName = preg_replace("/[^a-zA-Z0-9\._-]/", '', $this->savedFileName);
485
486
        $this->savedDestination = $this->uploadDir . '/' . $this->savedFileName;
487
488
        if (!move_uploaded_file($this->mediaTmpName, $this->savedDestination)) {
489
            $this->setErrors(sprintf(_ER_UP_FAILEDSAVEFILE, $this->savedDestination));
490
            return false;
491
        }
492
493
        // Check for IE XSS vulnerability for image files
494
        $ext = strtolower(substr(strrchr($this->savedDestination, '.'), 1));
495
        if (in_array($ext, $this->imageExtensions)) {
496
            $info = getimagesize($this->savedDestination);
497
            if ($info === false || $this->imageExtensions[(int) $info[2]] != $ext) {
498
                $this->setErrors(_ER_UP_SUSPICIOUSREFUSED);
499
                unlink($this->savedDestination);
500
                return false;
501
            }
502
        }
503
504
        if (false === chmod($this->savedDestination, $chmod)) {
505
            $this->setErrors(_ER_UP_MODE_NOT_CHANGED);
506
        }
507
508
        return true;
509
    }
510
511
    /**
512
     * Is the file the right size?
513
     *
514
     * @return bool
515
     */
516
    public function checkMaxFileSize()
517
    {
518
        if (!isset($this->maxFileSize)) {
519
            return true;
520
        }
521
        if ($this->mediaSize > $this->maxFileSize) {
522
            $this->setErrors(sprintf(_ER_UP_FILESIZETOOLARGE, $this->maxFileSize, $this->mediaSize));
523
524
            return false;
525
        }
526
527
        return true;
528
    }
529
530
    /**
531
     * Is the picture the right width?
532
     *
533
     * @return bool
534
     */
535
    public function checkMaxWidth()
536
    {
537
        if (!isset($this->maxWidth)) {
538
            return true;
539
        }
540
        if (false !== $dimension = getimagesize($this->mediaTmpName)) {
541
            if ($dimension[0] > $this->maxWidth) {
542
                $this->setErrors(sprintf(_ER_UP_FILEWIDTHTOOLARGE, $this->maxWidth, $dimension[0]));
543
544
                return false;
545
            }
546
        } else {
547
            trigger_error(sprintf(_ER_UP_FAILEDFETCHIMAGESIZE, $this->mediaTmpName), E_USER_WARNING);
548
        }
549
550
        return true;
551
    }
552
553
    /**
554
     * Is the picture the right height?
555
     *
556
     * @return bool
557
     */
558
    public function checkMaxHeight()
559
    {
560
        if (!isset($this->maxHeight)) {
561
            return true;
562
        }
563
        if (false !== $dimension = getimagesize($this->mediaTmpName)) {
564
            if ($dimension[1] > $this->maxHeight) {
565
                $this->setErrors(sprintf(_ER_UP_FILEHEIGHTTOOLARGE, $this->maxHeight, $dimension[1]));
566
567
                return false;
568
            }
569
        } else {
570
            trigger_error(sprintf(_ER_UP_FAILEDFETCHIMAGESIZE, $this->mediaTmpName), E_USER_WARNING);
571
        }
572
573
        return true;
574
    }
575
576
    /**
577
     * Check whether or not the uploaded file type is allowed
578
     *
579
     * @return bool
580
     */
581
    public function checkMimeType()
582
    {
583
        // if the browser supplied mime type looks suspicious, refuse it
584
        $structureCheck = (bool) preg_match('/^\w+\/[-+.\w]+$/', $this->mediaType);
585
        if (false === $structureCheck) {
586
            $this->mediaType = 'invalid';
587
            $this->setErrors(_ER_UP_UNKNOWNFILETYPEREJECTED);
588
            return false;
589
        }
590
591
        if (empty($this->mediaRealType) && empty($this->allowUnknownTypes)) {
592
            $this->setErrors(_ER_UP_UNKNOWNFILETYPEREJECTED);
593
594
            return false;
595
        }
596
597
        if ((!empty($this->allowedMimeTypes) && !in_array($this->mediaRealType, $this->allowedMimeTypes)) || (!empty($this->deniedMimeTypes) && in_array($this->mediaRealType, $this->deniedMimeTypes))) {
598
            $this->setErrors(sprintf(_ER_UP_MIMETYPENOTALLOWED, htmlspecialchars($this->mediaRealType, ENT_QUOTES | ENT_HTML5)));
599
600
            return false;
601
        }
602
603
        return true;
604
    }
605
606
    /**
607
     * Check whether or not the uploaded image type is valid
608
     *
609
     * @return bool
610
     */
611
    public function checkImageType()
612
    {
613
        if (empty($this->checkImageType)) {
614
            return true;
615
        }
616
617
        if (('image' === substr($this->mediaType, 0, strpos($this->mediaType, '/'))) || (!empty($this->mediaRealType) && 'image' === substr($this->mediaRealType, 0, strpos($this->mediaRealType, '/')))) {
618
            if (!($info = @getimagesize($this->mediaTmpName))) {
0 ignored issues
show
Unused Code introduced by
The assignment to $info is dead and can be removed.
Loading history...
619
                $this->setErrors(_ER_UP_INVALIDIMAGEFILE);
620
621
                return false;
622
            }
623
        }
624
625
        return true;
626
    }
627
628
    /**
629
     * Sanitize executable filename with multiple extensions
630
     */
631
    public function sanitizeMultipleExtensions()
632
    {
633
        if (empty($this->extensionsToBeSanitized)) {
634
            return null;
635
        }
636
637
        $patterns = [];
638
        $replaces = [];
639
        foreach ($this->extensionsToBeSanitized as $ext) {
640
            $patterns[] = "/\." . preg_quote($ext, '/') . "\./i";
641
            $replaces[] = '_' . $ext . '.';
642
        }
643
        $this->mediaName = preg_replace($patterns, $replaces, $this->mediaName);
644
    }
645
646
    /**
647
     * Add an error
648
     *
649
     * @param string $error
650
     */
651
    public function setErrors($error)
652
    {
653
        $this->errors[] = trim($error);
654
    }
655
656
    /**
657
     * Get generated errors
658
     *
659
     * @param  bool $ashtml Format using HTML?
660
     * @return array |string    Array of array messages OR HTML string
661
     */
662
    public function &getErrors($ashtml = true)
663
    {
664
        if (!$ashtml) {
665
            return $this->errors;
666
        } else {
667
            $ret = '';
668
            if (count($this->errors) > 0) {
669
                $ret = '<h4>' . sprintf(_ER_UP_ERRORSRETURNED, htmlspecialchars($this->mediaName, ENT_QUOTES | ENT_HTML5)) . '</h4>';
670
                foreach ($this->errors as $error) {
671
                    $ret .= $error . '<br>';
672
                }
673
            }
674
675
            return $ret;
676
        }
677
    }
678
679
    /**
680
     * Push value onto set.
681
     * Used in max file size calculation to eliminate -1 (unlimited) ini values
682
     *
683
     * @param array $set   array of values
684
     * @param int   $value value to push
685
     *
686
     * @return mixed
687
     */
688
    protected function arrayPushIfPositive($set, $value)
689
    {
690
        if ($value > 0) {
691
            array_push($set, $value);
692
        }
693
        return $set;
694
    }
695
}
696