Completed
Push — master ( 5caf16...14fdc0 )
by Anton
11s
created

Manager::getUploadPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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 Application\Users;
12
use Bluz\Application\Exception\BadRequestException;
13
use Bluz\Config\ConfigException;
14
use Bluz\Proxy\Auth;
15
use Bluz\Proxy\Config;
16
use Image\Thumbnail;
17
use Zend\Diactoros\UploadedFile;
18
19
/**
20
 * Manager
21
 *
22
 * @category Application
23
 * @package  Media
24
 * @author   Anton Shevchuk
25
 */
26
class Manager
27
{
28
    const THUMB_HEIGHT = 196;
29
    const THUMB_WIDTH = 196;
30
31
    /**
32
     * @var Row
33
     */
34
    protected $media;
35
36
    /**
37
     * @var UploadedFile
38
     */
39
    protected $file;
40
41
    /**
42
     * @var string
43
     */
44
    protected $name;
45
46
    /**
47
     * @var string
48
     */
49
    protected $publicPath;
50
51
    /**
52
     * @var string
53
     */
54
    protected $uploadPath;
55
56
    /**
57
     * @param  Row $media
58
     * @param  UploadedFile $file
59
     *
60
     */
61
    public function __construct($media, $file)
62
    {
63
        $this->media = $media;
64
        $this->media->module = $this->media->module ?: 'users';
65
        $this->media->userId = $this->media->userId ?: Auth::getIdentity()->id ?: Users\Table::SYSTEM_USER;
66
67
        $this->file = $file;
68
        $this->name = $media->title ?? pathinfo($file->getClientFilename(), PATHINFO_FILENAME);
69
70
        $this->checkError();
71
        $this->checkType();
72
    }
73
74
    /**
75
     * Move file to directory
76
     *
77
     * @param  string $directory
78
     *
79
     * @return void
80
     * @throws ConfigException
81
     */
82
    public function moveToDir($directory)
83
    {
84
        $uploadPath = Config::getModuleData('media', 'upload_path');
85
86
        if (empty($uploadPath)) {
87
            throw new ConfigException('Upload path is not configured');
88
        }
89
90
        $fullPath = PATH_PUBLIC.'/'.$uploadPath.'/'.$directory;
91
92
        if (!is_dir($fullPath) && !@mkdir($fullPath, 0755, true)) {
93
            throw new ConfigException('Upload folder is not exists, please create it');
94
        }
95
96
        if (!is_writable($fullPath)) {
97
            throw new ConfigException('Upload folder is not writable');
98
        }
99
100
        $fileName = $this->getFileName($fullPath);
101
102
        $this->publicPath = $uploadPath.'/'.$directory.'/'.$fileName;
103
        $this->uploadPath = $fullPath.'/'.$fileName;
104
105
        $this->file->moveTo($this->uploadPath);
106
    }
107
108
    /**
109
     * Create thumbnail
110
     *
111
     * @return string
112
     */
113
    public function createThumbnail()
114
    {
115
        // set full path
116
        $image = new Thumbnail($this->getUploadPath());
117
        $image->setHeight(self::THUMB_HEIGHT);
118
        $image->setWidth(self::THUMB_WIDTH);
119
        $thumb = $image->generate();
120
        // crop full path
121
        $thumb = substr($thumb, strlen(PATH_PUBLIC) + 1);
122
        return $thumb;
123
    }
124
125
    /**
126
     * Check Error code
127
     *
128
     * @return void
129
     * @throws BadRequestException
130
     */
131
    protected function checkError()
132
    {
133
        // check upload errors
134
        if ($this->file->getError() !== UPLOAD_ERR_OK) {
135
            switch ($this->file->getError()) {
136
                case UPLOAD_ERR_NO_FILE:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

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

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

Loading history...
137
                    $message = __('Please choose file for upload');
138
                    break;
139
                case UPLOAD_ERR_INI_SIZE:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

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

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

Loading history...
140
                    $message = __(
141
                        'The uploaded file size should be lower than %s',
142
                        ini_get('upload_max_filesize')
143
                    );
144
                    break;
145
                default:
146
                    $message = UploadedFile::ERROR_MESSAGES[$this->file->getError()];
147
            }
148
            throw new BadRequestException($message);
149
        }
150
    }
151
152
    /**
153
     * checkType
154
     *
155
     * @return void
156
     * @throws BadRequestException
157
     */
158
    protected function checkType()
159
    {
160
        // check files' types
161
        $allowTypes = ['image/png', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/gif'];
162
163
        if (!in_array($this->file->getClientMediaType(), $allowTypes, true)) {
164
            throw new BadRequestException('Wrong file type');
165
        }
166
    }
167
168
    /**
169
     * Prepare File name for path
170
     *
171
     * @param  string $path
172
     *
173
     * @return string
174
     */
175
    protected function getFileName($path) : string
176
    {
177
        /**
178
         * Generate image name
179
         */
180
        $pathInfo = pathinfo($this->file->getClientFilename());
181
182
        $fileName = strtolower($this->name ?? $pathInfo['filename']);
183
        $fileExt  = strtolower($pathInfo['extension']);
184
185
        // Prepare filename
186
        $fileName = preg_replace('/[ _;:]+/', '-', $fileName);
187
        $fileName = preg_replace('/[^a-z0-9.-]+/i', '', $fileName);
188
189
        // If name is empty, generate it with current time
190
        if (empty($fileName)) {
191
            $fileName = date('Y-m-d-His');
192
        }
193
194
        // If file already exists, increment name
195
        $originFileName = $fileName;
196
        $counter = 0;
197
        while (file_exists($path .'/'.$fileName.'.'.$fileExt)) {
198
            $counter++;
199
            $fileName = $originFileName.'-'.$counter;
200
        }
201
        return $fileName.'.'.$fileExt;
202
    }
203
204
    /**
205
     * @return string
206
     */
207
    public function getPublicPath(): string
208
    {
209
        return $this->publicPath;
210
    }
211
212
    /**
213
     * @return string
214
     */
215
    public function getUploadPath(): string
216
    {
217
        return $this->uploadPath;
218
    }
219
}
220