[ Index ]

PHP Cross Reference of phpBB-3.2.11-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              $preserve_headers_value = $this->config['img_strip_metadata'] ? 'false' : 'true';
 267              $resize = sprintf(
 268                  'resize: {width: %d, height: %d, quality: %d, preserve_headers: %s},',
 269                  (int) $this->config['img_max_width'],
 270                  (int) $this->config['img_max_height'],
 271                  (int) $this->config['img_quality'],
 272                  $preserve_headers_value
 273              );
 274          }
 275  
 276          return $resize;
 277      }
 278  
 279      /**
 280       * Checks various php.ini values to determine the maximum chunk
 281       * size a file should be split into for upload.
 282       *
 283       * The intention is to calculate a value which reflects whatever
 284       * the most restrictive limit is set to.  And to then set the chunk
 285       * size to half that value, to ensure any required transfer overhead
 286       * and POST data remains well within the limit.  Or, if all of the
 287       * limits are set to unlimited, the chunk size will also be unlimited.
 288       *
 289       * @return int
 290       *
 291       * @access public
 292       */
 293  	public function get_chunk_size()
 294      {
 295          $max = 0;
 296  
 297          $limits = [
 298              $this->php_ini->getBytes('memory_limit'),
 299              $this->php_ini->getBytes('upload_max_filesize'),
 300              $this->php_ini->getBytes('post_max_size'),
 301          ];
 302  
 303          foreach ($limits as $limit_type)
 304          {
 305              if ($limit_type > 0)
 306              {
 307                  $max = ($max !== 0) ? min($limit_type, $max) : $limit_type;
 308              }
 309          }
 310  
 311          return floor($max / 2);
 312      }
 313  
 314  	protected function temporary_filepath($file_name)
 315      {
 316          // Must preserve the extension for plupload to work.
 317          return sprintf(
 318              '%s/%s_%s%s',
 319              $this->temporary_directory,
 320              $this->config['plupload_salt'],
 321              md5($file_name),
 322              \phpbb\files\filespec::get_extension($file_name)
 323          );
 324      }
 325  
 326      /**
 327      * Checks whether the chunk we are about to deal with was actually uploaded
 328      * by PHP and actually exists, if not, it generates an error
 329      *
 330      * @param string $form_name The name of the file in the form data
 331      *
 332      * @return null
 333      */
 334  	protected function integrate_uploaded_file($form_name, $chunk, $file_path)
 335      {
 336          $is_multipart = $this->is_multipart();
 337          $upload = $this->request->file($form_name);
 338          if ($is_multipart && (!isset($upload['tmp_name']) || !is_uploaded_file($upload['tmp_name'])))
 339          {
 340              $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
 341          }
 342  
 343          $tmp_file = $this->temporary_filepath($upload['tmp_name']);
 344  
 345          if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file))
 346          {
 347              $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
 348          }
 349  
 350          $out = fopen("{$file_path}.part", $chunk == 0 ? 'wb' : 'ab');
 351          if (!$out)
 352          {
 353              $this->emit_error(102, 'PLUPLOAD_ERR_OUTPUT');
 354          }
 355  
 356          $in = fopen(($is_multipart) ? $tmp_file : 'php://input', 'rb');
 357          if (!$in)
 358          {
 359              $this->emit_error(101, 'PLUPLOAD_ERR_INPUT');
 360          }
 361  
 362          while ($buf = fread($in, 4096))
 363          {
 364              fwrite($out, $buf);
 365          }
 366  
 367          fclose($in);
 368          fclose($out);
 369  
 370          if ($is_multipart)
 371          {
 372              unlink($tmp_file);
 373          }
 374      }
 375  
 376      /**
 377      * Creates the temporary directory if it does not already exist.
 378      *
 379      * @return null
 380      */
 381  	protected function prepare_temporary_directory()
 382      {
 383          if (!file_exists($this->temporary_directory))
 384          {
 385              mkdir($this->temporary_directory);
 386  
 387              copy(
 388                  $this->upload_directory . '/index.htm',
 389                  $this->temporary_directory . '/index.htm'
 390              );
 391          }
 392      }
 393  
 394      /**
 395      * Sets the default directories for uploads
 396      *
 397      * @return null
 398      */
 399  	protected function set_default_directories()
 400      {
 401          $this->upload_directory = $this->phpbb_root_path . $this->config['upload_path'];
 402          $this->temporary_directory = $this->upload_directory . '/plupload';
 403      }
 404  
 405      /**
 406      * Sets the upload directories to the specified paths
 407      *
 408      * @param string $upload_directory Upload directory
 409      * @param string $temporary_directory Temporary directory
 410      *
 411      * @return null
 412      */
 413  	public function set_upload_directories($upload_directory, $temporary_directory)
 414      {
 415          $this->upload_directory = $upload_directory;
 416          $this->temporary_directory = $temporary_directory;
 417      }
 418  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1