1
|
|
|
<?php |
2
|
|
|
defined('ROOT_PATH') or exit('Access denied'); |
3
|
|
|
/** |
4
|
|
|
* TNH Framework |
5
|
|
|
* |
6
|
|
|
* A simple PHP framework using HMVC architecture |
7
|
|
|
* |
8
|
|
|
* This content is released under the MIT License (MIT) |
9
|
|
|
* |
10
|
|
|
* Copyright (c) 2017 TNH Framework |
11
|
|
|
* |
12
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
13
|
|
|
* of this software and associated documentation files (the "Software"), to deal |
14
|
|
|
* in the Software without restriction, including without limitation the rights |
15
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
16
|
|
|
* copies of the Software, and to permit persons to whom the Software is |
17
|
|
|
* furnished to do so, subject to the following conditions: |
18
|
|
|
* |
19
|
|
|
* The above copyright notice and this permission notice shall be included in all |
20
|
|
|
* copies or substantial portions of the Software. |
21
|
|
|
* |
22
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
23
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
24
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
25
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
26
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
27
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
28
|
|
|
* SOFTWARE. |
29
|
|
|
*/ |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Upload |
33
|
|
|
* |
34
|
|
|
* A complete class to upload files with php 5 or higher, but the best: very simple to use. |
35
|
|
|
* |
36
|
|
|
* @author Olaf Erlandsen <[email protected]> |
37
|
|
|
* @author http://www.webdevfreelance.com/ |
38
|
|
|
* |
39
|
|
|
* @package FileUpload |
40
|
|
|
* @version 1.5 |
41
|
|
|
*/ |
42
|
|
|
class Upload extends BaseClass { |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Version |
46
|
|
|
* |
47
|
|
|
* @since 1.5 |
48
|
|
|
* @version 1.0 |
49
|
|
|
*/ |
50
|
|
|
const VERSION = '1.5'; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Upload function name |
54
|
|
|
* Remember: |
55
|
|
|
* Default function: move_uploaded_file |
56
|
|
|
* Native options: |
57
|
|
|
* - move_uploaded_file (Default and best option) |
58
|
|
|
* - copy |
59
|
|
|
* |
60
|
|
|
* @since 1.0 |
61
|
|
|
* @version 1.0 |
62
|
|
|
* @var string |
63
|
|
|
*/ |
64
|
|
|
private $uploadFunction = 'move_uploaded_file'; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Array with the information obtained from the |
68
|
|
|
* variable $_FILES or $HTTP_POST_FILES. |
69
|
|
|
* |
70
|
|
|
* @since 1.0 |
71
|
|
|
* @version 1.0 |
72
|
|
|
* @var array |
73
|
|
|
*/ |
74
|
|
|
private $uploadedFileData = array(); |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* If the file you are trying to upload already exists it will |
78
|
|
|
* be overwritten if you set the variable to true. |
79
|
|
|
* |
80
|
|
|
* @since 1.0 |
81
|
|
|
* @version 1.0 |
82
|
|
|
* @var boolean |
83
|
|
|
*/ |
84
|
|
|
private $overwriteFile = false; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Input element |
88
|
|
|
* Example: |
89
|
|
|
* <input type="file" name="file" /> |
90
|
|
|
* Result: |
91
|
|
|
* FileUpload::$input = file |
92
|
|
|
* |
93
|
|
|
* @since 1.0 |
94
|
|
|
* @version 1.0 |
95
|
|
|
* @var string |
96
|
|
|
*/ |
97
|
|
|
private $input; |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Path output |
101
|
|
|
* |
102
|
|
|
* @since 1.0 |
103
|
|
|
* @version 1.0 |
104
|
|
|
* @var string |
105
|
|
|
*/ |
106
|
|
|
private $destinationDirectory; |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Output filename |
110
|
|
|
* |
111
|
|
|
* @since 1.0 |
112
|
|
|
* @version 1.0 |
113
|
|
|
* @var string |
114
|
|
|
*/ |
115
|
|
|
private $filename; |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Max file size |
119
|
|
|
* |
120
|
|
|
* @since 1.0 |
121
|
|
|
* @version 1.0 |
122
|
|
|
* @var float |
123
|
|
|
*/ |
124
|
|
|
private $maxFileSize = 0.0; |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* List of allowed mime types |
128
|
|
|
* |
129
|
|
|
* @since 1.0 |
130
|
|
|
* @version 1.0 |
131
|
|
|
* @var array |
132
|
|
|
*/ |
133
|
|
|
private $allowedMimeTypes = array(); |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Callbacks |
137
|
|
|
* |
138
|
|
|
* @since 1.0 |
139
|
|
|
* @version 1.0 |
140
|
|
|
* @var array |
141
|
|
|
*/ |
142
|
|
|
private $callbacks = array(); |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* File object |
146
|
|
|
* |
147
|
|
|
* @since 1.0 |
148
|
|
|
* @version 1.0 |
149
|
|
|
* @var object |
150
|
|
|
*/ |
151
|
|
|
private $file; |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Helping mime types |
155
|
|
|
* |
156
|
|
|
* @since 1.0 |
157
|
|
|
* @version 1.0 |
158
|
|
|
* @var array |
159
|
|
|
*/ |
160
|
|
|
private $mimeHelping = array( |
161
|
|
|
'text' => array('text/plain',), |
162
|
|
|
'image' => array( |
163
|
|
|
'image/jpeg', |
164
|
|
|
'image/jpg', |
165
|
|
|
'image/pjpeg', |
166
|
|
|
'image/png', |
167
|
|
|
'image/gif', |
168
|
|
|
), |
169
|
|
|
'document' => array( |
170
|
|
|
'application/pdf', |
171
|
|
|
'application/msword', |
172
|
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
173
|
|
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation', |
174
|
|
|
'application/vnd.ms-powerpoint', |
175
|
|
|
'application/vnd.ms-excel', |
176
|
|
|
'application/vnd.oasis.opendocument.spreadsheet', |
177
|
|
|
'application/vnd.oasis.opendocument.presentation', |
178
|
|
|
), |
179
|
|
|
'video' => array( |
180
|
|
|
'video/3gpp', |
181
|
|
|
'video/3gpp', |
182
|
|
|
'video/x-msvideo', |
183
|
|
|
'video/avi', |
184
|
|
|
'video/mpeg4', |
185
|
|
|
'video/mp4', |
186
|
|
|
'video/mpeg', |
187
|
|
|
'video/mpg', |
188
|
|
|
'video/quicktime', |
189
|
|
|
'video/x-sgi-movie', |
190
|
|
|
'video/x-ms-wmv', |
191
|
|
|
'video/x-flv', |
192
|
|
|
), |
193
|
|
|
); |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* The loaded translations errors messages |
197
|
|
|
* @var array |
198
|
|
|
*/ |
199
|
|
|
private $errorMessages = array(); |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* The upload error message |
203
|
|
|
* @var string |
204
|
|
|
*/ |
205
|
|
|
private $error = null; |
206
|
|
|
|
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Construct |
210
|
|
|
* |
211
|
|
|
* @since 0.1 |
212
|
|
|
* @version 1.0.1 |
213
|
|
|
* @return object |
214
|
|
|
* @method object __construct |
215
|
|
|
*/ |
216
|
|
|
public function __construct() { |
217
|
|
|
parent::__construct(); |
218
|
|
|
|
219
|
|
|
//Load language messages |
220
|
|
|
$this->loadLangMessages(); |
221
|
|
|
|
222
|
|
|
$this->file = array( |
223
|
|
|
'status' => false, // True: success upload |
224
|
|
|
'mime' => '', // Empty string |
225
|
|
|
'filename' => '', // Empty string |
226
|
|
|
'original' => '', // Empty string |
227
|
|
|
'size' => 0, // 0 Bytes |
228
|
|
|
'sizeFormated' => '0B', // 0 Bytes |
229
|
|
|
'destination' => './', // Default: ./ |
230
|
|
|
'allowed_mime_types' => array(), // Allowed mime types |
231
|
|
|
'error' => null, // File error |
232
|
|
|
); |
233
|
|
|
|
234
|
|
|
// Change dir to current dir |
235
|
|
|
$this->destinationDirectory = dirname(__FILE__) . DIRECTORY_SEPARATOR; |
236
|
|
|
|
237
|
|
|
// Set file array |
238
|
|
|
$this->uploadedFileData = get_instance()->globalvar->files(); |
239
|
|
|
$this->logger->info('The upload file information are : ' . stringify_vars($this->uploadedFileData)); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Set input. |
245
|
|
|
* If you have $_FILES["file"], you must use the key "file" |
246
|
|
|
* Example: |
247
|
|
|
* $object->setInput("file"); |
248
|
|
|
* |
249
|
|
|
* @since 1.0 |
250
|
|
|
* @version 1.0 |
251
|
|
|
* @param string $input |
252
|
|
|
* @return object |
253
|
|
|
* @method boolean setInput |
254
|
|
|
*/ |
255
|
|
|
public function setInput($input) { |
256
|
|
|
$this->input = $input; |
257
|
|
|
return $this; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Set new filename |
263
|
|
|
* Example: |
264
|
|
|
* FileUpload::setFilename("new file.txt") |
265
|
|
|
* Remember: |
266
|
|
|
* Use %s to retrive file extension |
267
|
|
|
* |
268
|
|
|
* @since 1.0 |
269
|
|
|
* @version 1.0 |
270
|
|
|
* @param string $filename |
271
|
|
|
* @return object |
272
|
|
|
* @method boolean setFilename |
273
|
|
|
*/ |
274
|
|
|
public function setFilename($filename) { |
275
|
|
|
if ($this->isFilename($filename)) { |
276
|
|
|
$this->filename = $filename; |
277
|
|
|
} |
278
|
|
|
return $this; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Set automatic filename |
283
|
|
|
* |
284
|
|
|
* @since 1.0 |
285
|
|
|
* @version 1.5 |
286
|
|
|
* @param string $extension |
287
|
|
|
* @return object |
288
|
|
|
* @method boolean setAutoFilename |
289
|
|
|
*/ |
290
|
|
|
public function setAutoFilename() { |
291
|
|
|
$this->filename = sha1(mt_rand(1, 9999) . uniqid()) . time(); |
292
|
|
|
return $this; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Set file size limit |
297
|
|
|
* |
298
|
|
|
* @since 1.0 |
299
|
|
|
* @version 1.0 |
300
|
|
|
* @param double $fileSize |
301
|
|
|
* @return object |
302
|
|
|
* @method boolean setMaxFileSize |
303
|
|
|
*/ |
304
|
|
|
public function setMaxFileSize($fileSize) { |
305
|
|
|
$size = $this->sizeInBytes($fileSize); |
306
|
|
|
if (is_numeric($size) && $size > -1) { |
307
|
|
|
// Get PHP upload max file size config |
308
|
|
|
$phpMaxUploadSize = ini_get('upload_max_filesize'); |
309
|
|
|
// check difference |
310
|
|
|
if ($this->sizeInBytes((int) $phpMaxUploadSize) < $size) { |
311
|
|
|
$this->logger->warning('The upload max file size you set [' . $fileSize . '] ' |
312
|
|
|
. 'is greather than the PHP configuration for upload max file size [' . $phpMaxUploadSize . ']'); |
313
|
|
|
} |
314
|
|
|
$this->maxFileSize = $size; |
315
|
|
|
} |
316
|
|
|
return $this; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Append a mime type to allowed mime types |
321
|
|
|
* |
322
|
|
|
* @since 1.0 |
323
|
|
|
* @version 1.0.1 |
324
|
|
|
* @param string $mime |
325
|
|
|
* @return object |
326
|
|
|
* @method boolean setAllowMimeType |
327
|
|
|
*/ |
328
|
|
|
public function setAllowMimeType($mime) { |
329
|
|
|
$this->allowedMimeTypes[] = strtolower($mime); |
330
|
|
|
$this->file['allowed_mime_types'][] = strtolower($mime); |
331
|
|
|
return $this; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
/** |
335
|
|
|
* Set array mime types |
336
|
|
|
* |
337
|
|
|
* @since 1.0 |
338
|
|
|
* @version 1.0 |
339
|
|
|
* @param array $mimes |
340
|
|
|
* @return object |
341
|
|
|
* @method boolean setAllowMimeTypes |
342
|
|
|
*/ |
343
|
|
|
public function setAllowMimeTypes(array $mimes) { |
344
|
|
|
array_map(array($this, 'setAllowMimeType'), $mimes); |
345
|
|
|
return $this; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
/** |
349
|
|
|
* Set allowed mime types from mime helping |
350
|
|
|
* |
351
|
|
|
* @since 1.0.1 |
352
|
|
|
* @version 1.0.1 |
353
|
|
|
* @return object |
354
|
|
|
* @method boolean setMimeHelping |
355
|
|
|
*/ |
356
|
|
|
public function setMimeHelping($name) { |
357
|
|
|
if (array_key_exists($name, $this->mimeHelping)) { |
358
|
|
|
return $this->setAllowMimeTypes($this->mimeHelping[$name]); |
359
|
|
|
} |
360
|
|
|
return $this; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* Clear allowed mime types cache |
365
|
|
|
* |
366
|
|
|
* @since 1.0 |
367
|
|
|
* @version 1.0 |
368
|
|
|
* @return object |
369
|
|
|
* @method boolean clearAllowedMimeTypes |
370
|
|
|
*/ |
371
|
|
|
public function clearAllowedMimeTypes() { |
372
|
|
|
$this->allowedMimeTypes = array(); |
373
|
|
|
$this->file['allowed_mime_types'] = array(); |
374
|
|
|
return $this; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Set input callback |
379
|
|
|
* |
380
|
|
|
* @since 1.0 |
381
|
|
|
* @version 1.0 |
382
|
|
|
* @param mixed $callback |
383
|
|
|
* @return object |
384
|
|
|
* @method boolean setCallbackInput |
385
|
|
|
*/ |
386
|
|
|
public function setCallbackInput($callback) { |
387
|
|
|
if (is_callable($callback, false)) { |
388
|
|
|
$this->callbacks['input'] = $callback; |
389
|
|
|
} |
390
|
|
|
return $this; |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* Set output callback |
395
|
|
|
* |
396
|
|
|
* @since 1.0 |
397
|
|
|
* @version 1.0 |
398
|
|
|
* @param mixed $callback |
399
|
|
|
* @return object |
400
|
|
|
* @method boolean setCallbackOutput |
401
|
|
|
*/ |
402
|
|
|
public function setCallbackOutput($callback) { |
403
|
|
|
if (is_callable($callback, false)) { |
404
|
|
|
$this->callbacks['output'] = $callback; |
405
|
|
|
} |
406
|
|
|
return $this; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* Set function to upload file |
411
|
|
|
* Examples: |
412
|
|
|
* 1.- FileUpload::setUploadFunction("move_uploaded_file"); |
413
|
|
|
* 2.- FileUpload::setUploadFunction("copy"); |
414
|
|
|
* |
415
|
|
|
* @since 1.0 |
416
|
|
|
* @version 1.0 |
417
|
|
|
* @param string $function |
418
|
|
|
* @return object |
419
|
|
|
* @method boolean setUploadFunction |
420
|
|
|
*/ |
421
|
|
|
public function setUploadFunction($function) { |
422
|
|
|
if (is_callable($function)) { |
423
|
|
|
$this->uploadFunction = $function; |
424
|
|
|
} |
425
|
|
|
return $this; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* Allow overwriting files |
430
|
|
|
* |
431
|
|
|
* @since 1.0 |
432
|
|
|
* @version 1.0 |
433
|
|
|
* @return object |
434
|
|
|
* @method boolean allowOverwriting |
435
|
|
|
*/ |
436
|
|
|
public function allowOverwriting($status = true) { |
437
|
|
|
$this->overwriteFile = $status; |
438
|
|
|
return $this; |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
/** |
442
|
|
|
* Get the allow overwriting |
443
|
|
|
* @return boolean |
444
|
|
|
*/ |
445
|
|
|
public function isAllowOverwriting() { |
446
|
|
|
return $this->overwriteFile ; |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
/** |
450
|
|
|
* Set destination output |
451
|
|
|
* |
452
|
|
|
* @since 1.0 |
453
|
|
|
* @version 1.0 |
454
|
|
|
* @param string $directory Destination path |
455
|
|
|
* @return object |
456
|
|
|
* @method boolean setDestinationDirectory |
457
|
|
|
*/ |
458
|
|
|
public function setDestinationDirectory($directory) { |
459
|
|
|
$dir = realpath($directory); |
460
|
|
|
$dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
461
|
|
|
if ($this->isDirpath($dir)) { |
462
|
|
|
if ($this->dirExists($dir)) { |
463
|
|
|
$this->destinationDirectory = $dir; |
464
|
|
|
} else { |
465
|
|
|
$this->logger->warning('The upload directory [' . $directory . '] does not exist'); |
466
|
|
|
} |
467
|
|
|
} |
468
|
|
|
return $this; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
/** |
472
|
|
|
* Check if the file is uploaded |
473
|
|
|
* @return boolean |
474
|
|
|
*/ |
475
|
|
|
public function isUploaded() { |
476
|
|
|
return isset($this->uploadedFileData[$this->input]) |
477
|
|
|
&& is_uploaded_file($this->uploadedFileData[$this->input]['tmp_name']); |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
/** |
481
|
|
|
* Upload file |
482
|
|
|
* |
483
|
|
|
* @since 1.0 |
484
|
|
|
* @version 1.0.1 |
485
|
|
|
* @return boolean |
486
|
|
|
* @method boolean save |
487
|
|
|
*/ |
488
|
|
|
public function save() { |
489
|
|
|
if (!$this->isUploaded()) { |
490
|
|
|
return false; |
491
|
|
|
} |
492
|
|
|
// set original filename if not have a new name |
493
|
|
|
$this->setFilenameUsingUploadedData(); |
494
|
|
|
|
495
|
|
|
// set file info |
496
|
|
|
$this->file['mime'] = $this->uploadedFileData[$this->input]['type']; |
497
|
|
|
$this->file['tmp'] = $this->uploadedFileData[$this->input]['tmp_name']; |
498
|
|
|
$this->file['original'] = $this->uploadedFileData[$this->input]['name']; |
499
|
|
|
$this->file['size'] = $this->uploadedFileData[$this->input]['size']; |
500
|
|
|
$this->file['sizeFormated'] = $this->sizeFormat($this->file['size']); |
501
|
|
|
$this->file['destination'] = $this->destinationDirectory . $this->filename; |
502
|
|
|
$this->file['filename'] = $this->filename; |
503
|
|
|
$this->file['error'] = $this->uploadedFileData[$this->input]['error']; |
504
|
|
|
|
505
|
|
|
$this->logger->info('The upload file information to process is : ' . stringify_vars($this->file)); |
506
|
|
|
|
507
|
|
|
if ($this->uploadHasError()) { |
508
|
|
|
return false; |
509
|
|
|
} |
510
|
|
|
// Execute input callback |
511
|
|
|
$this->runCallback('input'); |
512
|
|
|
|
513
|
|
|
$this->file['status'] = call_user_func_array( |
514
|
|
|
$this->uploadFunction, array( |
515
|
|
|
$this->uploadedFileData[$this->input]['tmp_name'], |
516
|
|
|
$this->destinationDirectory . $this->filename |
517
|
|
|
) |
518
|
|
|
); |
519
|
|
|
|
520
|
|
|
// Execute output callback |
521
|
|
|
$this->runCallback('output'); |
522
|
|
|
|
523
|
|
|
return $this->file['status']; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
/** |
527
|
|
|
* Get the upload error message |
528
|
|
|
* @return string |
529
|
|
|
*/ |
530
|
|
|
public function getError() { |
531
|
|
|
return $this->error; |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Retrive status of upload |
536
|
|
|
* |
537
|
|
|
* @since 1.0 |
538
|
|
|
* @version 1.0 |
539
|
|
|
* @return boolean |
540
|
|
|
* @method boolean getStatus |
541
|
|
|
*/ |
542
|
|
|
public function getStatus() { |
543
|
|
|
return $this->file['status']; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* File info |
548
|
|
|
* |
549
|
|
|
* @since 1.0 |
550
|
|
|
* @version 1.0 |
551
|
|
|
* @return object |
552
|
|
|
* @method object getInfo |
553
|
|
|
*/ |
554
|
|
|
public function getInfo() { |
555
|
|
|
return (object) $this->file; |
556
|
|
|
} |
557
|
|
|
|
558
|
|
|
|
559
|
|
|
/** |
560
|
|
|
* Check file exists |
561
|
|
|
* |
562
|
|
|
* @since 1.0 |
563
|
|
|
* @version 1.0.1 |
564
|
|
|
* @param string $file |
565
|
|
|
* @return boolean |
566
|
|
|
* @method boolean fileExists |
567
|
|
|
*/ |
568
|
|
|
protected function fileExists($file) { |
569
|
|
|
return $this->isFilename($file) |
570
|
|
|
&& file_exists($file) |
571
|
|
|
&& is_file($file); |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
/** |
575
|
|
|
* Set the filename if is empty using the uploaded data information |
576
|
|
|
* |
577
|
|
|
* @return object the current instance |
578
|
|
|
*/ |
579
|
|
|
protected function setFilenameUsingUploadedData() { |
580
|
|
|
// set original filename if not have a new name |
581
|
|
|
if (empty($this->filename)) { |
582
|
|
|
$this->filename = $this->uploadedFileData[$this->input]['name']; |
583
|
|
|
} else { |
584
|
|
|
// Replace %s for extension in filename |
585
|
|
|
// Before: /[\w\d]*(.[\d\w]+)$/i |
586
|
|
|
// After: /^[\s[:alnum:]\-\_\.]*\.([\d\w]+)$/iu |
587
|
|
|
// Support unicode(utf-8) characters |
588
|
|
|
// Example: "русские.jpeg" is valid; "Zhōngguó.jpeg" |
589
|
|
|
// is valid; "Tønsberg.jpeg" is valid |
590
|
|
|
$extension = preg_replace( |
591
|
|
|
'/^[\p{L}\d\s\-\_\.\(\)]*\.([\d\w]+)$/iu', |
592
|
|
|
'$1', |
593
|
|
|
$this->uploadedFileData[$this->input]['name'] |
594
|
|
|
); |
595
|
|
|
$this->filename = $this->filename . '.' . $extension; |
596
|
|
|
} |
597
|
|
|
return $this; |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
/** |
601
|
|
|
* Check dir exists |
602
|
|
|
* |
603
|
|
|
* @since 1.0 |
604
|
|
|
* @version 1.0.1 |
605
|
|
|
* @param string $path |
606
|
|
|
* @return boolean |
607
|
|
|
* @method boolean dirExists |
608
|
|
|
*/ |
609
|
|
|
protected function dirExists($path) { |
610
|
|
|
return $this->isDirpath($path) |
611
|
|
|
&& file_exists($path) |
612
|
|
|
&& is_dir($path); |
613
|
|
|
} |
614
|
|
|
|
615
|
|
|
/** |
616
|
|
|
* Check valid filename |
617
|
|
|
* |
618
|
|
|
* @since 1.0 |
619
|
|
|
* @version 1.0.1 |
620
|
|
|
* @param string $filename |
621
|
|
|
* @return boolean |
622
|
|
|
* @method boolean isFilename |
623
|
|
|
*/ |
624
|
|
|
protected function isFilename($filename) { |
625
|
|
|
$filename = basename($filename); |
626
|
|
|
return !empty($filename); |
627
|
|
|
} |
628
|
|
|
|
629
|
|
|
/** |
630
|
|
|
* Validate mime type with allowed mime types, |
631
|
|
|
* but if allowed mime types is empty, this method return true |
632
|
|
|
* |
633
|
|
|
* @since 1.0 |
634
|
|
|
* @version 1.0 |
635
|
|
|
* @param string $mime |
636
|
|
|
* @return boolean |
637
|
|
|
* @method boolean checkMimeType |
638
|
|
|
*/ |
639
|
|
|
protected function checkMimeType($mime) { |
640
|
|
|
if (count($this->allowedMimeTypes) === 0) { |
641
|
|
|
return true; |
642
|
|
|
} |
643
|
|
|
return in_array(strtolower($mime), $this->allowedMimeTypes); |
644
|
|
|
} |
645
|
|
|
|
646
|
|
|
/** |
647
|
|
|
* Validate max upload file size, |
648
|
|
|
* but if max size is 0, this method return true |
649
|
|
|
* |
650
|
|
|
* @since 1.0 |
651
|
|
|
* @version 1.0 |
652
|
|
|
* @param double|integer $size |
653
|
|
|
* @return boolean |
654
|
|
|
*/ |
655
|
|
|
protected function checkMaxSize($size) { |
656
|
|
|
if ($this->maxFileSize <= 0) { |
657
|
|
|
return true; |
658
|
|
|
} |
659
|
|
|
return $this->maxFileSize >= $size; |
660
|
|
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* Check the file overwritting |
664
|
|
|
* @since 1.0 |
665
|
|
|
* @version 1.0 |
666
|
|
|
* @return boolean |
667
|
|
|
*/ |
668
|
|
|
protected function checkFileOverwritting() { |
669
|
|
|
if ($this->fileExists($this->destinationDirectory . $this->filename)) { |
670
|
|
|
return $this->overwriteFile; |
671
|
|
|
} |
672
|
|
|
return true; |
673
|
|
|
} |
674
|
|
|
|
675
|
|
|
/** |
676
|
|
|
* Check valid path |
677
|
|
|
* |
678
|
|
|
* @since 1.0 |
679
|
|
|
* @version 1.0.1 |
680
|
|
|
* @param string $filename |
681
|
|
|
* @return boolean |
682
|
|
|
* @method boolean isDirpath |
683
|
|
|
*/ |
684
|
|
|
protected function isDirpath($path) { |
685
|
|
|
if (DIRECTORY_SEPARATOR == '/') { |
686
|
|
|
return (preg_match('/^[^*?"<>|:]*$/', $path) == 1); |
687
|
|
|
} |
688
|
|
|
return (preg_match("/^[^*?\"<>|:]*$/", substr($path, 2)) == 1); |
689
|
|
|
} |
690
|
|
|
|
691
|
|
|
/** |
692
|
|
|
* File size for humans. |
693
|
|
|
* |
694
|
|
|
* @since 1.0 |
695
|
|
|
* @version 1.0 |
696
|
|
|
* @param integer $bytes |
697
|
|
|
* @param integer $precision |
698
|
|
|
* @return string |
699
|
|
|
* @method string sizeFormat |
700
|
|
|
*/ |
701
|
|
|
protected function sizeFormat($size, $precision = 2) { |
702
|
|
|
if ($size > 0) { |
703
|
|
|
$base = log($size) / log(1024); |
704
|
|
|
$suffixes = array('B', 'K', 'M', 'G', 'T'); |
705
|
|
|
$suffixe = ''; |
706
|
|
|
if (isset($suffixes[floor($base)])) { |
707
|
|
|
$suffixe = $suffixes[floor($base)]; |
708
|
|
|
} |
709
|
|
|
return round(pow(1024, $base - floor($base)), $precision) . $suffixe; |
710
|
|
|
} |
711
|
|
|
return null; |
712
|
|
|
} |
713
|
|
|
|
714
|
|
|
|
715
|
|
|
/** |
716
|
|
|
* Convert human file size to bytes |
717
|
|
|
* |
718
|
|
|
* @since 1.0 |
719
|
|
|
* @version 1.0.1 |
720
|
|
|
* @param integer|double $size |
721
|
|
|
* @return integer|double |
722
|
|
|
* @method string sizeInBytes |
723
|
|
|
*/ |
724
|
|
|
protected function sizeInBytes($size) { |
725
|
|
|
$unit = 'B'; |
726
|
|
|
$units = array('B' => 0, 'K' => 1, 'M' => 2, 'G' => 3, 'T' => 4); |
727
|
|
|
$matches = array(); |
728
|
|
|
preg_match('/(?<size>[\d\.]+)\s*(?<unit>b|k|m|g|t)?/i', $size, $matches); |
729
|
|
|
if (array_key_exists('unit', $matches)) { |
730
|
|
|
$unit = strtoupper($matches['unit']); |
731
|
|
|
} |
732
|
|
|
return (floatval($matches['size']) * pow(1024, $units[$unit])); |
733
|
|
|
} |
734
|
|
|
|
735
|
|
|
/** |
736
|
|
|
* Set the upload error message |
737
|
|
|
* @param string $message the upload error message to set |
738
|
|
|
* |
739
|
|
|
* @return object the current instance |
740
|
|
|
*/ |
741
|
|
|
protected function setError($message) { |
742
|
|
|
$this->logger->error('The file upload got error : ' . $message); |
743
|
|
|
$this->error = $message; |
744
|
|
|
return $this; |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
/** |
748
|
|
|
* Run the callbacks in the file uploaded |
749
|
|
|
* @param string $type the type of callback "input" or "output" |
750
|
|
|
* @return void |
751
|
|
|
*/ |
752
|
|
|
protected function runCallback($type) { |
753
|
|
|
if (!empty($this->callbacks[$type])) { |
754
|
|
|
call_user_func($this->callbacks[$type], (object) $this->file); |
755
|
|
|
} |
756
|
|
|
} |
757
|
|
|
|
758
|
|
|
/** |
759
|
|
|
* Check if file upload has error |
760
|
|
|
* @return boolean |
761
|
|
|
*/ |
762
|
|
|
protected function uploadHasError() { |
763
|
|
|
//check if file upload is allowed in the configuration |
764
|
|
|
if (!ini_get('file_uploads')) { |
765
|
|
|
$this->setError($this->errorMessages['file_uploads']); |
766
|
|
|
return true; |
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
//check for php upload error |
770
|
|
|
$error = $this->getPhpUploadErrorMessageByCode($this->file['error']); |
771
|
|
|
if ($error) { |
772
|
|
|
$this->setError($error); |
773
|
|
|
return true; |
774
|
|
|
} |
775
|
|
|
|
776
|
|
|
//check for mime type |
777
|
|
|
if (!$this->checkMimeType($this->file['mime'])) { |
778
|
|
|
$this->setError($this->errorMessages['accept_file_types']); |
779
|
|
|
return true; |
780
|
|
|
} |
781
|
|
|
|
782
|
|
|
// Check file size |
783
|
|
|
if (!$this->checkMaxSize($this->file['size'])) { |
784
|
|
|
$this->setError(sprintf($this->errorMessages['max_file_size'], $this->sizeFormat($this->maxFileSize))); |
785
|
|
|
return true; |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
// Check if exists file |
789
|
|
|
if (!$this->checkFileOverwritting()) { |
790
|
|
|
$this->setError($this->errorMessages['overwritten_not_allowed']); |
791
|
|
|
return true; |
792
|
|
|
} |
793
|
|
|
return false; |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
/** |
797
|
|
|
* Get the PHP upload error message for the given code |
798
|
|
|
* @param int $code the error code |
799
|
|
|
* @return string the error message |
800
|
|
|
*/ |
801
|
|
|
protected function getPhpUploadErrorMessageByCode($code) { |
802
|
|
|
$error = null; |
803
|
|
|
$codeMessageMaps = array( |
804
|
|
|
1 => $this->errorMessages['upload_err_ini_size'], |
805
|
|
|
2 => $this->errorMessages['upload_err_form_size'], |
806
|
|
|
3 => $this->errorMessages['upload_err_partial'], |
807
|
|
|
4 => $this->errorMessages['upload_err_no_file'], |
808
|
|
|
6 => $this->errorMessages['upload_err_no_tmp_dir'], |
809
|
|
|
7 => $this->errorMessages['upload_err_cant_write'], |
810
|
|
|
8 => $this->errorMessages['upload_err_extension'], |
811
|
|
|
); |
812
|
|
|
if (isset($codeMessageMaps[$code])) { |
813
|
|
|
$error = $codeMessageMaps[$code]; |
814
|
|
|
} |
815
|
|
|
return $error; |
816
|
|
|
} |
817
|
|
|
|
818
|
|
|
/** |
819
|
|
|
* Load the language messages for upload |
820
|
|
|
*/ |
821
|
|
|
protected function loadLangMessages() { |
822
|
|
|
get_instance()->loader->lang('file_upload'); |
823
|
|
|
$this->errorMessages = array( |
824
|
|
|
'upload_err_ini_size' => get_instance()->lang->get('fu_upload_err_ini_size'), |
825
|
|
|
'upload_err_form_size' => get_instance()->lang->get('fu_upload_err_form_size'), |
826
|
|
|
'upload_err_partial' => get_instance()->lang->get('fu_upload_err_partial'), |
827
|
|
|
'upload_err_no_file' => get_instance()->lang->get('fu_upload_err_no_file'), |
828
|
|
|
'upload_err_no_tmp_dir' => get_instance()->lang->get('fu_upload_err_no_tmp_dir'), |
829
|
|
|
'upload_err_cant_write' => get_instance()->lang->get('fu_upload_err_cant_write'), |
830
|
|
|
'upload_err_extension' => get_instance()->lang->get('fu_upload_err_extension'), |
831
|
|
|
'accept_file_types' => get_instance()->lang->get('fu_accept_file_types'), |
832
|
|
|
'file_uploads' => get_instance()->lang->get('fu_file_uploads_disabled'), |
833
|
|
|
'max_file_size' => get_instance()->lang->get('fu_max_file_size'), |
834
|
|
|
'overwritten_not_allowed' => get_instance()->lang->get('fu_overwritten_not_allowed'), |
835
|
|
|
); |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
} |
839
|
|
|
|