Service   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 64
dl 0
loc 177
rs 10
c 0
b 0
f 0
wmc 22

6 Methods

Rating   Name   Duplication   Size   Complexity  
B save() 0 42 8
A checkUploadError() 0 18 4
A delete() 0 7 5
A thumbnail() 0 9 1
A upload() 0 27 2
A checkImageType() 0 7 2
1
<?php
2
/**
3
 * @copyright Bluz PHP Team
4
 * @link https://github.com/bluzphp/skeleton
5
 */
6
7
declare(strict_types=1);
8
9
namespace Application\Media;
10
11
use Bluz\Config\ConfigException;
12
use Bluz\Http\Exception\BadRequestException;
13
use Bluz\Proxy\Config;
14
use Exception;
15
use Image\Thumbnail;
0 ignored issues
show
Bug introduced by
The type Image\Thumbnail was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Zend\Diactoros\UploadedFile;
17
18
/**
19
 * Service
20
 *
21
 * @package  models\Media
22
 * @author   dark
23
 */
24
class Service
25
{
26
    public const THUMB_HEIGHT = 196;
27
    public const THUMB_WIDTH = 196;
28
29
    /**
30
     * @param Row          $row
31
     * @param UploadedFile $file
32
     * @param string       $module
33
     * @param integer      $userId
34
     *
35
     * @return Row
36
     * @throws Exception
37
     */
38
    public static function upload($row, $file, $module = 'users', $userId = null): Row
39
    {
40
        self::checkUploadError($file);
41
        self::checkImageType($file);
42
43
        $row->module = $module;
44
        $row->userId = $userId;
45
46
        // save media data
47
        try {
48
            // fill row data
49
            $row->title = $row->title ?? pathinfo($file->getClientFilename(), PATHINFO_FILENAME);
50
            $row->type = $file->getClientMediaType();
51
            $row->size = $file->getSize();
52
53
            // process request image
54
            $row->file = self::save($row, $file);
55
56
            // create thumbnail
57
            $row->thumb = self::thumbnail($row);
58
        } catch (Exception $e) {
59
            self::delete($row);
60
            /** @var Exception $e */
61
            throw $e;
62
        }
63
64
        return $row;
65
    }
66
67
    /**
68
     * Move files
69
     *
70
     * @param Row          $row
71
     * @param UploadedFile $file
72
     *
73
     * @return string
74
     * @throws ConfigException
75
     */
76
    protected static function save($row, $file): string
77
    {
78
        $uploadPath = Config::get('module.media', 'upload_path');
79
80
        if (empty($uploadPath)) {
81
            throw new ConfigException('Upload path is not configured');
82
        }
83
84
        $fullPath = PATH_PUBLIC.'/'.$uploadPath.'/'.$row->userId.'/'.$row->module;
0 ignored issues
show
Bug introduced by
The constant Application\Media\PATH_PUBLIC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
85
86
        if (!is_dir($fullPath) && !mkdir($fullPath, 0755, true) && !is_dir($fullPath)) {
87
            throw new ConfigException('Upload folder is not exists, please create it');
88
        }
89
90
        if (!is_writable($fullPath)) {
91
            throw new ConfigException('Upload folder is not writable');
92
        }
93
94
        $fileName = pathinfo($file->getClientFilename(), PATHINFO_FILENAME);
95
        $fileExt  = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
96
97
        // Prepare filename
98
        $fileName = preg_replace('/[ _;:]+/', '-', $fileName);
99
        $fileName = preg_replace('/[^a-z0-9.-]+/i', '', $fileName);
100
101
        // If name is empty, generate it with current time
102
        if (empty($fileName)) {
103
            $fileName = date('Y-m-d-His');
104
        }
105
106
        // If file already exists, increment name
107
        $originFileName = $fileName;
108
        $counter = 0;
109
        while (file_exists($fullPath .'/'.$fileName.'.'.$fileExt)) {
110
            $counter++;
111
            $fileName = $originFileName.'-'.$counter;
112
        }
113
        $fileName = $fileName.'.'.$fileExt;
114
115
        $file->moveTo($fullPath.'/'.$fileName);
116
117
        return $uploadPath.'/'.$row->userId.'/'.$row->module.'/'.$fileName;
118
    }
119
120
    /**
121
     * Create thumbnail
122
     *
123
     * @param Row $row
124
     * @param int $width
125
     * @param int $height
126
     *
127
     * @return string
128
     * @throws \Image\Exception
129
     * @throws \ImagickException
130
     */
131
    public static function thumbnail($row, $width = self::THUMB_WIDTH, $height = self::THUMB_HEIGHT)
132
    {
133
        // set full path
134
        $image = new Thumbnail(PATH_PUBLIC .'/'. $row->file);
0 ignored issues
show
Bug introduced by
The constant Application\Media\PATH_PUBLIC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
135
        $image->setWidth($width);
136
        $image->setHeight($height);
137
        $thumb = $image->generate();
138
        // crop full path
139
        return substr($thumb, strlen(PATH_PUBLIC) + 1);
140
    }
141
142
    /**
143
     * Delete files
144
     *
145
     * @param Row $row
146
     */
147
    public static function delete($row): void
148
    {
149
        if ($row->file && is_file(PATH_PUBLIC.'/'.$row->file)) {
0 ignored issues
show
Bug introduced by
The constant Application\Media\PATH_PUBLIC was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
150
            @unlink(PATH_PUBLIC.'/'.$row->file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). 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

150
            /** @scrutinizer ignore-unhandled */ @unlink(PATH_PUBLIC.'/'.$row->file);

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...
151
        }
152
        if ($row->thumb && is_file(PATH_PUBLIC.'/'.$row->thumb)) {
153
            @unlink(PATH_PUBLIC.'/'.$row->thumb);
154
        }
155
    }
156
157
    /**
158
     * Check Error code
159
     *
160
     * @param UploadedFile $file
161
     *
162
     * @return void
163
     * @throws BadRequestException
164
     */
165
    public static function checkUploadError($file): void
166
    {
167
        // check upload errors
168
        if ($file->getError() !== UPLOAD_ERR_OK) {
169
            switch ($file->getError()) {
170
                case UPLOAD_ERR_NO_FILE:
171
                    $message = __('Please choose file for upload');
172
                    break;
173
                case UPLOAD_ERR_INI_SIZE:
174
                    $message = __(
175
                        'The uploaded file size should be lower than %s',
176
                        ini_get('upload_max_filesize')
177
                    );
178
                    break;
179
                default:
180
                    $message = UploadedFile::ERROR_MESSAGES[$file->getError()];
181
            }
182
            throw new BadRequestException($message);
183
        }
184
    }
185
186
    /**
187
     * Check Media Type
188
     *
189
     * @param UploadedFile $file
190
     *
191
     * @return void
192
     * @throws BadRequestException
193
     */
194
    public static function checkImageType($file): void
195
    {
196
        // check files' types
197
        $allowTypes = ['image/png', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/gif'];
198
199
        if (!in_array($file->getClientMediaType(), $allowTypes, true)) {
200
            throw new BadRequestException('Wrong file type');
201
        }
202
    }
203
}
204