1 <?php
2 3 4 5 6 7 8 9 10 11 12
13 class Upload extends Controller {
14
15 16 17 18
19 protected $file;
20
21 22 23 24
25 protected $validator;
26
27 28 29 30 31 32
33 protected $tmpFile;
34
35 36 37 38 39 40
41 protected $errors = array();
42
43 44 45 46 47 48
49 public static $uploads_folder = "Uploads";
50
51 public function __construct() {
52 parent::__construct();
53 $this->validator = new Upload_Validator();
54 }
55
56 57 58 59 60
61 public function getValidator() {
62 return $this->validator;
63 }
64
65 66 67 68 69 70
71 public function setValidator($validator) {
72 $this->validator = $validator;
73 }
74
75 76 77 78 79 80 81
82 function load($tmpFile, $folderPath = false) {
83 $this->clearErrors();
84
85 if(!$folderPath) $folderPath = self::$uploads_folder;
86
87 if(!$this->file) $this->file = new File();
88
89 if(!is_array($tmpFile)) {
90 user_error("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR);
91 }
92
93 if(!$tmpFile['size']) {
94 $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.');
95 return false;
96 }
97
98 $valid = $this->validate($tmpFile);
99 if(!$valid) return false;
100
101
102
103 $base = Director::baseFolder();
104 $parentFolder = Folder::findOrMake($folderPath);
105
106
107 if(!file_exists(ASSETS_PATH)){
108 mkdir(ASSETS_PATH, Filesystem::$folder_create_mask);
109 }
110 if(!file_exists(ASSETS_PATH . "/" . $folderPath)){
111 mkdir(ASSETS_PATH . "/" . $folderPath, Filesystem::$folder_create_mask);
112 }
113
114
115 $fileName = Convert::rus2lat($tmpFile['name']);
116 $fileName = ereg_replace('^[_.-]+', '',$fileName);
117 $fileName = ereg_replace('[+\ ]+', '-',$fileName);
118 $fileName = ereg_replace('[^A-Za-z0-9._-]+','',$fileName);
119 $fileName = ereg_replace('-+', '-',$fileName);
120 $fileName = basename($fileName);
121
122 $relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/$fileName";
123
124
125 while(file_exists("$base/$relativeFilePath")) {
126 $i = isset($i) ? ($i+1) : 2;
127 $oldFilePath = $relativeFilePath;
128
129 if(substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' ||
130 substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') {
131 $relativeFilePath = ereg_replace('[0-9]*(\.tar\.[^.]+$)',$i . '\\1', $relativeFilePath);
132 } else if (strpos($relativeFilePath, '.') !== false) {
133 $relativeFilePath = ereg_replace('[0-9]*(\.[^.]+$)',$i . '\\1', $relativeFilePath);
134 } else if (strpos($relativeFilePath, '_') !== false) {
135 $relativeFilePath = ereg_replace('_([^_]+$)', '_'.$i, $relativeFilePath);
136 } else {
137 $relativeFilePath .= "_$i";
138 }
139 if($oldFilePath == $relativeFilePath && $i > 2) user_error("Couldn't fix $relativeFilePath with $i tries", E_USER_ERROR);
140 }
141
142 if(file_exists($tmpFile['tmp_name']) && move_uploaded_file($tmpFile['tmp_name'], "$base/$relativeFilePath")) {
143 $this->file->ParentID = $parentFolder->ID;
144
145 $this->file->Name = basename($relativeFilePath);
146 $this->file->Title = basename($tmpFile['name']);
147 $this->file->write();
148 return true;
149 } else {
150 $this->errors[] = _t('File.NOFILESIZE', 'Filesize is zero bytes.');
151 return false;
152 }
153 }
154
155 156 157 158 159 160 161
162 public function loadIntoFile($tmpFile, $file, $folderPath = false) {
163 $this->file = $file;
164 return $this->load($tmpFile, $folderPath);
165 }
166
167 168 169 170 171 172 173 174 175 176
177 public function validate($tmpFile) {
178 $validator = $this->validator;
179 $validator->setTmpFile($tmpFile);
180 $isValid = $validator->validate();
181 if($validator->getErrors()) {
182 $this->errors = array_merge($this->errors, $validator->getErrors());
183 }
184 return $isValid;
185 }
186
187 188 189 190 191 192
193 public function getFile() {
194 return $this->file;
195 }
196
197 198 199 200 201
202 public function setFile($file) {
203 $this->file = $file;
204 }
205
206 207 208 209 210 211 212 213
214 public function getAllowedMaxFileSize($ext = null) {
215 user_error('Upload::getAllowedMaxFileSize() is deprecated. Please use Upload_Validator::getAllowedMaxFileSize() instead', E_USER_NOTICE);
216 return $this->validator->getAllowedMaxFileSize($ext);
217 }
218
219 220 221 222 223 224 225 226 227 228 229 230 231 232
233 public function setAllowedMaxFileSize($rules) {
234 user_error('Upload::setAllowedMaxFileSize() is deprecated. Please use Upload_Validator::setAllowedMaxFileSize() instead', E_USER_NOTICE);
235 $this->validator->setAllowedMaxFileSize($rules);
236 }
237
238 239 240 241
242 public function getAllowedExtensions() {
243 user_error('Upload::getAllowedExtensions() is deprecated. Please use Upload_Validator::getAllowedExtensions() instead', E_USER_NOTICE);
244 return $this->validator->getAllowedExtensions();
245 }
246
247 248 249 250
251 public function setAllowedExtensions($rules) {
252 user_error('Upload::setAllowedExtensions() is deprecated. Please use Upload_Validator::setAllowedExtensions() instead', E_USER_NOTICE);
253 $this->validator->setAllowedExtensions($rules);
254 }
255
256 257 258 259 260 261 262 263 264 265
266 public function isValidSize($tmpFile) {
267 user_error('Upload::isValidSize() is deprecated. Please use Upload_Validator::isValidSize() instead', E_USER_NOTICE);
268 $validator = new Upload_Validator();
269 $validator->setTmpFile($tmpFile);
270 return $validator->isValidSize();
271 }
272
273 274 275 276 277 278 279 280
281 public function isValidExtension($tmpFile) {
282 user_error('Upload::isValidExtension() is deprecated. Please use Upload_Validator::isValidExtension() instead', E_USER_NOTICE);
283 $validator = new Upload_Validator();
284 $validator->setTmpFile($tmpFile);
285 return $validator->isValidExtension();
286 }
287
288 289 290
291 public function clearErrors() {
292 $this->errors = array();
293 }
294
295 296 297 298 299
300 public function isError() {
301 return (count($this->errors));
302 }
303
304 305 306 307 308 309
310 public function getErrors() {
311 return $this->errors;
312 }
313
314 }
315
316 317 318 319
320 class Upload_Validator {
321
322 323 324 325 326 327
328 protected $tmpFile;
329
330 protected $errors = array();
331
332 333 334 335 336 337 338
339 public $allowedMaxFileSize = array();
340
341 342 343 344 345 346 347 348 349
350 public $allowedExtensions = array();
351
352 353 354 355 356 357
358 public function getErrors() {
359 return $this->errors;
360 }
361
362 363 364 365
366 public function setTmpFile($tmpFile) {
367 $this->tmpFile = $tmpFile;
368 }
369
370 371 372 373 374 375
376 public function getAllowedMaxFileSize($ext = null) {
377 $ext = strtolower($ext);
378 if(isset($ext) && isset($this->allowedMaxFileSize[$ext])) {
379 return $this->allowedMaxFileSize[$ext];
380 } else {
381 return (isset($this->allowedMaxFileSize['*'])) ? $this->allowedMaxFileSize['*'] : false;
382 }
383 }
384
385 386 387 388 389 390 391 392 393 394 395 396
397 public function setAllowedMaxFileSize($rules) {
398 if(is_array($rules) && count($rules)) {
399
400 $rules = array_change_key_case($rules, CASE_LOWER);
401 $this->allowedMaxFileSize = $rules;
402 } elseif((int) $rules > 0) {
403 $this->allowedMaxFileSize['*'] = (int)$rules;
404 }
405 }
406
407 408 409
410 public function getAllowedExtensions() {
411 return $this->allowedExtensions;
412 }
413
414 415 416
417 public function setAllowedExtensions($rules) {
418 if(!is_array($rules)) return false;
419
420
421 foreach($rules as &$rule) $rule = strtolower($rule);
422
423 $this->allowedExtensions = $rules;
424 }
425
426 427 428 429 430 431 432
433 public function isValidSize() {
434 $pathInfo = pathinfo($this->tmpFile['name']);
435 $extension = isset($pathInfo['extension']) ? strtolower($pathInfo['extension']) : null;
436 $maxSize = $this->getAllowedMaxFileSize($extension);
437 return (!$this->tmpFile['size'] || !$maxSize || (int) $this->tmpFile['size'] < $maxSize);
438 }
439
440 441 442 443 444
445 public function isValidExtension() {
446 $pathInfo = pathinfo($this->tmpFile['name']);
447
448
449 if(!isset($pathInfo['extension'])) {
450 return in_array('', $this->allowedExtensions, true);
451 } else {
452 return (!count($this->allowedExtensions) || in_array(strtolower($pathInfo['extension']), $this->allowedExtensions));
453 }
454 }
455
456 457 458 459 460 461 462
463 public function validate() {
464
465 if(!isset($this->tmpFile['name']) || empty($this->tmpFile['name'])) return true;
466
467 if(isset($this->tmpFile['tmp_name']) && !ini_get("open_basedir") && !is_uploaded_file($this->tmpFile['tmp_name']) && !SapphireTest::is_running_test()) {
468 $this->errors[] = _t('File.NOVALIDUPLOAD', 'File is not a valid upload');
469 return false;
470 }
471
472 $pathInfo = pathinfo($this->tmpFile['name']);
473
474 if(!$this->isValidSize()) {
475 $ext = (isset($pathInfo['extension'])) ? $pathInfo['extension'] : '';
476 $arg = File::format_size($this->getAllowedMaxFileSize($ext));
477 $this->errors[] = sprintf(
478 _t(
479 'File.TOOLARGE',
480 'Filesize is too large, maximum %s allowed.',
481 PR_MEDIUM,
482 'Argument 1: Filesize (e.g. 1MB)'
483 ),
484 $arg
485 );
486 return false;
487 }
488
489
490 if(!$this->isValidExtension()) {
491 $this->errors[] = sprintf(
492 _t(
493 'File.INVALIDEXTENSION',
494 'Extension %s is not allowed (valid: %s)',
495 PR_MEDIUM,
496 'Argument 1: Comma-separated list of valid extensions'
497 ),
498 $pathInfo['extension'],
499 implode(',', $this->allowedExtensions)
500 );
501 return false;
502 }
503
504 return true;
505 }
506
507 }
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-