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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
plupload.php
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