MediaUploader   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 409
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 154
dl 0
loc 409
rs 3.36
c 0
b 0
f 0
wmc 63

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 4
A noAdminSizeCheck() 0 3 1
A getErrors() 0 14 4
A setTargetFileName() 0 3 1
A setErrors() 0 3 1
A getMediaTmpName() 0 3 1
A checkMaxFileSize() 0 10 3
D upload() 0 42 11
A checkMimeType() 0 7 3
A getSavedDestination() 0 3 1
A checkMaxWidth() 0 10 3
A getMediaType() 0 3 1
A checkMaxHeight() 0 10 3
A getMediaSize() 0 3 1
A getSavedFileName() 0 3 1
B _copyFile() 0 26 7
A getMediaName() 0 3 1
C fetchMedia() 0 72 15
A setPrefix() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like MediaUploader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

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

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

1
<?php
2
3
namespace XoopsModules\Xoopstube;
4
5
/**
6
 * Module: XoopsTube
7
 *
8
 * You may not change or alter any portion of this comment or credits
9
 * of supporting developers from this source code or any supporting source code
10
 * which is considered copyrighted (c) material of the original comment or credit authors.
11
 *
12
 * PHP version 5
13
 *
14
 * @category        Module
15
 * @package         Xoopstube
16
 * @author          XOOPS Development Team
17
 * @copyright       2001-2016 XOOPS Project (https://xoops.org)
18
 * @license         GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
19
 * @link            https://xoops.org/
20
 * @since           1.0.6
21
 */
22
23
use XoopsModules\Xoopstube;
24
25
/**
26
 * Class MediaUploader
27
 */
28
class MediaUploader
29
{
30
    public $mediaName;
31
    public $mediaType;
32
    public $mediaSize;
33
    public $mediaTmpName;
34
    public $mediaError;
35
    public $uploadDir        = '';
36
    public $allowedMimeTypes = [];
37
    public $maxFileSize      = 0;
38
    public $maxWidth;
39
    public $maxHeight;
40
    public $targetFileName;
41
    public $prefix;
42
    public $ext;
43
    public $dimension;
44
    public $errors           = [];
45
    public $savedDestination;
46
    public $savedFileName;
47
    /**
48
     * No admin check for uploads
49
     */
50
    public $noAdminSizeCheck;
51
52
    /**
53
     * Constructor
54
     *
55
     * @param string    $uploadDir
56
     * @param array|int $allowedMimeTypes
57
     * @param int       $maxFileSize
58
     * @param int       $maxWidth
59
     * @param int       $maxHeight
60
     *
61
     * @internal param int $cmodvalue
62
     */
63
    public function __construct($uploadDir, $allowedMimeTypes, $maxFileSize, $maxWidth = 0, $maxHeight = 0)
64
    {
65
        if (\is_array($allowedMimeTypes)) {
66
            $this->allowedMimeTypes = &$allowedMimeTypes;
67
        }
68
        $this->uploadDir   = $uploadDir;
69
        $this->maxFileSize = (int)$maxFileSize;
70
        if (isset($maxWidth)) {
71
            $this->maxWidth = (int)$maxWidth;
72
        }
73
        if (isset($maxHeight)) {
74
            $this->maxHeight = (int)$maxHeight;
75
        }
76
    }
77
78
    /**
79
     * @param $value
80
     */
81
    public function noAdminSizeCheck($value)
82
    {
83
        $this->noAdminSizeCheck = $value;
84
    }
85
86
    /**
87
     * Fetch the uploaded file
88
     *
89
     * @param string  $media_name Name of the file field
90
     * @param int     $index      Index of the file (if more than one uploaded under that name)
91
     *
92
     * @return bool
93
     * @global        $HTTP_POST_FILES
94
     */
95
    public function fetchMedia($media_name, $index = null)
96
    {
97
        global $_FILES;
98
99
        if (!isset($_FILES[$media_name])) {
100
            $this->setErrors(\_AM_XOOPSTUBE_READWRITEERROR);
101
102
            return false;
103
        }
104
105
        if (\is_array($_FILES[$media_name]['name']) && isset($index)) {
106
            $index              = (int)$index;
107
            $this->mediaName    = $_FILES[$media_name]['name'][$index];
108
            $this->mediaType    = $_FILES[$media_name]['type'][$index];
109
            $this->mediaSize    = $_FILES[$media_name]['size'][$index];
110
            $this->mediaTmpName = $_FILES[$media_name]['tmp_name'][$index];
111
            $this->mediaError   = !empty($_FILES[$media_name]['error'][$index]) ? $_FILES[$media_name]['error'][$index] : 0;
112
        } else {
113
            $media_name         = @$_FILES[$media_name];
114
            $this->mediaName    = $media_name['name'];
115
            $this->mediaType    = $media_name['type'];
116
            $this->mediaSize    = $media_name['size'];
117
            $this->mediaTmpName = $media_name['tmp_name'];
118
            $this->mediaError   = !empty($media_name['error']) ? $media_name['error'] : 0;
119
        }
120
        $this->dimension = \getimagesize($this->mediaTmpName);
121
122
        $this->errors = [];
123
124
        if ((int)$this->mediaSize < 0) {
125
            $this->setErrors(\_AM_XOOPSTUBE_INVALIDFILESIZE);
126
127
            return false;
128
        }
129
        if ('' === $this->mediaName) {
130
            $this->setErrors(\_AM_XOOPSTUBE_FILENAMEEMPTY);
131
132
            return false;
133
        }
134
135
        if ('none' === $this->mediaTmpName) {
136
            $this->setErrors(\_AM_XOOPSTUBE_NOFILEUPLOAD);
137
138
            return false;
139
        }
140
141
        if (!\is_uploaded_file($this->mediaTmpName)) {
142
            switch ($this->mediaError) {
143
                case 0: // no error; possible file attack!
144
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORZERO);
145
                    break;
146
                case 1: // uploaded file exceeds the upload_max_filesize directive in php.ini
147
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORONE);
148
                    break;
149
                case 2: // uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form
150
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORTWO);
151
                    break;
152
                case 3: // uploaded file was only partially uploaded
153
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORTHREE);
154
                    break;
155
                case 4: // no file was uploaded
156
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORFOUR);
157
                    break;
158
                default: // a default error, just in case!  :)
159
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORFIVE);
160
                    break;
161
            }
162
163
            return false;
164
        }
165
166
        return true;
167
    }
168
169
    /**
170
     * Set the target filename
171
     *
172
     * @param string $value
173
     */
174
    public function setTargetFileName($value)
175
    {
176
        $this->targetFileName = \trim($value);
177
    }
178
179
    /**
180
     * Set the prefix
181
     *
182
     * @param string $value
183
     */
184
    public function setPrefix($value)
185
    {
186
        $this->prefix = \trim($value);
187
    }
188
189
    /**
190
     * Get the uploaded filename
191
     *
192
     * @return string
193
     */
194
    public function getMediaName()
195
    {
196
        return $this->mediaName;
197
    }
198
199
    /**
200
     * Get the type of the uploaded file
201
     *
202
     * @return string
203
     */
204
    public function getMediaType()
205
    {
206
        return $this->mediaType;
207
    }
208
209
    /**
210
     * Get the size of the uploaded file
211
     *
212
     * @return int
213
     */
214
    public function getMediaSize()
215
    {
216
        return $this->mediaSize;
217
    }
218
219
    /**
220
     * Get the temporary name that the uploaded file was stored under
221
     *
222
     * @return string
223
     */
224
    public function getMediaTmpName()
225
    {
226
        return $this->mediaTmpName;
227
    }
228
229
    /**
230
     * Get the saved filename
231
     *
232
     * @return string
233
     */
234
    public function getSavedFileName()
235
    {
236
        return $this->savedFileName;
237
    }
238
239
    /**
240
     * Get the destination the file is saved to
241
     *
242
     * @return string
243
     */
244
    public function getSavedDestination()
245
    {
246
        return $this->savedDestination;
247
    }
248
249
    /**
250
     * Check the file and copy it to the destination
251
     *
252
     * @param int $chmod
253
     *
254
     * @return bool
255
     */
256
    public function upload($chmod = 0644)
257
    {
258
        if ('' === $this->uploadDir) {
259
            $this->setErrors(\_AM_XOOPSTUBE_NOUPLOADDIR);
260
261
            return false;
262
        }
263
264
        if (!\is_dir($this->uploadDir)) {
265
            $this->setErrors(\_AM_XOOPSTUBE_FAILOPENDIR . $this->uploadDir);
266
        }
267
268
        if (!\is_writable($this->uploadDir)) {
269
            $this->setErrors(\_AM_XOOPSTUBE_FAILOPENDIRWRITEPERM . $this->uploadDir);
270
        }
271
272
        if (!$this->checkMaxFileSize()) {
273
            $this->setErrors(\sprintf(\_AM_XOOPSTUBE_FILESIZEMAXSIZE, $this->mediaSize, $this->maxFileSize));
274
        }
275
276
        if (\is_array($this->dimension)) {
277
            if (!$this->checkMaxWidth($this->dimension[0])) {
278
                $this->setErrors(\sprintf(\_AM_XOOPSTUBE_FILESIZEMAXWIDTH, $this->dimension[0], $this->maxWidth));
279
            }
280
            if (!$this->checkMaxHeight($this->dimension[1])) {
281
                $this->setErrors(\sprintf(\_AM_XOOPSTUBE_FILESIZEMAXHEIGHT, $this->dimension[1], $this->maxHeight));
282
            }
283
        }
284
285
        if (!$this->checkMimeType()) {
286
            $this->setErrors(\_AM_XOOPSTUBE_MIMENOTALLOW . $this->mediaType);
287
        }
288
289
        if (!$this->_copyFile($chmod)) {
290
            $this->setErrors(\_AM_XOOPSTUBE_FAILEDUPLOADING . $this->mediaName);
291
        }
292
293
        if (\count($this->errors) > 0) {
294
            return false;
295
        }
296
297
        return true;
298
    }
299
300
    /**
301
     * Copy the file to its destination
302
     *
303
     * @param $chmod
304
     *
305
     * @return bool
306
     */
307
    public function _copyFile($chmod)
308
    {
309
        $matched = [];
310
        if (!\preg_match('/\.([a-zA-Z0-9]+)$/', $this->mediaName, $matched)) {
311
            return false;
312
        }
313
        if (isset($this->targetFileName)) {
314
            $this->savedFileName = $this->targetFileName;
315
        } elseif (isset($this->prefix)) {
316
            $this->savedFileName = \uniqid($this->prefix, true) . '.' . mb_strtolower($matched[1]);
317
        } else {
318
            $this->savedFileName = mb_strtolower($this->mediaName);
319
        }
320
        $this->savedFileName    = \preg_replace('!\s+!', '_', $this->savedFileName);
321
        $this->savedDestination = $this->uploadDir . $this->savedFileName;
322
        if (\is_file($this->savedDestination) && !!\is_dir($this->savedDestination)) {
323
            $this->setErrors(\_AM_XOOPSTUBE_FILE . $this->mediaName . \_AM_XOOPSTUBE_ALREADYEXISTTRYAGAIN);
324
325
            return false;
326
        }
327
        if (!\move_uploaded_file($this->mediaTmpName, $this->savedDestination)) {
328
            return false;
329
        }
330
        @\chmod($this->savedDestination, $chmod);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

330
        /** @scrutinizer ignore-unhandled */ @\chmod($this->savedDestination, $chmod);

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
331
332
        return true;
333
    }
334
335
    /**
336
     * Is the file the right size?
337
     *
338
     * @return bool
339
     */
340
    public function checkMaxFileSize()
341
    {
342
        if ($this->noAdminSizeCheck) {
343
            return true;
344
        }
345
        if ($this->mediaSize > $this->maxFileSize) {
346
            return false;
347
        }
348
349
        return true;
350
    }
351
352
    /**
353
     * Is the picture the right width?
354
     *
355
     * @param $dimension
356
     *
357
     * @return bool
358
     */
359
    public function checkMaxWidth($dimension)
360
    {
361
        if (!isset($this->maxWidth)) {
362
            return true;
363
        }
364
        if ($dimension > $this->maxWidth) {
365
            return false;
366
        }
367
368
        return true;
369
    }
370
371
    /**
372
     * Is the picture the right height?
373
     *
374
     * @param $dimension
375
     *
376
     * @return bool
377
     */
378
    public function checkMaxHeight($dimension)
379
    {
380
        if (!isset($this->maxHeight)) {
381
            return true;
382
        }
383
        if ($dimension > $this->maxWidth) {
384
            return false;
385
        }
386
387
        return true;
388
    }
389
390
    /**
391
     * Is the file the right Mime type
392
     *
393
     * (is there a right type of mime? ;-)
394
     *
395
     * @return bool
396
     */
397
    public function checkMimeType()
398
    {
399
        if (\count($this->allowedMimeTypes) > 0 && !\in_array($this->mediaType, $this->allowedMimeTypes)) {
400
            return false;
401
        }
402
403
        return true;
404
    }
405
406
    /**
407
     * Add an error
408
     *
409
     * @param string $error
410
     */
411
    public function setErrors($error)
412
    {
413
        $this->errors[] = \trim($error);
414
    }
415
416
    /**
417
     * Get generated errors
418
     *
419
     * @param bool $ashtml Format using HTML?
420
     *
421
     * @return array |string    Array of array messages OR HTML string
422
     */
423
    public function &getErrors($ashtml = true)
424
    {
425
        if (!$ashtml) {
426
            return $this->errors;
427
        }
428
        $ret = '';
429
        if (\count($this->errors) > 0) {
430
            $ret = \_AM_XOOPSTUBE_ERRORSRETURNUPLOAD;
431
            foreach ($this->errors as $error) {
432
                $ret .= $error . '<br>';
433
            }
434
        }
435
436
        return $ret;
437
    }
438
}
439