PageRenderTime 71ms CodeModel.GetById 23ms 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

Large files files are truncated, but you can click here to view the full file

  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. }

Large files files are truncated, but you can click here to view the full file