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