Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
filespec.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\files;
015
016 use phpbb\language\language;
017
018 /**
019 * Responsible for holding all file relevant information, as well as doing file-specific operations.
020 * The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on.
021 */
022 class filespec
023 {
024 /** @var string File name */
025 protected $filename = '';
026
027 /** @var string Real name of file */
028 protected $realname = '';
029
030 /** @var string Upload name of file */
031 protected $uploadname = '';
032
033 /** @var string Mimetype of file */
034 protected $mimetype = '';
035
036 /** @var string File extension */
037 protected $extension = '';
038
039 /** @var int File size */
040 protected $filesize = 0;
041
042 /** @var int Width of file */
043 protected $width = 0;
044
045 /** @var int Height of file */
046 protected $height = 0;
047
048 /** @var array Image info including type and size */
049 protected $image_info = array();
050
051 /** @var string Destination file name */
052 protected $destination_file = '';
053
054 /** @var string Destination file path */
055 protected $destination_path = '';
056
057 /** @var bool Whether file was moved */
058 protected $file_moved = false;
059
060 /** @var bool Whether file is local */
061 protected $local = false;
062
063 /** @var bool Class initialization flag */
064 protected $class_initialized = false;
065
066 /** @var array Error array */
067 public $error = array();
068
069 /** @var upload Instance of upload class */
070 public $upload;
071
072 /** @var \phpbb\filesystem\filesystem_interface */
073 protected $filesystem;
074
075 /** @var \bantu\IniGetWrapper\IniGetWrapper ini_get() wrapper class */
076 protected $php_ini;
077
078 /** @var \FastImageSize\FastImageSize */
079 protected $imagesize;
080
081 /** @var language Language class */
082 protected $language;
083
084 /** @var string phpBB root path */
085 protected $phpbb_root_path;
086
087 /** @var \phpbb\plupload\plupload The plupload object */
088 protected $plupload;
089
090 /** @var \phpbb\mimetype\guesser phpBB Mimetype guesser */
091 protected $mimetype_guesser;
092
093 /**
094 * File upload class
095 *
096 * @param \phpbb\filesystem\filesystem_interface $phpbb_filesystem Filesystem
097 * @param language $language Language
098 * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini ini_get() wrapper
099 * @param \FastImageSize\FastImageSize $imagesize Imagesize class
100 * @param string $phpbb_root_path phpBB root path
101 * @param \phpbb\mimetype\guesser $mimetype_guesser Mime type guesser
102 * @param \phpbb\plupload\plupload $plupload Plupload
103 */
104 public function __construct(\phpbb\filesystem\filesystem_interface $phpbb_filesystem, language $language, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
105 {
106 $this->filesystem = $phpbb_filesystem;
107 $this->language = $language;
108 $this->php_ini = $php_ini;
109 $this->imagesize = $imagesize;
110 $this->phpbb_root_path = $phpbb_root_path;
111 $this->plupload = $plupload;
112 $this->mimetype_guesser = $mimetype_guesser;
113 }
114
115 /**
116 * Set upload ary
117 *
118 * @param array $upload_ary Upload ary
119 *
120 * @return filespec This instance of the filespec class
121 */
122 public function set_upload_ary($upload_ary)
123 {
124 if (!isset($upload_ary) || !count($upload_ary))
125 {
126 return $this;
127 }
128
129 $this->class_initialized = true;
130 $this->filename = $upload_ary['tmp_name'];
131 $this->filesize = $upload_ary['size'];
132 $name = $upload_ary['name'];
133 $name = trim(utf8_basename($name));
134 $this->realname = $this->uploadname = $name;
135 $this->mimetype = $upload_ary['type'];
136
137 // Opera adds the name to the mime type
138 $this->mimetype = (strpos($this->mimetype, '; name') !== false) ? str_replace(strstr($this->mimetype, '; name'), '', $this->mimetype) : $this->mimetype;
139
140 if (!$this->mimetype)
141 {
142 $this->mimetype = 'application/octet-stream';
143 }
144
145 $this->extension = strtolower(self::get_extension($this->realname));
146
147 // Try to get real filesize from temporary folder (not always working) ;)
148 $this->filesize = ($this->get_filesize($this->filename)) ?: $this->filesize;
149
150 $this->width = $this->height = 0;
151 $this->file_moved = false;
152
153 $this->local = (isset($upload_ary['local_mode'])) ? true : false;
154
155 return $this;
156 }
157
158 /**
159 * Set the upload namespace
160 *
161 * @param upload $namespace Instance of upload class
162 *
163 * @return filespec This instance of the filespec class
164 */
165 public function set_upload_namespace($namespace)
166 {
167 $this->upload = $namespace;
168
169 return $this;
170 }
171
172 /**
173 * Check if class members were not properly initialised yet
174 *
175 * @return bool True if there was an init error, false if not
176 */
177 public function init_error()
178 {
179 return !$this->class_initialized;
180 }
181
182 /**
183 * Set error in error array
184 *
185 * @param mixed $error Content for error array
186 *
187 * @return \phpbb\files\filespec This instance of the filespec class
188 */
189 public function set_error($error)
190 {
191 $this->error[] = $error;
192
193 return $this;
194 }
195
196 /**
197 * Cleans destination filename
198 *
199 * @param string $mode Either real, unique, or unique_ext. Real creates a
200 * realname, filtering some characters, lowering every
201 * character. Unique creates a unique filename.
202 * @param string $prefix Prefix applied to filename
203 * @param string $user_id The user_id is only needed for when cleaning a user's avatar
204 */
205 public function clean_filename($mode = 'unique', $prefix = '', $user_id = '')
206 {
207 if ($this->init_error())
208 {
209 return;
210 }
211
212 switch ($mode)
213 {
214 case 'real':
215 // Remove every extension from filename (to not let the mime bug being exposed)
216 if (strpos($this->realname, '.') !== false)
217 {
218 $this->realname = substr($this->realname, 0, strpos($this->realname, '.'));
219 }
220
221 // Replace any chars which may cause us problems with _
222 $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|');
223
224 $this->realname = rawurlencode(str_replace($bad_chars, '_', strtolower($this->realname)));
225 $this->realname = preg_replace("/%(\w{2})/", '_', $this->realname);
226
227 $this->realname = $prefix . $this->realname . '.' . $this->extension;
228 break;
229
230 case 'unique':
231 $this->realname = $prefix . md5(unique_id());
232 break;
233
234 case 'avatar':
235 $this->extension = strtolower($this->extension);
236 $this->realname = $prefix . $user_id . '.' . $this->extension;
237
238 break;
239
240 case 'unique_ext':
241 default:
242 $this->realname = $prefix . md5(unique_id()) . '.' . $this->extension;
243 }
244 }
245
246 /**
247 * Get property from file object
248 *
249 * @param string $property Name of property
250 *
251 * @return mixed Content of property
252 */
253 public function get($property)
254 {
255 if ($this->init_error() || !isset($this->$property))
256 {
257 return false;
258 }
259
260 return $this->$property;
261 }
262
263 /**
264 * Check if file is an image (mime type)
265 *
266 * @return bool true if it is an image, false if not
267 */
268 public function is_image()
269 {
270 return (strpos($this->mimetype, 'image/') === 0);
271 }
272
273 /**
274 * Check if the file got correctly uploaded
275 *
276 * @return bool true if it is a valid upload, false if not
277 */
278 public function is_uploaded()
279 {
280 $is_plupload = $this->plupload && $this->plupload->is_active();
281
282 if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename))
283 {
284 return false;
285 }
286
287 if (($this->local || $is_plupload) && !file_exists($this->filename))
288 {
289 return false;
290 }
291
292 return true;
293 }
294
295 /**
296 * Remove file
297 */
298 public function remove()
299 {
300 if ($this->file_moved)
301 {
302 @unlink($this->destination_file);
303 }
304 }
305
306 /**
307 * Get file extension
308 *
309 * @param string $filename Filename that needs to be checked
310 *
311 * @return string Extension of the supplied filename
312 */
313 static public function get_extension($filename)
314 {
315 $filename = utf8_basename($filename);
316
317 if (strpos($filename, '.') === false)
318 {
319 return '';
320 }
321
322 $filename = explode('.', $filename);
323 return array_pop($filename);
324 }
325
326 /**
327 * Get mime type
328 *
329 * @param string $filename Filename that needs to be checked
330 * @return string Mime type of supplied filename
331 */
332 public function get_mimetype($filename)
333 {
334 if ($this->mimetype_guesser !== null)
335 {
336 $mimetype = $this->mimetype_guesser->guess($filename, $this->uploadname);
337
338 if ($mimetype !== 'application/octet-stream')
339 {
340 $this->mimetype = $mimetype;
341 }
342 }
343
344 return $this->mimetype;
345 }
346
347 /**
348 * Get file size
349 *
350 * @param string $filename File name of file to check
351 *
352 * @return int File size
353 */
354 public function get_filesize($filename)
355 {
356 return @filesize($filename);
357 }
358
359
360 /**
361 * Check the first 256 bytes for forbidden content
362 *
363 * @param array $disallowed_content Array containg disallowed content
364 *
365 * @return bool False if disallowed content found, true if not
366 */
367 public function check_content($disallowed_content)
368 {
369 if (empty($disallowed_content))
370 {
371 return true;
372 }
373
374 $fp = @fopen($this->filename, 'rb');
375
376 if ($fp !== false)
377 {
378 $ie_mime_relevant = fread($fp, 256);
379 fclose($fp);
380 foreach ($disallowed_content as $forbidden)
381 {
382 if (stripos($ie_mime_relevant, '<' . $forbidden) !== false)
383 {
384 return false;
385 }
386 }
387 }
388 return true;
389 }
390
391 /**
392 * Move file to destination folder
393 * The phpbb_root_path variable will be applied to the destination path
394 *
395 * @param string $destination Destination path, for example $config['avatar_path']
396 * @param bool $overwrite If set to true, an already existing file will be overwritten
397 * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped
398 * @param string|bool $chmod Permission mask for chmodding the file after a successful move.
399 * The mode entered here reflects the mode defined by {@link phpbb_chmod()}
400 *
401 * @return bool True if file was moved, false if not
402 * @access public
403 */
404 public function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false)
405 {
406 if (count($this->error))
407 {
408 return false;
409 }
410
411 $chmod = ($chmod === false) ? \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE : $chmod;
412
413 // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it...
414 $this->destination_path = $this->phpbb_root_path . $destination;
415
416 // Check if the destination path exist...
417 if (!file_exists($this->destination_path))
418 {
419 @unlink($this->filename);
420 return false;
421 }
422
423 $upload_mode = ($this->php_ini->getBool('open_basedir')) ? 'move' : 'copy';
424 $upload_mode = ($this->local) ? 'local' : $upload_mode;
425 $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname);
426
427 // Check if the file already exist, else there is something wrong...
428 if (file_exists($this->destination_file) && !$overwrite)
429 {
430 @unlink($this->filename);
431 $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
432 $this->file_moved = false;
433 return false;
434 }
435 else
436 {
437 if (file_exists($this->destination_file))
438 {
439 @unlink($this->destination_file);
440 }
441
442 switch ($upload_mode)
443 {
444 case 'copy':
445
446 if (!@copy($this->filename, $this->destination_file))
447 {
448 if (!@move_uploaded_file($this->filename, $this->destination_file))
449 {
450 $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
451 }
452 }
453
454 break;
455
456 case 'move':
457
458 if (!@move_uploaded_file($this->filename, $this->destination_file))
459 {
460 if (!@copy($this->filename, $this->destination_file))
461 {
462 $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
463 }
464 }
465
466 break;
467
468 case 'local':
469
470 if (!@copy($this->filename, $this->destination_file))
471 {
472 $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
473 }
474
475 break;
476 }
477
478 // Remove temporary filename
479 if (file_exists($this->filename))
480 {
481 @unlink($this->filename);
482 }
483
484 if (count($this->error))
485 {
486 return false;
487 }
488
489 try
490 {
491 $this->filesystem->phpbb_chmod($this->destination_file, $chmod);
492 }
493 catch (\phpbb\filesystem\exception\filesystem_exception $e)
494 {
495 // Do nothing
496 }
497 }
498
499 // Try to get real filesize from destination folder
500 $this->filesize = ($this->get_filesize($this->destination_file)) ?: $this->filesize;
501
502 // Get mimetype of supplied file
503 $this->mimetype = $this->get_mimetype($this->destination_file);
504
505 if ($this->is_image() && !$skip_image_check)
506 {
507 $this->width = $this->height = 0;
508
509 $this->image_info = $this->imagesize->getImageSize($this->destination_file, $this->mimetype);
510
511 if ($this->image_info !== false)
512 {
513 $this->width = $this->image_info['width'];
514 $this->height = $this->image_info['height'];
515
516 // Check image type
517 $types = upload::image_types();
518
519 if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']]))
520 {
521 if (!isset($types[$this->image_info['type']]))
522 {
523 $this->error[] = $this->language->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype);
524 }
525 else
526 {
527 $this->error[] = $this->language->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension);
528 }
529 }
530
531 // Make sure the dimensions match a valid image
532 if (empty($this->width) || empty($this->height))
533 {
534 $this->error[] = $this->language->lang('ATTACHED_IMAGE_NOT_IMAGE');
535 }
536 }
537 else
538 {
539 $this->error[] = $this->language->lang('UNABLE_GET_IMAGE_SIZE');
540 }
541 }
542
543 $this->file_moved = true;
544 $this->additional_checks();
545 unset($this->upload);
546
547 return true;
548 }
549
550 /**
551 * Performing additional checks
552 *
553 * @return bool False if issue was found, true if not
554 */
555 public function additional_checks()
556 {
557 if (!$this->file_moved)
558 {
559 return false;
560 }
561
562 // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
563 if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0))
564 {
565 $max_filesize = get_formatted_filesize($this->upload->max_filesize, false);
566
567 $this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']);
568
569 return false;
570 }
571
572 if (!$this->upload->valid_dimensions($this))
573 {
574 $this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_SIZE',
575 $this->language->lang('PIXELS', (int) $this->upload->min_width),
576 $this->language->lang('PIXELS', (int) $this->upload->min_height),
577 $this->language->lang('PIXELS', (int) $this->upload->max_width),
578 $this->language->lang('PIXELS', (int) $this->upload->max_height),
579 $this->language->lang('PIXELS', (int) $this->width),
580 $this->language->lang('PIXELS', (int) $this->height));
581
582 return false;
583 }
584
585 return true;
586 }
587 }
588