PageRenderTime 68ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/wwwroot/phpbb/includes/functions_posting.php

https://github.com/spring/spring-website
PHP | 2690 lines | 1975 code | 395 blank | 320 comment | 487 complexity | ed6ed29fb626fc546671a745addde241 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, LGPL-3.0, BSD-3-Clause
  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. * @ignore
  15. */
  16. if (!defined('IN_PHPBB'))
  17. {
  18. exit;
  19. }
  20. /**
  21. * Fill smiley templates (or just the variables) with smilies, either in a window or inline
  22. */
  23. function generate_smilies($mode, $forum_id)
  24. {
  25. global $db, $user, $config, $template, $phpbb_dispatcher;
  26. global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper;
  27. $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&amp;f=' . $forum_id);
  28. $pagination = $phpbb_container->get('pagination');
  29. $start = request_var('start', 0);
  30. if ($mode == 'window')
  31. {
  32. if ($forum_id)
  33. {
  34. $sql = 'SELECT forum_style
  35. FROM ' . FORUMS_TABLE . "
  36. WHERE forum_id = $forum_id";
  37. $result = $db->sql_query_limit($sql, 1);
  38. $row = $db->sql_fetchrow($result);
  39. $db->sql_freeresult($result);
  40. $user->setup('posting', (int) $row['forum_style']);
  41. }
  42. else
  43. {
  44. $user->setup('posting');
  45. }
  46. page_header($user->lang['SMILIES']);
  47. $sql = 'SELECT COUNT(smiley_id) AS item_count
  48. FROM ' . SMILIES_TABLE . '
  49. GROUP BY smiley_url';
  50. $result = $db->sql_query($sql, 3600);
  51. $smiley_count = 0;
  52. while ($row = $db->sql_fetchrow($result))
  53. {
  54. ++$smiley_count;
  55. }
  56. $db->sql_freeresult($result);
  57. $template->set_filenames(array(
  58. 'body' => 'posting_smilies.html')
  59. );
  60. $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count);
  61. $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start);
  62. }
  63. $display_link = false;
  64. if ($mode == 'inline')
  65. {
  66. $sql = 'SELECT smiley_id
  67. FROM ' . SMILIES_TABLE . '
  68. WHERE display_on_posting = 0';
  69. $result = $db->sql_query_limit($sql, 1, 0, 3600);
  70. if ($row = $db->sql_fetchrow($result))
  71. {
  72. $display_link = true;
  73. }
  74. $db->sql_freeresult($result);
  75. }
  76. if ($mode == 'window')
  77. {
  78. $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height, MIN(smiley_order) AS min_smiley_order
  79. FROM ' . SMILIES_TABLE . '
  80. GROUP BY smiley_url, smiley_width, smiley_height
  81. ORDER BY min_smiley_order';
  82. $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600);
  83. }
  84. else
  85. {
  86. $sql = 'SELECT *
  87. FROM ' . SMILIES_TABLE . '
  88. WHERE display_on_posting = 1
  89. ORDER BY smiley_order';
  90. $result = $db->sql_query($sql, 3600);
  91. }
  92. $smilies = array();
  93. while ($row = $db->sql_fetchrow($result))
  94. {
  95. if (empty($smilies[$row['smiley_url']]))
  96. {
  97. $smilies[$row['smiley_url']] = $row;
  98. }
  99. }
  100. $db->sql_freeresult($result);
  101. if (sizeof($smilies))
  102. {
  103. $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_path_helper->get_web_root_path();
  104. foreach ($smilies as $row)
  105. {
  106. $template->assign_block_vars('smiley', array(
  107. 'SMILEY_CODE' => $row['code'],
  108. 'A_SMILEY_CODE' => addslashes($row['code']),
  109. 'SMILEY_IMG' => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'],
  110. 'SMILEY_WIDTH' => $row['smiley_width'],
  111. 'SMILEY_HEIGHT' => $row['smiley_height'],
  112. 'SMILEY_DESC' => $row['emotion'])
  113. );
  114. }
  115. }
  116. /**
  117. * This event is called after the smilies are populated
  118. *
  119. * @event core.generate_smilies_after
  120. * @var string mode Mode of the smilies: window|inline
  121. * @var int forum_id The forum ID we are currently in
  122. * @var bool display_link Shall we display the "more smilies" link?
  123. * @since 3.1.0-a1
  124. */
  125. $vars = array('mode', 'forum_id', 'display_link');
  126. extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars)));
  127. if ($mode == 'inline' && $display_link)
  128. {
  129. $template->assign_vars(array(
  130. 'S_SHOW_SMILEY_LINK' => true,
  131. 'U_MORE_SMILIES' => $base_url,
  132. ));
  133. }
  134. if ($mode == 'window')
  135. {
  136. page_footer();
  137. }
  138. }
  139. /**
  140. * Update last post information
  141. * Should be used instead of sync() if only the last post information are out of sync... faster
  142. *
  143. * @param string $type Can be forum|topic
  144. * @param mixed $ids topic/forum ids
  145. * @param bool $return_update_sql true: SQL query shall be returned, false: execute SQL
  146. */
  147. function update_post_information($type, $ids, $return_update_sql = false)
  148. {
  149. global $db;
  150. if (empty($ids))
  151. {
  152. return;
  153. }
  154. if (!is_array($ids))
  155. {
  156. $ids = array($ids);
  157. }
  158. $update_sql = $empty_forums = $not_empty_forums = array();
  159. if ($type != 'topic')
  160. {
  161. $topic_join = ', ' . TOPICS_TABLE . ' t';
  162. $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED;
  163. }
  164. else
  165. {
  166. $topic_join = '';
  167. $topic_condition = '';
  168. }
  169. if (sizeof($ids) == 1)
  170. {
  171. $sql = 'SELECT MAX(p.post_id) as last_post_id
  172. FROM ' . POSTS_TABLE . " p $topic_join
  173. WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
  174. $topic_condition
  175. AND p.post_visibility = " . ITEM_APPROVED;
  176. }
  177. else
  178. {
  179. $sql = 'SELECT p.' . $type . '_id, MAX(p.post_id) as last_post_id
  180. FROM ' . POSTS_TABLE . " p $topic_join
  181. WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
  182. $topic_condition
  183. AND p.post_visibility = " . ITEM_APPROVED . "
  184. GROUP BY p.{$type}_id";
  185. }
  186. $result = $db->sql_query($sql);
  187. $last_post_ids = array();
  188. while ($row = $db->sql_fetchrow($result))
  189. {
  190. if (sizeof($ids) == 1)
  191. {
  192. $row[$type . '_id'] = $ids[0];
  193. }
  194. if ($type == 'forum')
  195. {
  196. $not_empty_forums[] = $row['forum_id'];
  197. if (empty($row['last_post_id']))
  198. {
  199. $empty_forums[] = $row['forum_id'];
  200. }
  201. }
  202. $last_post_ids[] = $row['last_post_id'];
  203. }
  204. $db->sql_freeresult($result);
  205. if ($type == 'forum')
  206. {
  207. $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums));
  208. foreach ($empty_forums as $void => $forum_id)
  209. {
  210. $update_sql[$forum_id][] = 'forum_last_post_id = 0';
  211. $update_sql[$forum_id][] = "forum_last_post_subject = ''";
  212. $update_sql[$forum_id][] = 'forum_last_post_time = 0';
  213. $update_sql[$forum_id][] = 'forum_last_poster_id = 0';
  214. $update_sql[$forum_id][] = "forum_last_poster_name = ''";
  215. $update_sql[$forum_id][] = "forum_last_poster_colour = ''";
  216. }
  217. }
  218. if (sizeof($last_post_ids))
  219. {
  220. $sql = 'SELECT p.' . $type . '_id, p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
  221. FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
  222. WHERE p.poster_id = u.user_id
  223. AND ' . $db->sql_in_set('p.post_id', $last_post_ids);
  224. $result = $db->sql_query($sql);
  225. while ($row = $db->sql_fetchrow($result))
  226. {
  227. $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id'];
  228. $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
  229. $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time'];
  230. $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id'];
  231. $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
  232. $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'";
  233. }
  234. $db->sql_freeresult($result);
  235. }
  236. unset($empty_forums, $ids, $last_post_ids);
  237. if ($return_update_sql || !sizeof($update_sql))
  238. {
  239. return $update_sql;
  240. }
  241. $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE;
  242. foreach ($update_sql as $update_id => $update_sql_ary)
  243. {
  244. $sql = "UPDATE $table
  245. SET " . implode(', ', $update_sql_ary) . "
  246. WHERE {$type}_id = $update_id";
  247. $db->sql_query($sql);
  248. }
  249. return;
  250. }
  251. /**
  252. * Generate Topic Icons for display
  253. */
  254. function posting_gen_topic_icons($mode, $icon_id)
  255. {
  256. global $phpbb_root_path, $config, $template, $cache;
  257. // Grab icons
  258. $icons = $cache->obtain_icons();
  259. if (!$icon_id)
  260. {
  261. $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"');
  262. }
  263. if (sizeof($icons))
  264. {
  265. $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path;
  266. foreach ($icons as $id => $data)
  267. {
  268. if ($data['display'])
  269. {
  270. $template->assign_block_vars('topic_icon', array(
  271. 'ICON_ID' => $id,
  272. 'ICON_IMG' => $root_path . $config['icons_path'] . '/' . $data['img'],
  273. 'ICON_WIDTH' => $data['width'],
  274. 'ICON_HEIGHT' => $data['height'],
  275. 'S_CHECKED' => ($id == $icon_id) ? true : false,
  276. 'S_ICON_CHECKED' => ($id == $icon_id) ? ' checked="checked"' : '')
  277. );
  278. }
  279. }
  280. return true;
  281. }
  282. return false;
  283. }
  284. /**
  285. * Build topic types able to be selected
  286. */
  287. function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
  288. {
  289. global $auth, $user, $template, $topic_type;
  290. $toggle = false;
  291. $topic_types = array(
  292. 'sticky' => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'),
  293. 'announce' => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'),
  294. 'global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL')
  295. );
  296. $topic_type_array = array();
  297. foreach ($topic_types as $auth_key => $topic_value)
  298. {
  299. // We do not have a special post global announcement permission
  300. $auth_key = ($auth_key == 'global') ? 'announce' : $auth_key;
  301. if ($auth->acl_get('f_' . $auth_key, $forum_id))
  302. {
  303. $toggle = true;
  304. $topic_type_array[] = array(
  305. 'VALUE' => $topic_value['const'],
  306. 'S_CHECKED' => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '',
  307. 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']]
  308. );
  309. }
  310. }
  311. if ($toggle)
  312. {
  313. $topic_type_array = array_merge(array(0 => array(
  314. 'VALUE' => POST_NORMAL,
  315. 'S_CHECKED' => ($cur_topic_type == POST_NORMAL) ? ' checked="checked"' : '',
  316. 'L_TOPIC_TYPE' => $user->lang['POST_NORMAL'])),
  317. $topic_type_array
  318. );
  319. foreach ($topic_type_array as $array)
  320. {
  321. $template->assign_block_vars('topic_type', $array);
  322. }
  323. $template->assign_vars(array(
  324. 'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)),
  325. 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_get('f_announce', $forum_id)))
  326. );
  327. }
  328. return $toggle;
  329. }
  330. //
  331. // Attachment related functions
  332. //
  333. /**
  334. * Upload Attachment - filedata is generated here
  335. * Uses upload class
  336. *
  337. * @param string $form_name The form name of the file upload input
  338. * @param int $forum_id The id of the forum
  339. * @param bool $local Whether the file is local or not
  340. * @param string $local_storage The path to the local file
  341. * @param bool $is_message Whether it is a PM or not
  342. * @param \filespec $local_filedata A filespec object created for the local file
  343. * @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype guesser object if used
  344. * @param \phpbb\plupload\plupload $plupload The plupload object if one is being used
  345. *
  346. * @return object filespec
  347. */
  348. function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
  349. {
  350. global $auth, $user, $config, $db, $cache;
  351. global $phpbb_root_path, $phpEx, $phpbb_dispatcher;
  352. $filedata = array(
  353. 'error' => array()
  354. );
  355. include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
  356. $upload = new fileupload();
  357. if ($config['check_attachment_content'] && isset($config['mime_triggers']))
  358. {
  359. $upload->set_disallowed_content(explode('|', $config['mime_triggers']));
  360. }
  361. else if (!$config['check_attachment_content'])
  362. {
  363. $upload->set_disallowed_content(array());
  364. }
  365. $filedata['post_attach'] = $local || $upload->is_valid($form_name);
  366. if (!$filedata['post_attach'])
  367. {
  368. $filedata['error'][] = $user->lang['NO_UPLOAD_FORM_FOUND'];
  369. return $filedata;
  370. }
  371. $extensions = $cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
  372. $upload->set_allowed_extensions(array_keys($extensions['_allowed_']));
  373. $file = ($local) ? $upload->local_upload($local_storage, $local_filedata, $mimetype_guesser) : $upload->form_upload($form_name, $mimetype_guesser, $plupload);
  374. if ($file->init_error)
  375. {
  376. $filedata['post_attach'] = false;
  377. return $filedata;
  378. }
  379. // Whether the uploaded file is in the image category
  380. $is_image = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
  381. if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id))
  382. {
  383. // Check Image Size, if it is an image
  384. if ($is_image)
  385. {
  386. $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']);
  387. }
  388. // Admins and mods are allowed to exceed the allowed filesize
  389. if (!empty($extensions[$file->get('extension')]['max_filesize']))
  390. {
  391. $allowed_filesize = $extensions[$file->get('extension')]['max_filesize'];
  392. }
  393. else
  394. {
  395. $allowed_filesize = ($is_message) ? $config['max_filesize_pm'] : $config['max_filesize'];
  396. }
  397. $file->upload->set_max_filesize($allowed_filesize);
  398. }
  399. $file->clean_filename('unique', $user->data['user_id'] . '_');
  400. // Are we uploading an image *and* this image being within the image category?
  401. // Only then perform additional image checks.
  402. $file->move_file($config['upload_path'], false, !$is_image);
  403. // Do we have to create a thumbnail?
  404. $filedata['thumbnail'] = ($is_image && $config['img_create_thumbnail']) ? 1 : 0;
  405. if (sizeof($file->error))
  406. {
  407. $file->remove();
  408. $filedata['error'] = array_merge($filedata['error'], $file->error);
  409. $filedata['post_attach'] = false;
  410. return $filedata;
  411. }
  412. // Make sure the image category only holds valid images...
  413. if ($is_image && !$file->is_image())
  414. {
  415. $file->remove();
  416. if ($plupload && $plupload->is_active())
  417. {
  418. $plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
  419. }
  420. // If this error occurs a user tried to exploit an IE Bug by renaming extensions
  421. // Since the image category is displaying content inline we need to catch this.
  422. trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']);
  423. }
  424. $filedata['filesize'] = $file->get('filesize');
  425. $filedata['mimetype'] = $file->get('mimetype');
  426. $filedata['extension'] = $file->get('extension');
  427. $filedata['physical_filename'] = $file->get('realname');
  428. $filedata['real_filename'] = $file->get('uploadname');
  429. $filedata['filetime'] = time();
  430. /**
  431. * Event to modify uploaded file before submit to the post
  432. *
  433. * @event core.modify_uploaded_file
  434. * @var array filedata Array containing uploaded file data
  435. * @var bool is_image Flag indicating if the file is an image
  436. * @since 3.1.0-RC3
  437. */
  438. $vars = array(
  439. 'filedata',
  440. 'is_image',
  441. );
  442. extract($phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
  443. // Check our complete quota
  444. if ($config['attachment_quota'])
  445. {
  446. if ($config['upload_dir_size'] + $file->get('filesize') > $config['attachment_quota'])
  447. {
  448. $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
  449. $filedata['post_attach'] = false;
  450. $file->remove();
  451. return $filedata;
  452. }
  453. }
  454. // Check free disk space
  455. if ($free_space = @disk_free_space($phpbb_root_path . $config['upload_path']))
  456. {
  457. if ($free_space <= $file->get('filesize'))
  458. {
  459. if ($auth->acl_get('a_'))
  460. {
  461. $filedata['error'][] = $user->lang['ATTACH_DISK_FULL'];
  462. }
  463. else
  464. {
  465. $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
  466. }
  467. $filedata['post_attach'] = false;
  468. $file->remove();
  469. return $filedata;
  470. }
  471. }
  472. // Create Thumbnail
  473. if ($filedata['thumbnail'])
  474. {
  475. $source = $file->get('destination_file');
  476. $destination = $file->get('destination_path') . '/thumb_' . $file->get('realname');
  477. if (!create_thumbnail($source, $destination, $file->get('mimetype')))
  478. {
  479. $filedata['thumbnail'] = 0;
  480. }
  481. }
  482. return $filedata;
  483. }
  484. /**
  485. * Calculate the needed size for Thumbnail
  486. */
  487. function get_img_size_format($width, $height)
  488. {
  489. global $config;
  490. // Maximum Width the Image can take
  491. $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400;
  492. if ($width > $height)
  493. {
  494. return array(
  495. round($width * ($max_width / $width)),
  496. round($height * ($max_width / $width))
  497. );
  498. }
  499. else
  500. {
  501. return array(
  502. round($width * ($max_width / $height)),
  503. round($height * ($max_width / $height))
  504. );
  505. }
  506. }
  507. /**
  508. * Return supported image types
  509. */
  510. function get_supported_image_types($type = false)
  511. {
  512. if (@extension_loaded('gd'))
  513. {
  514. $format = imagetypes();
  515. $new_type = 0;
  516. if ($type !== false)
  517. {
  518. // Type is one of the IMAGETYPE constants - it is fetched from getimagesize()
  519. switch ($type)
  520. {
  521. // GIF
  522. case IMAGETYPE_GIF:
  523. $new_type = ($format & IMG_GIF) ? IMG_GIF : false;
  524. break;
  525. // JPG, JPC, JP2
  526. case IMAGETYPE_JPEG:
  527. case IMAGETYPE_JPC:
  528. case IMAGETYPE_JPEG2000:
  529. case IMAGETYPE_JP2:
  530. case IMAGETYPE_JPX:
  531. case IMAGETYPE_JB2:
  532. $new_type = ($format & IMG_JPG) ? IMG_JPG : false;
  533. break;
  534. // PNG
  535. case IMAGETYPE_PNG:
  536. $new_type = ($format & IMG_PNG) ? IMG_PNG : false;
  537. break;
  538. // WBMP
  539. case IMAGETYPE_WBMP:
  540. $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false;
  541. break;
  542. }
  543. }
  544. else
  545. {
  546. $new_type = array();
  547. $go_through_types = array(IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP);
  548. foreach ($go_through_types as $check_type)
  549. {
  550. if ($format & $check_type)
  551. {
  552. $new_type[] = $check_type;
  553. }
  554. }
  555. }
  556. return array(
  557. 'gd' => ($new_type) ? true : false,
  558. 'format' => $new_type,
  559. 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1
  560. );
  561. }
  562. return array('gd' => false);
  563. }
  564. /**
  565. * Create Thumbnail
  566. */
  567. function create_thumbnail($source, $destination, $mimetype)
  568. {
  569. global $config;
  570. $min_filesize = (int) $config['img_min_thumb_filesize'];
  571. $img_filesize = (file_exists($source)) ? @filesize($source) : false;
  572. if (!$img_filesize || $img_filesize <= $min_filesize)
  573. {
  574. return false;
  575. }
  576. $dimension = @getimagesize($source);
  577. if ($dimension === false)
  578. {
  579. return false;
  580. }
  581. list($width, $height, $type, ) = $dimension;
  582. if (empty($width) || empty($height))
  583. {
  584. return false;
  585. }
  586. list($new_width, $new_height) = get_img_size_format($width, $height);
  587. // Do not create a thumbnail if the resulting width/height is bigger than the original one
  588. if ($new_width >= $width && $new_height >= $height)
  589. {
  590. return false;
  591. }
  592. $used_imagick = false;
  593. // Only use imagemagick if defined and the passthru function not disabled
  594. if ($config['img_imagick'] && function_exists('passthru'))
  595. {
  596. if (substr($config['img_imagick'], -1) !== '/')
  597. {
  598. $config['img_imagick'] .= '/';
  599. }
  600. @passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -geometry ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" "' . str_replace('\\', '/', $destination) . '"');
  601. if (file_exists($destination))
  602. {
  603. $used_imagick = true;
  604. }
  605. }
  606. if (!$used_imagick)
  607. {
  608. $type = get_supported_image_types($type);
  609. if ($type['gd'])
  610. {
  611. // If the type is not supported, we are not able to create a thumbnail
  612. if ($type['format'] === false)
  613. {
  614. return false;
  615. }
  616. switch ($type['format'])
  617. {
  618. case IMG_GIF:
  619. $image = @imagecreatefromgif($source);
  620. break;
  621. case IMG_JPG:
  622. @ini_set('gd.jpeg_ignore_warning', 1);
  623. $image = @imagecreatefromjpeg($source);
  624. break;
  625. case IMG_PNG:
  626. $image = @imagecreatefrompng($source);
  627. break;
  628. case IMG_WBMP:
  629. $image = @imagecreatefromwbmp($source);
  630. break;
  631. }
  632. if (empty($image))
  633. {
  634. return false;
  635. }
  636. if ($type['version'] == 1)
  637. {
  638. $new_image = imagecreate($new_width, $new_height);
  639. if ($new_image === false)
  640. {
  641. return false;
  642. }
  643. imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  644. }
  645. else
  646. {
  647. $new_image = imagecreatetruecolor($new_width, $new_height);
  648. if ($new_image === false)
  649. {
  650. return false;
  651. }
  652. // Preserve alpha transparency (png for example)
  653. @imagealphablending($new_image, false);
  654. @imagesavealpha($new_image, true);
  655. imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  656. }
  657. // If we are in safe mode create the destination file prior to using the gd functions to circumvent a PHP bug
  658. if (@ini_get('safe_mode') || @strtolower(ini_get('safe_mode')) == 'on')
  659. {
  660. @touch($destination);
  661. }
  662. switch ($type['format'])
  663. {
  664. case IMG_GIF:
  665. imagegif($new_image, $destination);
  666. break;
  667. case IMG_JPG:
  668. imagejpeg($new_image, $destination, 90);
  669. break;
  670. case IMG_PNG:
  671. imagepng($new_image, $destination);
  672. break;
  673. case IMG_WBMP:
  674. imagewbmp($new_image, $destination);
  675. break;
  676. }
  677. imagedestroy($new_image);
  678. }
  679. else
  680. {
  681. return false;
  682. }
  683. }
  684. if (!file_exists($destination))
  685. {
  686. return false;
  687. }
  688. phpbb_chmod($destination, CHMOD_READ | CHMOD_WRITE);
  689. return true;
  690. }
  691. /**
  692. * Assign Inline attachments (build option fields)
  693. */
  694. function posting_gen_inline_attachments(&$attachment_data)
  695. {
  696. global $template;
  697. if (sizeof($attachment_data))
  698. {
  699. $s_inline_attachment_options = '';
  700. foreach ($attachment_data as $i => $attachment)
  701. {
  702. $s_inline_attachment_options .= '<option value="' . $i . '">' . utf8_basename($attachment['real_filename']) . '</option>';
  703. }
  704. $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options);
  705. return true;
  706. }
  707. return false;
  708. }
  709. /**
  710. * Generate inline attachment entry
  711. */
  712. function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true)
  713. {
  714. global $template, $config, $phpbb_root_path, $phpEx, $user;
  715. // Some default template variables
  716. $template->assign_vars(array(
  717. 'S_SHOW_ATTACH_BOX' => $show_attach_box,
  718. 'S_HAS_ATTACHMENTS' => sizeof($attachment_data),
  719. 'FILESIZE' => $config['max_filesize'],
  720. 'FILE_COMMENT' => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '',
  721. ));
  722. if (sizeof($attachment_data))
  723. {
  724. // We display the posted attachments within the desired order.
  725. ($config['display_order']) ? krsort($attachment_data) : ksort($attachment_data);
  726. foreach ($attachment_data as $count => $attach_row)
  727. {
  728. $hidden = '';
  729. $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']);
  730. foreach ($attach_row as $key => $value)
  731. {
  732. $hidden .= '<input type="hidden" name="attachment_data[' . $count . '][' . $key . ']" value="' . $value . '" />';
  733. }
  734. $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&amp;id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false);
  735. $template->assign_block_vars('attach_row', array(
  736. 'FILENAME' => utf8_basename($attach_row['real_filename']),
  737. 'A_FILENAME' => addslashes(utf8_basename($attach_row['real_filename'])),
  738. 'FILE_COMMENT' => $attach_row['attach_comment'],
  739. 'ATTACH_ID' => $attach_row['attach_id'],
  740. 'S_IS_ORPHAN' => $attach_row['is_orphan'],
  741. 'ASSOC_INDEX' => $count,
  742. 'FILESIZE' => get_formatted_filesize($attach_row['filesize']),
  743. 'U_VIEW_ATTACHMENT' => $download_link,
  744. 'S_HIDDEN' => $hidden)
  745. );
  746. }
  747. }
  748. return sizeof($attachment_data);
  749. }
  750. //
  751. // General Post functions
  752. //
  753. /**
  754. * Load Drafts
  755. */
  756. function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0)
  757. {
  758. global $user, $db, $template, $auth;
  759. global $phpbb_root_path, $phpbb_dispatcher, $phpEx;
  760. $topic_ids = $forum_ids = $draft_rows = array();
  761. // Load those drafts not connected to forums/topics
  762. // If forum_id == 0 AND topic_id == 0 then this is a PM draft
  763. if (!$topic_id && !$forum_id)
  764. {
  765. $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0';
  766. }
  767. else
  768. {
  769. $sql_and = '';
  770. $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : '';
  771. $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : '';
  772. }
  773. $sql = 'SELECT d.*, f.forum_id, f.forum_name
  774. FROM ' . DRAFTS_TABLE . ' d
  775. LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id)
  776. WHERE d.user_id = ' . $user->data['user_id'] . "
  777. $sql_and
  778. ORDER BY d.save_time DESC";
  779. $result = $db->sql_query($sql);
  780. while ($row = $db->sql_fetchrow($result))
  781. {
  782. if ($row['topic_id'])
  783. {
  784. $topic_ids[] = (int) $row['topic_id'];
  785. }
  786. $draft_rows[] = $row;
  787. }
  788. $db->sql_freeresult($result);
  789. if (!sizeof($draft_rows))
  790. {
  791. return;
  792. }
  793. $topic_rows = array();
  794. if (sizeof($topic_ids))
  795. {
  796. $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster
  797. FROM ' . TOPICS_TABLE . '
  798. WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids));
  799. $result = $db->sql_query($sql);
  800. while ($row = $db->sql_fetchrow($result))
  801. {
  802. $topic_rows[$row['topic_id']] = $row;
  803. }
  804. $db->sql_freeresult($result);
  805. }
  806. /**
  807. * Drafts found and their topics
  808. * Edit $draft_rows in order to add or remove drafts loaded
  809. *
  810. * @event core.load_drafts_draft_list_result
  811. * @var array draft_rows The drafts query result. Includes its forum id and everything about the draft
  812. * @var array topic_ids The list of topics got from the topics table
  813. * @var array topic_rows The topics that draft_rows references
  814. * @since 3.1.0-RC3
  815. */
  816. $vars = array('draft_rows', 'topic_ids', 'topic_rows');
  817. extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars)));
  818. unset($topic_ids);
  819. $template->assign_var('S_SHOW_DRAFTS', true);
  820. foreach ($draft_rows as $draft)
  821. {
  822. $link_topic = $link_forum = $link_pm = false;
  823. $insert_url = $view_url = $title = '';
  824. if (isset($topic_rows[$draft['topic_id']])
  825. && (
  826. ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id']))
  827. ||
  828. (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read'))
  829. ))
  830. {
  831. $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id;
  832. $link_topic = true;
  833. $view_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_forum_id . '&amp;t=' . $draft['topic_id']);
  834. $title = $topic_rows[$draft['topic_id']]['topic_title'];
  835. $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $topic_forum_id . '&amp;t=' . $draft['topic_id'] . '&amp;mode=reply&amp;d=' . $draft['draft_id']);
  836. }
  837. else if ($draft['forum_id'] && $auth->acl_get('f_read', $draft['forum_id']))
  838. {
  839. $link_forum = true;
  840. $view_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $draft['forum_id']);
  841. $title = $draft['forum_name'];
  842. $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $draft['forum_id'] . '&amp;mode=post&amp;d=' . $draft['draft_id']);
  843. }
  844. else
  845. {
  846. // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards...
  847. $link_pm = true;
  848. $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&amp;mode=compose&amp;d={$draft['draft_id']}" . (($pm_action) ? "&amp;action=$pm_action" : '') . (($msg_id) ? "&amp;p=$msg_id" : ''));
  849. }
  850. $template->assign_block_vars('draftrow', array(
  851. 'DRAFT_ID' => $draft['draft_id'],
  852. 'DATE' => $user->format_date($draft['save_time']),
  853. 'DRAFT_SUBJECT' => $draft['draft_subject'],
  854. 'TITLE' => $title,
  855. 'U_VIEW' => $view_url,
  856. 'U_INSERT' => $insert_url,
  857. 'S_LINK_PM' => $link_pm,
  858. 'S_LINK_TOPIC' => $link_topic,
  859. 'S_LINK_FORUM' => $link_forum)
  860. );
  861. }
  862. }
  863. /**
  864. * Topic Review
  865. */
  866. function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true)
  867. {
  868. global $user, $auth, $db, $template, $cache;
  869. global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
  870. $phpbb_content_visibility = $phpbb_container->get('content.visibility');
  871. $sql_sort = ($mode == 'post_review') ? 'ASC' : 'DESC';
  872. // Go ahead and pull all data for this topic
  873. $sql = 'SELECT p.post_id
  874. FROM ' . POSTS_TABLE . ' p' . "
  875. WHERE p.topic_id = $topic_id
  876. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . '
  877. ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . '
  878. ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . '
  879. ORDER BY p.post_time ' . $sql_sort . ', p.post_id ' . $sql_sort;
  880. $result = $db->sql_query_limit($sql, $config['posts_per_page']);
  881. $post_list = array();
  882. while ($row = $db->sql_fetchrow($result))
  883. {
  884. $post_list[] = $row['post_id'];
  885. }
  886. $db->sql_freeresult($result);
  887. if (!sizeof($post_list))
  888. {
  889. return false;
  890. }
  891. // Handle 'post_review_edit' like 'post_review' from now on
  892. if ($mode == 'post_review_edit')
  893. {
  894. $mode = 'post_review';
  895. }
  896. $sql_ary = array(
  897. 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe',
  898. 'FROM' => array(
  899. USERS_TABLE => 'u',
  900. POSTS_TABLE => 'p',
  901. ),
  902. 'LEFT_JOIN' => array(
  903. array(
  904. 'FROM' => array(ZEBRA_TABLE => 'z'),
  905. 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id',
  906. ),
  907. ),
  908. 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . '
  909. AND u.user_id = p.poster_id',
  910. );
  911. $sql = $db->sql_build_query('SELECT', $sql_ary);
  912. $result = $db->sql_query($sql);
  913. $rowset = array();
  914. $has_attachments = false;
  915. while ($row = $db->sql_fetchrow($result))
  916. {
  917. $rowset[$row['post_id']] = $row;
  918. if ($row['post_attachment'])
  919. {
  920. $has_attachments = true;
  921. }
  922. }
  923. $db->sql_freeresult($result);
  924. // Grab extensions
  925. $extensions = $attachments = array();
  926. if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
  927. {
  928. $extensions = $cache->obtain_attach_extensions($forum_id);
  929. // Get attachments...
  930. $sql = 'SELECT *
  931. FROM ' . ATTACHMENTS_TABLE . '
  932. WHERE ' . $db->sql_in_set('post_msg_id', $post_list) . '
  933. AND in_message = 0
  934. ORDER BY filetime DESC, post_msg_id ASC';
  935. $result = $db->sql_query($sql);
  936. while ($row = $db->sql_fetchrow($result))
  937. {
  938. $attachments[$row['post_msg_id']][] = $row;
  939. }
  940. $db->sql_freeresult($result);
  941. }
  942. for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
  943. {
  944. // A non-existing rowset only happens if there was no user present for the entered poster_id
  945. // This could be a broken posts table.
  946. if (!isset($rowset[$post_list[$i]]))
  947. {
  948. continue;
  949. }
  950. $row = $rowset[$post_list[$i]];
  951. $poster_id = $row['user_id'];
  952. $post_subject = $row['post_subject'];
  953. $decoded_message = false;
  954. if ($show_quote_button && $auth->acl_get('f_reply', $forum_id))
  955. {
  956. $decoded_message = censor_text($row['post_text']);
  957. decode_message($decoded_message, $row['bbcode_uid']);
  958. $decoded_message = bbcode_nl2br($decoded_message);
  959. }
  960. $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
  961. $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
  962. $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true);
  963. if (!empty($attachments[$row['post_id']]))
  964. {
  965. $update_count = array();
  966. parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count);
  967. }
  968. $post_subject = censor_text($post_subject);
  969. $post_anchor = ($mode == 'post_review') ? 'ppr' . $row['post_id'] : 'pr' . $row['post_id'];
  970. $u_show_post = append_sid($phpbb_root_path . 'viewtopic.' . $phpEx, "f=$forum_id&amp;t=$topic_id&amp;p={$row['post_id']}&amp;view=show#p{$row['post_id']}");
  971. $post_row = array(
  972. 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
  973. 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
  974. 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
  975. 'U_POST_AUTHOR' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
  976. 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false,
  977. 'S_FRIEND' => ($row['friend']) ? true : false,
  978. 'S_IGNORE_POST' => ($row['foe']) ? true : false,
  979. 'L_IGNORE_POST' => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), "<a href=\"{$u_show_post}\" onclick=\"phpbb.toggleDisplay('{$post_anchor}', 1); return false;\">", '</a>') : '',
  980. 'POST_SUBJECT' => $post_subject,
  981. 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']),
  982. 'POST_DATE' => $user->format_date($row['post_time']),
  983. 'MESSAGE' => $message,
  984. 'DECODED_MESSAGE' => $decoded_message,
  985. 'POST_ID' => $row['post_id'],
  986. 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
  987. 'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&amp;mode=post_details&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
  988. 'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '',
  989. );
  990. $current_row_number = $i;
  991. /**
  992. * Event to modify the template data block for topic reviews
  993. *
  994. * @event core.topic_review_modify_row
  995. * @var string mode The review mode
  996. * @var int topic_id The topic that is being reviewed
  997. * @var int forum_id The topic's forum
  998. * @var int cur_post_id Post offset id
  999. * @var int current_row_number Number of the current row being iterated
  1000. * @var array post_row Template block array of the current post
  1001. * @var array row Array with original post and user data
  1002. * @since 3.1.4-RC1
  1003. */
  1004. $vars = array(
  1005. 'mode',
  1006. 'topic_id',
  1007. 'forum_id',
  1008. 'cur_post_id',
  1009. 'current_row_number',
  1010. 'post_row',
  1011. 'row',
  1012. );
  1013. extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_row', compact($vars)));
  1014. $template->assign_block_vars($mode . '_row', $post_row);
  1015. // Display not already displayed Attachments for this post, we already parsed them. ;)
  1016. if (!empty($attachments[$row['post_id']]))
  1017. {
  1018. foreach ($attachments[$row['post_id']] as $attachment)
  1019. {
  1020. $template->assign_block_vars($mode . '_row.attachment', array(
  1021. 'DISPLAY_ATTACHMENT' => $attachment)
  1022. );
  1023. }
  1024. }
  1025. unset($rowset[$post_list[$i]]);
  1026. }
  1027. if ($mode == 'topic_review')
  1028. {
  1029. $template->assign_var('QUOTE_IMG', $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']));
  1030. }
  1031. return true;
  1032. }
  1033. //
  1034. // Post handling functions
  1035. //
  1036. /**
  1037. * Delete Post
  1038. */
  1039. function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '')
  1040. {
  1041. global $db, $user, $auth, $phpbb_container;
  1042. global $config, $phpEx, $phpbb_root_path;
  1043. // Specify our post mode
  1044. $post_mode = 'delete';
  1045. if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1))
  1046. {
  1047. $post_mode = 'delete_topic';
  1048. }
  1049. else if ($data['topic_first_post_id'] == $post_id)
  1050. {
  1051. $post_mode = 'delete_first_post';
  1052. }
  1053. else if ($data['topic_last_post_id'] == $post_id)
  1054. {
  1055. $post_mode = 'delete_last_post';
  1056. }
  1057. $sql_data = array();
  1058. $next_post_id = false;
  1059. include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
  1060. $db->sql_transaction('begin');
  1061. // we must make sure to update forums that contain the shadow'd topic
  1062. if ($post_mode == 'delete_topic')
  1063. {
  1064. $shadow_forum_ids = array();
  1065. $sql = 'SELECT forum_id
  1066. FROM ' . TOPICS_TABLE . '
  1067. WHERE ' . $db->sql_in_set('topic_moved_id', $topic_id);
  1068. $result = $db->sql_query($sql);
  1069. while ($row = $db->sql_fetchrow($result))
  1070. {
  1071. if (!isset($shadow_forum_ids[(int) $row['forum_id']]))
  1072. {
  1073. $shadow_forum_ids[(int) $row['forum_id']] = 1;
  1074. }
  1075. else
  1076. {
  1077. $shadow_forum_ids[(int) $row['forum_id']]++;
  1078. }
  1079. }
  1080. $db->sql_freeresult($result);
  1081. }
  1082. $phpbb_content_visibility = $phpbb_container->get('content.visibility');
  1083. // (Soft) delete the post
  1084. if ($is_soft && ($post_mode != 'delete_topic'))
  1085. {
  1086. $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $post_id, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason, ($data['topic_first_post_id'] == $post_id), ($data['topic_last_post_id'] == $post_id));
  1087. }
  1088. else if (!$is_soft)
  1089. {
  1090. if (!delete_posts('post_id', array($post_id), false, false, false))
  1091. {
  1092. // Try to delete topic, we may had an previous error causing inconsistency
  1093. if ($post_mode == 'delete_topic')
  1094. {
  1095. delete_topics('topic_id', array($topic_id), false);
  1096. }
  1097. trigger_error('ALREADY_DELETED');
  1098. }
  1099. }
  1100. $db->sql_transaction('commit');
  1101. // Collect the necessary information for updating the tables
  1102. $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = '';
  1103. switch ($post_mode)
  1104. {
  1105. case 'delete_topic':
  1106. foreach ($shadow_forum_ids as $updated_forum => $topic_count)
  1107. {
  1108. // counting is fun! we only have to do sizeof($forum_ids) number of queries,
  1109. // even if the topic is moved back to where its shadow lives (we count how many times it is in a forum)
  1110. $sql = 'UPDATE ' . FORUMS_TABLE . '
  1111. SET forum_topics_approved = forum_topics_approved - ' . $topic_count . '
  1112. WHERE forum_id = ' . $updated_forum;
  1113. $db->sql_query($sql);
  1114. update_post_information('forum', $updated_forum);
  1115. }
  1116. if ($is_soft)
  1117. {
  1118. $topic_row = array();
  1119. $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason);
  1120. }
  1121. else
  1122. {
  1123. delete_topics('topic_id', array($topic_id), false);
  1124. $phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data);
  1125. $update_sql = update_post_information('forum', $forum_id, true);
  1126. if (sizeof($update_sql))
  1127. {
  1128. $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
  1129. $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
  1130. }
  1131. }
  1132. break;
  1133. case 'delete_first_post':
  1134. $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
  1135. FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
  1136. WHERE p.topic_id = $topic_id
  1137. AND p.poster_id = u.user_id
  1138. AND p.post_visibility = " . ITEM_APPROVED . '
  1139. ORDER BY p.post_time ASC, p.post_id ASC';
  1140. $result = $db->sql_query_limit($sql, 1);
  1141. $row = $db->sql_fetchrow($result);
  1142. $db->sql_freeresult($result);
  1143. if (!$row)
  1144. {
  1145. // No approved post, so the first is a not-approved post (unapproved or soft deleted)
  1146. $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
  1147. FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
  1148. WHERE p.topic_id = $topic_id
  1149. AND p.poster_id = u.user_id
  1150. ORDER BY p.post_time ASC, p.post_id ASC";
  1151. $result = $db->sql_query_limit($sql, 1);
  1152. $row = $db->sql_fetchrow($result);
  1153. $db->sql_freeresult($result);
  1154. }
  1155. $next_post_id = (int) $row['post_id'];
  1156. $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array(
  1157. 'topic_poster' => (int) $row['poster_id'],
  1158. 'topic_first_post_id' => (int) $row['post_id'],
  1159. 'topic_first_poster_colour' => $row['user_colour'],
  1160. 'topic_first_poster_name' => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'],
  1161. 'topic_time' => (int) $row['post_time'],
  1162. ));
  1163. break;
  1164. case 'delete_last_post':
  1165. if (!$is_soft)
  1166. {
  1167. // Update last post information when hard deleting. Soft delete already did that by itself.
  1168. $update_sql = update_post_information('forum', $forum_id, true);
  1169. if (sizeof($update_sql))
  1170. {
  1171. $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]);
  1172. }
  1173. $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0';
  1174. $update_sql = update_post_information('topic', $topic_id, true);
  1175. if (!empty($update_sql))
  1176. {
  1177. $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]);
  1178. $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]);
  1179. }
  1180. }
  1181. if (!$next_post_id)
  1182. {
  1183. $sql = 'SELECT MAX(post_id) as last_post_id
  1184. FROM ' . POSTS_TABLE . "
  1185. WHERE topic_id = $topic_id
  1186. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
  1187. $result = $db->sql_query($sql);
  1188. $next_post_id = (int) $db->sql_fetchfield('last_post_id');
  1189. $db->sql_freeresult($result);
  1190. }
  1191. break;
  1192. case 'delete':
  1193. $sql = 'SELECT post_id
  1194. FROM ' . POSTS_TABLE . "
  1195. WHERE topic_id = $topic_id
  1196. AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . '
  1197. AND post_time > ' . $data['post_time'] . '
  1198. ORDER BY post_time ASC, post_id ASC';
  1199. $result = $db->sql_query_limit($sql, 1);
  1200. $next_post_id = (int) $db->sql_fetchfield('post_id');
  1201. $db->sql_freeresult($result);
  1202. break;
  1203. }
  1204. if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post'))
  1205. {
  1206. if (!$is_soft)
  1207. {
  1208. $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data);
  1209. }
  1210. $sql = 'SELECT 1 AS has_attachments
  1211. FROM ' . ATTACHMENTS_TABLE . '
  1212. WHERE topic_id = ' . $topic_id;
  1213. $result = $db->sql_query_limit($sql, 1);
  1214. $has_attachments = (int) $db->sql_fetchfield('has_attachments');
  1215. $db->sql_freeresult($result);
  1216. if (!$has_attachments)
  1217. {
  1218. $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0';
  1219. }
  1220. }
  1221. $db->sql_transaction('begin');
  1222. $where_sql = array(
  1223. FORUMS_TABLE => "forum_id = $forum_id",
  1224. TOPICS_TABLE => "topic_id = $topic_id",
  1225. USERS_TABLE => 'user_id = ' . $data['poster_id'],
  1226. );
  1227. foreach ($sql_data as $table => $update_sql)
  1228. {
  1229. if ($update_sql)
  1230. {
  1231. $db->sql_query("UPDATE $table SET $update_sql WHERE " . $where_sql[$table]);
  1232. }
  1233. }
  1234. // Adjust posted info for this user by looking for a post by him/her within this topic...
  1235. if ($post_mode != 'delete_topic' && $config['load_db_track'] && $data['poster_id'] != ANONYMOUS)
  1236. {
  1237. $sql = 'SELECT poster_id
  1238. FROM ' . POSTS_TABLE . '
  1239. WHERE topic_id = ' . $topic_id . '
  1240. AND poster_id = ' . $data['poster_id'];
  1241. $result = $db->sql_query_limit($sql, 1);
  1242. $poster_id = (int) $db->sql_fetchfield('poster_id');
  1243. $db->sql_freeresult($result);
  1244. // The user is not having any more posts within this topic
  1245. if (!$poster_id)
  1246. {
  1247. $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
  1248. WHERE topic_id = ' . $topic_id . '
  1249. AND user_id = ' . $data['poster_id'];
  1250. $db->sql_query($sql);
  1251. }
  1252. }
  1253. $db->sql_transaction('commit');
  1254. if ($data['post_reported'] && ($post_mode != 'delete_topic'))
  1255. {
  1256. sync('topic_reported', 'topic_id', array($topic_id));
  1257. }
  1258. return $next_post_id;
  1259. }
  1260. /**
  1261. * Submit Post
  1262. * @todo Split up and create lightweight, simple API for this.
  1263. */
  1264. function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true, $update_search_index = true)
  1265. {
  1266. global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
  1267. /**
  1268. * Modify the data for post submitting
  1269. *
  1270. * @event core.modify_submit_post_data
  1271. * @var string mode Variable containing posting mode value
  1272. * @var string subject Variable containing post subject value
  1273. * @var string username Variable containing post author name
  1274. * @var int topic_type Variable containing topic type value
  1275. * @var array poll Array with the poll data for the post
  1276. * @var array data Array with the data for the post
  1277. * @var bool update_message Flag indicating if the post will be updated
  1278. * @var bool update_search_index Flag indicating if the search index will be updated
  1279. * @since 3.1.0-a4
  1280. */
  1281. $vars = array(
  1282. 'mode',
  1283. 'subject',
  1284. 'username',
  1285. 'topic_type',
  1286. 'poll',
  1287. 'data',
  1288. 'update_message',
  1289. 'update_search_index',
  1290. );
  1291. extract($phpbb_dispatcher->trigger_event('core.modify_submit_post_data', compact($vars)));
  1292. // We do not handle erasing posts here
  1293. if ($mode == 'delete')
  1294. {
  1295. return false;
  1296. }
  1297. $current_time = time();
  1298. if ($mode == 'post')
  1299. {
  1300. $post_mode = 'post';
  1301. $update_message = true;
  1302. }
  1303. else if ($mode != 'edit')
  1304. {
  1305. $post_mode = 'reply';
  1306. $update_message = true;
  1307. }
  1308. else if ($mode == 'edit')
  1309. {
  1310. $post_mode = ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit'));
  1311. }
  1312. // First of all make sure the subject and topic title are having the correct length.
  1313. // To achieve this without cutting off between special chars we convert to an array and then count the elements.
  1314. $subject = truncate_string($subject, 120);
  1315. $data['topic_title'] = truncate_string($data['topic_title'], 120);
  1316. // Collect some basic information about which tables and which rows to update/insert
  1317. $sql_data = $topic_row = array();
  1318. $poster_id = ($mode == 'edit') ? $data['poster_id'] : (int) $user->data['user_id'];
  1319. // Retrieve some additional information if not present
  1320. if ($mode == 'edit' && (!isset($data['post_visibility']) || !isset($data['topic_visibility']) || $data['post_visibility'] === false || $data['topic_visibility'] === false))
  1321. {
  1322. $sql = 'SELECT p.post_visibility, t.topic_type, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_visibility
  1323. FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
  1324. WHERE t.topic_id = p.topic_id
  1325. AND p.post_id = ' . $data['post_id'];
  1326. $result = $db->sql_query($sql);
  1327. $topic_row = $db->sql_fetchrow($result);
  1328. $db->sql_freeresult($result);
  1329. $data['topic_visibility'] = $topic_row['topic_visibility'];
  1330. $data['post_visibility'] = $topic_row['post_visibility'];
  1331. }
  1332. // This variable indicates if the user is able to post or put into the queue
  1333. $post_visibility = ITEM_APPROVED;
  1334. // Check the permissions for post approval.
  1335. // Moderators must go through post approval like ordinary users.
  1336. if (!$auth->acl_get('f_noapprove', $data['forum_id']))
  1337. {
  1338. // Post not approved, but in queue
  1339. $post_visibility = ITEM_UNAPPROVED;
  1340. switch ($post_mode)
  1341. {
  1342. case 'edit_first_post':
  1343. case 'edit':
  1344. case 'edit_last_post':
  1345. case 'edit_topic':
  1346. $post_visibility = ITEM_REAPPROVE;
  1347. break;
  1348. }
  1349. }
  1350. // MODs/Extensions are able to force any visibility on posts
  1351. if (isset($data['force_approved_state']))
  1352. {
  1353. $post_visibility = (in_array((int) $data['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data['force_approved_state'] : $post_visibility;
  1354. }
  1355. if (isset($data['force_visibility']))
  1356. {
  1357. $post_visibility = (in_array((int) $data['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data['force_visibility'] : $post_visibility;
  1358. }
  1359. // Start the transaction here
  1360. $db->sql_transaction('begin');
  1361. // Collect Information
  1362. switch ($post_mode)
  1363. {
  1364. case 'post':
  1365. case 'reply':
  1366. $sql_data[POSTS_TABLE]['sql'] = array(
  1367. 'forum_id' => $data['forum_id'],
  1368. 'poster_id' => (int) $user->data['user_id'],
  1369. 'icon_id' => $data['icon_id'],
  1370. 'poster_ip' => $user->ip,
  1371. 'post_time' => $current_time,
  1372. 'post_visibility' => $post_visibility,
  1373. 'enable_bbcode' => $data['enable_bbcode'],
  1374. 'enable_smilies' => $data['enable_smilies'],
  1375. 'enable_magic_url' => $data['enable_urls'],
  1376. 'enable_sig' => $data['enable_sig'],
  1377. 'post_username' => (!$user->data['is_registered']) ? $username : '',
  1378. 'post_subject' => $subject,
  1379. 'post_text' => $data['message'],
  1380. 'post_checksum' => $data['message_md5'],
  1381. 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
  1382. 'bbcode_bitfield' => $data['bbcode_bitfield'],
  1383. 'bbcode_uid' => $data['bbcode_uid'],
  1384. 'post_postcount' => ($auth->acl_get('f_postcount', $data['forum_id'])) ? 1 : 0,
  1385. 'post_edit_locked' => $data['post_edit_locked']
  1386. );
  1387. break;
  1388. case 'edit_first_post':
  1389. case 'edit':
  1390. case 'edit_last_post':
  1391. case 'edit_topic':
  1392. // If edit reason is given always display edit info
  1393. // If editing last post then display no edit info
  1394. // If m_edit permission then display no edit info
  1395. // If normal edit display edit info
  1396. // Display edit info if edit reason given or user is editing his post, which is not the last within the topic.
  1397. if ($data['post_edit_reason'] || (!$auth->acl_get('m_edit', $data['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post')))
  1398. {
  1399. $data['post_edit_reason'] = truncate_string($data['post_edit_reason'], 255, 255, false);
  1400. $sql_data[POSTS_TABLE]['sql'] = array(
  1401. 'post_edit_time' => $current_time,
  1402. 'post_edit_reason' => $data['post_edit_reason'],
  1403. 'post_edit_user' => (int) $data['post_edit_user'],
  1404. );
  1405. $sql_data[POSTS_TABLE]['stat'][] = 'post_edit_count = post_edit_count + 1';
  1406. }
  1407. else if (!$data['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data['forum_id']))
  1408. {
  1409. $sql_data[POSTS_TABLE]['sql'] = array(
  1410. 'post_edit_reason' => '',
  1411. );
  1412. }
  1413. // If the person editing this post is different to the one having posted then we will add a log entry stating the edit
  1414. // Could be simplified by only adding to the log if the edit is not tracked - but this may confuse admins/mods
  1415. if ($user->data['user_id'] != $poster_id)
  1416. {
  1417. $log_subject = ($subject) ? $subject : $data['topic_title'];
  1418. add_log('mod', $data['forum_id'], $data['topic_id'], 'LOG_POST_EDITED', $log_subject, (!empty($username)) ? $username : $user->lang['GUEST'], $data['post_edit_reason']);
  1419. }
  1420. if (!isset($sql_data[POSTS_TABLE]['sql']))
  1421. {
  1422. $sql_data[POSTS_TABLE]['sql'] = array();
  1423. }
  1424. $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
  1425. 'forum_id' => $data['forum_id'],
  1426. 'poster_id' => $data['poster_id'],
  1427. 'icon_id' => $data['icon_id'],
  1428. // We will change the visibility later
  1429. //'post_visibility' => $post_visibility,
  1430. 'enable_bbcode' => $data['enable_bbcode'],
  1431. 'enable_smilies' => $data['enable_smilies'],
  1432. 'enable_magic_url' => $data['enable_urls'],
  1433. 'enable_sig' => $data['enable_sig'],
  1434. 'post_username' => ($username && $data['poster_id'] == ANONYMOUS) ? $username : '',
  1435. 'post_subject' => $subject,
  1436. 'post_checksum' => $data['message_md5'],
  1437. 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
  1438. 'bbcode_bitfield' => $data['bbcode_bitfield'],
  1439. 'bbcode_uid' => $data['bbcode_uid'],
  1440. 'post_edit_locked' => $data['post_edit_locked'])
  1441. );
  1442. if ($update_message)
  1443. {
  1444. $sql_data[POSTS_TABLE]['sql']['post_text'] = $data['message'];
  1445. }
  1446. break;
  1447. }
  1448. $topic_row = array();
  1449. // And the topic ladies and gentlemen
  1450. switch ($post_mode)
  1451. {
  1452. case 'post':
  1453. $sql_data[TOPICS_TABLE]['sql'] = array(
  1454. 'topic_poster' => (int) $user->data['user_id'],
  1455. 'topic_time' => $current_time,
  1456. 'topic_last_view_time' => $current_time,
  1457. 'forum_id' => $data['forum_id'],
  1458. 'icon_id' => $data['icon_id'],
  1459. 'topic_posts_approved' => ($post_visibility == ITEM_APPROVED) ? 1 : 0,
  1460. 'topic_posts_softdeleted' => ($post_visibility == ITEM_DELETED) ? 1 : 0,
  1461. 'topic_posts_unapproved' => ($post_visibility == ITEM_UNAPPROVED) ? 1 : 0,
  1462. 'topic_visibility' => $post_visibility,
  1463. 'topic_delete_user' => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0,
  1464. 'topic_title' => $subject,
  1465. 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
  1466. 'topic_first_poster_colour' => $user->data['user_colour'],
  1467. 'topic_type' => $topic_type,
  1468. 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0,
  1469. 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
  1470. );
  1471. if (isset($poll['poll_options']) && !empty($poll['poll_options']))
  1472. {
  1473. $poll_start = ($poll['poll_start']) ? $poll['poll_start'] : $current_time;
  1474. $poll_length = $poll['poll_length'] * 86400;
  1475. if ($poll_length < 0)
  1476. {
  1477. $poll_start = $poll_start + $poll_length;
  1478. if ($poll_start < 0)
  1479. {
  1480. $poll_start = 0;
  1481. }
  1482. $poll_length = 1;
  1483. }
  1484. $sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array(
  1485. 'poll_title' => $poll['poll_title'],
  1486. 'poll_start' => $poll_start,
  1487. 'poll_max_options' => $poll['poll_max_options'],
  1488. 'poll_length' => $poll_length,
  1489. 'poll_vote_change' => $poll['poll_vote_change'])
  1490. );
  1491. }
  1492. $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
  1493. if ($post_visibility == ITEM_APPROVED)
  1494. {
  1495. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1';
  1496. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
  1497. }
  1498. else if ($post_visibility == ITEM_UNAPPROVED)
  1499. {
  1500. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1';
  1501. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
  1502. }
  1503. else if ($post_visibility == ITEM_DELETED)
  1504. {
  1505. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1';
  1506. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
  1507. }
  1508. break;
  1509. case 'reply':
  1510. $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ',
  1511. topic_bumped = 0,
  1512. topic_bumper = 0' .
  1513. (($post_visibility == ITEM_APPROVED) ? ', topic_posts_approved = topic_posts_approved + 1' : '') .
  1514. (($post_visibility == ITEM_UNAPPROVED) ? ', topic_posts_unapproved = topic_posts_unapproved + 1' : '') .
  1515. (($post_visibility == ITEM_DELETED) ? ', topic_posts_softdeleted = topic_posts_softdeleted + 1' : '') .
  1516. ((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : '');
  1517. $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
  1518. if ($post_visibility == ITEM_APPROVED)
  1519. {
  1520. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
  1521. }
  1522. else if ($post_visibility == ITEM_UNAPPROVED)
  1523. {
  1524. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
  1525. }
  1526. else if ($post_visibility == ITEM_DELETED)
  1527. {
  1528. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
  1529. }
  1530. break;
  1531. case 'edit_topic':
  1532. case 'edit_first_post':
  1533. if (isset($poll['poll_options']))
  1534. {
  1535. $poll_start = ($poll['poll_start'] || empty($poll['poll_options'])) ? $poll['poll_start'] : $current_time;
  1536. $poll_length = $poll['poll_length'] * 86400;
  1537. if ($poll_length < 0)
  1538. {
  1539. $poll_start = $poll_start + $poll_length;
  1540. if ($poll_start < 0)
  1541. {
  1542. $poll_start = 0;
  1543. }
  1544. $poll_length = 1;
  1545. }
  1546. }
  1547. $sql_data[TOPICS_TABLE]['sql'] = array(
  1548. 'forum_id' => $data['forum_id'],
  1549. 'icon_id' => $data['icon_id'],
  1550. 'topic_title' => $subject,
  1551. 'topic_first_poster_name' => $username,
  1552. 'topic_type' => $topic_type,
  1553. 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0,
  1554. 'poll_title' => (isset($poll['poll_options'])) ? $poll['poll_title'] : '',
  1555. 'poll_start' => (isset($poll['poll_options'])) ? $poll_start : 0,
  1556. 'poll_max_options' => (isset($poll['poll_options'])) ? $poll['poll_max_options'] : 1,
  1557. 'poll_length' => (isset($poll['poll_options'])) ? $poll_length : 0,
  1558. 'poll_vote_change' => (isset($poll['poll_vote_change'])) ? $poll['poll_vote_change'] : 0,
  1559. 'topic_last_view_time' => $current_time,
  1560. 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0),
  1561. );
  1562. break;
  1563. }
  1564. /**
  1565. * Modify sql query data for post submitting
  1566. *
  1567. * @event core.submit_post_modify_sql_data
  1568. * @var array data Array with the data for the post
  1569. * @var array poll Array with the poll data for the post
  1570. * @var string post_mode Variable containing posting mode value
  1571. * @var bool sql_data Array with the data for the posting SQL query
  1572. * @var string subject Variable containing post subject value
  1573. * @var int topic_type Variable containing topic type value
  1574. * @var string username Variable containing post author name
  1575. * @since 3.1.3-RC1
  1576. */
  1577. $vars = array(
  1578. 'data',
  1579. 'poll',
  1580. 'post_mode',
  1581. 'sql_data',
  1582. 'subject',
  1583. 'topic_type',
  1584. 'username',
  1585. );
  1586. extract($phpbb_dispatcher->trigger_event('core.submit_post_modify_sql_data', compact($vars)));
  1587. // Submit new topic
  1588. if ($post_mode == 'post')
  1589. {
  1590. $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' .
  1591. $db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']);
  1592. $db->sql_query($sql);
  1593. $data['topic_id'] = $db->sql_nextid();
  1594. $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
  1595. 'topic_id' => $data['topic_id'])
  1596. );
  1597. unset($sql_data[TOPICS_TABLE]['sql']);
  1598. }
  1599. // Submit new post
  1600. if ($post_mode == 'post' || $post_mode == 'reply')
  1601. {
  1602. if ($post_mode == 'reply')
  1603. {
  1604. $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
  1605. 'topic_id' => $data['topic_id'],
  1606. ));
  1607. }
  1608. $sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']);
  1609. $db->sql_query($sql);
  1610. $data['post_id'] = $db->sql_nextid();
  1611. if ($post_mode == 'post' || $post_visibility == ITEM_APPROVED)
  1612. {
  1613. $sql_data[TOPICS_TABLE]['sql'] = array(
  1614. 'topic_last_post_id' => $data['post_id'],
  1615. 'topic_last_post_time' => $current_time,
  1616. 'topic_last_poster_id' => $sql_data[POSTS_TABLE]['sql']['poster_id'],
  1617. 'topic_last_poster_name' => ($user->data['user_id'] == ANONYMOUS) ? $sql_data[POSTS_TABLE]['sql']['post_username'] : $user->data['username'],
  1618. 'topic_last_poster_colour' => $user->data['user_colour'],
  1619. 'topic_last_post_subject' => (string) $subject,
  1620. );
  1621. }
  1622. if ($post_mode == 'post')
  1623. {
  1624. $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data['post_id'];
  1625. }
  1626. // Update total post count and forum information
  1627. if ($post_visibility == ITEM_APPROVED)
  1628. {
  1629. if ($post_mode == 'post')
  1630. {
  1631. set_config_count('num_topics', 1, true);
  1632. }
  1633. set_config_count('num_posts', 1, true);
  1634. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id'];
  1635. $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
  1636. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
  1637. $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
  1638. $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
  1639. $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'";
  1640. }
  1641. unset($sql_data[POSTS_TABLE]['sql']);
  1642. }
  1643. // Update the topics table
  1644. if (isset($sql_data[TOPICS_TABLE]['sql']))
  1645. {
  1646. $sql = 'UPDATE ' . TOPICS_TABLE . '
  1647. SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . '
  1648. WHERE topic_id = ' . $data['topic_id'];
  1649. $db->sql_query($sql);
  1650. unset($sql_data[TOPICS_TABLE]['sql']);
  1651. }
  1652. // Update the posts table
  1653. if (isset($sql_data[POSTS_TABLE]['sql']))
  1654. {
  1655. $sql = 'UPDATE ' . POSTS_TABLE . '
  1656. SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . '
  1657. WHERE post_id = ' . $data['post_id'];
  1658. $db->sql_query($sql);
  1659. unset($sql_data[POSTS_TABLE]['sql']);
  1660. }
  1661. // Update Poll Tables
  1662. if (isset($poll['poll_options']))
  1663. {
  1664. $cur_poll_options = array();
  1665. if ($mode == 'edit')
  1666. {
  1667. $sql = 'SELECT *
  1668. FROM ' . POLL_OPTIONS_TABLE . '
  1669. WHERE topic_id = ' . $data['topic_id'] . '
  1670. ORDER BY poll_option_id';
  1671. $result = $db->sql_query($sql);
  1672. $cur_poll_options = array();
  1673. while ($row = $db->sql_fetchrow($result))
  1674. {
  1675. $cur_poll_options[] = $row;
  1676. }
  1677. $db->sql_freeresult($result);
  1678. }
  1679. $sql_insert_ary = array();
  1680. for ($i = 0, $size = sizeof($poll['poll_options']); $i < $size; $i++)
  1681. {
  1682. if (strlen(trim($poll['poll_options'][$i])))
  1683. {
  1684. if (empty($cur_poll_options[$i]))
  1685. {
  1686. // If we add options we need to put them to the end to be able to preserve votes...
  1687. $sql_insert_ary[] = array(
  1688. 'poll_option_id' => (int) sizeof($cur_poll_options) + 1 + sizeof($sql_insert_ary),
  1689. 'topic_id' => (int) $data['topic_id'],
  1690. 'poll_option_text' => (string) $poll['poll_options'][$i]
  1691. );
  1692. }
  1693. else if ($poll['poll_options'][$i] != $cur_poll_options[$i])
  1694. {
  1695. $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . "
  1696. SET poll_option_text = '" . $db->sql_escape($poll['poll_options'][$i]) . "'
  1697. WHERE poll_option_id = " . $cur_poll_options[$i]['poll_option_id'] . '
  1698. AND topic_id = ' . $data['topic_id'];
  1699. $db->sql_query($sql);
  1700. }
  1701. }
  1702. }
  1703. $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary);
  1704. if (sizeof($poll['poll_options']) < sizeof($cur_poll_options))
  1705. {
  1706. $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . '
  1707. WHERE poll_option_id > ' . sizeof($poll['poll_options']) . '
  1708. AND topic_id = ' . $data['topic_id'];
  1709. $db->sql_query($sql);
  1710. }
  1711. // If edited, we would need to reset votes (since options can be re-ordered above, you can't be sure if the change is for changing the text or adding an option
  1712. if ($mode == 'edit' && sizeof($poll['poll_options']) != sizeof($cur_poll_options))
  1713. {
  1714. $db->sql_query('DELETE FROM ' . POLL_VOTES_TABLE . ' WHERE topic_id = ' . $data['topic_id']);
  1715. $db->sql_query('UPDATE ' . POLL_OPTIONS_TABLE . ' SET poll_option_total = 0 WHERE topic_id = ' . $data['topic_id']);
  1716. }
  1717. }
  1718. // Submit Attachments
  1719. if (!empty($data['attachment_data']) && $data['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit')))
  1720. {
  1721. $space_taken = $files_added = 0;
  1722. $orphan_rows = array();
  1723. foreach ($data['attachment_data'] as $pos => $attach_row)
  1724. {
  1725. $orphan_rows[(int) $attach_row['attach_id']] = array();
  1726. }
  1727. if (sizeof($orphan_rows))
  1728. {
  1729. $sql = 'SELECT attach_id, filesize, physical_filename
  1730. FROM ' . ATTACHMENTS_TABLE . '
  1731. WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
  1732. AND is_orphan = 1
  1733. AND poster_id = ' . $user->data['user_id'];
  1734. $result = $db->sql_query($sql);
  1735. $orphan_rows = array();
  1736. while ($row = $db->sql_fetchrow($result))
  1737. {
  1738. $orphan_rows[$row['attach_id']] = $row;
  1739. }
  1740. $db->sql_freeresult($result);
  1741. }
  1742. foreach ($data['attachment_data'] as $pos => $attach_row)
  1743. {
  1744. if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
  1745. {
  1746. continue;
  1747. }
  1748. if (!$attach_row['is_orphan'])
  1749. {
  1750. // update entry in db if attachment already stored in db and filespace
  1751. $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
  1752. SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
  1753. WHERE attach_id = " . (int) $attach_row['attach_id'] . '
  1754. AND is_orphan = 0';
  1755. $db->sql_query($sql);
  1756. }
  1757. else
  1758. {
  1759. // insert attachment into db
  1760. if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
  1761. {
  1762. continue;
  1763. }
  1764. $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
  1765. $files_added++;
  1766. $attach_sql = array(
  1767. 'post_msg_id' => $data['post_id'],
  1768. 'topic_id' => $data['topic_id'],
  1769. 'is_orphan' => 0,
  1770. 'poster_id' => $poster_id,
  1771. 'attach_comment' => $attach_row['attach_comment'],
  1772. );
  1773. $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
  1774. WHERE attach_id = ' . $attach_row['attach_id'] . '
  1775. AND is_orphan = 1
  1776. AND poster_id = ' . $user->data['user_id'];
  1777. $db->sql_query($sql);
  1778. }
  1779. }
  1780. if ($space_taken && $files_added)
  1781. {
  1782. set_config_count('upload_dir_size', $space_taken, true);
  1783. set_config_count('num_files', $files_added, true);
  1784. }
  1785. }
  1786. $first_post_has_topic_info = ($post_mode == 'edit_first_post' &&
  1787. (($post_visibility == ITEM_DELETED && $data['topic_posts_softdeleted'] == 1) ||
  1788. ($post_visibility == ITEM_UNAPPROVED && $data['topic_posts_unapproved'] == 1) ||
  1789. ($post_visibility == ITEM_REAPPROVE && $data['topic_posts_unapproved'] == 1) ||
  1790. ($post_visibility == ITEM_APPROVED && $data['topic_posts_approved'] == 1)));
  1791. // Fix the post's and topic's visibility and first/last post information, when the post is edited
  1792. if (($post_mode != 'post' && $post_mode != 'reply') && $data['post_visibility'] != $post_visibility)
  1793. {
  1794. // If the post was not approved, it could also be the starter,
  1795. // so we sync the starter after approving/restoring, to ensure that the stats are correct
  1796. // Same applies for the last post
  1797. $is_starter = ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED);
  1798. $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED);
  1799. $phpbb_content_visibility = $phpbb_container->get('content.visibility');
  1800. $phpbb_content_visibility->set_post_visibility($post_visibility, $data['post_id'], $data['topic_id'], $data['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest);
  1801. }
  1802. else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $first_post_has_topic_info)
  1803. {
  1804. if ($post_visibility == ITEM_APPROVED || $data['topic_visibility'] == $post_visibility)
  1805. {
  1806. // only the subject can be changed from edit
  1807. $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
  1808. // Maybe not only the subject, but also changing anonymous usernames. ;)
  1809. if ($data['poster_id'] == ANONYMOUS)
  1810. {
  1811. $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'";
  1812. }
  1813. if ($post_visibility == ITEM_APPROVED)
  1814. {
  1815. // this does not _necessarily_ mean that we must update the info again,
  1816. // it just means that we might have to
  1817. $sql = 'SELECT forum_last_post_id, forum_last_post_subject
  1818. FROM ' . FORUMS_TABLE . '
  1819. WHERE forum_id = ' . (int) $data['forum_id'];
  1820. $result = $db->sql_query($sql);
  1821. $row = $db->sql_fetchrow($result);
  1822. $db->sql_freeresult($result);
  1823. // this post is the latest post in the forum, better update
  1824. if ($row['forum_last_post_id'] == $data['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS))
  1825. {
  1826. // the post's subject changed
  1827. if ($row['forum_last_post_subject'] !== $subject)
  1828. {
  1829. $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
  1830. }
  1831. // Update the user name if poster is anonymous... just in case a moderator changed it
  1832. if ($data['poster_id'] == ANONYMOUS)
  1833. {
  1834. $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
  1835. }
  1836. }
  1837. }
  1838. }
  1839. }
  1840. // Update forum stats
  1841. $where_sql = array(
  1842. POSTS_TABLE => 'post_id = ' . $data['post_id'],
  1843. TOPICS_TABLE => 'topic_id = ' . $data['topic_id'],
  1844. FORUMS_TABLE => 'forum_id = ' . $data['forum_id'],
  1845. USERS_TABLE => 'user_id = ' . $poster_id
  1846. );
  1847. foreach ($sql_data as $table => $update_ary)
  1848. {
  1849. if (isset($update_ary['stat']) && implode('', $update_ary['stat']))
  1850. {
  1851. $sql = "UPDATE $table SET " . implode(', ', $update_ary['stat']) . ' WHERE ' . $where_sql[$table];
  1852. $db->sql_query($sql);
  1853. }
  1854. }
  1855. // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement
  1856. if ($topic_type == POST_GLOBAL)
  1857. {
  1858. $sql = 'DELETE FROM ' . TOPICS_TABLE . '
  1859. WHERE topic_moved_id = ' . $data['topic_id'];
  1860. $db->sql_query($sql);
  1861. }
  1862. // Committing the transaction before updating search index
  1863. $db->sql_transaction('commit');
  1864. // Delete draft if post was loaded...
  1865. $draft_id = request_var('draft_loaded', 0);
  1866. if ($draft_id)
  1867. {
  1868. $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
  1869. WHERE draft_id = $draft_id
  1870. AND user_id = {$user->data['user_id']}";
  1871. $db->sql_query($sql);
  1872. }
  1873. // Index message contents
  1874. if ($update_search_index && $data['enable_indexing'])
  1875. {
  1876. // Select the search method and do some additional checks to ensure it can actually be utilised
  1877. $search_type = $config['search_type'];
  1878. if (!class_exists($search_type))
  1879. {
  1880. trigger_error('NO_SUCH_SEARCH_MODULE');
  1881. }
  1882. $error = false;
  1883. $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
  1884. if ($error)
  1885. {
  1886. trigger_error($error);
  1887. }
  1888. $search->index($mode, $data['post_id'], $data['message'], $subject, $poster_id, $data['forum_id']);
  1889. }
  1890. // Topic Notification, do not change if moderator is changing other users posts...
  1891. if ($user->data['user_id'] == $poster_id)
  1892. {
  1893. if (!$data['notify_set'] && $data['notify'])
  1894. {
  1895. $sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id)
  1896. VALUES (' . $user->data['user_id'] . ', ' . $data['topic_id'] . ')';
  1897. $db->sql_query($sql);
  1898. }
  1899. else if (($config['email_enable'] || $config['jab_enable']) && $data['notify_set'] && !$data['notify'])
  1900. {
  1901. $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . '
  1902. WHERE user_id = ' . $user->data['user_id'] . '
  1903. AND topic_id = ' . $data['topic_id'];
  1904. $db->sql_query($sql);
  1905. }
  1906. }
  1907. if ($mode == 'post' || $mode == 'reply' || $mode == 'quote')
  1908. {
  1909. // Mark this topic as posted to
  1910. markread('post', $data['forum_id'], $data['topic_id']);
  1911. }
  1912. // Mark this topic as read
  1913. // We do not use post_time here, this is intended (post_time can have a date in the past if editing a message)
  1914. markread('topic', $data['forum_id'], $data['topic_id'], time());
  1915. //
  1916. if ($config['load_db_lastread'] && $user->data['is_registered'])
  1917. {
  1918. $sql = 'SELECT mark_time
  1919. FROM ' . FORUMS_TRACK_TABLE . '
  1920. WHERE user_id = ' . $user->data['user_id'] . '
  1921. AND forum_id = ' . $data['forum_id'];
  1922. $result = $db->sql_query($sql);
  1923. $f_mark_time = (int) $db->sql_fetchfield('mark_time');
  1924. $db->sql_freeresult($result);
  1925. }
  1926. else if ($config['load_anon_lastread'] || $user->data['is_registered'])
  1927. {
  1928. $f_mark_time = false;
  1929. }
  1930. if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
  1931. {
  1932. // Update forum info
  1933. $sql = 'SELECT forum_last_post_time
  1934. FROM ' . FORUMS_TABLE . '
  1935. WHERE forum_id = ' . $data['forum_id'];
  1936. $result = $db->sql_query($sql);
  1937. $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
  1938. $db->sql_freeresult($result);
  1939. update_forum_tracking_info($data['forum_id'], $forum_last_post_time, $f_mark_time, false);
  1940. }
  1941. // If a username was supplied or the poster is a guest, we will use the supplied username.
  1942. // Doing it this way we can use "...post by guest-username..." in notifications when
  1943. // "guest-username" is supplied or ommit the username if it is not.
  1944. $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username'];
  1945. // Send Notifications
  1946. $notification_data = array_merge($data, array(
  1947. 'topic_title' => (isset($data['topic_title'])) ? $data['topic_title'] : $subject,
  1948. 'post_username' => $username,
  1949. 'poster_id' => $poster_id,
  1950. 'post_text' => $data['message'],
  1951. 'post_time' => $current_time,
  1952. 'post_subject' => $subject,
  1953. ));
  1954. $phpbb_notifications = $phpbb_container->get('notification_manager');
  1955. if ($post_visibility == ITEM_APPROVED)
  1956. {
  1957. switch ($mode)
  1958. {
  1959. case 'post':
  1960. $phpbb_notifications->add_notifications(array(
  1961. 'notification.type.quote',
  1962. 'notification.type.topic',
  1963. ), $notification_data);
  1964. break;
  1965. case 'reply':
  1966. case 'quote':
  1967. $phpbb_notifications->add_notifications(array(
  1968. 'notification.type.quote',
  1969. 'notification.type.bookmark',
  1970. 'notification.type.post',
  1971. ), $notification_data);
  1972. break;
  1973. case 'edit_topic':
  1974. case 'edit_first_post':
  1975. case 'edit':
  1976. case 'edit_last_post':
  1977. $phpbb_notifications->update_notifications(array(
  1978. 'notification.type.quote',
  1979. 'notification.type.bookmark',
  1980. 'notification.type.topic',
  1981. 'notification.type.post',
  1982. ), $notification_data);
  1983. break;
  1984. }
  1985. }
  1986. else if ($post_visibility == ITEM_UNAPPROVED)
  1987. {
  1988. switch ($mode)
  1989. {
  1990. case 'post':
  1991. $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data);
  1992. break;
  1993. case 'reply':
  1994. case 'quote':
  1995. $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data);
  1996. break;
  1997. case 'edit_topic':
  1998. case 'edit_first_post':
  1999. case 'edit':
  2000. case 'edit_last_post':
  2001. // Nothing to do here
  2002. break;
  2003. }
  2004. }
  2005. else if ($post_visibility == ITEM_REAPPROVE)
  2006. {
  2007. switch ($mode)
  2008. {
  2009. case 'edit_topic':
  2010. case 'edit_first_post':
  2011. $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data);
  2012. // Delete the approve_post notification so we can notify the user again,
  2013. // when his post got reapproved
  2014. $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']);
  2015. break;
  2016. case 'edit':
  2017. case 'edit_last_post':
  2018. $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data);
  2019. // Delete the approve_post notification so we can notify the user again,
  2020. // when his post got reapproved
  2021. $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']);
  2022. break;
  2023. case 'post':
  2024. case 'reply':
  2025. case 'quote':
  2026. // Nothing to do here
  2027. break;
  2028. }
  2029. }
  2030. else if ($post_visibility == ITEM_DELETED)
  2031. {
  2032. switch ($mode)
  2033. {
  2034. case 'post':
  2035. case 'reply':
  2036. case 'quote':
  2037. case 'edit_topic':
  2038. case 'edit_first_post':
  2039. case 'edit':
  2040. case 'edit_last_post':
  2041. // Nothing to do here
  2042. break;
  2043. }
  2044. }
  2045. $params = $add_anchor = '';
  2046. if ($post_visibility == ITEM_APPROVED)
  2047. {
  2048. $params .= '&amp;t=' . $data['topic_id'];
  2049. if ($mode != 'post')
  2050. {
  2051. $params .= '&amp;p=' . $data['post_id'];
  2052. $add_anchor = '#p' . $data['post_id'];
  2053. }
  2054. }
  2055. else if ($mode != 'post' && $post_mode != 'edit_first_post' && $post_mode != 'edit_topic')
  2056. {
  2057. $params .= '&amp;t=' . $data['topic_id'];
  2058. }
  2059. $url = (!$params) ? "{$phpbb_root_path}viewforum.$phpEx" : "{$phpbb_root_path}viewtopic.$phpEx";
  2060. $url = append_sid($url, 'f=' . $data['forum_id'] . $params) . $add_anchor;
  2061. /**
  2062. * This event is used for performing actions directly after a post or topic
  2063. * has been submitted. When a new topic is posted, the topic ID is
  2064. * available in the $data array.
  2065. *
  2066. * The only action that can be done by altering data made available to this
  2067. * event is to modify the return URL ($url).
  2068. *
  2069. * @event core.submit_post_end
  2070. * @var string mode Variable containing posting mode value
  2071. * @var string subject Variable containing post subject value
  2072. * @var string username Variable containing post author name
  2073. * @var int topic_type Variable containing topic type value
  2074. * @var array poll Array with the poll data for the post
  2075. * @var array data Array with the data for the post
  2076. * @var int post_visibility Variable containing up to date post visibility
  2077. * @var bool update_message Flag indicating if the post will be updated
  2078. * @var bool update_search_index Flag indicating if the search index will be updated
  2079. * @var string url The "Return to topic" URL
  2080. *
  2081. * @since 3.1.0-a3
  2082. * @change 3.1.0-RC3 Added vars mode, subject, username, topic_type,
  2083. * poll, update_message, update_search_index
  2084. */
  2085. $vars = array(
  2086. 'mode',
  2087. 'subject',
  2088. 'username',
  2089. 'topic_type',
  2090. 'poll',
  2091. 'data',
  2092. 'post_visibility',
  2093. 'update_message',
  2094. 'update_search_index',
  2095. 'url',
  2096. );
  2097. extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars)));
  2098. return $url;
  2099. }
  2100. /**
  2101. * Handle topic bumping
  2102. * @param int $forum_id The ID of the forum the topic is being bumped belongs to
  2103. * @param int $topic_id The ID of the topic is being bumping
  2104. * @param array $post_data Passes some topic parameters:
  2105. * - 'topic_title'
  2106. * - 'topic_last_post_id'
  2107. * - 'topic_last_poster_id'
  2108. * - 'topic_last_post_subject'
  2109. * - 'topic_last_poster_name'
  2110. * - 'topic_last_poster_colour'
  2111. * @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time().
  2112. * @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&amptopic_id=2&ampp=3#p3
  2113. */
  2114. function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false)
  2115. {
  2116. global $config, $db, $user, $phpEx, $phpbb_root_path;
  2117. if ($bump_time === false)
  2118. {
  2119. $bump_time = time();
  2120. }
  2121. // Begin bumping
  2122. $db->sql_transaction('begin');
  2123. // Update the topic's last post post_time
  2124. $sql = 'UPDATE ' . POSTS_TABLE . "
  2125. SET post_time = $bump_time
  2126. WHERE post_id = {$post_data['topic_last_post_id']}
  2127. AND topic_id = $topic_id";
  2128. $db->sql_query($sql);
  2129. // Sync the topic's last post time, the rest of the topic's last post data isn't changed
  2130. $sql = 'UPDATE ' . TOPICS_TABLE . "
  2131. SET topic_last_post_time = $bump_time,
  2132. topic_bumped = 1,
  2133. topic_bumper = " . $user->data['user_id'] . "
  2134. WHERE topic_id = $topic_id";
  2135. $db->sql_query($sql);
  2136. // Update the forum's last post info
  2137. $sql = 'UPDATE ' . FORUMS_TABLE . "
  2138. SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ",
  2139. forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ",
  2140. forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "',
  2141. forum_last_post_time = $bump_time,
  2142. forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "',
  2143. forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "'
  2144. WHERE forum_id = $forum_id";
  2145. $db->sql_query($sql);
  2146. // Update bumper's time of the last posting to prevent flood
  2147. $sql = 'UPDATE ' . USERS_TABLE . "
  2148. SET user_lastpost_time = $bump_time
  2149. WHERE user_id = " . $user->data['user_id'];
  2150. $db->sql_query($sql);
  2151. $db->sql_transaction('commit');
  2152. // Mark this topic as posted to
  2153. markread('post', $forum_id, $topic_id, $bump_time);
  2154. // Mark this topic as read
  2155. markread('topic', $forum_id, $topic_id, $bump_time);
  2156. // Update forum tracking info
  2157. if ($config['load_db_lastread'] && $user->data['is_registered'])
  2158. {
  2159. $sql = 'SELECT mark_time
  2160. FROM ' . FORUMS_TRACK_TABLE . '
  2161. WHERE user_id = ' . $user->data['user_id'] . '
  2162. AND forum_id = ' . $forum_id;
  2163. $result = $db->sql_query($sql);
  2164. $f_mark_time = (int) $db->sql_fetchfield('mark_time');
  2165. $db->sql_freeresult($result);
  2166. }
  2167. else if ($config['load_anon_lastread'] || $user->data['is_registered'])
  2168. {
  2169. $f_mark_time = false;
  2170. }
  2171. if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
  2172. {
  2173. // Update forum info
  2174. $sql = 'SELECT forum_last_post_time
  2175. FROM ' . FORUMS_TABLE . '
  2176. WHERE forum_id = ' . $forum_id;
  2177. $result = $db->sql_query($sql);
  2178. $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
  2179. $db->sql_freeresult($result);
  2180. update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false);
  2181. }
  2182. add_log('mod', $forum_id, $topic_id, 'LOG_BUMP_TOPIC', $post_data['topic_title']);
  2183. $url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}";
  2184. return $url;
  2185. }
  2186. /**
  2187. * Show upload popup (progress bar)
  2188. */
  2189. function phpbb_upload_popup($forum_style = 0)
  2190. {
  2191. global $template, $user;
  2192. ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting');
  2193. page_header($user->lang['PROGRESS_BAR']);
  2194. $template->set_filenames(array(
  2195. 'popup' => 'posting_progress_bar.html')
  2196. );
  2197. $template->assign_vars(array(
  2198. 'PROGRESS_BAR' => $user->img('upload_bar', $user->lang['UPLOAD_IN_PROGRESS']))
  2199. );
  2200. $template->display('popup');
  2201. garbage_collection();
  2202. exit_handler();
  2203. }
  2204. /**
  2205. * Do the various checks required for removing posts as well as removing it
  2206. */
  2207. function phpbb_handle_post_delete($forum_id, $topic_id, $post_id, &$post_data, $is_soft = false, $delete_reason = '')
  2208. {
  2209. global $user, $auth, $config, $request;
  2210. global $phpbb_root_path, $phpEx;
  2211. $perm_check = ($is_soft) ? 'softdelete' : 'delete';
  2212. // If moderator removing post or user itself removing post, present a confirmation screen
  2213. if ($auth->acl_get("m_$perm_check", $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get("f_$perm_check", $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time'])))
  2214. {
  2215. $s_hidden_fields = array(
  2216. 'p' => $post_id,
  2217. 'f' => $forum_id,
  2218. 'mode' => ($is_soft) ? 'soft_delete' : 'delete',
  2219. );
  2220. if (confirm_box(true))
  2221. {
  2222. $data = array(
  2223. 'topic_first_post_id' => $post_data['topic_first_post_id'],
  2224. 'topic_last_post_id' => $post_data['topic_last_post_id'],
  2225. 'topic_posts_approved' => $post_data['topic_posts_approved'],
  2226. 'topic_posts_unapproved' => $post_data['topic_posts_unapproved'],
  2227. 'topic_posts_softdeleted' => $post_data['topic_posts_softdeleted'],
  2228. 'topic_visibility' => $post_data['topic_visibility'],
  2229. 'topic_type' => $post_data['topic_type'],
  2230. 'post_visibility' => $post_data['post_visibility'],
  2231. 'post_reported' => $post_data['post_reported'],
  2232. 'post_time' => $post_data['post_time'],
  2233. 'poster_id' => $post_data['poster_id'],
  2234. 'post_postcount' => $post_data['post_postcount'],
  2235. );
  2236. $next_post_id = delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $delete_reason);
  2237. $post_username = ($post_data['poster_id'] == ANONYMOUS && !empty($post_data['post_username'])) ? $post_data['post_username'] : $post_data['username'];
  2238. if ($next_post_id === false)
  2239. {
  2240. add_log('mod', $forum_id, $topic_id, (($is_soft) ? 'LOG_SOFTDELETE_TOPIC' : 'LOG_DELETE_TOPIC'), $post_data['topic_title'], $post_username, $delete_reason);
  2241. $meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id");
  2242. $message = $user->lang['POST_DELETED'];
  2243. }
  2244. else
  2245. {
  2246. add_log('mod', $forum_id, $topic_id, (($is_soft) ? 'LOG_SOFTDELETE_POST' : 'LOG_DELETE_POST'), $post_data['post_subject'], $post_username, $delete_reason);
  2247. $meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p=$next_post_id") . "#p$next_post_id";
  2248. $message = $user->lang['POST_DELETED'];
  2249. if (!$request->is_ajax())
  2250. {
  2251. $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $meta_info . '">', '</a>');
  2252. }
  2253. }
  2254. meta_refresh(3, $meta_info);
  2255. if (!$request->is_ajax())
  2256. {
  2257. $message .= '<br /><br />' . $user->lang('RETURN_FORUM', '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
  2258. }
  2259. trigger_error($message);
  2260. }
  2261. else
  2262. {
  2263. global $user, $template, $request;
  2264. $can_delete = $auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id));
  2265. $can_softdelete = $auth->acl_get('m_softdelete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_softdelete', $forum_id));
  2266. $template->assign_vars(array(
  2267. 'S_SOFTDELETED' => $post_data['post_visibility'] == ITEM_DELETED,
  2268. 'S_CHECKED_PERMANENT' => $request->is_set_post('delete_permanent') ? ' checked="checked"' : '',
  2269. 'S_ALLOWED_DELETE' => $can_delete,
  2270. 'S_ALLOWED_SOFTDELETE' => $can_softdelete,
  2271. ));
  2272. $l_confirm = 'DELETE_POST';
  2273. if ($post_data['post_visibility'] == ITEM_DELETED)
  2274. {
  2275. $l_confirm .= '_PERMANENTLY';
  2276. $s_hidden_fields['delete_permanent'] = '1';
  2277. }
  2278. else if (!$can_softdelete)
  2279. {
  2280. $s_hidden_fields['delete_permanent'] = '1';
  2281. }
  2282. confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
  2283. }
  2284. }
  2285. // If we are here the user is not able to delete - present the correct error message
  2286. if ($post_data['poster_id'] != $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id))
  2287. {
  2288. trigger_error('DELETE_OWN_POSTS');
  2289. }
  2290. if ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && $post_id != $post_data['topic_last_post_id'])
  2291. {
  2292. trigger_error('CANNOT_DELETE_REPLIED');
  2293. }
  2294. trigger_error('USER_CANNOT_DELETE');
  2295. }