Passed
Pull Request — master (#19)
by Michael
02:30
created

MediaUploader   F

Complexity

Total Complexity 63

Size/Duplication

Total Lines 407
Duplicated Lines 0 %

Importance

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

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getErrors() 0 14 4
A setTargetFileName() 0 3 1
A setErrors() 0 3 1
A getMediaTmpName() 0 3 1
A __construct() 0 12 4
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 70 15
A noAdminSizeCheck() 0 3 1
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
        } elseif (\is_array($_FILES[$media_name]['name']) && isset($index)) {
104
            $index              = (int)$index;
105
            $this->mediaName    = $_FILES[$media_name]['name'][$index];
106
            $this->mediaType    = $_FILES[$media_name]['type'][$index];
107
            $this->mediaSize    = $_FILES[$media_name]['size'][$index];
108
            $this->mediaTmpName = $_FILES[$media_name]['tmp_name'][$index];
109
            $this->mediaError   = !empty($_FILES[$media_name]['error'][$index]) ? $_FILES[$media_name]['error'][$index] : 0;
110
        } else {
111
            $media_name         = @$_FILES[$media_name];
112
            $this->mediaName    = $media_name['name'];
113
            $this->mediaType    = $media_name['type'];
114
            $this->mediaSize    = $media_name['size'];
115
            $this->mediaTmpName = $media_name['tmp_name'];
116
            $this->mediaError   = !empty($media_name['error']) ? $media_name['error'] : 0;
117
        }
118
        $this->dimension = \getimagesize($this->mediaTmpName);
119
120
        $this->errors = [];
121
122
        if ((int)$this->mediaSize < 0) {
123
            $this->setErrors(\_AM_XOOPSTUBE_INVALIDFILESIZE);
124
125
            return false;
126
        }
127
        if ('' === $this->mediaName) {
128
            $this->setErrors(\_AM_XOOPSTUBE_FILENAMEEMPTY);
129
130
            return false;
131
        }
132
133
        if ('none' === $this->mediaTmpName) {
134
            $this->setErrors(\_AM_XOOPSTUBE_NOFILEUPLOAD);
135
136
            return false;
137
        }
138
139
        if (!\is_uploaded_file($this->mediaTmpName)) {
140
            switch ($this->mediaError) {
141
                case 0: // no error; possible file attack!
142
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORZERO);
143
                    break;
144
                case 1: // uploaded file exceeds the upload_max_filesize directive in php.ini
145
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORONE);
146
                    break;
147
                case 2: // uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form
148
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORTWO);
149
                    break;
150
                case 3: // uploaded file was only partially uploaded
151
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORTHREE);
152
                    break;
153
                case 4: // no file was uploaded
154
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORFOUR);
155
                    break;
156
                default: // a default error, just in case!  :)
157
                    $this->setErrors(\_AM_XOOPSTUBE_UPLOADERRORFIVE);
158
                    break;
159
            }
160
161
            return false;
162
        }
163
164
        return true;
165
    }
166
167
    /**
168
     * Set the target filename
169
     *
170
     * @param string $value
171
     */
172
    public function setTargetFileName($value)
173
    {
174
        $this->targetFileName = \trim($value);
175
    }
176
177
    /**
178
     * Set the prefix
179
     *
180
     * @param string $value
181
     */
182
    public function setPrefix($value)
183
    {
184
        $this->prefix = \trim($value);
185
    }
186
187
    /**
188
     * Get the uploaded filename
189
     *
190
     * @return string
191
     */
192
    public function getMediaName()
193
    {
194
        return $this->mediaName;
195
    }
196
197
    /**
198
     * Get the type of the uploaded file
199
     *
200
     * @return string
201
     */
202
    public function getMediaType()
203
    {
204
        return $this->mediaType;
205
    }
206
207
    /**
208
     * Get the size of the uploaded file
209
     *
210
     * @return int
211
     */
212
    public function getMediaSize()
213
    {
214
        return $this->mediaSize;
215
    }
216
217
    /**
218
     * Get the temporary name that the uploaded file was stored under
219
     *
220
     * @return string
221
     */
222
    public function getMediaTmpName()
223
    {
224
        return $this->mediaTmpName;
225
    }
226
227
    /**
228
     * Get the saved filename
229
     *
230
     * @return string
231
     */
232
    public function getSavedFileName()
233
    {
234
        return $this->savedFileName;
235
    }
236
237
    /**
238
     * Get the destination the file is saved to
239
     *
240
     * @return string
241
     */
242
    public function getSavedDestination()
243
    {
244
        return $this->savedDestination;
245
    }
246
247
    /**
248
     * Check the file and copy it to the destination
249
     *
250
     * @param int $chmod
251
     *
252
     * @return bool
253
     */
254
    public function upload($chmod = 0644)
255
    {
256
        if ('' === $this->uploadDir) {
257
            $this->setErrors(\_AM_XOOPSTUBE_NOUPLOADDIR);
258
259
            return false;
260
        }
261
262
        if (!\is_dir($this->uploadDir)) {
263
            $this->setErrors(\_AM_XOOPSTUBE_FAILOPENDIR . $this->uploadDir);
264
        }
265
266
        if (!\is_writable($this->uploadDir)) {
267
            $this->setErrors(\_AM_XOOPSTUBE_FAILOPENDIRWRITEPERM . $this->uploadDir);
268
        }
269
270
        if (!$this->checkMaxFileSize()) {
271
            $this->setErrors(\sprintf(\_AM_XOOPSTUBE_FILESIZEMAXSIZE, $this->mediaSize, $this->maxFileSize));
272
        }
273
274
        if (\is_array($this->dimension)) {
275
            if (!$this->checkMaxWidth($this->dimension[0])) {
276
                $this->setErrors(\sprintf(\_AM_XOOPSTUBE_FILESIZEMAXWIDTH, $this->dimension[0], $this->maxWidth));
277
            }
278
            if (!$this->checkMaxHeight($this->dimension[1])) {
279
                $this->setErrors(\sprintf(\_AM_XOOPSTUBE_FILESIZEMAXHEIGHT, $this->dimension[1], $this->maxHeight));
280
            }
281
        }
282
283
        if (!$this->checkMimeType()) {
284
            $this->setErrors(\_AM_XOOPSTUBE_MIMENOTALLOW . $this->mediaType);
285
        }
286
287
        if (!$this->_copyFile($chmod)) {
288
            $this->setErrors(\_AM_XOOPSTUBE_FAILEDUPLOADING . $this->mediaName);
289
        }
290
291
        if (\count($this->errors) > 0) {
292
            return false;
293
        }
294
295
        return true;
296
    }
297
298
    /**
299
     * Copy the file to its destination
300
     *
301
     * @param $chmod
302
     *
303
     * @return bool
304
     */
305
    public function _copyFile($chmod)
306
    {
307
        $matched = [];
308
        if (!\preg_match('/\.([a-zA-Z0-9]+)$/', $this->mediaName, $matched)) {
309
            return false;
310
        }
311
        if (isset($this->targetFileName)) {
312
            $this->savedFileName = $this->targetFileName;
313
        } elseif (isset($this->prefix)) {
314
            $this->savedFileName = \uniqid($this->prefix, true) . '.' . mb_strtolower($matched[1]);
315
        } else {
316
            $this->savedFileName = mb_strtolower($this->mediaName);
317
        }
318
        $this->savedFileName    = \preg_replace('!\s+!', '_', $this->savedFileName);
319
        $this->savedDestination = $this->uploadDir . $this->savedFileName;
320
        if (\is_file($this->savedDestination) && !!\is_dir($this->savedDestination)) {
321
            $this->setErrors(\_AM_XOOPSTUBE_FILE . $this->mediaName . \_AM_XOOPSTUBE_ALREADYEXISTTRYAGAIN);
322
323
            return false;
324
        }
325
        if (!\move_uploaded_file($this->mediaTmpName, $this->savedDestination)) {
326
            return false;
327
        }
328
        @\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

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