PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/phpBB/phpbb/attachment/upload.php

http://github.com/phpbb/phpbb
PHP | 378 lines | 210 code | 60 blank | 108 comment | 29 complexity | ac9dfbd7247ec4a58b720b1aabe2eb60 MD5 | raw file
Possible License(s): GPL-3.0, AGPL-1.0
  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. namespace phpbb\attachment;
  14. use phpbb\auth\auth;
  15. use \phpbb\cache\service;
  16. use \phpbb\config\config;
  17. use \phpbb\event\dispatcher;
  18. use \phpbb\language\language;
  19. use \phpbb\mimetype\guesser;
  20. use \phpbb\plupload\plupload;
  21. use \phpbb\storage\storage;
  22. use \phpbb\filesystem\temp;
  23. use \phpbb\user;
  24. /**
  25. * Attachment upload class
  26. */
  27. class upload
  28. {
  29. /** @var auth */
  30. protected $auth;
  31. /** @var service */
  32. protected $cache;
  33. /** @var config */
  34. protected $config;
  35. /** @var \phpbb\files\upload Upload class */
  36. protected $files_upload;
  37. /** @var language */
  38. protected $language;
  39. /** @var guesser Mimetype guesser */
  40. protected $mimetype_guesser;
  41. /** @var dispatcher */
  42. protected $phpbb_dispatcher;
  43. /** @var plupload Plupload */
  44. protected $plupload;
  45. /** @var storage */
  46. protected $storage;
  47. /** @var temp */
  48. protected $temp;
  49. /** @var user */
  50. protected $user;
  51. /** @var \phpbb\files\filespec Current filespec instance */
  52. private $file;
  53. /** @var array File data */
  54. private $file_data = array(
  55. 'error' => array()
  56. );
  57. /** @var array Extensions array */
  58. private $extensions;
  59. /**
  60. * Constructor for attachments upload class
  61. *
  62. * @param auth $auth
  63. * @param service $cache
  64. * @param config $config
  65. * @param \phpbb\files\upload $files_upload
  66. * @param language $language
  67. * @param guesser $mimetype_guesser
  68. * @param dispatcher $phpbb_dispatcher
  69. * @param plupload $plupload
  70. * @param storage $storage
  71. * @param temp $temp
  72. * @param user $user
  73. */
  74. public function __construct(auth $auth, service $cache, config $config, \phpbb\files\upload $files_upload, language $language, guesser $mimetype_guesser, dispatcher $phpbb_dispatcher, plupload $plupload, storage $storage, temp $temp, user $user)
  75. {
  76. $this->auth = $auth;
  77. $this->cache = $cache;
  78. $this->config = $config;
  79. $this->files_upload = $files_upload;
  80. $this->language = $language;
  81. $this->mimetype_guesser = $mimetype_guesser;
  82. $this->phpbb_dispatcher = $phpbb_dispatcher;
  83. $this->plupload = $plupload;
  84. $this->storage = $storage;
  85. $this->temp = $temp;
  86. $this->user = $user;
  87. }
  88. /**
  89. * Upload Attachment - filedata is generated here
  90. * Uses upload class
  91. *
  92. * @param string $form_name The form name of the file upload input
  93. * @param int $forum_id The id of the forum
  94. * @param bool $local Whether the file is local or not
  95. * @param string $local_storage The path to the local file
  96. * @param bool $is_message Whether it is a PM or not
  97. * @param array $local_filedata An file data object created for the local file
  98. *
  99. * @return array File data array
  100. */
  101. public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = array())
  102. {
  103. $this->init_files_upload($forum_id, $is_message);
  104. $this->file_data['post_attach'] = $local || $this->files_upload->is_valid($form_name);
  105. if (!$this->file_data['post_attach'])
  106. {
  107. $this->file_data['error'][] = $this->language->lang('NO_UPLOAD_FORM_FOUND');
  108. return $this->file_data;
  109. }
  110. $this->file = ($local) ? $this->files_upload->handle_upload('files.types.local_storage', $local_storage, $local_filedata) : $this->files_upload->handle_upload('files.types.form_storage', $form_name);
  111. if ($this->file->init_error())
  112. {
  113. $this->file_data['post_attach'] = false;
  114. return $this->file_data;
  115. }
  116. // Whether the uploaded file is in the image category
  117. $is_image = (isset($this->extensions[$this->file->get('extension')]['display_cat'])) ? $this->extensions[$this->file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
  118. if (!$this->auth->acl_get('a_') && !$this->auth->acl_get('m_', $forum_id))
  119. {
  120. // Check Image Size, if it is an image
  121. if ($is_image)
  122. {
  123. $this->file->upload->set_allowed_dimensions(0, 0, $this->config['img_max_width'], $this->config['img_max_height']);
  124. }
  125. // Admins and mods are allowed to exceed the allowed filesize
  126. if (!empty($this->extensions[$this->file->get('extension')]['max_filesize']))
  127. {
  128. $allowed_filesize = $this->extensions[$this->file->get('extension')]['max_filesize'];
  129. }
  130. else
  131. {
  132. $allowed_filesize = ($is_message) ? $this->config['max_filesize_pm'] : $this->config['max_filesize'];
  133. }
  134. $this->file->upload->set_max_filesize($allowed_filesize);
  135. }
  136. $this->file->clean_filename('unique', $this->user->data['user_id'] . '_');
  137. // Do we have to create a thumbnail?
  138. $this->file_data['thumbnail'] = ($is_image && $this->config['img_create_thumbnail']) ? 1 : 0;
  139. // Make sure the image category only holds valid images...
  140. $this->check_image($is_image);
  141. if (count($this->file->error))
  142. {
  143. $this->file->remove($this->storage);
  144. $this->file_data['error'] = array_merge($this->file_data['error'], $this->file->error);
  145. $this->file_data['post_attach'] = false;
  146. return $this->file_data;
  147. }
  148. $this->fill_file_data();
  149. $filedata = $this->file_data;
  150. /**
  151. * Event to modify uploaded file before submit to the post
  152. *
  153. * @event core.modify_uploaded_file
  154. * @var array filedata Array containing uploaded file data
  155. * @var bool is_image Flag indicating if the file is an image
  156. * @since 3.1.0-RC3
  157. */
  158. $vars = array(
  159. 'filedata',
  160. 'is_image',
  161. );
  162. extract($this->phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
  163. $this->file_data = $filedata;
  164. unset($filedata);
  165. // Check for attachment quota and free space
  166. if (!$this->check_attach_quota() || !$this->check_disk_space())
  167. {
  168. $this->file->remove($this->storage);
  169. return $this->file_data;
  170. }
  171. // Create Thumbnail
  172. $this->create_thumbnail();
  173. // Are we uploading an image *and* this image being within the image category?
  174. // Only then perform additional image checks.
  175. $this->file->move_file($this->storage, false, !$is_image);
  176. if (count($this->file->error))
  177. {
  178. $this->file->remove($this->storage);
  179. // Remove thumbnail if exists
  180. $thumbnail_file = 'thumb_' . $this->file->get('realname');
  181. if ($this->storage->exists($thumbnail_file))
  182. {
  183. $this->storage->delete($thumbnail_file);
  184. }
  185. $this->file_data['error'] = array_merge($this->file_data['error'], $this->file->error);
  186. $this->file_data['post_attach'] = false;
  187. return $this->file_data;
  188. }
  189. return $this->file_data;
  190. }
  191. /**
  192. * Create thumbnail for file if necessary
  193. *
  194. * @return array Updated $filedata
  195. */
  196. protected function create_thumbnail()
  197. {
  198. if ($this->file_data['thumbnail'])
  199. {
  200. $source = $this->file->get('filename');
  201. $destination_name = 'thumb_' . $this->file->get('realname');
  202. $destination = $this->temp->get_dir() . '/' . $destination_name;
  203. if (create_thumbnail($source, $destination, $this->file->get('mimetype')))
  204. {
  205. // Move the thumbnail from temp folder to the storage
  206. $fp = fopen($destination, 'rb');
  207. $this->storage->write_stream($destination_name, $fp);
  208. if (is_resource($fp))
  209. {
  210. fclose($fp);
  211. }
  212. }
  213. else
  214. {
  215. $this->file_data['thumbnail'] = 0;
  216. }
  217. }
  218. }
  219. /**
  220. * Init files upload class
  221. *
  222. * @param int $forum_id Forum ID
  223. * @param bool $is_message Whether attachment is inside PM or not
  224. */
  225. protected function init_files_upload($forum_id, $is_message)
  226. {
  227. if ($this->config['check_attachment_content'] && isset($this->config['mime_triggers']))
  228. {
  229. $this->files_upload->set_disallowed_content(explode('|', $this->config['mime_triggers']));
  230. }
  231. else if (!$this->config['check_attachment_content'])
  232. {
  233. $this->files_upload->set_disallowed_content(array());
  234. }
  235. $this->extensions = $this->cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
  236. $this->files_upload->set_allowed_extensions(array_keys($this->extensions['_allowed_']));
  237. }
  238. /**
  239. * Check if uploaded file is really an image
  240. *
  241. * @param bool $is_image Whether file is image
  242. */
  243. protected function check_image($is_image)
  244. {
  245. // Make sure the image category only holds valid images...
  246. if ($is_image && !$this->file->is_image())
  247. {
  248. $this->file->remove($this->storage);
  249. if ($this->plupload && $this->plupload->is_active())
  250. {
  251. $this->plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
  252. }
  253. // If this error occurs a user tried to exploit an IE Bug by renaming extensions
  254. // Since the image category is displaying content inline we need to catch this.
  255. $this->file->set_error($this->language->lang('ATTACHED_IMAGE_NOT_IMAGE'));
  256. }
  257. }
  258. /**
  259. * Check if attachment quota was reached
  260. *
  261. * @return bool False if attachment quota was reached, true if not
  262. */
  263. protected function check_attach_quota()
  264. {
  265. if ($this->config['attachment_quota'])
  266. {
  267. if (intval($this->config['upload_dir_size']) + $this->file->get('filesize') > $this->config['attachment_quota'])
  268. {
  269. $this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
  270. $this->file_data['post_attach'] = false;
  271. return false;
  272. }
  273. }
  274. return true;
  275. }
  276. /**
  277. * Check if there is enough free space available on disk
  278. *
  279. * @return bool True if disk space is available or not limited, false if not
  280. */
  281. protected function check_disk_space()
  282. {
  283. try
  284. {
  285. $free_space = $this->storage->free_space();
  286. if ($free_space <= $this->file->get('filesize'))
  287. {
  288. if ($this->auth->acl_get('a_'))
  289. {
  290. $this->file_data['error'][] = $this->language->lang('ATTACH_DISK_FULL');
  291. }
  292. else
  293. {
  294. $this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
  295. }
  296. $this->file_data['post_attach'] = false;
  297. return false;
  298. }
  299. }
  300. catch (\phpbb\storage\exception\exception $e)
  301. {
  302. // Do nothing
  303. }
  304. return true;
  305. }
  306. /**
  307. * Fills file data with file information and current time as filetime
  308. */
  309. protected function fill_file_data()
  310. {
  311. $this->file_data['filesize'] = $this->file->get('filesize');
  312. $this->file_data['mimetype'] = $this->file->get('mimetype');
  313. $this->file_data['extension'] = $this->file->get('extension');
  314. $this->file_data['physical_filename'] = $this->file->get('realname');
  315. $this->file_data['real_filename'] = $this->file->get('uploadname');
  316. $this->file_data['filetime'] = time();
  317. }
  318. }