Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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

plupload.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 10.54 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\plupload;
015   
016  /**
017  * This class handles all server-side plupload functions
018  */
019  class plupload
020  {
021      /**
022      * @var string
023      */
024      protected $phpbb_root_path;
025   
026      /**
027      * @var \phpbb\config\config
028      */
029      protected $config;
030   
031      /**
032      * @var \phpbb\request\request_interface
033      */
034      protected $request;
035   
036      /**
037      * @var \phpbb\user
038      */
039      protected $user;
040   
041      /**
042      * @var \bantu\IniGetWrapper\IniGetWrapper
043      */
044      protected $php_ini;
045   
046      /**
047      * @var \phpbb\mimetype\guesser
048      */
049      protected $mimetype_guesser;
050   
051      /**
052      * Final destination for uploaded files, i.e. the "files" directory.
053      * @var string
054      */
055      protected $upload_directory;
056   
057      /**
058      * Temporary upload directory for plupload uploads.
059      * @var string
060      */
061      protected $temporary_directory;
062   
063      /**
064      * Constructor.
065      *
066      * @param string $phpbb_root_path
067      * @param \phpbb\config\config $config
068      * @param \phpbb\request\request_interface $request
069      * @param \phpbb\user $user
070      * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini
071      * @param \phpbb\mimetype\guesser $mimetype_guesser
072      */
073      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)
074      {
075          $this->phpbb_root_path = $phpbb_root_path;
076          $this->config = $config;
077          $this->request = $request;
078          $this->user = $user;
079          $this->php_ini = $php_ini;
080          $this->mimetype_guesser = $mimetype_guesser;
081   
082          $this->set_default_directories();
083      }
084   
085      /**
086      * Plupload allows for chunking so we must check for that and assemble
087      * the whole file first before performing any checks on it.
088      *
089      * @param string $form_name The name of the file element in the upload form
090      *
091      * @return array|null    null if there are no chunks to piece together
092      *                        otherwise array containing the path to the
093      *                        pieced-together file and its size
094      */
095      public function handle_upload($form_name)
096      {
097          $chunks_expected = $this->request->variable('chunks', 0);
098   
099          // 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'    => html_entity_decode($s_action, ENT_COMPAT),
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      * @param int $chunk Chunk number
332      * @param string $file_path File path
333      *
334      * @return null
335      */
336      protected function integrate_uploaded_file($form_name, $chunk, $file_path)
337      {
338          $is_multipart = $this->is_multipart();
339          $upload = $this->request->file($form_name);
340          if ($is_multipart && (!isset($upload['tmp_name']) || !is_uploaded_file($upload['tmp_name'])))
341          {
342              $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
343          }
344   
345          $tmp_file = $this->temporary_filepath($upload['tmp_name']);
346   
347          if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file))
348          {
349              $this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');
350          }
351   
352          $out = fopen("{$file_path}.part", $chunk == 0 ? 'wb' : 'ab');
353          if (!$out)
354          {
355              $this->emit_error(102, 'PLUPLOAD_ERR_OUTPUT');
356          }
357   
358          $in = fopen(($is_multipart) ? $tmp_file : 'php://input', 'rb');
359          if (!$in)
360          {
361              $this->emit_error(101, 'PLUPLOAD_ERR_INPUT');
362          }
363   
364          while ($buf = fread($in, 4096))
365          {
366              fwrite($out, $buf);
367          }
368   
369          fclose($in);
370          fclose($out);
371   
372          if ($is_multipart)
373          {
374              unlink($tmp_file);
375          }
376      }
377   
378      /**
379      * Creates the temporary directory if it does not already exist.
380      *
381      * @return null
382      */
383      protected function prepare_temporary_directory()
384      {
385          if (!file_exists($this->temporary_directory))
386          {
387              mkdir($this->temporary_directory);
388   
389              copy(
390                  $this->upload_directory . '/index.htm',
391                  $this->temporary_directory . '/index.htm'
392              );
393          }
394      }
395   
396      /**
397      * Sets the default directories for uploads
398      *
399      * @return null
400      */
401      protected function set_default_directories()
402      {
403          $this->upload_directory = $this->phpbb_root_path . $this->config['upload_path'];
404          $this->temporary_directory = $this->upload_directory . '/plupload';
405      }
406   
407      /**
408      * Sets the upload directories to the specified paths
409      *
410      * @param string $upload_directory Upload directory
411      * @param string $temporary_directory Temporary directory
412      *
413      * @return null
414      */
415      public function set_upload_directories($upload_directory, $temporary_directory)
416      {
417          $this->upload_directory = $upload_directory;
418          $this->temporary_directory = $temporary_directory;
419      }
420  }
421