/
Storage.php
343 lines (308 loc) · 10.2 KB
/
Storage.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
<?php
namespace x000000\StorageManager;
use Imagine\Image\ImagineInterface;
class Storage
{
/**
* GD2 driver definition for Imagine implementation using the GD library.
*/
const DRIVER_GD2 = 'gd2';
/**
* imagick driver definition.
*/
const DRIVER_IMAGICK = 'imagick';
/**
* gmagick driver definition.
*/
const DRIVER_GMAGICK = 'gmagick';
/**
* @var string|string[] Driver(s) to use. This can be either a single driver name or an array of driver names.
* If the latter, the first available driver will be used.
*/
private $_driver;
private $_imagine;
private $_deepLevel = 4;
private $_webDir;
private $_webSrc;
private $_webThumb;
private $_baseDir;
private $_baseSrc;
private $_baseThumb;
private $_finfo;
private $_allowedFiles = [
'images' => [
// 'bmp' => ['image/bmp'],
'gif' => ['image/gif'],
'jpeg' => ['image/jpeg'],
'jpg' => ['image/jpeg'],
'png' => ['image/png'],
// 'tif' => ['image/tiff'],
// 'tiff' => ['image/tiff'],
],
'docs' => [
'pdf' => ['application/pdf', 'application/x-pdf'],
'txt' => ['text/plain'],
'rtf' => ['application/rtf', 'text/rtf'],
'odt' => ['application/vnd.oasis.opendocument.text'],
'ott' => ['application/vnd.oasis.opendocument.text-template'],
'odp' => ['application/vnd.oasis.opendocument.presentation'],
'otp' => ['application/vnd.oasis.opendocument.presentation-template'],
'ods' => ['application/vnd.oasis.opendocument.spreadsheet'],
'ots' => ['application/vnd.oasis.opendocument.spreadsheet-template'],
'odc' => ['application/vnd.oasis.opendocument.chart'],
'odf' => ['application/vnd.oasis.opendocument.formula'],
'doc' => ['application/msword', 'application/x-msword'],
'xls' => ['application/excel', 'application/vnd.ms-excel'],
'xlsm' => ['application/vnd.ms-excel.sheet.macroenabled.12'],
'ppt' => ['application/vnd.ms-powerpoint'],
'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.template'],
'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
],
'video' => [
'avi' => ['video/x-msvideo'],
'flv' => ['video/x-flv'],
'mov' => ['video/quicktime'],
'mp4' => ['video/vnd.objectvideo'],
'mpg' => ['video/mpeg'],
'wmv' => ['video/x-ms-wmv'],
],
'archives' => [
'7z' => ['application/x-7z-compressed', 'application/7z'],
'rar' => ['application/x-rar-compressed', 'application/rar'],
'zip' => ['application/x-zip-compressed', 'application/zip'],
'gz' => ['application/x-gzip','application/gzip'],
'tar' => ['application/x-tar', 'application/tar'],
'tgz' => ['application/gzip', 'application/tar', 'application/tar+gzip'],
],
'audio' => [
'mp3' => ['audio/mpeg'],
'ogg' => ['application/ogg'],
'wma' => ['audio/x-ms-wma'],
],
];
public function __construct($baseDir, $webDir, $deepLevel = 4, $driver = null)
{
if (!($deepLevel > 0 && $deepLevel < 16)) {
throw new \Exception("Invalid deep level!");
}
if (empty($baseDir)) {
throw new \Exception("Base directory have not set!");
}
if (empty($webDir)) {
throw new \Exception("Web directory have not set!");
}
$this->_deepLevel = $deepLevel;
$this->_baseDir = $baseDir;
$this->_webDir = $webDir;
$this->_baseSrc = "{$this->_baseDir}/source";
$this->_baseThumb = "{$this->_baseDir}/thumb";
$this->_webSrc = "{$this->_webDir}/source";
$this->_webThumb = "{$this->_webDir}/thumb";
$this->_driver = $driver ?: [self::DRIVER_GMAGICK, self::DRIVER_IMAGICK, self::DRIVER_GD2];
if (class_exists('\finfo', false)) {
$this->_finfo = new \finfo();
}
}
/**
* Returns an `Imagine` object for thumbnails creating.
* @return ImagineInterface The `Imagine` object based on the [[_driver]] or one which set via [[setImagine()]]
* @throws \Exception see [[createImagine()]]
*/
public function getImagine()
{
if ($this->_imagine === null) {
$this->_imagine = self::createImagine($this->_driver);
}
return $this->_imagine;
}
/**
* Sets an `Imagine` object for thumbnails creating.
* @param ImagineInterface $imagine An `Imagine` object
*/
public function setImagine(ImagineInterface $imagine)
{
$this->_imagine = $imagine;
}
/**
* Creates a new `Imagine` object
* @param string|string[] $drivers Driver(s) to create the `Imagine` object based on. See [[_driver]] for more info.
* @return ImagineInterface the new `Imagine` object
* @throws \Exception if [[$drivers]] is unknown or the system doesn't support any [[$drivers]].
*/
public static function createImagine($drivers)
{
foreach ((array) $drivers as $driver) {
switch ($driver) {
case self::DRIVER_GMAGICK:
if (class_exists('Gmagick', false)) {
return new \Imagine\Gmagick\Imagine();
}
break;
case self::DRIVER_IMAGICK:
if (class_exists('Imagick', false)) {
return new \Imagine\Imagick\Imagine();
}
break;
case self::DRIVER_GD2:
if (function_exists('gd_info')) {
return new \Imagine\Gd\Imagine();
}
break;
default:
throw new \Exception("Unknown driver: $driver");
}
}
throw new \Exception("Your system does not support any of these drivers: " . implode(',', (array) $drivers));
}
/**
* Check file extension against allowed file types
* @param string $ext file extension
* @return string|bool File extension's mime-types of false if extension is not allowed
*/
public function isAllowed($ext)
{
foreach ($this->_allowedFiles as $collection) {
if (isset($collection[$ext])) {
return $collection[$ext];
}
}
return false;
}
/**
* Get $file's source url<br/>
* Important: method do not check file existence for performance purpose!
* @param string $file File name (see $this->processFile()'s return value)
* @return string|bool File's source url or false on empty $file
*/
public function getSource($file)
{
return empty($file)
? false
: $this->_webSrc . '/' . $this->getFileDir($file) . '/' . $file;
}
/**
* Get $file's thumb url. method works for image types only.
* @param string $file File name (see $this->processFile()'s return value)
* @param Transforms\AbstractTransform[] $transforms Transforms ro be applied
* @return string|bool File's thumb url or false on fail
*/
public function getThumb($file, $transforms = [])
{
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (!isset($this->_allowedFiles['images'][$ext])) {
return false;
}
$relDir = $this->getFileDir($file);
$dir = $this->_baseThumb . "/$relDir";
if (is_dir($dir)) {
$name = pathinfo($file, PATHINFO_FILENAME) . Helper::serializeTransforms($transforms) . ".$ext";
if (file_exists("$dir/$name")) {
return $this->_webThumb . "/$relDir/$name";
}
}
return $this->createThumb($file, $transforms);
}
/**
* Get $file's directory relative to $this->baseDir
* @param string $file File name (see $this->processFile()'s return value)
* @return string $file's directory under $this->baseDir
*/
public function getFileDir($file)
{
$dir = '';
for ($i = 1; $i < $this->_deepLevel; $i++) {
$dir .= '/' . substr($file, 0, $i);
}
return substr($dir, 1);
}
/**
* Process uploaded file<br/>See $this->processFile()
* @param array $file File entry from $_FILES
* @return string|boolean process result (see $this->processFile()'s return value)
*/
public function processUploadedFile($file)
{
if (UPLOAD_ERR_OK == $file['error']) {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$tempfile = $file['tmp_name'];
if ($file = $this->processFileInternal($tempfile, $ext, false)) {
unlink($tempfile);
return $file;
}
}
return false;
}
/**
* Process file and store it under new name in the storage folder
* @param string $file Full path to the file
* @param bool $removeOriginal Should be $file be deleted after success process
* @return string|false Processed file or false on fail
**/
public function processFile($file, $removeOriginal = true)
{
return $this->processFileInternal($file, pathinfo($file, PATHINFO_EXTENSION), $removeOriginal);
}
private function processFileInternal($file, $type, $removeOriginal = true)
{
foreach ($this->_allowedFiles as $list) {
if (isset($list[$type])) {
if ($this->_finfo && $mime = $this->_finfo->file($file, FILEINFO_MIME_TYPE)) {
if (!in_array($mime, $list[$type])) {
return false;
}
}
$name = md5_file($file);
$dest = $this->_baseSrc . '/' . $this->getFileDir($name);
if (!is_dir($dest)) {
mkdir($dest, 0775, true);
}
$dest .= "/$name.$type";
if ($removeOriginal) {
return rename($file, $dest) ? "$name.$type" : false;
} else {
return copy($file, $dest) ? "$name.$type" : false;
}
}
}
return false;
}
/**
* Create a thumbnail of the source $file with given $transforms
* @param string $file Source File (see $this->processFile()'s return value)
* @param Transforms\AbstractTransform[] $transforms Transforms ro be applied
* @return string|bool Thumb url or false on fail
*/
public function createThumb($file, $transforms = [])
{
$finfo = pathinfo($file);
$relDir = $this->getFileDir($file);
$thbPath = "/$relDir/" . $finfo['filename'] . Helper::serializeTransforms($transforms) . '.' . $finfo['extension'];
if (is_dir($this->_baseThumb . "/$relDir")) {
if (file_exists($this->_baseThumb . $thbPath)) {
return $this->_webThumb . $thbPath;
}
}
elseif (!mkdir($this->_baseThumb . "/$relDir", 0775, true)) {
return false;
}
$imagine = $this->getImagine();
$image = $imagine->open($this->_baseSrc . "/$relDir/$file");
foreach ($transforms as $transform) {
$transform->apply($image, $imagine);
}
$image->save($this->_baseThumb . $thbPath, ['quality' => 90]);
return $this->_webThumb . $thbPath;
}
/**
* Get Transform object of the $source image<br/>
* This is just a helper method for convenience
* @param string $source File name (see $this->processFile()'s return value)
* @return Transform Transform object for chained modify
*/
public function thumb($source)
{
return new Transform($this, $source);
}
}