Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
functions_posting.php
0001 <?php
0002 /**
0003 *
0004 * This file is part of the phpBB Forum Software package.
0005 *
0006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007 * @license GNU General Public License, version 2 (GPL-2.0)
0008 *
0009 * For full copyright and license information, please see
0010 * the docs/CREDITS.txt file.
0011 *
0012 */
0013
0014 /**
0015 * @ignore
0016 */
0017 if (!defined('IN_PHPBB'))
0018 {
0019 exit;
0020 }
0021
0022 /**
0023 * Fill smiley templates (or just the variables) with smilies, either in a window or inline
0024 */
0025 function generate_smilies($mode, $forum_id)
0026 {
0027 global $db, $user, $config, $template, $phpbb_dispatcher, $request;
0028 global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper;
0029
0030 /* @var $pagination \phpbb\pagination */
0031 $pagination = $phpbb_container->get('pagination');
0032 $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id);
0033 $start = $request->variable('start', 0);
0034
0035 if ($mode == 'window')
0036 {
0037 if ($forum_id)
0038 {
0039 $sql = 'SELECT forum_style
0040 FROM ' . FORUMS_TABLE . "
0041 WHERE forum_id = $forum_id";
0042 $result = $db->sql_query_limit($sql, 1);
0043 $row = $db->sql_fetchrow($result);
0044 $db->sql_freeresult($result);
0045
0046 $user->setup('posting', (int) $row['forum_style']);
0047 }
0048 else
0049 {
0050 $user->setup('posting');
0051 }
0052
0053 page_header($user->lang['SMILIES']);
0054
0055 $sql_ary = [
0056 'SELECT' => 'COUNT(s.smiley_id) AS item_count',
0057 'FROM' => [
0058 SMILIES_TABLE => 's',
0059 ],
0060 'GROUP_BY' => 's.smiley_url',
0061 ];
0062
0063 /**
0064 * Modify SQL query that fetches the total number of smilies in window mode
0065 *
0066 * @event core.generate_smilies_count_sql_before
0067 * @var int forum_id Forum where smilies are generated
0068 * @var array sql_ary Array with the SQL query
0069 * @var string base_url URL for the "More smilies" link and its pagination
0070 * @since 3.2.9-RC1
0071 * @changed 3.2.10-RC1 Added base_url
0072 */
0073 $vars = [
0074 'forum_id',
0075 'sql_ary',
0076 'base_url',
0077 ];
0078 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_count_sql_before', compact($vars)));
0079
0080 $sql = $db->sql_build_query('SELECT', $sql_ary);
0081 $result = $db->sql_query($sql, 3600);
0082
0083 $smiley_count = 0;
0084 while ($row = $db->sql_fetchrow($result))
0085 {
0086 ++$smiley_count;
0087 }
0088 $db->sql_freeresult($result);
0089
0090 $template->set_filenames(array(
0091 'body' => 'posting_smilies.html')
0092 );
0093
0094 $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count);
0095 $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start);
0096 }
0097
0098 $display_link = false;
0099 if ($mode == 'inline')
0100 {
0101 $sql = 'SELECT smiley_id
0102 FROM ' . SMILIES_TABLE . '
0103 WHERE display_on_posting = 0';
0104 $result = $db->sql_query_limit($sql, 1, 0, 3600);
0105
0106 if ($row = $db->sql_fetchrow($result))
0107 {
0108 $display_link = true;
0109 }
0110 $db->sql_freeresult($result);
0111 }
0112
0113 if ($mode == 'window')
0114 {
0115 $sql_ary = [
0116 'SELECT' => 's.smiley_url, MIN(s.emotion) AS emotion, MIN(s.code) AS code, s.smiley_width, s.smiley_height, MIN(s.smiley_order) AS min_smiley_order',
0117 'FROM' => [
0118 SMILIES_TABLE => 's',
0119 ],
0120 'GROUP_BY' => 's.smiley_url, s.smiley_width, s.smiley_height',
0121 'ORDER_BY' => $db->sql_quote('min_smiley_order'),
0122 ];
0123 }
0124 else
0125 {
0126 $sql_ary = [
0127 'SELECT' => 's.*',
0128 'FROM' => [
0129 SMILIES_TABLE => 's',
0130 ],
0131 'WHERE' => 's.display_on_posting = 1',
0132 'ORDER_BY' => 's.smiley_order',
0133 ];
0134 }
0135
0136 /**
0137 * Modify the SQL query that fetches the smilies
0138 *
0139 * @event core.generate_smilies_modify_sql
0140 * @var string mode Smiley mode, either window or inline
0141 * @var int forum_id Forum where smilies are generated, or 0 if composing a private message
0142 * @var array sql_ary Array with SQL query data
0143 * @since 3.2.10-RC1
0144 * @since 3.3.1-RC1
0145 */
0146 $vars = [
0147 'mode',
0148 'forum_id',
0149 'sql_ary',
0150 ];
0151 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_modify_sql', compact($vars)));
0152
0153 $sql = $db->sql_build_query('SELECT', $sql_ary);
0154
0155 if ($mode == 'window')
0156 {
0157 $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600);
0158 }
0159 else
0160 {
0161 $result = $db->sql_query($sql, 3600);
0162 }
0163
0164 $smilies = array();
0165 while ($row = $db->sql_fetchrow($result))
0166 {
0167 if (empty($smilies[$row['smiley_url']]))
0168 {
0169 $smilies[$row['smiley_url']] = $row;
0170 }
0171 }
0172 $db->sql_freeresult($result);
0173
0174 /**
0175 * Modify smilies before they are assigned to the template
0176 *
0177 * @event core.generate_smilies_modify_rowset
0178 * @var string mode Smiley mode, either window or inline
0179 * @var int forum_id Forum where smilies are generated, or 0 if composing a private message
0180 * @var array smilies Smiley rows fetched from the database
0181 * @since 3.2.9-RC1
0182 */
0183 $vars = [
0184 'mode',
0185 'forum_id',
0186 'smilies',
0187 ];
0188 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_modify_rowset', compact($vars)));
0189
0190 if (count($smilies))
0191 {
0192 $root_path = $phpbb_path_helper->get_web_root_path();
0193
0194 foreach ($smilies as $row)
0195 {
0196 /**
0197 * Modify smiley root path before populating smiley list
0198 *
0199 * @event core.generate_smilies_before
0200 * @var string root_path root_path for smilies
0201 * @since 3.1.11-RC1
0202 */
0203 $vars = array('root_path');
0204 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_before', compact($vars)));
0205 $template->assign_block_vars('smiley', array(
0206 'SMILEY_CODE' => $row['code'],
0207 'A_SMILEY_CODE' => addslashes($row['code']),
0208 'SMILEY_IMG' => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'],
0209 'SMILEY_WIDTH' => $row['smiley_width'],
0210 'SMILEY_HEIGHT' => $row['smiley_height'],
0211 'SMILEY_DESC' => $row['emotion'])
0212 );
0213 }
0214 }
0215
0216 /**
0217 * This event is called after the smilies are populated
0218 *
0219 * @event core.generate_smilies_after
0220 * @var string mode Mode of the smilies: window|inline
0221 * @var int forum_id The forum ID we are currently in
0222 * @var bool display_link Shall we display the "more smilies" link?
0223 * @var string base_url URL for the "More smilies" link and its pagination
0224 * @since 3.1.0-a1
0225 * @changed 3.2.10-RC1 Added base_url
0226 */
0227 $vars = [
0228 'mode',
0229 'forum_id',
0230 'display_link',
0231 'base_url',
0232 ];
0233 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars)));
0234
0235 if ($mode == 'inline' && $display_link)
0236 {
0237 $template->assign_vars(array(
0238 'S_SHOW_SMILEY_LINK' => true,
0239 'U_MORE_SMILIES' => $base_url,
0240 ));
0241 }
0242
0243 if ($mode == 'window')
0244 {
0245 page_footer();
0246 }
0247 }
0248
0249 /**
0250 * Update last post information
0251 * Should be used instead of sync() if only the last post information are out of sync... faster
0252 *
0253 * @param string $type Can be forum|topic
0254 * @param mixed $ids topic/forum ids
0255 * @param bool $return_update_sql true: SQL query shall be returned, false: execute SQL
0256 */
0257 function update_post_information($type, $ids, $return_update_sql = false)
0258 {
0259 global $db, $phpbb_dispatcher;
0260
0261 if (empty($ids))
0262 {
0263 return;
0264 }
0265 if (!is_array($ids))
0266 {
0267 $ids = array($ids);
0268 }
0269
0270 $update_sql = $empty_forums = $not_empty_forums = array();
0271
0272 if ($type != 'topic')
0273 {
0274 $topic_join = ', ' . TOPICS_TABLE . ' t';
0275 $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED;
0276 }
0277 else
0278 {
0279 $topic_join = '';
0280 $topic_condition = '';
0281 }
0282
0283 if (count($ids) == 1)
0284 {
0285 $sql = 'SELECT p.post_id as last_post_id
0286 FROM ' . POSTS_TABLE . " p $topic_join
0287 WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
0288 $topic_condition
0289 AND p.post_visibility = " . ITEM_APPROVED . "
0290 ORDER BY p.post_id DESC";
0291 $result = $db->sql_query_limit($sql, 1);
0292 }
0293 else
0294 {
0295 $sql = 'SELECT p.' . $type . '_id, MAX(p.post_id) as last_post_id
0296 FROM ' . POSTS_TABLE . " p $topic_join
0297 WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
0298 $topic_condition
0299 AND p.post_visibility = " . ITEM_APPROVED . "
0300 GROUP BY p.{$type}_id";
0301 $result = $db->sql_query($sql);
0302 }
0303
0304 $last_post_ids = array();
0305 while ($row = $db->sql_fetchrow($result))
0306 {
0307 if (count($ids) == 1)
0308 {
0309 $row[$type . '_id'] = $ids[0];
0310 }
0311
0312 if ($type == 'forum')
0313 {
0314 $not_empty_forums[] = $row['forum_id'];
0315
0316 if (empty($row['last_post_id']))
0317 {
0318 $empty_forums[] = $row['forum_id'];
0319 }
0320 }
0321
0322 $last_post_ids[] = $row['last_post_id'];
0323 }
0324 $db->sql_freeresult($result);
0325
0326 if ($type == 'forum')
0327 {
0328 $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums));
0329
0330 foreach ($empty_forums as $void => $forum_id)
0331 {
0332 $update_sql[$forum_id][] = 'forum_last_post_id = 0';
0333 $update_sql[$forum_id][] = "forum_last_post_subject = ''";
0334 $update_sql[$forum_id][] = 'forum_last_post_time = 0';
0335 $update_sql[$forum_id][] = 'forum_last_poster_id = 0';
0336 $update_sql[$forum_id][] = "forum_last_poster_name = ''";
0337 $update_sql[$forum_id][] = "forum_last_poster_colour = ''";
0338 }
0339 }
0340
0341 if (count($last_post_ids))
0342 {
0343 $sql_ary = array(
0344 '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',
0345 'FROM' => array(
0346 POSTS_TABLE => 'p',
0347 USERS_TABLE => 'u',
0348 ),
0349 'WHERE' => $db->sql_in_set('p.post_id', $last_post_ids) . '
0350 AND p.poster_id = u.user_id',
0351 );
0352
0353 /**
0354 * Event to modify the SQL array to get the post and user data from all last posts
0355 *
0356 * @event core.update_post_info_modify_posts_sql
0357 * @var string type The table being updated (forum or topic)
0358 * @var array sql_ary SQL array to get some of the last posts' data
0359 * @since 3.3.5-RC1
0360 */
0361 $vars = [
0362 'type',
0363 'sql_ary',
0364 ];
0365 extract($phpbb_dispatcher->trigger_event('core.update_post_info_modify_posts_sql', compact($vars)));
0366 $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
0367
0368 $rowset = array();
0369 while ($row = $db->sql_fetchrow($result))
0370 {
0371 $rowset[] = $row;
0372 $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id'];
0373 $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
0374 $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time'];
0375 $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id'];
0376 $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
0377 $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'";
0378 }
0379 $db->sql_freeresult($result);
0380
0381 /**
0382 * Event to modify the update_sql array to add new update data for forum or topic last posts
0383 *
0384 * @event core.update_post_info_modify_sql
0385 * @var string type The table being updated (forum or topic)
0386 * @var array rowset Array with the posts data
0387 * @var array update_sql Array with SQL data to update the forums or topics table with
0388 * @since 3.3.5-RC1
0389 */
0390 $vars = [
0391 'type',
0392 'rowset',
0393 'update_sql',
0394 ];
0395 extract($phpbb_dispatcher->trigger_event('core.update_post_info_modify_sql', compact($vars)));
0396 unset($rowset);
0397 }
0398 unset($empty_forums, $ids, $last_post_ids);
0399
0400 if ($return_update_sql || !count($update_sql))
0401 {
0402 return $update_sql;
0403 }
0404
0405 $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE;
0406
0407 foreach ($update_sql as $update_id => $update_sql_ary)
0408 {
0409 $sql = "UPDATE $table
0410 SET " . implode(', ', $update_sql_ary) . "
0411 WHERE {$type}_id = $update_id";
0412 $db->sql_query($sql);
0413 }
0414
0415 return;
0416 }
0417
0418 /**
0419 * Generate Topic Icons for display
0420 */
0421 function posting_gen_topic_icons($mode, $icon_id)
0422 {
0423 global $phpbb_root_path, $phpbb_path_helper, $config, $template, $cache;
0424
0425 // Grab icons
0426 $icons = $cache->obtain_icons();
0427
0428 if (!$icon_id)
0429 {
0430 $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"');
0431 }
0432
0433 if (count($icons))
0434 {
0435 $root_path = $phpbb_path_helper->get_web_root_path();
0436
0437 foreach ($icons as $id => $data)
0438 {
0439 if ($data['display'])
0440 {
0441 $template->assign_block_vars('topic_icon', array(
0442 'ICON_ID' => $id,
0443 'ICON_IMG' => $root_path . $config['icons_path'] . '/' . $data['img'],
0444 'ICON_WIDTH' => $data['width'],
0445 'ICON_HEIGHT' => $data['height'],
0446 'ICON_ALT' => $data['alt'],
0447
0448 'S_CHECKED' => ($id == $icon_id) ? true : false,
0449 'S_ICON_CHECKED' => ($id == $icon_id) ? ' checked="checked"' : '')
0450 );
0451 }
0452 }
0453
0454 return true;
0455 }
0456
0457 return false;
0458 }
0459
0460 /**
0461 * Build topic types able to be selected
0462 */
0463 function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
0464 {
0465 global $auth, $user, $template;
0466
0467 $toggle = false;
0468
0469 $topic_types = array(
0470 'sticky' => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'),
0471 'announce' => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'),
0472 'announce_global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL')
0473 );
0474
0475 $topic_type_array = array();
0476
0477 foreach ($topic_types as $auth_key => $topic_value)
0478 {
0479 if ($auth->acl_get('f_' . $auth_key, $forum_id))
0480 {
0481 $toggle = true;
0482
0483 $topic_type_array[] = array(
0484 'VALUE' => $topic_value['const'],
0485 'S_CHECKED' => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '',
0486 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']]
0487 );
0488 }
0489 }
0490
0491 if ($toggle)
0492 {
0493 $topic_type_array = array_merge(array(0 => array(
0494 'VALUE' => POST_NORMAL,
0495 'S_CHECKED' => ($cur_topic_type == POST_NORMAL) ? ' checked="checked"' : '',
0496 'L_TOPIC_TYPE' => $user->lang['POST_NORMAL'])),
0497
0498 $topic_type_array
0499 );
0500
0501 foreach ($topic_type_array as $array)
0502 {
0503 $template->assign_block_vars('topic_type', $array);
0504 }
0505
0506 $template->assign_vars(array(
0507 'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)),
0508 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_gets('f_announce', 'f_announce_global', $forum_id)),
0509 ));
0510 }
0511
0512 return $toggle;
0513 }
0514
0515 //
0516 // Attachment related functions
0517 //
0518 /**
0519 * Calculate the needed size for Thumbnail
0520 */
0521 function get_img_size_format($width, $height)
0522 {
0523 global $config;
0524
0525 // Maximum Width the Image can take
0526 $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400;
0527
0528 if ($width > $height)
0529 {
0530 return array(
0531 round($width * ($max_width / $width)),
0532 round($height * ($max_width / $width))
0533 );
0534 }
0535 else
0536 {
0537 return array(
0538 round($width * ($max_width / $height)),
0539 round($height * ($max_width / $height))
0540 );
0541 }
0542 }
0543
0544 /**
0545 * Return supported image types
0546 */
0547 function get_supported_image_types($type = false)
0548 {
0549 if (@extension_loaded('gd'))
0550 {
0551 $format = imagetypes();
0552 $new_type = 0;
0553
0554 if ($type !== false)
0555 {
0556 // Type is one of the IMAGETYPE constants - it is fetched from getimagesize()
0557 switch ($type)
0558 {
0559 // GIF
0560 case IMAGETYPE_GIF:
0561 $new_type = ($format & IMG_GIF) ? IMG_GIF : false;
0562 break;
0563
0564 // JPG, JPC, JP2
0565 case IMAGETYPE_JPEG:
0566 case IMAGETYPE_JPC:
0567 case IMAGETYPE_JPEG2000:
0568 case IMAGETYPE_JP2:
0569 case IMAGETYPE_JPX:
0570 case IMAGETYPE_JB2:
0571 $new_type = ($format & IMG_JPG) ? IMG_JPG : false;
0572 break;
0573
0574 // PNG
0575 case IMAGETYPE_PNG:
0576 $new_type = ($format & IMG_PNG) ? IMG_PNG : false;
0577 break;
0578
0579 // WBMP
0580 case IMAGETYPE_WBMP:
0581 $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false;
0582 break;
0583
0584 // WEBP
0585 case IMAGETYPE_WEBP:
0586 $new_type = ($format & IMG_WEBP) ? IMG_WEBP : false;
0587 break;
0588 }
0589 }
0590 else
0591 {
0592 $new_type = [];
0593 $go_through_types = [IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP, IMG_WEBP];
0594
0595 foreach ($go_through_types as $check_type)
0596 {
0597 if ($format & $check_type)
0598 {
0599 $new_type[] = $check_type;
0600 }
0601 }
0602 }
0603
0604 return [
0605 'gd' => ($new_type) ? true : false,
0606 'format' => $new_type,
0607 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1
0608 ];
0609 }
0610
0611 return ['gd' => false];
0612 }
0613
0614 /**
0615 * Create Thumbnail
0616 */
0617 function create_thumbnail($source, $destination, $mimetype)
0618 {
0619 global $config, $phpbb_filesystem, $phpbb_dispatcher;
0620
0621 $min_filesize = (int) $config['img_min_thumb_filesize'];
0622 $img_filesize = (file_exists($source)) ? @filesize($source) : false;
0623
0624 if (!$img_filesize || $img_filesize <= $min_filesize)
0625 {
0626 return false;
0627 }
0628
0629 $dimension = @getimagesize($source);
0630
0631 if ($dimension === false)
0632 {
0633 return false;
0634 }
0635
0636 list($width, $height, $type, ) = $dimension;
0637
0638 if (empty($width) || empty($height))
0639 {
0640 return false;
0641 }
0642
0643 list($new_width, $new_height) = get_img_size_format($width, $height);
0644
0645 // Do not create a thumbnail if the resulting width/height is bigger than the original one
0646 if ($new_width >= $width && $new_height >= $height)
0647 {
0648 return false;
0649 }
0650
0651 $thumbnail_created = false;
0652
0653 /**
0654 * Create thumbnail event to replace GD thumbnail creation with for example ImageMagick
0655 *
0656 * @event core.thumbnail_create_before
0657 * @var string source Image source path
0658 * @var string destination Thumbnail destination path
0659 * @var string mimetype Image mime type
0660 * @var float new_width Calculated thumbnail width
0661 * @var float new_height Calculated thumbnail height
0662 * @var bool thumbnail_created Set to true to skip default GD thumbnail creation
0663 * @since 3.2.4
0664 */
0665 $vars = array(
0666 'source',
0667 'destination',
0668 'mimetype',
0669 'new_width',
0670 'new_height',
0671 'thumbnail_created',
0672 );
0673 extract($phpbb_dispatcher->trigger_event('core.thumbnail_create_before', compact($vars)));
0674
0675 if (!$thumbnail_created)
0676 {
0677 $type = get_supported_image_types($type);
0678
0679 if ($type['gd'])
0680 {
0681 // If the type is not supported, we are not able to create a thumbnail
0682 if ($type['format'] === false)
0683 {
0684 return false;
0685 }
0686
0687 switch ($type['format'])
0688 {
0689 case IMG_GIF:
0690 $image = @imagecreatefromgif($source);
0691 break;
0692
0693 case IMG_JPG:
0694 @ini_set('gd.jpeg_ignore_warning', 1);
0695 $image = @imagecreatefromjpeg($source);
0696 break;
0697
0698 case IMG_PNG:
0699 $image = @imagecreatefrompng($source);
0700 break;
0701
0702 case IMG_WBMP:
0703 $image = @imagecreatefromwbmp($source);
0704 break;
0705
0706 case IMG_WEBP:
0707 $image = @imagecreatefromwebp($source);
0708 break;
0709 }
0710
0711 if (empty($image))
0712 {
0713 return false;
0714 }
0715
0716 if ($type['version'] == 1)
0717 {
0718 $new_image = imagecreate($new_width, $new_height);
0719
0720 if ($new_image === false)
0721 {
0722 return false;
0723 }
0724
0725 imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
0726 }
0727 else
0728 {
0729 $new_image = imagecreatetruecolor($new_width, $new_height);
0730
0731 if ($new_image === false)
0732 {
0733 return false;
0734 }
0735
0736 // Preserve alpha transparency (png for example)
0737 @imagealphablending($new_image, false);
0738 @imagesavealpha($new_image, true);
0739
0740 imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
0741 }
0742
0743 switch ($type['format'])
0744 {
0745 case IMG_GIF:
0746 imagegif($new_image, $destination);
0747 break;
0748
0749 case IMG_JPG:
0750 imagejpeg($new_image, $destination, 90);
0751 break;
0752
0753 case IMG_PNG:
0754 imagepng($new_image, $destination);
0755 break;
0756
0757 case IMG_WBMP:
0758 imagewbmp($new_image, $destination);
0759 break;
0760
0761 case IMG_WEBP:
0762 imagewebp($new_image, $destination);
0763 break;
0764 }
0765
0766 imagedestroy($new_image);
0767 }
0768 else
0769 {
0770 return false;
0771 }
0772 }
0773
0774 if (!file_exists($destination))
0775 {
0776 return false;
0777 }
0778
0779 try
0780 {
0781 $phpbb_filesystem->phpbb_chmod($destination, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
0782 }
0783 catch (\phpbb\filesystem\exception\filesystem_exception $e)
0784 {
0785 // Do nothing
0786 }
0787
0788 return true;
0789 }
0790
0791 /**
0792 * Assign Inline attachments (build option fields)
0793 */
0794 function posting_gen_inline_attachments(&$attachment_data)
0795 {
0796 global $template;
0797
0798 if (count($attachment_data))
0799 {
0800 $s_inline_attachment_options = '';
0801
0802 foreach ($attachment_data as $i => $attachment)
0803 {
0804 $s_inline_attachment_options .= '<option value="' . $i . '">' . utf8_basename($attachment['real_filename']) . '</option>';
0805 }
0806
0807 $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options);
0808
0809 return true;
0810 }
0811
0812 return false;
0813 }
0814
0815 /**
0816 * Generate inline attachment entry
0817 *
0818 * @param array $attachment_data The attachment data
0819 * @param string $filename_data The filename data (filecomment)
0820 * @param bool $show_attach_box Whether to show the attach box
0821 * @param mixed $forum_id The forum id to check or false if private message
0822 * @return int
0823 */
0824 function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true, $forum_id = false)
0825 {
0826 global $template, $cache, $config, $phpbb_root_path, $phpEx, $user, $phpbb_dispatcher;
0827
0828 $allowed_attachments = array_keys($cache->obtain_attach_extensions($forum_id)['_allowed_']);
0829
0830 // Some default template variables
0831 $default_vars = [
0832 'S_SHOW_ATTACH_BOX' => $show_attach_box,
0833 'S_HAS_ATTACHMENTS' => count($attachment_data),
0834 'FILESIZE' => $config['max_filesize'],
0835 'FILE_COMMENT' => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '',
0836 'MAX_ATTACHMENT_FILESIZE' => $config['max_filesize'] > 0 ? $user->lang('MAX_ATTACHMENT_FILESIZE', get_formatted_filesize($config['max_filesize'])) : '',
0837 'ALLOWED_ATTACHMENTS' => !empty($allowed_attachments) ? '.' . implode(',.', $allowed_attachments) : '',
0838 ];
0839
0840 /**
0841 * Modify default attachments template vars
0842 *
0843 * @event core.modify_default_attachments_template_vars
0844 * @var array allowed_attachments Array containing allowed attachments data
0845 * @var array default_vars Array containing default attachments template vars
0846 * @since 3.3.6-RC1
0847 */
0848 $vars = ['allowed_attachments', 'default_vars'];
0849 extract($phpbb_dispatcher->trigger_event('core.modify_default_attachments_template_vars', compact($vars)));
0850
0851 $template->assign_vars($default_vars);
0852
0853 if (count($attachment_data))
0854 {
0855 // We display the posted attachments within the desired order.
0856 ($config['display_order']) ? krsort($attachment_data) : ksort($attachment_data);
0857
0858 $attachrow_template_vars = [];
0859
0860 foreach ($attachment_data as $count => $attach_row)
0861 {
0862 $hidden = '';
0863 $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']);
0864
0865 foreach ($attach_row as $key => $value)
0866 {
0867 $hidden .= '<input type="hidden" name="attachment_data[' . $count . '][' . $key . ']" value="' . $value . '" />';
0868 }
0869
0870 $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false);
0871
0872 $attachrow_template_vars[(int) $attach_row['attach_id']] = array(
0873 'FILENAME' => utf8_basename($attach_row['real_filename']),
0874 'A_FILENAME' => addslashes(utf8_basename($attach_row['real_filename'])),
0875 'FILE_COMMENT' => $attach_row['attach_comment'],
0876 'ATTACH_ID' => $attach_row['attach_id'],
0877 'S_IS_ORPHAN' => $attach_row['is_orphan'],
0878 'ASSOC_INDEX' => $count,
0879 'FILESIZE' => get_formatted_filesize($attach_row['filesize']),
0880
0881 'U_VIEW_ATTACHMENT' => $download_link,
0882 'S_HIDDEN' => $hidden,
0883 );
0884 }
0885
0886 /**
0887 * Modify inline attachments template vars
0888 *
0889 * @event core.modify_inline_attachments_template_vars
0890 * @var array attachment_data Array containing attachments data
0891 * @var array attachrow_template_vars Array containing attachments template vars
0892 * @since 3.2.2-RC1
0893 */
0894 $vars = array('attachment_data', 'attachrow_template_vars');
0895 extract($phpbb_dispatcher->trigger_event('core.modify_inline_attachments_template_vars', compact($vars)));
0896
0897 $template->assign_block_vars_array('attach_row', $attachrow_template_vars);
0898 }
0899
0900 return count($attachment_data);
0901 }
0902
0903 //
0904 // General Post functions
0905 //
0906
0907 /**
0908 * Load Drafts
0909 */
0910 function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0)
0911 {
0912 global $user, $db, $template, $auth;
0913 global $phpbb_root_path, $phpbb_dispatcher, $phpEx;
0914
0915 $topic_ids = $forum_ids = $draft_rows = array();
0916
0917 // Load those drafts not connected to forums/topics
0918 // If forum_id == 0 AND topic_id == 0 then this is a PM draft
0919 if (!$topic_id && !$forum_id)
0920 {
0921 $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0';
0922 }
0923 else
0924 {
0925 $sql_and = '';
0926 $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : '';
0927 $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : '';
0928 }
0929
0930 $sql = 'SELECT d.*, f.forum_id, f.forum_name
0931 FROM ' . DRAFTS_TABLE . ' d
0932 LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id)
0933 WHERE d.user_id = ' . $user->data['user_id'] . "
0934 $sql_and
0935 ORDER BY d.save_time DESC";
0936 $result = $db->sql_query($sql);
0937
0938 while ($row = $db->sql_fetchrow($result))
0939 {
0940 if ($row['topic_id'])
0941 {
0942 $topic_ids[] = (int) $row['topic_id'];
0943 }
0944 $draft_rows[] = $row;
0945 }
0946 $db->sql_freeresult($result);
0947
0948 if (!count($draft_rows))
0949 {
0950 return;
0951 }
0952
0953 $topic_rows = array();
0954 if (count($topic_ids))
0955 {
0956 $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster
0957 FROM ' . TOPICS_TABLE . '
0958 WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids));
0959 $result = $db->sql_query($sql);
0960
0961 while ($row = $db->sql_fetchrow($result))
0962 {
0963 $topic_rows[$row['topic_id']] = $row;
0964 }
0965 $db->sql_freeresult($result);
0966 }
0967
0968 /**
0969 * Drafts found and their topics
0970 * Edit $draft_rows in order to add or remove drafts loaded
0971 *
0972 * @event core.load_drafts_draft_list_result
0973 * @var array draft_rows The drafts query result. Includes its forum id and everything about the draft
0974 * @var array topic_ids The list of topics got from the topics table
0975 * @var array topic_rows The topics that draft_rows references
0976 * @since 3.1.0-RC3
0977 */
0978 $vars = array('draft_rows', 'topic_ids', 'topic_rows');
0979 extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars)));
0980
0981 unset($topic_ids);
0982
0983 $template->assign_var('S_SHOW_DRAFTS', true);
0984
0985 foreach ($draft_rows as $draft)
0986 {
0987 $link_topic = $link_forum = $link_pm = false;
0988 $view_url = $title = '';
0989
0990 if (isset($topic_rows[$draft['topic_id']])
0991 && (
0992 ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id']))
0993 ||
0994 (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read'))
0995 ))
0996 {
0997 $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id;
0998
0999 $link_topic = true;
1000 $view_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $draft['topic_id']);
1001 $title = $topic_rows[$draft['topic_id']]['topic_title'];
1002
1003 $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 't=' . $draft['topic_id'] . '&mode=reply&d=' . $draft['draft_id']);
1004 }
1005 else if ($draft['forum_id'] && $auth->acl_get('f_read', $draft['forum_id']))
1006 {
1007 $link_forum = true;
1008 $view_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $draft['forum_id']);
1009 $title = $draft['forum_name'];
1010
1011 $insert_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'f=' . $draft['forum_id'] . '&mode=post&d=' . $draft['draft_id']);
1012 }
1013 else
1014 {
1015 // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards...
1016 $link_pm = true;
1017 $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&d={$draft['draft_id']}" . (($pm_action) ? "&action=$pm_action" : '') . (($msg_id) ? "&p=$msg_id" : ''));
1018 }
1019
1020 $template->assign_block_vars('draftrow', array(
1021 'DRAFT_ID' => $draft['draft_id'],
1022 'DATE' => $user->format_date($draft['save_time']),
1023 'DRAFT_SUBJECT' => $draft['draft_subject'],
1024
1025 'TITLE' => $title,
1026 'U_VIEW' => $view_url,
1027 'U_INSERT' => $insert_url,
1028
1029 'S_LINK_PM' => $link_pm,
1030 'S_LINK_TOPIC' => $link_topic,
1031 'S_LINK_FORUM' => $link_forum)
1032 );
1033 }
1034 }
1035
1036 /**
1037 * Topic Review
1038 */
1039 function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true)
1040 {
1041 global $user, $auth, $db, $template;
1042 global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
1043
1044 /* @var $phpbb_content_visibility \phpbb\content_visibility */
1045 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
1046 $sql_sort = ($mode == 'post_review') ? 'ASC' : 'DESC';
1047
1048 // Go ahead and pull all data for this topic
1049 $sql = 'SELECT p.post_id
1050 FROM ' . POSTS_TABLE . ' p' . "
1051 WHERE p.topic_id = $topic_id
1052 AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . '
1053 ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . '
1054 ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . '
1055 ORDER BY p.post_time ' . $sql_sort . ', p.post_id ' . $sql_sort;
1056 $result = $db->sql_query_limit($sql, $config['posts_per_page']);
1057
1058 $post_list = array();
1059
1060 while ($row = $db->sql_fetchrow($result))
1061 {
1062 $post_list[] = $row['post_id'];
1063 }
1064
1065 $db->sql_freeresult($result);
1066
1067 if (!count($post_list))
1068 {
1069 return false;
1070 }
1071
1072 // Handle 'post_review_edit' like 'post_review' from now on
1073 if ($mode == 'post_review_edit')
1074 {
1075 $mode = 'post_review';
1076 }
1077
1078 $sql_ary = array(
1079 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe, uu.username as post_delete_username, uu.user_colour as post_delete_user_colour',
1080
1081 'FROM' => array(
1082 USERS_TABLE => 'u',
1083 POSTS_TABLE => 'p',
1084 ),
1085
1086 'LEFT_JOIN' => array(
1087 array(
1088 'FROM' => array(ZEBRA_TABLE => 'z'),
1089 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id',
1090 ),
1091 array(
1092 'FROM' => array(USERS_TABLE => 'uu'),
1093 'ON' => 'uu.user_id = p.post_delete_user',
1094 ),
1095 ),
1096
1097 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . '
1098 AND u.user_id = p.poster_id',
1099 );
1100
1101 /**
1102 * Event to modify the SQL query for topic reviews
1103 *
1104 * @event core.topic_review_modify_sql_ary
1105 * @var int topic_id The topic ID that is being reviewed
1106 * @var int forum_id The topic's forum ID
1107 * @var string mode The topic review mode
1108 * @var int cur_post_id Post offset ID
1109 * @var bool show_quote_button Flag indicating if the quote button should be displayed
1110 * @var array post_list Array with the post IDs
1111 * @var array sql_ary Array with the SQL query
1112 * @since 3.2.8-RC1
1113 */
1114 $vars = array(
1115 'topic_id',
1116 'forum_id',
1117 'mode',
1118 'cur_post_id',
1119 'show_quote_button',
1120 'post_list',
1121 'sql_ary',
1122 );
1123 extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_sql_ary', compact($vars)));
1124
1125 $sql = $db->sql_build_query('SELECT', $sql_ary);
1126 $result = $db->sql_query($sql);
1127
1128 $rowset = array();
1129 $has_attachments = false;
1130 while ($row = $db->sql_fetchrow($result))
1131 {
1132 $rowset[$row['post_id']] = $row;
1133
1134 if ($row['post_attachment'])
1135 {
1136 $has_attachments = true;
1137 }
1138 }
1139 $db->sql_freeresult($result);
1140
1141 // Grab extensions
1142 $attachments = array();
1143 if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
1144 {
1145 // Get attachments...
1146 $sql = 'SELECT *
1147 FROM ' . ATTACHMENTS_TABLE . '
1148 WHERE ' . $db->sql_in_set('post_msg_id', $post_list) . '
1149 AND in_message = 0
1150 ORDER BY filetime DESC, post_msg_id ASC';
1151 $result = $db->sql_query($sql);
1152
1153 while ($row = $db->sql_fetchrow($result))
1154 {
1155 $attachments[$row['post_msg_id']][] = $row;
1156 }
1157 $db->sql_freeresult($result);
1158 }
1159
1160 /**
1161 * Event to modify the posts list for topic reviews
1162 *
1163 * @event core.topic_review_modify_post_list
1164 * @var array attachments Array with the post attachments data
1165 * @var int cur_post_id Post offset ID
1166 * @var int forum_id The topic's forum ID
1167 * @var string mode The topic review mode
1168 * @var array post_list Array with the post IDs
1169 * @var array rowset Array with the posts data
1170 * @var bool show_quote_button Flag indicating if the quote button should be displayed
1171 * @var int topic_id The topic ID that is being reviewed
1172 * @since 3.1.9-RC1
1173 */
1174 $vars = array(
1175 'attachments',
1176 'cur_post_id',
1177 'forum_id',
1178 'mode',
1179 'post_list',
1180 'rowset',
1181 'show_quote_button',
1182 'topic_id',
1183 );
1184 extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_post_list', compact($vars)));
1185
1186 for ($i = 0, $end = count($post_list); $i < $end; ++$i)
1187 {
1188 // A non-existing rowset only happens if there was no user present for the entered poster_id
1189 // This could be a broken posts table.
1190 if (!isset($rowset[$post_list[$i]]))
1191 {
1192 continue;
1193 }
1194
1195 $row = $rowset[$post_list[$i]];
1196
1197 $poster_id = $row['user_id'];
1198 $post_subject = $row['post_subject'];
1199
1200 $decoded_message = false;
1201
1202 if ($show_quote_button && $auth->acl_get('f_reply', $forum_id))
1203 {
1204 $decoded_message = censor_text($row['post_text']);
1205 decode_message($decoded_message, $row['bbcode_uid']);
1206
1207 $decoded_message = bbcode_nl2br($decoded_message);
1208 }
1209
1210 $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
1211 $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
1212 $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true);
1213
1214 if (!empty($attachments[$row['post_id']]))
1215 {
1216 $update_count = array();
1217 parse_attachments($forum_id, $message, $attachments[$row['post_id']], $update_count);
1218 }
1219
1220 $post_subject = censor_text($post_subject);
1221
1222 $post_anchor = ($mode == 'post_review') ? 'ppr' . $row['post_id'] : 'pr' . $row['post_id'];
1223 $u_show_post = append_sid($phpbb_root_path . 'viewtopic.' . $phpEx, "t=$topic_id&p={$row['post_id']}&view=show#p{$row['post_id']}");
1224
1225 $l_deleted_message = '';
1226 if ($row['post_visibility'] == ITEM_DELETED)
1227 {
1228 $display_postername = get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']);
1229
1230 // User having deleted the post also being the post author?
1231 if (!$row['post_delete_user'] || $row['post_delete_user'] == $poster_id)
1232 {
1233 $display_username = $display_postername;
1234 }
1235 else
1236 {
1237 $display_username = get_username_string('full', $row['post_delete_user'], $row['post_delete_username'], $row['post_delete_user_colour']);
1238 }
1239
1240 if ($row['post_delete_reason'])
1241 {
1242 $l_deleted_message = $user->lang('POST_DELETED_BY_REASON', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true), $row['post_delete_reason']);
1243 }
1244 else
1245 {
1246 $l_deleted_message = $user->lang('POST_DELETED_BY', $display_postername, $display_username, $user->format_date($row['post_delete_time'], false, true));
1247 }
1248 }
1249
1250 $post_row = array(
1251 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1252 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1253 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1254 'U_POST_AUTHOR' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']),
1255
1256 'S_HAS_ATTACHMENTS' => !empty($attachments[$row['post_id']]),
1257 'S_FRIEND' => (bool) $row['friend'],
1258 'S_IGNORE_POST' => (bool) $row['foe'],
1259 'L_IGNORE_POST' => $row['foe'] ? $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>') : '',
1260 'S_POST_DELETED' => $row['post_visibility'] == ITEM_DELETED,
1261 'L_DELETE_POST' => $l_deleted_message,
1262
1263 'POST_SUBJECT' => $post_subject,
1264 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']),
1265 'POST_DATE' => $user->format_date($row['post_time']),
1266 'MESSAGE' => $message,
1267 'DECODED_MESSAGE' => $decoded_message,
1268 'POST_ID' => $row['post_id'],
1269 'POST_TIME' => $row['post_time'],
1270 'USER_ID' => $row['user_id'],
1271 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
1272 'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=post_details&p=' . $row['post_id'], true, $user->session_id) : '',
1273 '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'])) : '',
1274 );
1275
1276 $current_row_number = $i;
1277
1278 /**
1279 * Event to modify the template data block for topic reviews
1280 *
1281 * @event core.topic_review_modify_row
1282 * @var string mode The review mode
1283 * @var int topic_id The topic that is being reviewed
1284 * @var int forum_id The topic's forum
1285 * @var int cur_post_id Post offset id
1286 * @var int current_row_number Number of the current row being iterated
1287 * @var array post_row Template block array of the current post
1288 * @var array row Array with original post and user data
1289 * @since 3.1.4-RC1
1290 */
1291 $vars = array(
1292 'mode',
1293 'topic_id',
1294 'forum_id',
1295 'cur_post_id',
1296 'current_row_number',
1297 'post_row',
1298 'row',
1299 );
1300 extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_row', compact($vars)));
1301
1302 $template->assign_block_vars($mode . '_row', $post_row);
1303
1304 // Display not already displayed Attachments for this post, we already parsed them. ;)
1305 if (!empty($attachments[$row['post_id']]))
1306 {
1307 foreach ($attachments[$row['post_id']] as $attachment)
1308 {
1309 $template->assign_block_vars($mode . '_row.attachment', array(
1310 'DISPLAY_ATTACHMENT' => $attachment)
1311 );
1312 }
1313 }
1314
1315 unset($rowset[$post_list[$i]]);
1316 }
1317
1318 if ($mode == 'topic_review')
1319 {
1320 $template->assign_var('QUOTE_IMG', $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']));
1321 }
1322
1323 return true;
1324 }
1325
1326 //
1327 // Post handling functions
1328 //
1329
1330 /**
1331 * Delete Post
1332 */
1333 function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '')
1334 {
1335 global $db, $user, $phpbb_container, $phpbb_dispatcher;
1336 global $config, $phpEx, $phpbb_root_path;
1337
1338 // Specify our post mode
1339 $post_mode = 'delete';
1340 if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1))
1341 {
1342 $post_mode = 'delete_topic';
1343 }
1344 else if ($data['topic_first_post_id'] == $post_id)
1345 {
1346 $post_mode = 'delete_first_post';
1347 }
1348 else if ($data['topic_last_post_id'] <= $post_id)
1349 {
1350 $post_mode = 'delete_last_post';
1351 }
1352 $sql_data = array();
1353 $next_post_id = false;
1354
1355 include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1356
1357 $db->sql_transaction('begin');
1358
1359 // we must make sure to update forums that contain the shadow'd topic
1360 if ($post_mode == 'delete_topic')
1361 {
1362 $shadow_forum_ids = array();
1363
1364 $sql = 'SELECT forum_id
1365 FROM ' . TOPICS_TABLE . '
1366 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_id);
1367 $result = $db->sql_query($sql);
1368 while ($row = $db->sql_fetchrow($result))
1369 {
1370 if (!isset($shadow_forum_ids[(int) $row['forum_id']]))
1371 {
1372 $shadow_forum_ids[(int) $row['forum_id']] = 1;
1373 }
1374 else
1375 {
1376 $shadow_forum_ids[(int) $row['forum_id']]++;
1377 }
1378 }
1379 $db->sql_freeresult($result);
1380 }
1381
1382 /* @var $phpbb_content_visibility \phpbb\content_visibility */
1383 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
1384
1385 // (Soft) delete the post
1386 if ($is_soft && ($post_mode != 'delete_topic'))
1387 {
1388 $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));
1389 }
1390 else if (!$is_soft)
1391 {
1392 if (!delete_posts('post_id', array($post_id), false, false, false))
1393 {
1394 // Try to delete topic, we may had an previous error causing inconsistency
1395 if ($post_mode == 'delete_topic')
1396 {
1397 delete_topics('topic_id', array($topic_id), false);
1398 }
1399 trigger_error('ALREADY_DELETED');
1400 }
1401 }
1402
1403 $db->sql_transaction('commit');
1404
1405 // Collect the necessary information for updating the tables
1406 $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = '';
1407 switch ($post_mode)
1408 {
1409 case 'delete_topic':
1410
1411 foreach ($shadow_forum_ids as $updated_forum => $topic_count)
1412 {
1413 // counting is fun! we only have to do count($forum_ids) number of queries,
1414 // even if the topic is moved back to where its shadow lives (we count how many times it is in a forum)
1415 $sql = 'UPDATE ' . FORUMS_TABLE . '
1416 SET forum_topics_approved = forum_topics_approved - ' . $topic_count . '
1417 WHERE forum_id = ' . $updated_forum;
1418 $db->sql_query($sql);
1419 update_post_information('forum', $updated_forum);
1420 }
1421
1422 if ($is_soft)
1423 {
1424 $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason);
1425 }
1426 else
1427 {
1428 delete_topics('topic_id', array($topic_id), false);
1429
1430 $phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data);
1431 $config->increment('num_posts', -1, false);
1432
1433 $update_sql = update_post_information('forum', $forum_id, true);
1434 if (count($update_sql))
1435 {
1436 $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
1437 $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
1438 }
1439 }
1440
1441 break;
1442
1443 case 'delete_first_post':
1444 $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
1445 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
1446 WHERE p.topic_id = $topic_id
1447 AND p.poster_id = u.user_id
1448 AND p.post_visibility = " . ITEM_APPROVED . '
1449 ORDER BY p.post_time ASC, p.post_id ASC';
1450 $result = $db->sql_query_limit($sql, 1);
1451 $row = $db->sql_fetchrow($result);
1452 $db->sql_freeresult($result);
1453
1454 if (!$row)
1455 {
1456 // No approved post, so the first is a not-approved post (unapproved or soft deleted)
1457 $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
1458 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
1459 WHERE p.topic_id = $topic_id
1460 AND p.poster_id = u.user_id
1461 ORDER BY p.post_time ASC, p.post_id ASC";
1462 $result = $db->sql_query_limit($sql, 1);
1463 $row = $db->sql_fetchrow($result);
1464 $db->sql_freeresult($result);
1465 }
1466
1467 $next_post_id = (int) $row['post_id'];
1468
1469 $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array(
1470 'topic_poster' => (int) $row['poster_id'],
1471 'topic_first_post_id' => (int) $row['post_id'],
1472 'topic_first_poster_colour' => $row['user_colour'],
1473 'topic_first_poster_name' => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'],
1474 'topic_time' => (int) $row['post_time'],
1475 ));
1476 break;
1477
1478 case 'delete_last_post':
1479 if (!$is_soft)
1480 {
1481 // Update last post information when hard deleting. Soft delete already did that by itself.
1482 $update_sql = update_post_information('forum', $forum_id, true);
1483 if (count($update_sql))
1484 {
1485 $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]);
1486 }
1487
1488 $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0';
1489
1490 $update_sql = update_post_information('topic', $topic_id, true);
1491 if (!empty($update_sql))
1492 {
1493 $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]);
1494 $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]);
1495 }
1496 }
1497
1498 if (!$next_post_id)
1499 {
1500 $sql = 'SELECT MAX(post_id) as last_post_id
1501 FROM ' . POSTS_TABLE . "
1502 WHERE topic_id = $topic_id
1503 AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
1504 $result = $db->sql_query($sql);
1505 $next_post_id = (int) $db->sql_fetchfield('last_post_id');
1506 $db->sql_freeresult($result);
1507 }
1508 break;
1509
1510 case 'delete':
1511 $sql = 'SELECT post_id
1512 FROM ' . POSTS_TABLE . "
1513 WHERE topic_id = $topic_id
1514 AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . '
1515 AND post_time > ' . $data['post_time'] . '
1516 ORDER BY post_time ASC, post_id ASC';
1517 $result = $db->sql_query_limit($sql, 1);
1518 $next_post_id = (int) $db->sql_fetchfield('post_id');
1519 $db->sql_freeresult($result);
1520 break;
1521 }
1522
1523 if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post'))
1524 {
1525 if (!$is_soft)
1526 {
1527 $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data);
1528 }
1529
1530 $sql = 'SELECT 1 AS has_attachments
1531 FROM ' . ATTACHMENTS_TABLE . '
1532 WHERE topic_id = ' . $topic_id;
1533 $result = $db->sql_query_limit($sql, 1);
1534 $has_attachments = (int) $db->sql_fetchfield('has_attachments');
1535 $db->sql_freeresult($result);
1536
1537 if (!$has_attachments)
1538 {
1539 $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0';
1540 }
1541 }
1542
1543 $db->sql_transaction('begin');
1544
1545 $where_sql = array(
1546 FORUMS_TABLE => "forum_id = $forum_id",
1547 TOPICS_TABLE => "topic_id = $topic_id",
1548 USERS_TABLE => 'user_id = ' . $data['poster_id'],
1549 );
1550
1551 foreach ($sql_data as $table => $update_sql)
1552 {
1553 if ($update_sql)
1554 {
1555 $db->sql_query("UPDATE $table SET $update_sql WHERE " . $where_sql[$table]);
1556 }
1557 }
1558
1559 // Adjust posted info for this user by looking for a post by him/her within this topic...
1560 if ($post_mode != 'delete_topic' && $config['load_db_track'] && $data['poster_id'] != ANONYMOUS)
1561 {
1562 $sql = 'SELECT poster_id
1563 FROM ' . POSTS_TABLE . '
1564 WHERE topic_id = ' . $topic_id . '
1565 AND poster_id = ' . $data['poster_id'];
1566 $result = $db->sql_query_limit($sql, 1);
1567 $poster_id = (int) $db->sql_fetchfield('poster_id');
1568 $db->sql_freeresult($result);
1569
1570 // The user is not having any more posts within this topic
1571 if (!$poster_id)
1572 {
1573 $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
1574 WHERE topic_id = ' . $topic_id . '
1575 AND user_id = ' . $data['poster_id'];
1576 $db->sql_query($sql);
1577 }
1578 }
1579
1580 $db->sql_transaction('commit');
1581
1582 if ($data['post_reported'] && ($post_mode != 'delete_topic'))
1583 {
1584 sync('topic_reported', 'topic_id', array($topic_id));
1585 }
1586
1587 /**
1588 * This event is used for performing actions directly after a post or topic
1589 * has been deleted.
1590 *
1591 * @event core.delete_post_after
1592 * @var int forum_id Post forum ID
1593 * @var int topic_id Post topic ID
1594 * @var int post_id Post ID
1595 * @var array data Post data
1596 * @var bool is_soft Soft delete flag
1597 * @var string softdelete_reason Soft delete reason
1598 * @var string post_mode delete_topic, delete_first_post, delete_last_post or delete
1599 * @var mixed next_post_id Next post ID in the topic (post ID or false)
1600 *
1601 * @since 3.1.11-RC1
1602 */
1603 $vars = array(
1604 'forum_id',
1605 'topic_id',
1606 'post_id',
1607 'data',
1608 'is_soft',
1609 'softdelete_reason',
1610 'post_mode',
1611 'next_post_id',
1612 );
1613 extract($phpbb_dispatcher->trigger_event('core.delete_post_after', compact($vars)));
1614
1615 return $next_post_id;
1616 }
1617
1618 /**
1619 * Submit Post
1620 * @todo Split up and create lightweight, simple API for this.
1621 */
1622 function submit_post($mode, $subject, $username, $topic_type, &$poll_ary, &$data_ary, $update_message = true, $update_search_index = true)
1623 {
1624 global $db, $auth, $user, $config, $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request;
1625
1626 $poll = $poll_ary;
1627 $data = $data_ary;
1628 /**
1629 * Modify the data for post submitting
1630 *
1631 * @event core.modify_submit_post_data
1632 * @var string mode Variable containing posting mode value
1633 * @var string subject Variable containing post subject value
1634 * @var string username Variable containing post author name
1635 * @var int topic_type Variable containing topic type value
1636 * @var array poll Array with the poll data for the post
1637 * @var array data Array with the data for the post
1638 * @var bool update_message Flag indicating if the post will be updated
1639 * @var bool update_search_index Flag indicating if the search index will be updated
1640 * @since 3.1.0-a4
1641 */
1642 $vars = array(
1643 'mode',
1644 'subject',
1645 'username',
1646 'topic_type',
1647 'poll',
1648 'data',
1649 'update_message',
1650 'update_search_index',
1651 );
1652 extract($phpbb_dispatcher->trigger_event('core.modify_submit_post_data', compact($vars)));
1653 $poll_ary = $poll;
1654 $data_ary = $data;
1655 unset($poll);
1656 unset($data);
1657
1658 // We do not handle erasing posts here
1659 if ($mode == 'delete')
1660 {
1661 return false;
1662 }
1663
1664 if (!empty($data_ary['post_time']))
1665 {
1666 $current_time = $data_ary['post_time'];
1667 }
1668 else
1669 {
1670 $current_time = time();
1671 }
1672
1673 if ($mode == 'post')
1674 {
1675 $post_mode = 'post';
1676 $update_message = true;
1677 }
1678 else if ($mode != 'edit')
1679 {
1680 $post_mode = 'reply';
1681 $update_message = true;
1682 }
1683 else if ($mode == 'edit')
1684 {
1685 $post_mode = ($data_ary['topic_posts_approved'] + $data_ary['topic_posts_unapproved'] + $data_ary['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data_ary['topic_first_post_id'] == $data_ary['post_id']) ? 'edit_first_post' : (($data_ary['topic_last_post_id'] == $data_ary['post_id']) ? 'edit_last_post' : 'edit'));
1686 }
1687
1688 // First of all make sure the subject and topic title are having the correct length.
1689 // To achieve this without cutting off between special chars we convert to an array and then count the elements.
1690 $subject = truncate_string($subject, 120);
1691 $data_ary['topic_title'] = truncate_string($data_ary['topic_title'], 120);
1692
1693 // Collect some basic information about which tables and which rows to update/insert
1694 $sql_data = $topic_row = array();
1695 $poster_id = ($mode == 'edit') ? $data_ary['poster_id'] : (int) $user->data['user_id'];
1696
1697 // Retrieve some additional information if not present
1698 if ($mode == 'edit' && (!isset($data_ary['post_visibility']) || !isset($data_ary['topic_visibility']) || $data_ary['post_visibility'] === false || $data_ary['topic_visibility'] === false))
1699 {
1700 $sql = 'SELECT p.post_visibility, t.topic_type, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_visibility
1701 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
1702 WHERE t.topic_id = p.topic_id
1703 AND p.post_id = ' . $data_ary['post_id'];
1704 $result = $db->sql_query($sql);
1705 $topic_row = $db->sql_fetchrow($result);
1706 $db->sql_freeresult($result);
1707
1708 $data_ary['topic_visibility'] = $topic_row['topic_visibility'];
1709 $data_ary['post_visibility'] = $topic_row['post_visibility'];
1710 }
1711
1712 // This variable indicates if the user is able to post or put into the queue
1713 $post_visibility = ITEM_APPROVED;
1714
1715 // Check the permissions for post approval.
1716 // Moderators must go through post approval like ordinary users.
1717 if (!$auth->acl_get('f_noapprove', $data_ary['forum_id']))
1718 {
1719 // Post not approved, but in queue
1720 $post_visibility = ITEM_UNAPPROVED;
1721 switch ($post_mode)
1722 {
1723 case 'edit_first_post':
1724 case 'edit':
1725 case 'edit_last_post':
1726 case 'edit_topic':
1727 $post_visibility = ITEM_REAPPROVE;
1728 break;
1729 }
1730 }
1731 else if (isset($data_ary['post_visibility']) && $data_ary['post_visibility'] !== false)
1732 {
1733 $post_visibility = $data_ary['post_visibility'];
1734 }
1735
1736 // MODs/Extensions are able to force any visibility on posts
1737 if (isset($data_ary['force_approved_state']))
1738 {
1739 $post_visibility = (in_array((int) $data_ary['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data_ary['force_approved_state'] : $post_visibility;
1740 }
1741 if (isset($data_ary['force_visibility']))
1742 {
1743 $post_visibility = (in_array((int) $data_ary['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data_ary['force_visibility'] : $post_visibility;
1744 }
1745
1746 // Start the transaction here
1747 $db->sql_transaction('begin');
1748
1749 // Collect Information
1750 switch ($post_mode)
1751 {
1752 case 'post':
1753 case 'reply':
1754 $sql_data[POSTS_TABLE]['sql'] = array(
1755 'forum_id' => $data_ary['forum_id'],
1756 'poster_id' => (int) $user->data['user_id'],
1757 'icon_id' => $data_ary['icon_id'],
1758 'poster_ip' => $user->ip,
1759 'post_time' => $current_time,
1760 'post_visibility' => $post_visibility,
1761 'enable_bbcode' => $data_ary['enable_bbcode'],
1762 'enable_smilies' => $data_ary['enable_smilies'],
1763 'enable_magic_url' => $data_ary['enable_urls'],
1764 'enable_sig' => $data_ary['enable_sig'],
1765 'post_username' => (!$user->data['is_registered']) ? $username : '',
1766 'post_subject' => $subject,
1767 'post_text' => $data_ary['message'],
1768 'post_checksum' => $data_ary['message_md5'],
1769 'post_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : 0,
1770 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
1771 'bbcode_uid' => $data_ary['bbcode_uid'],
1772 'post_postcount' => ($auth->acl_get('f_postcount', $data_ary['forum_id'])) ? 1 : 0,
1773 'post_edit_locked' => $data_ary['post_edit_locked']
1774 );
1775 break;
1776
1777 case 'edit_first_post':
1778 case 'edit':
1779
1780 case 'edit_last_post':
1781 case 'edit_topic':
1782
1783 // If edit reason is given always display edit info
1784
1785 // If editing last post then display no edit info
1786 // If m_edit permission then display no edit info
1787 // If normal edit display edit info
1788
1789 // Display edit info if edit reason given or user is editing his post, which is not the last within the topic.
1790 if ($data_ary['post_edit_reason'] || (!$auth->acl_get('m_edit', $data_ary['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post')))
1791 {
1792 $data_ary['post_edit_reason'] = truncate_string($data_ary['post_edit_reason'], 255, 255, false);
1793
1794 $sql_data[POSTS_TABLE]['sql'] = array(
1795 'post_edit_time' => $current_time,
1796 'post_edit_reason' => $data_ary['post_edit_reason'],
1797 'post_edit_user' => (int) $data_ary['post_edit_user'],
1798 );
1799
1800 $sql_data[POSTS_TABLE]['stat'][] = 'post_edit_count = post_edit_count + 1';
1801 }
1802 else if (!$data_ary['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data_ary['forum_id']))
1803 {
1804 $sql_data[POSTS_TABLE]['sql'] = array(
1805 'post_edit_reason' => '',
1806 );
1807 }
1808
1809 // If the person editing this post is different to the one having posted then we will add a log entry stating the edit
1810 // Could be simplified by only adding to the log if the edit is not tracked - but this may confuse admins/mods
1811 if ($user->data['user_id'] != $poster_id)
1812 {
1813 $log_subject = ($subject) ? $subject : $data_ary['topic_title'];
1814 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_POST_EDITED', false, array(
1815 'forum_id' => $data_ary['forum_id'],
1816 'topic_id' => $data_ary['topic_id'],
1817 'post_id' => $data_ary['post_id'],
1818 $log_subject,
1819 (!empty($username)) ? $username : $user->lang['GUEST'],
1820 $data_ary['post_edit_reason']
1821 ));
1822 }
1823
1824 if (!isset($sql_data[POSTS_TABLE]['sql']))
1825 {
1826 $sql_data[POSTS_TABLE]['sql'] = array();
1827 }
1828
1829 $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
1830 'forum_id' => $data_ary['forum_id'],
1831 'poster_id' => $data_ary['poster_id'],
1832 'icon_id' => $data_ary['icon_id'],
1833 // We will change the visibility later
1834 //'post_visibility' => $post_visibility,
1835 'enable_bbcode' => $data_ary['enable_bbcode'],
1836 'enable_smilies' => $data_ary['enable_smilies'],
1837 'enable_magic_url' => $data_ary['enable_urls'],
1838 'enable_sig' => $data_ary['enable_sig'],
1839 'post_username' => ($username && $data_ary['poster_id'] == ANONYMOUS) ? $username : '',
1840 'post_subject' => $subject,
1841 'post_checksum' => $data_ary['message_md5'],
1842 'post_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : 0,
1843 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
1844 'bbcode_uid' => $data_ary['bbcode_uid'],
1845 'post_edit_locked' => $data_ary['post_edit_locked'])
1846 );
1847
1848 if ($update_message)
1849 {
1850 $sql_data[POSTS_TABLE]['sql']['post_text'] = $data_ary['message'];
1851 }
1852
1853 break;
1854 }
1855
1856 // And the topic ladies and gentlemen
1857 switch ($post_mode)
1858 {
1859 case 'post':
1860 $sql_data[TOPICS_TABLE]['sql'] = array(
1861 'topic_poster' => (int) $user->data['user_id'],
1862 'topic_time' => $current_time,
1863 'topic_last_view_time' => $current_time,
1864 'forum_id' => $data_ary['forum_id'],
1865 'icon_id' => $data_ary['icon_id'],
1866 'topic_posts_approved' => ($post_visibility == ITEM_APPROVED) ? 1 : 0,
1867 'topic_posts_softdeleted' => ($post_visibility == ITEM_DELETED) ? 1 : 0,
1868 'topic_posts_unapproved' => ($post_visibility == ITEM_UNAPPROVED) ? 1 : 0,
1869 'topic_visibility' => $post_visibility,
1870 'topic_delete_user' => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0,
1871 'topic_title' => $subject,
1872 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
1873 'topic_first_poster_colour' => $user->data['user_colour'],
1874 'topic_type' => $topic_type,
1875 'topic_time_limit' => $topic_type != POST_NORMAL ? ($data_ary['topic_time_limit'] * 86400) : 0,
1876 'topic_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : 0,
1877 'topic_status' => (isset($data_ary['topic_status'])) ? $data_ary['topic_status'] : ITEM_UNLOCKED,
1878 );
1879
1880 if (isset($poll_ary['poll_options']) && !empty($poll_ary['poll_options']))
1881 {
1882 $poll_start = ($poll_ary['poll_start']) ? $poll_ary['poll_start'] : $current_time;
1883 $poll_length = $poll_ary['poll_length'] * 86400;
1884 if ($poll_length < 0)
1885 {
1886 $poll_start = $poll_start + $poll_length;
1887 if ($poll_start < 0)
1888 {
1889 $poll_start = 0;
1890 }
1891 $poll_length = 1;
1892 }
1893
1894 $sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array(
1895 'poll_title' => $poll_ary['poll_title'],
1896 'poll_start' => $poll_start,
1897 'poll_max_options' => $poll_ary['poll_max_options'],
1898 'poll_length' => $poll_length,
1899 'poll_vote_change' => $poll_ary['poll_vote_change'])
1900 );
1901 }
1902
1903 $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
1904
1905 if ($post_visibility == ITEM_APPROVED)
1906 {
1907 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1';
1908 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
1909 }
1910 else if ($post_visibility == ITEM_UNAPPROVED)
1911 {
1912 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1';
1913 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
1914 }
1915 else if ($post_visibility == ITEM_DELETED)
1916 {
1917 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1';
1918 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
1919 }
1920 break;
1921
1922 case 'reply':
1923 $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ',
1924 topic_bumped = 0,
1925 topic_bumper = 0' .
1926 (($post_visibility == ITEM_APPROVED) ? ', topic_posts_approved = topic_posts_approved + 1' : '') .
1927 (($post_visibility == ITEM_UNAPPROVED) ? ', topic_posts_unapproved = topic_posts_unapproved + 1' : '') .
1928 (($post_visibility == ITEM_DELETED) ? ', topic_posts_softdeleted = topic_posts_softdeleted + 1' : '') .
1929 ((!empty($data_ary['attachment_data']) || (isset($data_ary['topic_attachment']) && $data_ary['topic_attachment'])) ? ', topic_attachment = 1' : '');
1930
1931 $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
1932
1933 if ($post_visibility == ITEM_APPROVED)
1934 {
1935 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
1936 }
1937 else if ($post_visibility == ITEM_UNAPPROVED)
1938 {
1939 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
1940 }
1941 else if ($post_visibility == ITEM_DELETED)
1942 {
1943 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
1944 }
1945 break;
1946
1947 case 'edit_topic':
1948 case 'edit_first_post':
1949 if (isset($poll_ary['poll_options']))
1950 {
1951 $poll_start = ($poll_ary['poll_start'] || empty($poll_ary['poll_options'])) ? $poll_ary['poll_start'] : $current_time;
1952 $poll_length = $poll_ary['poll_length'] * 86400;
1953 if ($poll_length < 0)
1954 {
1955 $poll_start = $poll_start + $poll_length;
1956 if ($poll_start < 0)
1957 {
1958 $poll_start = 0;
1959 }
1960 $poll_length = 1;
1961 }
1962 }
1963
1964 $sql_data[TOPICS_TABLE]['sql'] = array(
1965 'forum_id' => $data_ary['forum_id'],
1966 'icon_id' => $data_ary['icon_id'],
1967 'topic_title' => $subject,
1968 'topic_first_poster_name' => $username,
1969 'topic_type' => $topic_type,
1970 'topic_time_limit' => $topic_type != POST_NORMAL ? ($data_ary['topic_time_limit'] * 86400) : 0,
1971 'poll_title' => (isset($poll_ary['poll_options'])) ? $poll_ary['poll_title'] : '',
1972 'poll_start' => (isset($poll_ary['poll_options'])) ? $poll_start : 0,
1973 'poll_max_options' => (isset($poll_ary['poll_options'])) ? $poll_ary['poll_max_options'] : 1,
1974 'poll_length' => (isset($poll_ary['poll_options'])) ? $poll_length : 0,
1975 'poll_vote_change' => (isset($poll_ary['poll_vote_change'])) ? $poll_ary['poll_vote_change'] : 0,
1976 'topic_last_view_time' => $current_time,
1977
1978 'topic_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : (isset($data_ary['topic_attachment']) ? $data_ary['topic_attachment'] : 0),
1979 );
1980
1981 break;
1982 }
1983
1984 $poll = $poll_ary;
1985 $data = $data_ary;
1986 /**
1987 * Modify sql query data for post submitting
1988 *
1989 * @event core.submit_post_modify_sql_data
1990 * @var array data Array with the data for the post
1991 * @var array poll Array with the poll data for the post
1992 * @var string post_mode Variable containing posting mode value
1993 * @var bool sql_data Array with the data for the posting SQL query
1994 * @var string subject Variable containing post subject value
1995 * @var int topic_type Variable containing topic type value
1996 * @var string username Variable containing post author name
1997 * @since 3.1.3-RC1
1998 */
1999 $vars = array(
2000 'data',
2001 'poll',
2002 'post_mode',
2003 'sql_data',
2004 'subject',
2005 'topic_type',
2006 'username',
2007 );
2008 extract($phpbb_dispatcher->trigger_event('core.submit_post_modify_sql_data', compact($vars)));
2009 $poll_ary = $poll;
2010 $data_ary = $data;
2011 unset($poll);
2012 unset($data);
2013
2014 // Submit new topic
2015 if ($post_mode == 'post')
2016 {
2017 $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' .
2018 $db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']);
2019 $db->sql_query($sql);
2020
2021 $data_ary['topic_id'] = $db->sql_nextid();
2022
2023 $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
2024 'topic_id' => $data_ary['topic_id'])
2025 );
2026 unset($sql_data[TOPICS_TABLE]['sql']);
2027 }
2028
2029 // Submit new post
2030 if ($post_mode == 'post' || $post_mode == 'reply')
2031 {
2032 if ($post_mode == 'reply')
2033 {
2034 $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
2035 'topic_id' => $data_ary['topic_id'],
2036 ));
2037 }
2038
2039 $sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']);
2040 $db->sql_query($sql);
2041 $data_ary['post_id'] = $db->sql_nextid();
2042
2043 if ($post_mode == 'post' || $post_visibility == ITEM_APPROVED)
2044 {
2045 $sql_data[TOPICS_TABLE]['sql'] = array(
2046 'topic_last_post_id' => $data_ary['post_id'],
2047 'topic_last_post_time' => $current_time,
2048 'topic_last_poster_id' => $sql_data[POSTS_TABLE]['sql']['poster_id'],
2049 'topic_last_poster_name' => ($user->data['user_id'] == ANONYMOUS) ? $sql_data[POSTS_TABLE]['sql']['post_username'] : $user->data['username'],
2050 'topic_last_poster_colour' => $user->data['user_colour'],
2051 'topic_last_post_subject' => (string) $subject,
2052 );
2053 }
2054
2055 if ($post_mode == 'post')
2056 {
2057 $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data_ary['post_id'];
2058 }
2059
2060 // Update total post count and forum information
2061 if ($post_visibility == ITEM_APPROVED)
2062 {
2063 if ($post_mode == 'post')
2064 {
2065 $config->increment('num_topics', 1, false);
2066 }
2067 $config->increment('num_posts', 1, false);
2068
2069 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data_ary['post_id'];
2070 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
2071 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
2072 $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
2073 $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'] : '')) . "'";
2074 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'";
2075 }
2076
2077 unset($sql_data[POSTS_TABLE]['sql']);
2078 }
2079
2080 // Update the topics table
2081 if (isset($sql_data[TOPICS_TABLE]['sql']))
2082 {
2083 $sql = 'UPDATE ' . TOPICS_TABLE . '
2084 SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . '
2085 WHERE topic_id = ' . $data_ary['topic_id'];
2086 $db->sql_query($sql);
2087
2088 unset($sql_data[TOPICS_TABLE]['sql']);
2089 }
2090
2091 // Update the posts table
2092 if (isset($sql_data[POSTS_TABLE]['sql']))
2093 {
2094 $sql = 'UPDATE ' . POSTS_TABLE . '
2095 SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . '
2096 WHERE post_id = ' . $data_ary['post_id'];
2097 $db->sql_query($sql);
2098
2099 unset($sql_data[POSTS_TABLE]['sql']);
2100 }
2101
2102 // Update Poll Tables
2103 if (isset($poll_ary['poll_options']))
2104 {
2105 $cur_poll_options = array();
2106
2107 if ($mode == 'edit')
2108 {
2109 $sql = 'SELECT *
2110 FROM ' . POLL_OPTIONS_TABLE . '
2111 WHERE topic_id = ' . $data_ary['topic_id'] . '
2112 ORDER BY poll_option_id';
2113 $result = $db->sql_query($sql);
2114
2115 $cur_poll_options = array();
2116 while ($row = $db->sql_fetchrow($result))
2117 {
2118 $cur_poll_options[] = $row;
2119 }
2120 $db->sql_freeresult($result);
2121 }
2122
2123 $sql_insert_ary = array();
2124
2125 for ($i = 0, $size = count($poll_ary['poll_options']); $i < $size; $i++)
2126 {
2127 if (strlen(trim($poll_ary['poll_options'][$i])))
2128 {
2129 if (empty($cur_poll_options[$i]))
2130 {
2131 // If we add options we need to put them to the end to be able to preserve votes...
2132 $sql_insert_ary[] = array(
2133 'poll_option_id' => (int) count($cur_poll_options) + 1 + count($sql_insert_ary),
2134 'topic_id' => (int) $data_ary['topic_id'],
2135 'poll_option_text' => (string) $poll_ary['poll_options'][$i]
2136 );
2137 }
2138 else if ($poll_ary['poll_options'][$i] != $cur_poll_options[$i])
2139 {
2140 $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . "
2141 SET poll_option_text = '" . $db->sql_escape($poll_ary['poll_options'][$i]) . "'
2142 WHERE poll_option_id = " . $cur_poll_options[$i]['poll_option_id'] . '
2143 AND topic_id = ' . $data_ary['topic_id'];
2144 $db->sql_query($sql);
2145 }
2146 }
2147 }
2148
2149 $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary);
2150
2151 if (count($poll_ary['poll_options']) < count($cur_poll_options))
2152 {
2153 $sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . '
2154 WHERE poll_option_id > ' . count($poll_ary['poll_options']) . '
2155 AND topic_id = ' . $data_ary['topic_id'];
2156 $db->sql_query($sql);
2157 }
2158
2159 // 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
2160 if ($mode == 'edit' && count($poll_ary['poll_options']) != count($cur_poll_options))
2161 {
2162 $db->sql_query('DELETE FROM ' . POLL_VOTES_TABLE . ' WHERE topic_id = ' . $data_ary['topic_id']);
2163 $db->sql_query('UPDATE ' . POLL_OPTIONS_TABLE . ' SET poll_option_total = 0 WHERE topic_id = ' . $data_ary['topic_id']);
2164 }
2165 }
2166
2167 // Submit Attachments
2168 if (!empty($data_ary['attachment_data']) && $data_ary['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit')))
2169 {
2170 $space_taken = $files_added = 0;
2171 $orphan_rows = array();
2172
2173 foreach ($data_ary['attachment_data'] as $pos => $attach_row)
2174 {
2175 $orphan_rows[(int) $attach_row['attach_id']] = array();
2176 }
2177
2178 if (count($orphan_rows))
2179 {
2180 $sql = 'SELECT attach_id, filesize, physical_filename
2181 FROM ' . ATTACHMENTS_TABLE . '
2182 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
2183 AND is_orphan = 1
2184 AND poster_id = ' . $user->data['user_id'];
2185 $result = $db->sql_query($sql);
2186
2187 $orphan_rows = array();
2188 while ($row = $db->sql_fetchrow($result))
2189 {
2190 $orphan_rows[$row['attach_id']] = $row;
2191 }
2192 $db->sql_freeresult($result);
2193 }
2194
2195 foreach ($data_ary['attachment_data'] as $pos => $attach_row)
2196 {
2197 if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
2198 {
2199 continue;
2200 }
2201
2202 if (preg_match('/[\x{10000}-\x{10FFFF}]/u', $attach_row['attach_comment']))
2203 {
2204 trigger_error('ATTACH_COMMENT_NO_EMOJIS');
2205 }
2206
2207 if (!$attach_row['is_orphan'])
2208 {
2209 // update entry in db if attachment already stored in db and filespace
2210 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
2211 SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
2212 WHERE attach_id = " . (int) $attach_row['attach_id'] . '
2213 AND is_orphan = 0';
2214 $db->sql_query($sql);
2215 }
2216 else
2217 {
2218 // insert attachment into db
2219 if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
2220 {
2221 continue;
2222 }
2223
2224 $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
2225 $files_added++;
2226
2227 $attach_sql = array(
2228 'post_msg_id' => $data_ary['post_id'],
2229 'topic_id' => $data_ary['topic_id'],
2230 'is_orphan' => 0,
2231 'poster_id' => $poster_id,
2232 'attach_comment' => $attach_row['attach_comment'],
2233 );
2234
2235 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
2236 WHERE attach_id = ' . $attach_row['attach_id'] . '
2237 AND is_orphan = 1
2238 AND poster_id = ' . $user->data['user_id'];
2239 $db->sql_query($sql);
2240 }
2241 }
2242
2243 if ($space_taken && $files_added)
2244 {
2245 $config->increment('upload_dir_size', $space_taken, false);
2246 $config->increment('num_files', $files_added, false);
2247 }
2248 }
2249
2250 $first_post_has_topic_info = ($post_mode == 'edit_first_post' &&
2251 (($post_visibility == ITEM_DELETED && $data_ary['topic_posts_softdeleted'] == 1) ||
2252 ($post_visibility == ITEM_UNAPPROVED && $data_ary['topic_posts_unapproved'] == 1) ||
2253 ($post_visibility == ITEM_REAPPROVE && $data_ary['topic_posts_unapproved'] == 1) ||
2254 ($post_visibility == ITEM_APPROVED && $data_ary['topic_posts_approved'] == 1)));
2255 // Fix the post's and topic's visibility and first/last post information, when the post is edited
2256 if (($post_mode != 'post' && $post_mode != 'reply') && $data_ary['post_visibility'] != $post_visibility)
2257 {
2258 // If the post was not approved, it could also be the starter,
2259 // so we sync the starter after approving/restoring, to ensure that the stats are correct
2260 // Same applies for the last post
2261 $is_starter = ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic' || $data_ary['post_visibility'] != ITEM_APPROVED);
2262 $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data_ary['post_visibility'] != ITEM_APPROVED);
2263
2264 /* @var $phpbb_content_visibility \phpbb\content_visibility */
2265 $phpbb_content_visibility = $phpbb_container->get('content.visibility');
2266 $phpbb_content_visibility->set_post_visibility($post_visibility, $data_ary['post_id'], $data_ary['topic_id'], $data_ary['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest);
2267 }
2268 else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $first_post_has_topic_info)
2269 {
2270 if ($post_visibility == ITEM_APPROVED || $data_ary['topic_visibility'] == $post_visibility)
2271 {
2272 // only the subject can be changed from edit
2273 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
2274
2275 // Maybe not only the subject, but also changing anonymous usernames. ;)
2276 if ($data_ary['poster_id'] == ANONYMOUS)
2277 {
2278 $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'";
2279 }
2280
2281 if ($post_visibility == ITEM_APPROVED)
2282 {
2283 // this does not _necessarily_ mean that we must update the info again,
2284 // it just means that we might have to
2285 $sql = 'SELECT forum_last_post_id, forum_last_post_subject
2286 FROM ' . FORUMS_TABLE . '
2287 WHERE forum_id = ' . (int) $data_ary['forum_id'];
2288 $result = $db->sql_query($sql);
2289 $row = $db->sql_fetchrow($result);
2290 $db->sql_freeresult($result);
2291
2292 // this post is the latest post in the forum, better update
2293 if ($row['forum_last_post_id'] == $data_ary['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data_ary['poster_id'] == ANONYMOUS))
2294 {
2295 // the post's subject changed
2296 if ($row['forum_last_post_subject'] !== $subject)
2297 {
2298 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
2299 }
2300
2301 // Update the user name if poster is anonymous... just in case a moderator changed it
2302 if ($data_ary['poster_id'] == ANONYMOUS)
2303 {
2304 $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
2305 }
2306 }
2307 }
2308 }
2309 }
2310
2311 // Update forum stats
2312 $where_sql = array(
2313 POSTS_TABLE => 'post_id = ' . $data_ary['post_id'],
2314 TOPICS_TABLE => 'topic_id = ' . $data_ary['topic_id'],
2315 FORUMS_TABLE => 'forum_id = ' . $data_ary['forum_id'],
2316 USERS_TABLE => 'user_id = ' . $poster_id
2317 );
2318
2319 foreach ($sql_data as $table => $update_ary)
2320 {
2321 if (isset($update_ary['stat']) && implode('', $update_ary['stat']))
2322 {
2323 $sql = "UPDATE $table SET " . implode(', ', $update_ary['stat']) . ' WHERE ' . $where_sql[$table];
2324 $db->sql_query($sql);
2325 }
2326 }
2327
2328 // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement
2329 if ($topic_type == POST_GLOBAL)
2330 {
2331 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
2332 WHERE topic_moved_id = ' . $data_ary['topic_id'];
2333 $db->sql_query($sql);
2334 }
2335
2336 // Committing the transaction before updating search index
2337 $db->sql_transaction('commit');
2338
2339 // Delete draft if post was loaded...
2340 $draft_id = $request->variable('draft_loaded', 0);
2341 if ($draft_id)
2342 {
2343 $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
2344 WHERE draft_id = $draft_id
2345 AND user_id = {$user->data['user_id']}";
2346 $db->sql_query($sql);
2347 }
2348
2349 // Index message contents
2350 if ($update_search_index && $data_ary['enable_indexing'])
2351 {
2352 // Select the search method and do some additional checks to ensure it can actually be utilised
2353 $search_type = $config['search_type'];
2354
2355 if (!class_exists($search_type))
2356 {
2357 trigger_error('NO_SUCH_SEARCH_MODULE');
2358 }
2359
2360 $error = false;
2361 $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
2362
2363 if ($error)
2364 {
2365 trigger_error($error);
2366 }
2367
2368 $search->index($mode, $data_ary['post_id'], $data_ary['message'], $subject, $poster_id, $data_ary['forum_id']);
2369 }
2370
2371 // Topic Notification, do not change if moderator is changing other users posts...
2372 if ($user->data['user_id'] == $poster_id)
2373 {
2374 if (!$data_ary['notify_set'] && $data_ary['notify'])
2375 {
2376 $sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id)
2377 VALUES (' . $user->data['user_id'] . ', ' . $data_ary['topic_id'] . ')';
2378 $db->sql_query($sql);
2379 }
2380 else if (($config['email_enable'] || $config['jab_enable']) && $data_ary['notify_set'] && !$data_ary['notify'])
2381 {
2382 $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . '
2383 WHERE user_id = ' . $user->data['user_id'] . '
2384 AND topic_id = ' . $data_ary['topic_id'];
2385 $db->sql_query($sql);
2386 }
2387 }
2388
2389 if ($mode == 'post' || $mode == 'reply' || $mode == 'quote')
2390 {
2391 // Mark this topic as posted to
2392 markread('post', $data_ary['forum_id'], $data_ary['topic_id']);
2393 }
2394
2395 // Mark this topic as read
2396 // We do not use post_time here, this is intended (post_time can have a date in the past if editing a message)
2397 markread('topic', $data_ary['forum_id'], $data_ary['topic_id'], time());
2398
2399 //
2400 if ($config['load_db_lastread'] && $user->data['is_registered'])
2401 {
2402 $sql = 'SELECT mark_time
2403 FROM ' . FORUMS_TRACK_TABLE . '
2404 WHERE user_id = ' . $user->data['user_id'] . '
2405 AND forum_id = ' . $data_ary['forum_id'];
2406 $result = $db->sql_query($sql);
2407 $f_mark_time = (int) $db->sql_fetchfield('mark_time');
2408 $db->sql_freeresult($result);
2409 }
2410 else if ($config['load_anon_lastread'] || $user->data['is_registered'])
2411 {
2412 $f_mark_time = false;
2413 }
2414
2415 if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
2416 {
2417 // Update forum info
2418 $sql = 'SELECT forum_last_post_time
2419 FROM ' . FORUMS_TABLE . '
2420 WHERE forum_id = ' . $data_ary['forum_id'];
2421 $result = $db->sql_query($sql);
2422 $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
2423 $db->sql_freeresult($result);
2424
2425 update_forum_tracking_info($data_ary['forum_id'], $forum_last_post_time, $f_mark_time, false);
2426 }
2427
2428 // If a username was supplied or the poster is a guest, we will use the supplied username.
2429 // Doing it this way we can use "...post by guest-username..." in notifications when
2430 // "guest-username" is supplied or ommit the username if it is not.
2431 $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username'];
2432
2433 // Send Notifications
2434 $notification_data = array_merge($data_ary, array(
2435 'topic_title' => (isset($data_ary['topic_title'])) ? $data_ary['topic_title'] : $subject,
2436 'post_username' => $username,
2437 'poster_id' => $poster_id,
2438 'post_text' => $data_ary['message'],
2439 'post_time' => $current_time,
2440 'post_subject' => $subject,
2441 ));
2442
2443 /**
2444 * This event allows you to modify the notification data upon submission
2445 *
2446 * @event core.modify_submit_notification_data
2447 * @var array notification_data The notification data to be inserted in to the database
2448 * @var array data_ary The data array with a lot of the post submission data
2449 * @var string mode The posting mode
2450 * @var int poster_id The poster id
2451 * @since 3.2.4-RC1
2452 */
2453 $vars = array('notification_data', 'data_ary', 'mode', 'poster_id');
2454 extract($phpbb_dispatcher->trigger_event('core.modify_submit_notification_data', compact($vars)));
2455
2456 /* @var $phpbb_notifications \phpbb\notification\manager */
2457 $phpbb_notifications = $phpbb_container->get('notification_manager');
2458
2459 if ($post_visibility == ITEM_APPROVED)
2460 {
2461 switch ($mode)
2462 {
2463 case 'post':
2464 $phpbb_notifications->add_notifications(array(
2465 'notification.type.quote',
2466 'notification.type.topic',
2467 ), $notification_data);
2468 break;
2469
2470 case 'reply':
2471 case 'quote':
2472 $phpbb_notifications->add_notifications(array(
2473 'notification.type.quote',
2474 'notification.type.bookmark',
2475 'notification.type.post',
2476 'notification.type.forum',
2477 ), $notification_data);
2478 break;
2479
2480 case 'edit_topic':
2481 case 'edit_first_post':
2482 case 'edit':
2483 case 'edit_last_post':
2484 if ($user->data['user_id'] == $poster_id)
2485 {
2486 $phpbb_notifications->update_notifications(array(
2487 'notification.type.quote',
2488 ), $notification_data);
2489 }
2490
2491 $phpbb_notifications->update_notifications(array(
2492 'notification.type.bookmark',
2493 'notification.type.topic',
2494 'notification.type.post',
2495 'notification.type.forum',
2496 ), $notification_data);
2497 break;
2498 }
2499 }
2500 else if ($post_visibility == ITEM_UNAPPROVED)
2501 {
2502 switch ($mode)
2503 {
2504 case 'post':
2505 $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data);
2506 break;
2507
2508 case 'reply':
2509 case 'quote':
2510 $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data);
2511 break;
2512
2513 case 'edit_topic':
2514 case 'edit_first_post':
2515 case 'edit':
2516 case 'edit_last_post':
2517 // Nothing to do here
2518 break;
2519 }
2520 }
2521 else if ($post_visibility == ITEM_REAPPROVE)
2522 {
2523 switch ($mode)
2524 {
2525 case 'edit_topic':
2526 case 'edit_first_post':
2527 $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data);
2528
2529 // Delete the approve_post notification so we can notify the user again,
2530 // when his post got reapproved
2531 $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']);
2532 break;
2533
2534 case 'edit':
2535 case 'edit_last_post':
2536 $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data);
2537
2538 // Delete the approve_post notification so we can notify the user again,
2539 // when his post got reapproved
2540 $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']);
2541 break;
2542
2543 case 'post':
2544 case 'reply':
2545 case 'quote':
2546 // Nothing to do here
2547 break;
2548 }
2549 }
2550 else if ($post_visibility == ITEM_DELETED)
2551 {
2552 switch ($mode)
2553 {
2554 case 'post':
2555 case 'reply':
2556 case 'quote':
2557 case 'edit_topic':
2558 case 'edit_first_post':
2559 case 'edit':
2560 case 'edit_last_post':
2561 // Nothing to do here
2562 break;
2563 }
2564 }
2565
2566 $params = [];
2567 $add_anchor = '';
2568 $url = "{$phpbb_root_path}viewtopic.$phpEx";
2569
2570 if ($post_visibility == ITEM_APPROVED ||
2571 ($auth->acl_get('m_softdelete', $data_ary['forum_id']) && $post_visibility == ITEM_DELETED) ||
2572 ($auth->acl_get('m_approve', $data_ary['forum_id']) && in_array($post_visibility, array(ITEM_UNAPPROVED, ITEM_REAPPROVE))))
2573 {
2574 if ($mode != 'post')
2575 {
2576 $params['p'] = $data_ary['post_id'];
2577 $add_anchor = '#p' . $data_ary['post_id'];
2578 }
2579 else
2580 {
2581 $params['t'] = $data_ary['topic_id'];
2582 }
2583 }
2584 else if ($mode != 'post' && $post_mode != 'edit_first_post' && $post_mode != 'edit_topic')
2585 {
2586 $params['t'] = $data_ary['topic_id'];
2587 }
2588 else
2589 {
2590 $url = "{$phpbb_root_path}viewforum.$phpEx";
2591 $params['f'] = $data_ary['forum_id'];
2592 }
2593
2594 $url = append_sid($url, $params) . $add_anchor;
2595
2596 $poll = $poll_ary;
2597 $data = $data_ary;
2598 /**
2599 * This event is used for performing actions directly after a post or topic
2600 * has been submitted. When a new topic is posted, the topic ID is
2601 * available in the $data array.
2602 *
2603 * The only action that can be done by altering data made available to this
2604 * event is to modify the return URL ($url).
2605 *
2606 * @event core.submit_post_end
2607 * @var string mode Variable containing posting mode value
2608 * @var string subject Variable containing post subject value
2609 * @var string username Variable containing post author name
2610 * @var int topic_type Variable containing topic type value
2611 * @var array poll Array with the poll data for the post
2612 * @var array data Array with the data for the post
2613 * @var int post_visibility Variable containing up to date post visibility
2614 * @var bool update_message Flag indicating if the post will be updated
2615 * @var bool update_search_index Flag indicating if the search index will be updated
2616 * @var string url The "Return to topic" URL
2617 *
2618 * @since 3.1.0-a3
2619 * @changed 3.1.0-RC3 Added vars mode, subject, username, topic_type,
2620 * poll, update_message, update_search_index
2621 */
2622 $vars = array(
2623 'mode',
2624 'subject',
2625 'username',
2626 'topic_type',
2627 'poll',
2628 'data',
2629 'post_visibility',
2630 'update_message',
2631 'update_search_index',
2632 'url',
2633 );
2634 extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars)));
2635 $data_ary = $data;
2636 $poll_ary = $poll;
2637 unset($data);
2638 unset($poll);
2639
2640 return $url;
2641 }
2642
2643 /**
2644 * Handle topic bumping
2645 * @param int $forum_id The ID of the forum the topic is being bumped belongs to
2646 * @param int $topic_id The ID of the topic is being bumping
2647 * @param array $post_data Passes some topic parameters:
2648 * - 'topic_title'
2649 * - 'topic_last_post_id'
2650 * - 'topic_last_poster_id'
2651 * - 'topic_last_post_subject'
2652 * - 'topic_last_poster_name'
2653 * - 'topic_last_poster_colour'
2654 * @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time().
2655 * @return string An URL to the bumped topic, example: ./viewtopic.php?p=3#p3
2656 */
2657 function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false)
2658 {
2659 global $config, $db, $user, $phpEx, $phpbb_root_path, $phpbb_log;
2660
2661 if ($bump_time === false)
2662 {
2663 $bump_time = time();
2664 }
2665
2666 // Begin bumping
2667 $db->sql_transaction('begin');
2668
2669 // Update the topic's last post post_time
2670 $sql = 'UPDATE ' . POSTS_TABLE . "
2671 SET post_time = $bump_time
2672 WHERE post_id = {$post_data['topic_last_post_id']}
2673 AND topic_id = $topic_id";
2674 $db->sql_query($sql);
2675
2676 // Sync the topic's last post time, the rest of the topic's last post data isn't changed
2677 $sql = 'UPDATE ' . TOPICS_TABLE . "
2678 SET topic_last_post_time = $bump_time,
2679 topic_bumped = 1,
2680 topic_bumper = " . $user->data['user_id'] . "
2681 WHERE topic_id = $topic_id";
2682 $db->sql_query($sql);
2683
2684 // Update the forum's last post info
2685 $sql = 'UPDATE ' . FORUMS_TABLE . "
2686 SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ",
2687 forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ",
2688 forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "',
2689 forum_last_post_time = $bump_time,
2690 forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "',
2691 forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "'
2692 WHERE forum_id = $forum_id";
2693 $db->sql_query($sql);
2694
2695 // Update bumper's time of the last posting to prevent flood
2696 $sql = 'UPDATE ' . USERS_TABLE . "
2697 SET user_lastpost_time = $bump_time
2698 WHERE user_id = " . $user->data['user_id'];
2699 $db->sql_query($sql);
2700
2701 $db->sql_transaction('commit');
2702
2703 // Mark this topic as posted to
2704 markread('post', $forum_id, $topic_id, $bump_time);
2705
2706 // Mark this topic as read
2707 markread('topic', $forum_id, $topic_id, $bump_time);
2708
2709 // Update forum tracking info
2710 if ($config['load_db_lastread'] && $user->data['is_registered'])
2711 {
2712 $sql = 'SELECT mark_time
2713 FROM ' . FORUMS_TRACK_TABLE . '
2714 WHERE user_id = ' . $user->data['user_id'] . '
2715 AND forum_id = ' . $forum_id;
2716 $result = $db->sql_query($sql);
2717 $f_mark_time = (int) $db->sql_fetchfield('mark_time');
2718 $db->sql_freeresult($result);
2719 }
2720 else if ($config['load_anon_lastread'] || $user->data['is_registered'])
2721 {
2722 $f_mark_time = false;
2723 }
2724
2725 if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered'])
2726 {
2727 // Update forum info
2728 $sql = 'SELECT forum_last_post_time
2729 FROM ' . FORUMS_TABLE . '
2730 WHERE forum_id = ' . $forum_id;
2731 $result = $db->sql_query($sql);
2732 $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
2733 $db->sql_freeresult($result);
2734
2735 update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false);
2736 }
2737
2738 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_BUMP_TOPIC', false, array(
2739 'forum_id' => $forum_id,
2740 'topic_id' => $topic_id,
2741 $post_data['topic_title']
2742 ));
2743
2744 $url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}";
2745
2746 return $url;
2747 }
2748
2749 /**
2750 * Show upload popup (progress bar)
2751 */
2752 function phpbb_upload_popup($forum_style = 0)
2753 {
2754 global $template, $user;
2755
2756 ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting');
2757
2758 page_header($user->lang['PROGRESS_BAR']);
2759
2760 $template->set_filenames(array(
2761 'popup' => 'posting_progress_bar.html')
2762 );
2763
2764 $template->assign_vars(array(
2765 'PROGRESS_BAR' => $user->img('upload_bar', $user->lang['UPLOAD_IN_PROGRESS']))
2766 );
2767
2768 $template->display('popup');
2769
2770 garbage_collection();
2771 exit_handler();
2772 }
2773
2774 /**
2775 * Do the various checks required for removing posts as well as removing it
2776 *
2777 * @param int $forum_id The id of the forum
2778 * @param int $topic_id The id of the topic
2779 * @param int $post_id The id of the post
2780 * @param array $post_data Array with the post data
2781 * @param bool $is_soft The flag indicating whether it is the soft delete mode
2782 * @param string $delete_reason Description for the post deletion reason
2783 *
2784 * @return null
2785 */
2786 function phpbb_handle_post_delete($forum_id, $topic_id, $post_id, &$post_data, $is_soft = false, $delete_reason = '')
2787 {
2788 global $user, $auth, $config, $request;
2789 global $phpbb_root_path, $phpEx, $phpbb_log, $phpbb_dispatcher;
2790
2791 $force_delete_allowed = $force_softdelete_allowed = false;
2792 $perm_check = ($is_soft) ? 'softdelete' : 'delete';
2793
2794 /**
2795 * This event allows to modify the conditions for the post deletion
2796 *
2797 * @event core.handle_post_delete_conditions
2798 * @var int forum_id The id of the forum
2799 * @var int topic_id The id of the topic
2800 * @var int post_id The id of the post
2801 * @var array post_data Array with the post data
2802 * @var bool is_soft The flag indicating whether it is the soft delete mode
2803 * @var string delete_reason Description for the post deletion reason
2804 * @var bool force_delete_allowed Allow the user to delete the post (all permissions and conditions are ignored)
2805 * @var bool force_softdelete_allowed Allow the user to softdelete the post (all permissions and conditions are ignored)
2806 * @var string perm_check The deletion mode softdelete|delete
2807 * @since 3.1.11-RC1
2808 */
2809 $vars = array(
2810 'forum_id',
2811 'topic_id',
2812 'post_id',
2813 'post_data',
2814 'is_soft',
2815 'delete_reason',
2816 'force_delete_allowed',
2817 'force_softdelete_allowed',
2818 'perm_check',
2819 );
2820 extract($phpbb_dispatcher->trigger_event('core.handle_post_delete_conditions', compact($vars)));
2821
2822 // If moderator removing post or user itself removing post, present a confirmation screen
2823 if ($force_delete_allowed || ($is_soft && $force_softdelete_allowed) || $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'])))
2824 {
2825 $s_hidden_fields = array(
2826 'p' => $post_id,
2827 'f' => $forum_id,
2828 'mode' => ($is_soft) ? 'soft_delete' : 'delete',
2829 );
2830
2831 if (confirm_box(true))
2832 {
2833 $data = array(
2834 'topic_first_post_id' => $post_data['topic_first_post_id'],
2835 'topic_last_post_id' => $post_data['topic_last_post_id'],
2836 'topic_posts_approved' => $post_data['topic_posts_approved'],
2837 'topic_posts_unapproved' => $post_data['topic_posts_unapproved'],
2838 'topic_posts_softdeleted' => $post_data['topic_posts_softdeleted'],
2839 'topic_visibility' => $post_data['topic_visibility'],
2840 'topic_type' => $post_data['topic_type'],
2841 'post_visibility' => $post_data['post_visibility'],
2842 'post_reported' => $post_data['post_reported'],
2843 'post_time' => $post_data['post_time'],
2844 'poster_id' => $post_data['poster_id'],
2845 'post_postcount' => $post_data['post_postcount'],
2846 );
2847
2848 $next_post_id = delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $delete_reason);
2849 $post_username = ($post_data['poster_id'] == ANONYMOUS && !empty($post_data['post_username'])) ? $post_data['post_username'] : $post_data['username'];
2850
2851 if ($next_post_id === false)
2852 {
2853 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, (($is_soft) ? 'LOG_SOFTDELETE_TOPIC' : 'LOG_DELETE_TOPIC'), false, array(
2854 'forum_id' => $forum_id,
2855 'topic_id' => $topic_id,
2856 $post_data['topic_title'],
2857 $post_username,
2858 $delete_reason
2859 ));
2860
2861 $meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id");
2862 $message = $user->lang['POST_DELETED'];
2863 }
2864 else
2865 {
2866 $phpbb_log->add('mod', $user->data['user_id'], $user->ip, (($is_soft) ? 'LOG_SOFTDELETE_POST' : 'LOG_DELETE_POST'), false, array(
2867 'forum_id' => $forum_id,
2868 'topic_id' => $topic_id,
2869 'post_id' => $post_id,
2870 $post_data['post_subject'],
2871 $post_username,
2872 $delete_reason
2873 ));
2874
2875 if ($next_post_id > 0)
2876 {
2877 $meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "p=$next_post_id") . "#p$next_post_id";
2878 }
2879 else
2880 {
2881 $meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id");
2882 }
2883 $message = $user->lang['POST_DELETED'];
2884
2885 if (!$request->is_ajax())
2886 {
2887 $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $meta_info . '">', '</a>');
2888 }
2889 }
2890
2891 meta_refresh(3, $meta_info);
2892 if (!$request->is_ajax())
2893 {
2894 $message .= '<br /><br />' . $user->lang('RETURN_FORUM', '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
2895 }
2896 trigger_error($message);
2897 }
2898 else
2899 {
2900 global $template;
2901
2902 $can_delete = $force_delete_allowed || ($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)));
2903 $can_softdelete = $force_softdelete_allowed || ($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)));
2904
2905 $template->assign_vars(array(
2906 'S_SOFTDELETED' => $post_data['post_visibility'] == ITEM_DELETED,
2907 'S_CHECKED_PERMANENT' => $request->is_set_post('delete_permanent') ? ' checked="checked"' : '',
2908 'S_ALLOWED_DELETE' => $can_delete,
2909 'S_ALLOWED_SOFTDELETE' => $can_softdelete,
2910 ));
2911
2912 $l_confirm = 'DELETE_POST';
2913 if ($post_data['post_visibility'] == ITEM_DELETED)
2914 {
2915 $l_confirm .= '_PERMANENTLY';
2916 $s_hidden_fields['delete_permanent'] = '1';
2917 }
2918 else if (!$can_softdelete)
2919 {
2920 $s_hidden_fields['delete_permanent'] = '1';
2921 }
2922
2923 confirm_box(false, [$l_confirm, 1], build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
2924 }
2925 }
2926
2927 // If we are here the user is not able to delete - present the correct error message
2928 if ($post_data['poster_id'] != $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id))
2929 {
2930 trigger_error('DELETE_OWN_POSTS');
2931 }
2932
2933 if ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && $post_id != $post_data['topic_last_post_id'])
2934 {
2935 trigger_error('CANNOT_DELETE_REPLIED');
2936 }
2937
2938 trigger_error('USER_CANNOT_DELETE');
2939 }
2940