[ Index ]

PHP Cross Reference of phpBB-3.3.0-deutsch

title

Body

[close]

/phpbb/plupload/ -> plupload.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\plupload;
  15  
  16  /**
  17  * This class handles all server-side plupload functions
  18  */
  19  class plupload
  20  {
  21      /**
  22      * @var string
  23      */
  24      protected $phpbb_root_path;
  25  
  26      /**
  27      * @var \phpbb\config\config
  28      */
  29      protected $config;
  30  
  31      /**
  32      * @var \phpbb\request\request_interface
  33      */
  34      protected $request;
  35  
  36      /**
  37      * @var \phpbb\user
  38      */
  39      protected $user;
  40  
  41      /**
  42      * @var \bantu\IniGetWrapper\IniGetWrapper
  43      */
  44      protected $php_ini;
  45  
  46      /**
  47      * @var \phpbb\mimetype\guesser
  48      */
  49      protected $mimetype_guesser;
  50  
  51      /**
  52      * Final destination for uploaded files, i.e. the "files" directory.
  53      * @var string
  54      */
  55      protected $upload_directory;
  56  
  57      /**
  58      * Temporary upload directory for plupload uploads.
  59      * @var string
  60      */
  61      protected $temporary_directory;
  62  
  63      /**
  64      * Constructor.
  65      *
  66      * @param string $phpbb_root_path
  67      * @param \phpbb\config\config $config
  68      * @param \phpbb\request\request_interface $request
  69      * @param \phpbb\user $user
  70      * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini
  71      * @param \phpbb\mimetype\guesser $mimetype_guesser
  72      */
  73  	public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\user $user, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \phpbb\mimetype\guesser $mimetype_guesser)
  74      {
  75          $this->phpbb_root_path = $phpbb_root_path;
  76          $this->config = $config;
  77          $this->request = $request;
  78          $this->user = $user;
  79          $this->php_ini = $php_ini;
  80          $this->mimetype_guesser = $mimetype_guesser;
  81  
  82          $this->set_default_directories();
  83      }
  84  
  85      /**
  86      * Plupload allows for chunking so we must check for that and assemble
  87      * the whole file first before performing any checks on it.
  88      *
  89      * @param string $form_name The name of the file element in the upload form
  90      *
  91      * @return array|null    null if there are no chunks to piece together
  92      *                        otherwise array containing the path to the
  93      *                        pieced-together file and its size
  94      */
  95  	public function handle_upload($form_name)
  96      {
  97          $chunks_expected = $this->request->variable('chunks', 0);
  98  
  99          // If chunking is disabled or we are not using plupload, just return
 100          // and handle the file as usual
 101          if ($chunks_expected < 2)
 102          {
 103              return;
 104          }
 105  
 106          $file_name = $this->request->variable('name', '');
 107          $chunk = $this->request->variable('chunk', 0);
 108  
 109          $this->user->add_lang('plupload');
 110          $this->prepare_temporary_directory();
 111  
 112          $file_path = $this->temporary_filepath($file_name);
 113          $this->integrate_uploaded_file($form_name, $chunk, $file_path);
 114  
 115          // If we are done with all the chunks, strip the .part suffix and then
 116          // handle the resulting file as normal, otherwise die and await the
 117          // next chunk.
 118          if ($chunk == $chunks_expected - 1)
 119          {
 120              rename("{$file_path}.part", $file_path);
 121  
 122              // Reset upload directories to defaults once completed
 123              $this->set_default_directories();
 124  
 125              // Need to modify some of the $_FILES values to reflect the new file
 126              return array(
 127                  'tmp_name' => $file_path,
 128                  'name' => $this->request->variable('real_filename', '', true),
 129                  'size' => filesize($file_path),
 130                  'type' => $this->mimetype_guesser->guess($file_path, $file_name),
 131              );
 132          }
 133          else
 134          {
 135              $json_response = new \phpbb\json_response();
 136              $json_response->send(array(
 137                  'jsonrpc' => '2.0',
 138                  'id' => 'id',
 139                  'result' => null,
 140              ));
 141          }
 142      }
 143  
 144      /**
 145      * Fill in the plupload configuration options in the template
 146      *
 147      * @param \phpbb\cache\service        $cache
 148      * @param \phpbb\template\template    $template
 149      * @param string                        $s_action The URL to submit the POST data to
 150      * @param int                        $forum_id The ID of the forum
 151      * @param int                        $max_files Maximum number of files allowed. 0 for unlimited.
 152      *
 153      * @return null
 154      */
 155  	public function configure(\phpbb\cache\service $cache, \phpbb\template\template $template, $s_action, $forum_id, $max_files)
 156      {
 157          $filters = $this->generate_filter_string($cache, $forum_id);
 158          $chunk_size = $this->get_chunk_size();
 159          $resize = $this->generate_resize_string();
 160  
 161          $template->assign_vars(array(
 162              'S_RESIZE'            => $resize,
 163              'S_PLUPLOAD'        => true,
 164              'FILTERS'            => $filters,
 165              'CHUNK_SIZE'        => $chunk_size,
 166              'S_PLUPLOAD_URL'    => htmlspecialchars_decode($s_action),
 167              'MAX_ATTACHMENTS'    => $max_files,
 168              'ATTACH_ORDER'        => ($this->config['display_order']) ? 'asc' : 'desc',
 169              'L_TOO_MANY_ATTACHMENTS'    => $this->user->lang('TOO_MANY_ATTACHMENTS', $max_files),
 170          ));
 171  
 172          $this->user->add_lang('plupload');
 173      }
 174  
 175      /**
 176      * Checks whether the page request was sent by plupload or not
 177      *
 178      * @return bool
 179      */
 180  	public function is_active()
 181      {
 182          return $this->request->header('X-PHPBB-USING-PLUPLOAD', false);
 183      }
 184  
 185      /**
 186      * Returns whether the current HTTP request is a multipart request.
 187      *
 188      * @return bool
 189      */
 190  	public function is_multipart()
 191      {
 192          $content_type = $this->request->server('CONTENT_TYPE');
 193  
 194          return strpos($content_type, 'multipart') === 0;
 195      }
 196  
 197      /**
 198      * Sends an error message back to the client via JSON response
 199      *
 200      * @param int $code        The error code
 201      * @param string $msg    The translation string of the message to be sent
 202      *
 203      * @return null
 204      */
 205  	public function emit_error($code, $msg)
 206      {
 207          $json_response = new \phpbb\json_response();
 208          $json_response->send(array(
 209              'jsonrpc' => '2.0',
 210              'id' => 'id',
 211              'error' => array(
 212                  'code' => $code,
 213                  'message' => $this->user->lang($msg),
 214              ),
 215          ));
 216      }
 217  
 218      /**
 219       * Looks at the list of allowed extensions and generates a string
 220       * appropriate for use in configuring plupload with
 221       *
 222       * @param \phpbb\cache\service    $cache        Cache service object
 223       * @param string                $forum_id    The forum identifier
 224       *
 225       * @return string
 226       */
 227  	public function generate_filter_string(\phpbb\cache\service $cache, $forum_id)
 228      {
 229          $groups = [];
 230          $filters = [];
 231  
 232          $attach_extensions = $cache->obtain_attach_extensions($forum_id);
 233          unset($attach_extensions['_allowed_']);
 234  
 235          // Re-arrange the extension array to $groups[$group_name][]
 236          foreach ($attach_extensions as $extension => $extension_info)
 237          {
 238              $groups[$extension_info['group_name']]['extensions'][] = $extension;
 239              $groups[$extension_info['group_name']]['max_file_size'] = (int) $extension_info['max_filesize'];
 240          }
 241  
 242          foreach ($groups as $group => $group_info)
 243          {
 244              $filters[] = sprintf(
 245                  "{title: '%s', extensions: '%s', max_file_size: %s}",
 246                  addslashes(ucfirst(strtolower($group))),
 247                  addslashes(implode(',', $group_info['extensions'])),
 248                  $group_info['max_file_size']
 249              );
 250          }
 251  
 252          return implode(',', $filters);
 253      }
 254  
 255      /**
 256      * Generates a string that is used to tell plupload to automatically resize
 257      * files before uploading them.
 258      *
 259      * @return string
 260      */
 261  	public function generate_resize_string()
 262      {
 263          $resize = '';
 264          if ($this->config['img_max_height'] > 0 && $this->config['img_max_width'] > 0)
 265          {
 266              $resize = sprintf(
 267                  'resize: {width: %d, height: %d, quality: 85},',
 268                  (int) $this->config['img_max_width'],
 269                  (int) $this->config['img_max_height']
 270              );
 271          }
 272  
 273          return $resize;
 274      }
 275  
 276      /**
 277       * Checks various php.ini values to determine the maximum chunk
 278       * size a file should be split into for upload.
 279       *
 280       * The intention is to calculate a value which reflects whatever
 281       * the most restrictive limit is set to.  And to then set the chunk
 282       * size to half that value, to ensure any required transfer overhead
 283       * and POST data remains well within the limit.  Or, if all of the
 284       * limits are set to unlimited, the chunk size will also be unlimited.
 285       *
 286       * @return int
 287       *
 288       * @access public
 289       */
 290  	public function get_chunk_size()
 291      {
 292          $max = 0;
 293  
 294          $limits = [
 295              $this->php_ini->getBytes('memory_limit'),
 296              $this->php_ini->getBytes('upload_max_filesize'),
 297              $this->php_ini->getBytes('post_max_size'),
 298          ];
 299  
 300          foreach ($limits as $limit_type)
 301          {
 302              if ($limit_type > 0)
 303              {
 304                  $max = ($max !== 0) ? min($limit_type, $max) : $limit_type;
 305              }
 306          }
 307  
 308          return floor($max / 2);
 309      }
 310  
 311  	protected function temporary_filepath($file_name)
 312      {
 313          // Must preserve the extension for plupload to work.
 314          return sprintf(
 315              '%s/%s_%s%s',
 316              $this->temporary_directory,
 317              $this->config['plupload_salt'],
 318              md5($file_name),
 319              \phpbb\files\filespec::get_extension($file_name)
 320          );
 321      }
 322  
 323      /**
 324      * Checks whether the chunk we are about to deal with was actually uploaded
 325      * by PHP and actually exists, if not, it generates an error
 326      *
 327      * @param string $form_name The name of the file in the form data
 328      * @param int $chunk Chunk number
 329      * @param string $file_path File path
 330      *
 331      * @return null
 332      */
 333  	protected function integrate_uploaded_file($form_name, $chunk, $file_path)
 334      {
 335          $is_multipart = $this->is_multipart();
 336          $upload = $this->request->file($form_name);
 337          if ($is_multipart && (!isset($upload['tmp_name']) || !is_uploaded_file($upload['tmp_name'])))
 338          {
 339              $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
 340          }
 341  
 342          $tmp_file = $this->temporary_filepath($upload['tmp_name']);
 343  
 344          if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file))
 345          {
 346              $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
 347          }
 348  
 349          $out = fopen("{$file_path}.part", $chunk == 0 ? 'wb' : 'ab');
 350          if (!$out)
 351          {
 352              $this->emit_error(102, 'PLUPLOAD_ERR_OUTPUT');
 353          }
 354  
 355          $in = fopen(($is_multipart) ? $tmp_file : 'php://input', 'rb');
 356          if (!$in)
 357          {
 358              $this->emit_error(101, 'PLUPLOAD_ERR_INPUT');
 359          }
 360  
 361          while ($buf = fread($in, 4096))
 362          {
 363              fwrite($out, $buf);
 364          }
 365  
 366          fclose($in);
 367          fclose($out);
 368  
 369          if ($is_multipart)
 370          {
 371              unlink($tmp_file);
 372          }
 373      }
 374  
 375      /**
 376      * Creates the temporary directory if it does not already exist.
 377      *
 378      * @return null
 379      */
 380  	protected function prepare_temporary_directory()
 381      {
 382          if (!file_exists($this->temporary_directory))
 383          {
 384              mkdir($this->temporary_directory);
 385  
 386              copy(
 387                  $this->upload_directory . '/index.htm',
 388                  $this->temporary_directory . '/index.htm'
 389              );
 390          }
 391      }
 392  
 393      /**
 394      * Sets the default directories for uploads
 395      *
 396      * @return null
 397      */
 398  	protected function set_default_directories()
 399      {
 400          $this->upload_directory = $this->phpbb_root_path . $this->config['upload_path'];
 401          $this->temporary_directory = $this->upload_directory . '/plupload';
 402      }
 403  
 404      /**
 405      * Sets the upload directories to the specified paths
 406      *
 407      * @param string $upload_directory Upload directory
 408      * @param string $temporary_directory Temporary directory
 409      *
 410      * @return null
 411      */
 412  	public function set_upload_directories($upload_directory, $temporary_directory)
 413      {
 414          $this->upload_directory = $upload_directory;
 415          $this->temporary_directory = $temporary_directory;
 416      }
 417  }


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