[ Index ]

PHP Cross Reference of phpBB-3.3.0-deutsch

title

Body

[close]

/phpbb/files/ -> filespec.php (source)

   1  <?php
   2  /**
   3   *
   4   * This file is part of the phpBB Forum Software package.
   5   *
   6   * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7   * @license GNU General Public License, version 2 (GPL-2.0)
   8   *
   9   * For full copyright and license information, please see
  10   * the docs/CREDITS.txt file.
  11   *
  12   */
  13  
  14  namespace phpbb\files;
  15  
  16  use phpbb\language\language;
  17  
  18  /**
  19   * Responsible for holding all file relevant information, as well as doing file-specific operations.
  20   * The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on.
  21   */
  22  class filespec
  23  {
  24      /** @var string File name */
  25      protected $filename = '';
  26  
  27      /** @var string Real name of file */
  28      protected $realname = '';
  29  
  30      /** @var string Upload name of file */
  31      protected $uploadname = '';
  32  
  33      /** @var string Mimetype of file */
  34      protected $mimetype = '';
  35  
  36      /** @var string File extension */
  37      protected $extension = '';
  38  
  39      /** @var int File size */
  40      protected $filesize = 0;
  41  
  42      /** @var int Width of file */
  43      protected $width = 0;
  44  
  45      /** @var int Height of file */
  46      protected $height = 0;
  47  
  48      /** @var array Image info including type and size */
  49      protected $image_info = array();
  50  
  51      /** @var string Destination file name */
  52      protected $destination_file = '';
  53  
  54      /** @var string Destination file path */
  55      protected $destination_path = '';
  56  
  57      /** @var bool Whether file was moved */
  58      protected $file_moved = false;
  59  
  60      /** @var bool Whether file is local */
  61      protected $local = false;
  62  
  63      /** @var bool Class initialization flag */
  64      protected $class_initialized = false;
  65  
  66      /** @var array Error array */
  67      public $error = array();
  68  
  69      /** @var upload Instance of upload class  */
  70      public $upload;
  71  
  72      /** @var \phpbb\filesystem\filesystem_interface */
  73      protected $filesystem;
  74  
  75      /** @var \bantu\IniGetWrapper\IniGetWrapper ini_get() wrapper class */
  76      protected $php_ini;
  77  
  78      /** @var \FastImageSize\FastImageSize */
  79      protected $imagesize;
  80  
  81      /** @var language Language class */
  82      protected $language;
  83  
  84      /** @var string phpBB root path */
  85      protected $phpbb_root_path;
  86  
  87      /** @var \phpbb\plupload\plupload The plupload object */
  88      protected $plupload;
  89  
  90      /** @var \phpbb\mimetype\guesser phpBB Mimetype guesser */
  91      protected $mimetype_guesser;
  92  
  93      /**
  94       * File upload class
  95       *
  96       * @param \phpbb\filesystem\filesystem_interface    $phpbb_filesystem Filesystem
  97       * @param language                    $language Language
  98       * @param \bantu\IniGetWrapper\IniGetWrapper            $php_ini ini_get() wrapper
  99       * @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) ? CHMOD_READ | 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              @unlink($this->filename);
 480  
 481              if (count($this->error))
 482              {
 483                  return false;
 484              }
 485  
 486              try
 487              {
 488                  $this->filesystem->phpbb_chmod($this->destination_file, $chmod);
 489              }
 490              catch (\phpbb\filesystem\exception\filesystem_exception $e)
 491              {
 492                  // Do nothing
 493              }
 494          }
 495  
 496          // Try to get real filesize from destination folder
 497          $this->filesize = ($this->get_filesize($this->destination_file)) ?: $this->filesize;
 498  
 499          // Get mimetype of supplied file
 500          $this->mimetype = $this->get_mimetype($this->destination_file);
 501  
 502          if ($this->is_image() && !$skip_image_check)
 503          {
 504              $this->width = $this->height = 0;
 505  
 506              $this->image_info = $this->imagesize->getImageSize($this->destination_file, $this->mimetype);
 507  
 508              if ($this->image_info !== false)
 509              {
 510                  $this->width = $this->image_info['width'];
 511                  $this->height = $this->image_info['height'];
 512  
 513                  // Check image type
 514                  $types = upload::image_types();
 515  
 516                  if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']]))
 517                  {
 518                      if (!isset($types[$this->image_info['type']]))
 519                      {
 520                          $this->error[] = $this->language->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype);
 521                      }
 522                      else
 523                      {
 524                          $this->error[] = $this->language->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension);
 525                      }
 526                  }
 527  
 528                  // Make sure the dimensions match a valid image
 529                  if (empty($this->width) || empty($this->height))
 530                  {
 531                      $this->error[] = $this->language->lang('ATTACHED_IMAGE_NOT_IMAGE');
 532                  }
 533              }
 534              else
 535              {
 536                  $this->error[] = $this->language->lang('UNABLE_GET_IMAGE_SIZE');
 537              }
 538          }
 539  
 540          $this->file_moved = true;
 541          $this->additional_checks();
 542          unset($this->upload);
 543  
 544          return true;
 545      }
 546  
 547      /**
 548       * Performing additional checks
 549       *
 550       * @return bool False if issue was found, true if not
 551       */
 552  	public function additional_checks()
 553      {
 554          if (!$this->file_moved)
 555          {
 556              return false;
 557          }
 558  
 559          // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
 560          if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0))
 561          {
 562              $max_filesize = get_formatted_filesize($this->upload->max_filesize, false);
 563  
 564              $this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']);
 565  
 566              return false;
 567          }
 568  
 569          if (!$this->upload->valid_dimensions($this))
 570          {
 571              $this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_SIZE',
 572                  $this->language->lang('PIXELS', (int) $this->upload->min_width),
 573                  $this->language->lang('PIXELS', (int) $this->upload->min_height),
 574                  $this->language->lang('PIXELS', (int) $this->upload->max_width),
 575                  $this->language->lang('PIXELS', (int) $this->upload->max_height),
 576                  $this->language->lang('PIXELS', (int) $this->width),
 577                  $this->language->lang('PIXELS', (int) $this->height));
 578  
 579              return false;
 580          }
 581  
 582          return true;
 583      }
 584  }


Generated: Tue Apr 7 19:44:41 2020 Cross-referenced by PHPXref 0.7.1