Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_upload.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 27.55 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * This file is part of the phpBB Forum Software package.
 0005  *
 0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
 0007  * @license GNU General Public License, version 2 (GPL-2.0)
 0008  *
 0009  * For full copyright and license information, please see
 0010  * the docs/CREDITS.txt file.
 0011  *
 0012  */
 0013   
 0014  /**
 0015  * @ignore
 0016  */
 0017  if (!defined('IN_PHPBB'))
 0018  {
 0019      exit;
 0020  }
 0021   
 0022  /**
 0023  * Responsible for holding all file relevant information, as well as doing file-specific operations.
 0024  * The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on.
 0025  */
 0026  class filespec
 0027  {
 0028      var $filename = '';
 0029      var $realname = '';
 0030      var $uploadname = '';
 0031      var $mimetype = '';
 0032      var $extension = '';
 0033      var $filesize = 0;
 0034      var $width = 0;
 0035      var $height = 0;
 0036      var $image_info = array();
 0037   
 0038      var $destination_file = '';
 0039      var $destination_path = '';
 0040   
 0041      var $file_moved = false;
 0042      var $init_error = false;
 0043      var $local = false;
 0044   
 0045      var $error = array();
 0046   
 0047      var $upload = '';
 0048   
 0049      /**
 0050       * The plupload object
 0051       * @var \phpbb\plupload\plupload
 0052       */
 0053      protected $plupload;
 0054   
 0055      /**
 0056       * phpBB Mimetype guesser
 0057       * @var \phpbb\mimetype\guesser
 0058       */
 0059      protected $mimetype_guesser;
 0060   
 0061      /**
 0062      * File Class
 0063      * @access private
 0064      */
 0065      function filespec($upload_ary, $upload_namespace, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
 0066      {
 0067          if (!isset($upload_ary))
 0068          {
 0069              $this->init_error = true;
 0070              return;
 0071          }
 0072   
 0073          $this->filename = $upload_ary['tmp_name'];
 0074          $this->filesize = $upload_ary['size'];
 0075          $name = (STRIP) ? stripslashes($upload_ary['name']) : $upload_ary['name'];
 0076          $name = trim(utf8_basename($name));
 0077          $this->realname = $this->uploadname = $name;
 0078          $this->mimetype = $upload_ary['type'];
 0079   
 0080          // Opera adds the name to the mime type
 0081          $this->mimetype    = (strpos($this->mimetype, '; name') !== false) ? str_replace(strstr($this->mimetype, '; name'), '', $this->mimetype) : $this->mimetype;
 0082   
 0083          if (!$this->mimetype)
 0084          {
 0085              $this->mimetype = 'application/octet-stream';
 0086          }
 0087   
 0088          $this->extension = strtolower(self::get_extension($this->realname));
 0089   
 0090          // Try to get real filesize from temporary folder (not always working) ;)
 0091          $this->filesize = (@filesize($this->filename)) ? @filesize($this->filename) : $this->filesize;
 0092   
 0093          $this->width = $this->height = 0;
 0094          $this->file_moved = false;
 0095   
 0096          $this->local = (isset($upload_ary['local_mode'])) ? true : false;
 0097          $this->upload = $upload_namespace;
 0098          $this->plupload = $plupload;
 0099          $this->mimetype_guesser = $mimetype_guesser;
 0100      }
 0101   
 0102      /**
 0103      * Cleans destination filename
 0104      *
 0105      * @param real|unique|unique_ext $mode real creates a realname, filtering some characters, lowering every character. Unique creates an unique filename
 0106      * @param string $prefix Prefix applied to filename
 0107      * @param string $user_id The user_id is only needed for when cleaning a user's avatar
 0108      * @access public
 0109      */
 0110      function clean_filename($mode = 'unique', $prefix = '', $user_id = '')
 0111      {
 0112          if ($this->init_error)
 0113          {
 0114              return;
 0115          }
 0116   
 0117          switch ($mode)
 0118          {
 0119              case 'real':
 0120                  // Remove every extension from filename (to not let the mime bug being exposed)
 0121                  if (strpos($this->realname, '.') !== false)
 0122                  {
 0123                      $this->realname = substr($this->realname, 0, strpos($this->realname, '.'));
 0124                  }
 0125   
 0126                  // Replace any chars which may cause us problems with _
 0127                  $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|');
 0128   
 0129                  $this->realname = rawurlencode(str_replace($bad_chars, '_', strtolower($this->realname)));
 0130                  $this->realname = preg_replace("/%(\w{2})/", '_', $this->realname);
 0131   
 0132                  $this->realname = $prefix . $this->realname . '.' . $this->extension;
 0133              break;
 0134   
 0135              case 'unique':
 0136                  $this->realname = $prefix . md5(unique_id());
 0137              break;
 0138   
 0139              case 'avatar':
 0140                  $this->extension = strtolower($this->extension);
 0141                  $this->realname = $prefix . $user_id . '.' . $this->extension;
 0142   
 0143              break;
 0144   
 0145              case 'unique_ext':
 0146              default:
 0147                  $this->realname = $prefix . md5(unique_id()) . '.' . $this->extension;
 0148              break;
 0149          }
 0150      }
 0151   
 0152      /**
 0153      * Get property from file object
 0154      */
 0155      function get($property)
 0156      {
 0157          if ($this->init_error || !isset($this->$property))
 0158          {
 0159              return false;
 0160          }
 0161   
 0162          return $this->$property;
 0163      }
 0164   
 0165      /**
 0166      * Check if file is an image (mimetype)
 0167      *
 0168      * @return true if it is an image, false if not
 0169      */
 0170      function is_image()
 0171      {
 0172          return (strpos($this->mimetype, 'image/') === 0);
 0173      }
 0174   
 0175      /**
 0176      * Check if the file got correctly uploaded
 0177      *
 0178      * @return true if it is a valid upload, false if not
 0179      */
 0180      function is_uploaded()
 0181      {
 0182          $is_plupload = $this->plupload && $this->plupload->is_active();
 0183   
 0184          if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename))
 0185          {
 0186              return false;
 0187          }
 0188   
 0189          if (($this->local || $is_plupload) && !file_exists($this->filename))
 0190          {
 0191              return false;
 0192          }
 0193   
 0194          return true;
 0195      }
 0196   
 0197      /**
 0198      * Remove file
 0199      */
 0200      function remove()
 0201      {
 0202          if ($this->file_moved)
 0203          {
 0204              @unlink($this->destination_file);
 0205          }
 0206      }
 0207   
 0208      /**
 0209      * Get file extension
 0210      *
 0211      * @param string Filename that needs to be checked
 0212      * @return string Extension of the supplied filename
 0213      */
 0214      static public function get_extension($filename)
 0215      {
 0216          if (strpos($filename, '.') === false)
 0217          {
 0218              return '';
 0219          }
 0220   
 0221          $filename = explode('.', $filename);
 0222          return array_pop($filename);
 0223      }
 0224   
 0225      /**
 0226      * Get mimetype
 0227      *
 0228      * @param string $filename Filename that needs to be checked
 0229      * @return string Mimetype of supplied filename
 0230      */
 0231      function get_mimetype($filename)
 0232      {
 0233          if ($this->mimetype_guesser !== null)
 0234          {
 0235              $mimetype = $this->mimetype_guesser->guess($filename, $this->uploadname);
 0236   
 0237              if ($mimetype !== 'application/octet-stream')
 0238              {
 0239                  $this->mimetype = $mimetype;
 0240              }
 0241          }
 0242   
 0243          return $this->mimetype;
 0244      }
 0245   
 0246      /**
 0247      * Get filesize
 0248      */
 0249      function get_filesize($filename)
 0250      {
 0251          return @filesize($filename);
 0252      }
 0253   
 0254   
 0255      /**
 0256      * Check the first 256 bytes for forbidden content
 0257      */
 0258      function check_content($disallowed_content)
 0259      {
 0260          if (empty($disallowed_content))
 0261          {
 0262              return true;
 0263          }
 0264   
 0265          $fp = @fopen($this->filename, 'rb');
 0266   
 0267          if ($fp !== false)
 0268          {
 0269              $ie_mime_relevant = fread($fp, 256);
 0270              fclose($fp);
 0271              foreach ($disallowed_content as $forbidden)
 0272              {
 0273                  if (stripos($ie_mime_relevant, '<' . $forbidden) !== false)
 0274                  {
 0275                      return false;
 0276                  }
 0277              }
 0278          }
 0279          return true;
 0280      }
 0281   
 0282      /**
 0283      * Move file to destination folder
 0284      * The phpbb_root_path variable will be applied to the destination path
 0285      *
 0286      * @param string $destination Destination path, for example $config['avatar_path']
 0287      * @param bool $overwrite If set to true, an already existing file will be overwritten
 0288      * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped
 0289      * @param string $chmod Permission mask for chmodding the file after a successful move. The mode entered here reflects the mode defined by {@link phpbb_chmod()}
 0290      *
 0291      * @access public
 0292      */
 0293      function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false)
 0294      {
 0295          global $user, $phpbb_root_path;
 0296   
 0297          if (sizeof($this->error))
 0298          {
 0299              return false;
 0300          }
 0301   
 0302          $chmod = ($chmod === false) ? CHMOD_READ | CHMOD_WRITE : $chmod;
 0303   
 0304          // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it...
 0305          $this->destination_path = $phpbb_root_path . $destination;
 0306   
 0307          // Check if the destination path exist...
 0308          if (!file_exists($this->destination_path))
 0309          {
 0310              @unlink($this->filename);
 0311              return false;
 0312          }
 0313   
 0314          $upload_mode = (@ini_get('open_basedir') || @ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'on') ? 'move' : 'copy';
 0315          $upload_mode = ($this->local) ? 'local' : $upload_mode;
 0316          $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname);
 0317   
 0318          // Check if the file already exist, else there is something wrong...
 0319          if (file_exists($this->destination_file) && !$overwrite)
 0320          {
 0321              @unlink($this->filename);
 0322              $this->error[] = $user->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
 0323              $this->file_moved = false;
 0324              return false;
 0325          }
 0326          else
 0327          {
 0328              if (file_exists($this->destination_file))
 0329              {
 0330                  @unlink($this->destination_file);
 0331              }
 0332   
 0333              switch ($upload_mode)
 0334              {
 0335                  case 'copy':
 0336   
 0337                      if (!@copy($this->filename, $this->destination_file))
 0338                      {
 0339                          if (!@move_uploaded_file($this->filename, $this->destination_file))
 0340                          {
 0341                              $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
 0342                          }
 0343                      }
 0344   
 0345                  break;
 0346   
 0347                  case 'move':
 0348   
 0349                      if (!@move_uploaded_file($this->filename, $this->destination_file))
 0350                      {
 0351                          if (!@copy($this->filename, $this->destination_file))
 0352                          {
 0353                              $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
 0354                          }
 0355                      }
 0356   
 0357                  break;
 0358   
 0359                  case 'local':
 0360   
 0361                      if (!@copy($this->filename, $this->destination_file))
 0362                      {
 0363                          $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
 0364                      }
 0365   
 0366                  break;
 0367              }
 0368   
 0369              // Remove temporary filename
 0370              @unlink($this->filename);
 0371   
 0372              if (sizeof($this->error))
 0373              {
 0374                  return false;
 0375              }
 0376   
 0377              phpbb_chmod($this->destination_file, $chmod);
 0378          }
 0379   
 0380          // Try to get real filesize from destination folder
 0381          $this->filesize = (@filesize($this->destination_file)) ? @filesize($this->destination_file) : $this->filesize;
 0382   
 0383          // Get mimetype of supplied file
 0384          $this->mimetype = $this->get_mimetype($this->destination_file);
 0385   
 0386          if ($this->is_image() && !$skip_image_check)
 0387          {
 0388              $this->width = $this->height = 0;
 0389   
 0390              if (($this->image_info = @getimagesize($this->destination_file)) !== false)
 0391              {
 0392                  $this->width = $this->image_info[0];
 0393                  $this->height = $this->image_info[1];
 0394   
 0395                  if (!empty($this->image_info['mime']))
 0396                  {
 0397                      $this->mimetype = $this->image_info['mime'];
 0398                  }
 0399   
 0400                  // Check image type
 0401                  $types = fileupload::image_types();
 0402   
 0403                  if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]]))
 0404                  {
 0405                      if (!isset($types[$this->image_info[2]]))
 0406                      {
 0407                          $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info[2], $this->mimetype);
 0408                      }
 0409                      else
 0410                      {
 0411                          $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info[2]][0], $this->extension);
 0412                      }
 0413                  }
 0414   
 0415                  // Make sure the dimensions match a valid image
 0416                  if (empty($this->width) || empty($this->height))
 0417                  {
 0418                      $this->error[] = $user->lang['ATTACHED_IMAGE_NOT_IMAGE'];
 0419                  }
 0420              }
 0421              else
 0422              {
 0423                  $this->error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
 0424              }
 0425          }
 0426   
 0427          $this->file_moved = true;
 0428          $this->additional_checks();
 0429          unset($this->upload);
 0430   
 0431          return true;
 0432      }
 0433   
 0434      /**
 0435      * Performing additional checks
 0436      */
 0437      function additional_checks()
 0438      {
 0439          global $user;
 0440   
 0441          if (!$this->file_moved)
 0442          {
 0443              return false;
 0444          }
 0445   
 0446          // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
 0447          if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0))
 0448          {
 0449              $max_filesize = get_formatted_filesize($this->upload->max_filesize, false);
 0450   
 0451              $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
 0452   
 0453              return false;
 0454          }
 0455   
 0456          if (!$this->upload->valid_dimensions($this))
 0457          {
 0458              $this->error[] = $user->lang($this->upload->error_prefix . 'WRONG_SIZE',
 0459                  $user->lang('PIXELS', (int) $this->upload->min_width),
 0460                  $user->lang('PIXELS', (int) $this->upload->min_height),
 0461                  $user->lang('PIXELS', (int) $this->upload->max_width),
 0462                  $user->lang('PIXELS', (int) $this->upload->max_height),
 0463                  $user->lang('PIXELS', (int) $this->width),
 0464                  $user->lang('PIXELS', (int) $this->height));
 0465   
 0466              return false;
 0467          }
 0468   
 0469          return true;
 0470      }
 0471  }
 0472   
 0473  /**
 0474  * Class for assigning error messages before a real filespec class can be assigned
 0475  */
 0476  class fileerror extends filespec
 0477  {
 0478      function fileerror($error_msg)
 0479      {
 0480          $this->error[] = $error_msg;
 0481      }
 0482  }
 0483   
 0484  /**
 0485  * File upload class
 0486  * Init class (all parameters optional and able to be set/overwritten separately) - scope is global and valid for all uploads
 0487  */
 0488  class fileupload
 0489  {
 0490      var $allowed_extensions = array();
 0491      var $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title');
 0492      var $max_filesize = 0;
 0493      var $min_width = 0;
 0494      var $min_height = 0;
 0495      var $max_width = 0;
 0496      var $max_height = 0;
 0497      var $error_prefix = '';
 0498   
 0499      /** @var int Timeout for remote upload */
 0500      var $upload_timeout = 6;
 0501   
 0502      /**
 0503      * Init file upload class.
 0504      *
 0505      * @param string $error_prefix Used error messages will get prefixed by this string
 0506      * @param array $allowed_extensions Array of allowed extensions, for example array('jpg', 'jpeg', 'gif', 'png')
 0507      * @param int $max_filesize Maximum filesize
 0508      * @param int $min_width Minimum image width (only checked for images)
 0509      * @param int $min_height Minimum image height (only checked for images)
 0510      * @param int $max_width Maximum image width (only checked for images)
 0511      * @param int $max_height Maximum image height (only checked for images)
 0512      * @param bool|array $disallowed_content If enabled, the first 256 bytes of the file must not
 0513      *                                        contain any of its values. Defaults to false.
 0514      *
 0515      */
 0516      function fileupload($error_prefix = '', $allowed_extensions = false, $max_filesize = false, $min_width = false, $min_height = false, $max_width = false, $max_height = false, $disallowed_content = false)
 0517      {
 0518          $this->set_allowed_extensions($allowed_extensions);
 0519          $this->set_max_filesize($max_filesize);
 0520          $this->set_allowed_dimensions($min_width, $min_height, $max_width, $max_height);
 0521          $this->set_error_prefix($error_prefix);
 0522          $this->set_disallowed_content($disallowed_content);
 0523      }
 0524   
 0525      /**
 0526      * Reset vars
 0527      */
 0528      function reset_vars()
 0529      {
 0530          $this->max_filesize = 0;
 0531          $this->min_width = $this->min_height = $this->max_width = $this->max_height = 0;
 0532          $this->error_prefix = '';
 0533          $this->allowed_extensions = array();
 0534          $this->disallowed_content = array();
 0535      }
 0536   
 0537      /**
 0538      * Set allowed extensions
 0539      */
 0540      function set_allowed_extensions($allowed_extensions)
 0541      {
 0542          if ($allowed_extensions !== false && is_array($allowed_extensions))
 0543          {
 0544              $this->allowed_extensions = $allowed_extensions;
 0545          }
 0546      }
 0547   
 0548      /**
 0549      * Set allowed dimensions
 0550      */
 0551      function set_allowed_dimensions($min_width, $min_height, $max_width, $max_height)
 0552      {
 0553          $this->min_width = (int) $min_width;
 0554          $this->min_height = (int) $min_height;
 0555          $this->max_width = (int) $max_width;
 0556          $this->max_height = (int) $max_height;
 0557      }
 0558   
 0559      /**
 0560      * Set maximum allowed filesize
 0561      */
 0562      function set_max_filesize($max_filesize)
 0563      {
 0564          if ($max_filesize !== false && (int) $max_filesize)
 0565          {
 0566              $this->max_filesize = (int) $max_filesize;
 0567          }
 0568      }
 0569   
 0570      /**
 0571      * Set disallowed strings
 0572      */
 0573      function set_disallowed_content($disallowed_content)
 0574      {
 0575          if ($disallowed_content !== false && is_array($disallowed_content))
 0576          {
 0577              $this->disallowed_content = array_diff($disallowed_content, array(''));
 0578          }
 0579      }
 0580   
 0581      /**
 0582      * Set error prefix
 0583      */
 0584      function set_error_prefix($error_prefix)
 0585      {
 0586          $this->error_prefix = $error_prefix;
 0587      }
 0588   
 0589      /**
 0590      * Form upload method
 0591      * Upload file from users harddisk
 0592      *
 0593      * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified)
 0594      * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser
 0595      * @param \phpbb\plupload\plupload $plupload The plupload object
 0596      *
 0597      * @return object $file Object "filespec" is returned, all further operations can be done with this object
 0598      * @access public
 0599      */
 0600      function form_upload($form_name, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
 0601      {
 0602          global $user, $request;
 0603   
 0604          $upload = $request->file($form_name);
 0605          unset($upload['local_mode']);
 0606   
 0607          if ($plupload)
 0608          {
 0609              $result = $plupload->handle_upload($form_name);
 0610              if (is_array($result))
 0611              {
 0612                  $upload = array_merge($upload, $result);
 0613              }
 0614          }
 0615   
 0616          $file = new filespec($upload, $this, $mimetype_guesser, $plupload);
 0617   
 0618          if ($file->init_error)
 0619          {
 0620              $file->error[] = '';
 0621              return $file;
 0622          }
 0623   
 0624          // Error array filled?
 0625          if (isset($upload['error']))
 0626          {
 0627              $error = $this->assign_internal_error($upload['error']);
 0628   
 0629              if ($error !== false)
 0630              {
 0631                  $file->error[] = $error;
 0632                  return $file;
 0633              }
 0634          }
 0635   
 0636          // Check if empty file got uploaded (not catched by is_uploaded_file)
 0637          if (isset($upload['size']) && $upload['size'] == 0)
 0638          {
 0639              $file->error[] = $user->lang[$this->error_prefix . 'EMPTY_FILEUPLOAD'];
 0640              return $file;
 0641          }
 0642   
 0643          // PHP Upload filesize exceeded
 0644          if ($file->get('filename') == 'none')
 0645          {
 0646              $max_filesize = @ini_get('upload_max_filesize');
 0647              $unit = 'MB';
 0648   
 0649              if (!empty($max_filesize))
 0650              {
 0651                  $unit = strtolower(substr($max_filesize, -1, 1));
 0652                  $max_filesize = (int) $max_filesize;
 0653   
 0654                  $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
 0655              }
 0656   
 0657              $file->error[] = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
 0658              return $file;
 0659          }
 0660   
 0661          // Not correctly uploaded
 0662          if (!$file->is_uploaded())
 0663          {
 0664              $file->error[] = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
 0665              return $file;
 0666          }
 0667   
 0668          $this->common_checks($file);
 0669   
 0670          return $file;
 0671      }
 0672   
 0673      /**
 0674      * Move file from another location to phpBB
 0675      */
 0676      function local_upload($source_file, $filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null)
 0677      {
 0678          global $user, $request;
 0679   
 0680          $upload = array();
 0681   
 0682          $upload['local_mode'] = true;
 0683          $upload['tmp_name'] = $source_file;
 0684   
 0685          if ($filedata === false)
 0686          {
 0687              $upload['name'] = utf8_basename($source_file);
 0688              $upload['size'] = 0;
 0689          }
 0690          else
 0691          {
 0692              $upload['name'] = $filedata['realname'];
 0693              $upload['size'] = $filedata['size'];
 0694              $upload['type'] = $filedata['type'];
 0695          }
 0696   
 0697          $file = new filespec($upload, $this, $mimetype_guesser);
 0698   
 0699          if ($file->init_error)
 0700          {
 0701              $file->error[] = '';
 0702              return $file;
 0703          }
 0704   
 0705          if (isset($upload['error']))
 0706          {
 0707              $error = $this->assign_internal_error($upload['error']);
 0708   
 0709              if ($error !== false)
 0710              {
 0711                  $file->error[] = $error;
 0712                  return $file;
 0713              }
 0714          }
 0715   
 0716          // PHP Upload filesize exceeded
 0717          if ($file->get('filename') == 'none')
 0718          {
 0719              $max_filesize = @ini_get('upload_max_filesize');
 0720              $unit = 'MB';
 0721   
 0722              if (!empty($max_filesize))
 0723              {
 0724                  $unit = strtolower(substr($max_filesize, -1, 1));
 0725                  $max_filesize = (int) $max_filesize;
 0726   
 0727                  $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
 0728              }
 0729   
 0730              $file->error[] = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
 0731              return $file;
 0732          }
 0733   
 0734          // Not correctly uploaded
 0735          if (!$file->is_uploaded())
 0736          {
 0737              $file->error[] = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
 0738              return $file;
 0739          }
 0740   
 0741          $this->common_checks($file);
 0742          $request->overwrite('local', $upload, \phpbb\request\request_interface::FILES);
 0743   
 0744          return $file;
 0745      }
 0746   
 0747      /**
 0748      * Remote upload method
 0749      * Uploads file from given url
 0750      *
 0751      * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif
 0752      * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser
 0753      * @return object $file Object "filespec" is returned, all further operations can be done with this object
 0754      * @access public
 0755      */
 0756      function remote_upload($upload_url, \phpbb\mimetype\guesser $mimetype_guesser = null)
 0757      {
 0758          global $user, $phpbb_root_path;
 0759   
 0760          $upload_ary = array();
 0761          $upload_ary['local_mode'] = true;
 0762   
 0763          if (!preg_match('#^(https?://).*?\.(' . implode('|', $this->allowed_extensions) . ')$#i', $upload_url, $match))
 0764          {
 0765              $file = new fileerror($user->lang[$this->error_prefix . 'URL_INVALID']);
 0766              return $file;
 0767          }
 0768   
 0769          if (empty($match[2]))
 0770          {
 0771              $file = new fileerror($user->lang[$this->error_prefix . 'URL_INVALID']);
 0772              return $file;
 0773          }
 0774   
 0775          $url = parse_url($upload_url);
 0776   
 0777          $host = $url['host'];
 0778          $path = $url['path'];
 0779          $port = (!empty($url['port'])) ? (int) $url['port'] : 80;
 0780   
 0781          $upload_ary['type'] = 'application/octet-stream';
 0782   
 0783          $url['path'] = explode('.', $url['path']);
 0784          $ext = array_pop($url['path']);
 0785   
 0786          $url['path'] = implode('', $url['path']);
 0787          $upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : '');
 0788          $filename = $url['path'];
 0789          $filesize = 0;
 0790   
 0791          $remote_max_filesize = $this->max_filesize;
 0792          if (!$remote_max_filesize)
 0793          {
 0794              $max_filesize = @ini_get('upload_max_filesize');
 0795   
 0796              if (!empty($max_filesize))
 0797              {
 0798                  $unit = strtolower(substr($max_filesize, -1, 1));
 0799                  $remote_max_filesize = (int) $max_filesize;
 0800   
 0801                  switch ($unit)
 0802                  {
 0803                      case 'g':
 0804                          $remote_max_filesize *= 1024;
 0805                      // no break
 0806                      case 'm':
 0807                          $remote_max_filesize *= 1024;
 0808                      // no break
 0809                      case 'k':
 0810                          $remote_max_filesize *= 1024;
 0811                      // no break
 0812                  }
 0813              }
 0814          }
 0815   
 0816          $errno = 0;
 0817          $errstr = '';
 0818   
 0819          if (!($fsock = @fsockopen($host, $port, $errno, $errstr)))
 0820          {
 0821              $file = new fileerror($user->lang[$this->error_prefix . 'NOT_UPLOADED']);
 0822              return $file;
 0823          }
 0824   
 0825          // Make sure $path not beginning with /
 0826          if (strpos($path, '/') === 0)
 0827          {
 0828              $path = substr($path, 1);
 0829          }
 0830   
 0831          fputs($fsock, 'GET /' . $path . " HTTP/1.1\r\n");
 0832          fputs($fsock, "HOST: " . $host . "\r\n");
 0833          fputs($fsock, "Connection: close\r\n\r\n");
 0834   
 0835          // Set a proper timeout for the socket
 0836          socket_set_timeout($fsock, $this->upload_timeout);
 0837   
 0838          $get_info = false;
 0839          $data = '';
 0840          $length = false;
 0841          $timer_stop = time() + $this->upload_timeout;
 0842   
 0843          while ((!$length || $filesize < $length) && !@feof($fsock))
 0844          {
 0845              if ($get_info)
 0846              {
 0847                  if ($length)
 0848                  {
 0849                      // Don't attempt to read past end of file if server indicated length
 0850                      $block = @fread($fsock, min($length - $filesize, 1024));
 0851                  }
 0852                  else
 0853                  {
 0854                      $block = @fread($fsock, 1024);
 0855                  }
 0856   
 0857                  $filesize += strlen($block);
 0858   
 0859                  if ($remote_max_filesize && $filesize > $remote_max_filesize)
 0860                  {
 0861                      $max_filesize = get_formatted_filesize($remote_max_filesize, false);
 0862   
 0863                      $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']));
 0864                      return $file;
 0865                  }
 0866   
 0867                  $data .= $block;
 0868              }
 0869              else
 0870              {
 0871                  $line = @fgets($fsock, 1024);
 0872   
 0873                  if ($line == "\r\n")
 0874                  {
 0875                      $get_info = true;
 0876                  }
 0877                  else
 0878                  {
 0879                      if (stripos($line, 'content-type: ') !== false)
 0880                      {
 0881                          $upload_ary['type'] = rtrim(str_replace('content-type: ', '', strtolower($line)));
 0882                      }
 0883                      else if ($this->max_filesize && stripos($line, 'content-length: ') !== false)
 0884                      {
 0885                          $length = (int) str_replace('content-length: ', '', strtolower($line));
 0886   
 0887                          if ($remote_max_filesize && $length && $length > $remote_max_filesize)
 0888                          {
 0889                              $max_filesize = get_formatted_filesize($remote_max_filesize, false);
 0890   
 0891                              $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']));
 0892                              return $file;
 0893                          }
 0894                      }
 0895                      else if (stripos($line, '404 not found') !== false)
 0896                      {
 0897                          $file = new fileerror($user->lang[$this->error_prefix . 'URL_NOT_FOUND']);
 0898                          return $file;
 0899                      }
 0900                  }
 0901              }
 0902   
 0903              $stream_meta_data = stream_get_meta_data($fsock);
 0904   
 0905              // Cancel upload if we exceed timeout
 0906              if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop)
 0907              {
 0908                  $file = new fileerror($user->lang[$this->error_prefix . 'REMOTE_UPLOAD_TIMEOUT']);
 0909                  return $file;
 0910              }
 0911          }
 0912          @fclose($fsock);
 0913   
 0914          if (empty($data))
 0915          {
 0916              $file = new fileerror($user->lang[$this->error_prefix . 'EMPTY_REMOTE_DATA']);
 0917              return $file;
 0918          }
 0919   
 0920          $tmp_path = (!@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'off') ? false : $phpbb_root_path . 'cache';
 0921          $filename = tempnam($tmp_path, unique_id() . '-');
 0922   
 0923          if (!($fp = @fopen($filename, 'wb')))
 0924          {
 0925              $file = new fileerror($user->lang[$this->error_prefix . 'NOT_UPLOADED']);
 0926              return $file;
 0927          }
 0928   
 0929          $upload_ary['size'] = fwrite($fp, $data);
 0930          fclose($fp);
 0931          unset($data);
 0932   
 0933          $upload_ary['tmp_name'] = $filename;
 0934   
 0935          $file = new filespec($upload_ary, $this, $mimetype_guesser);
 0936          $this->common_checks($file);
 0937   
 0938          return $file;
 0939      }
 0940   
 0941      /**
 0942      * Assign internal error
 0943      * @access private
 0944      */
 0945      function assign_internal_error($errorcode)
 0946      {
 0947          global $user;
 0948   
 0949          switch ($errorcode)
 0950          {
 0951              case 1:
 0952                  $max_filesize = @ini_get('upload_max_filesize');
 0953                  $unit = 'MB';
 0954   
 0955                  if (!empty($max_filesize))
 0956                  {
 0957                      $unit = strtolower(substr($max_filesize, -1, 1));
 0958                      $max_filesize = (int) $max_filesize;
 0959   
 0960                      $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
 0961                  }
 0962   
 0963                  $error = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
 0964              break;
 0965   
 0966              case 2:
 0967                  $max_filesize = get_formatted_filesize($this->max_filesize, false);
 0968   
 0969                  $error = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
 0970              break;
 0971   
 0972              case 3:
 0973                  $error = $user->lang[$this->error_prefix . 'PARTIAL_UPLOAD'];
 0974              break;
 0975   
 0976              case 4:
 0977                  $error = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
 0978              break;
 0979   
 0980              case 6:
 0981                  $error = 'Temporary folder could not be found. Please check your PHP installation.';
 0982              break;
 0983   
 0984              default:
 0985                  $error = false;
 0986              break;
 0987          }
 0988   
 0989          return $error;
 0990      }
 0991   
 0992      /**
 0993      * Perform common checks
 0994      */
 0995      function common_checks(&$file)
 0996      {
 0997          global $user;
 0998   
 0999          // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
 1000          if ($this->max_filesize && ($file->get('filesize') > $this->max_filesize || $file->get('filesize') == 0))
 1001          {
 1002              $max_filesize = get_formatted_filesize($this->max_filesize, false);
 1003   
 1004              $file->error[] = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
 1005          }
 1006   
 1007          // check Filename
 1008          if (preg_match("#[\\/:*?\"<>|]#i", $file->get('realname')))
 1009          {
 1010              $file->error[] = sprintf($user->lang[$this->error_prefix . 'INVALID_FILENAME'], $file->get('realname'));
 1011          }
 1012   
 1013          // Invalid Extension
 1014          if (!$this->valid_extension($file))
 1015          {
 1016              $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_EXTENSION'], $file->get('extension'));
 1017          }
 1018   
 1019          // MIME Sniffing
 1020          if (!$this->valid_content($file))
 1021          {
 1022              $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_CONTENT']);
 1023          }
 1024      }
 1025   
 1026      /**
 1027      * Check for allowed extension
 1028      */
 1029      function valid_extension(&$file)
 1030      {
 1031          return (in_array($file->get('extension'), $this->allowed_extensions)) ? true : false;
 1032      }
 1033   
 1034      /**
 1035      * Check for allowed dimension
 1036      */
 1037      function valid_dimensions(&$file)
 1038      {
 1039          if (!$this->max_width && !$this->max_height && !$this->min_width && !$this->min_height)
 1040          {
 1041              return true;
 1042          }
 1043   
 1044          if (($file->get('width') > $this->max_width && $this->max_width) ||
 1045              ($file->get('height') > $this->max_height && $this->max_height) ||
 1046              ($file->get('width') < $this->min_width && $this->min_width) ||
 1047              ($file->get('height') < $this->min_height && $this->min_height))
 1048          {
 1049              return false;
 1050          }
 1051   
 1052          return true;
 1053      }
 1054   
 1055      /**
 1056      * Check if form upload is valid
 1057      */
 1058      function is_valid($form_name)
 1059      {
 1060          global $request;
 1061          $upload = $request->file($form_name);
 1062   
 1063          return (!empty($upload) && $upload['name'] !== 'none');
 1064      }
 1065   
 1066   
 1067      /**
 1068      * Check for bad content (IE mime-sniffing)
 1069      */
 1070      function valid_content(&$file)
 1071      {
 1072          return ($file->check_content($this->disallowed_content));
 1073      }
 1074   
 1075      /**
 1076      * Get image type/extension mapping
 1077      *
 1078      * @return array Array containing the image types and their extensions
 1079      */
 1080      static public function image_types()
 1081      {
 1082          $result = array(
 1083              IMAGETYPE_GIF        => array('gif'),
 1084              IMAGETYPE_JPEG        => array('jpg', 'jpeg'),
 1085              IMAGETYPE_PNG        => array('png'),
 1086              IMAGETYPE_SWF        => array('swf'),
 1087              IMAGETYPE_PSD        => array('psd'),
 1088              IMAGETYPE_BMP        => array('bmp'),
 1089              IMAGETYPE_TIFF_II    => array('tif', 'tiff'),
 1090              IMAGETYPE_TIFF_MM    => array('tif', 'tiff'),
 1091              IMAGETYPE_JPC        => array('jpg', 'jpeg'),
 1092              IMAGETYPE_JP2        => array('jpg', 'jpeg'),
 1093              IMAGETYPE_JPX        => array('jpg', 'jpeg'),
 1094              IMAGETYPE_JB2        => array('jpg', 'jpeg'),
 1095              IMAGETYPE_IFF        => array('iff'),
 1096              IMAGETYPE_WBMP        => array('wbmp'),
 1097              IMAGETYPE_XBM        => array('xbm'),
 1098          );
 1099   
 1100          if (defined('IMAGETYPE_SWC'))
 1101          {
 1102              $result[IMAGETYPE_SWC] = array('swc');
 1103          }
 1104   
 1105          return $result;
 1106      }
 1107  }
 1108