[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 /** 15 * @ignore 16 */ 17 if (!defined('IN_PHPBB')) 18 { 19 exit; 20 } 21 22 /** 23 * Fill smiley templates (or just the variables) with smilies, either in a window or inline 24 */ 25 function generate_smilies($mode, $forum_id) 26 { 27 global $db, $user, $config, $template, $phpbb_dispatcher, $request; 28 global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper; 29 30 /* @var $pagination \phpbb\pagination */ 31 $pagination = $phpbb_container->get('pagination'); 32 $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id); 33 $start = $request->variable('start', 0); 34 35 if ($mode == 'window') 36 { 37 if ($forum_id) 38 { 39 $sql = 'SELECT forum_style 40 FROM ' . FORUMS_TABLE . " 41 WHERE forum_id = $forum_id"; 42 $result = $db->sql_query_limit($sql, 1); 43 $row = $db->sql_fetchrow($result); 44 $db->sql_freeresult($result); 45 46 $user->setup('posting', (int) $row['forum_style']); 47 } 48 else 49 { 50 $user->setup('posting'); 51 } 52 53 page_header($user->lang['SMILIES']); 54 55 $sql_ary = [ 56 'SELECT' => 'COUNT(s.smiley_id) AS item_count', 57 'FROM' => [ 58 SMILIES_TABLE => 's', 59 ], 60 'GROUP_BY' => 's.smiley_url', 61 ]; 62 63 /** 64 * Modify SQL query that fetches the total number of smilies in window mode 65 * 66 * @event core.generate_smilies_count_sql_before 67 * @var int forum_id Forum where smilies are generated 68 * @var array sql_ary Array with the SQL query 69 * @var string base_url URL for the "More smilies" link and its pagination 70 * @since 3.2.9-RC1 71 * @changed 3.2.10-RC1 Added base_url 72 */ 73 $vars = [ 74 'forum_id', 75 'sql_ary', 76 'base_url', 77 ]; 78 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_count_sql_before', compact($vars))); 79 80 $sql = $db->sql_build_query('SELECT', $sql_ary); 81 $result = $db->sql_query($sql, 3600); 82 83 $smiley_count = 0; 84 while ($row = $db->sql_fetchrow($result)) 85 { 86 ++$smiley_count; 87 } 88 $db->sql_freeresult($result); 89 90 $template->set_filenames(array( 91 'body' => 'posting_smilies.html') 92 ); 93 94 $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count); 95 $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start); 96 } 97 98 $display_link = false; 99 if ($mode == 'inline') 100 { 101 $sql = 'SELECT smiley_id 102 FROM ' . SMILIES_TABLE . ' 103 WHERE display_on_posting = 0'; 104 $result = $db->sql_query_limit($sql, 1, 0, 3600); 105 106 if ($row = $db->sql_fetchrow($result)) 107 { 108 $display_link = true; 109 } 110 $db->sql_freeresult($result); 111 } 112 113 if ($mode == 'window') 114 { 115 $sql_ary = [ 116 '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', 117 'FROM' => [ 118 SMILIES_TABLE => 's', 119 ], 120 'GROUP_BY' => 's.smiley_url, s.smiley_width, s.smiley_height', 121 'ORDER_BY' => $db->sql_quote('min_smiley_order'), 122 ]; 123 } 124 else 125 { 126 $sql_ary = [ 127 'SELECT' => 's.*', 128 'FROM' => [ 129 SMILIES_TABLE => 's', 130 ], 131 'WHERE' => 's.display_on_posting = 1', 132 'ORDER_BY' => 's.smiley_order', 133 ]; 134 } 135 136 /** 137 * Modify the SQL query that fetches the smilies 138 * 139 * @event core.generate_smilies_modify_sql 140 * @var string mode Smiley mode, either window or inline 141 * @var int forum_id Forum where smilies are generated, or 0 if composing a private message 142 * @var array sql_ary Array with SQL query data 143 * @since 3.2.10-RC1 144 * @since 3.3.1-RC1 145 */ 146 $vars = [ 147 'mode', 148 'forum_id', 149 'sql_ary', 150 ]; 151 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_modify_sql', compact($vars))); 152 153 $sql = $db->sql_build_query('SELECT', $sql_ary); 154 155 if ($mode == 'window') 156 { 157 $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600); 158 } 159 else 160 { 161 $result = $db->sql_query($sql, 3600); 162 } 163 164 $smilies = array(); 165 while ($row = $db->sql_fetchrow($result)) 166 { 167 if (empty($smilies[$row['smiley_url']])) 168 { 169 $smilies[$row['smiley_url']] = $row; 170 } 171 } 172 $db->sql_freeresult($result); 173 174 /** 175 * Modify smilies before they are assigned to the template 176 * 177 * @event core.generate_smilies_modify_rowset 178 * @var string mode Smiley mode, either window or inline 179 * @var int forum_id Forum where smilies are generated, or 0 if composing a private message 180 * @var array smilies Smiley rows fetched from the database 181 * @since 3.2.9-RC1 182 */ 183 $vars = [ 184 'mode', 185 'forum_id', 186 'smilies', 187 ]; 188 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_modify_rowset', compact($vars))); 189 190 if (count($smilies)) 191 { 192 $root_path = $phpbb_path_helper->get_web_root_path(); 193 194 foreach ($smilies as $row) 195 { 196 /** 197 * Modify smiley root path before populating smiley list 198 * 199 * @event core.generate_smilies_before 200 * @var string root_path root_path for smilies 201 * @since 3.1.11-RC1 202 */ 203 $vars = array('root_path'); 204 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_before', compact($vars))); 205 $template->assign_block_vars('smiley', array( 206 'SMILEY_CODE' => $row['code'], 207 'A_SMILEY_CODE' => addslashes($row['code']), 208 'SMILEY_IMG' => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'], 209 'SMILEY_WIDTH' => $row['smiley_width'], 210 'SMILEY_HEIGHT' => $row['smiley_height'], 211 'SMILEY_DESC' => $row['emotion']) 212 ); 213 } 214 } 215 216 /** 217 * This event is called after the smilies are populated 218 * 219 * @event core.generate_smilies_after 220 * @var string mode Mode of the smilies: window|inline 221 * @var int forum_id The forum ID we are currently in 222 * @var bool display_link Shall we display the "more smilies" link? 223 * @var string base_url URL for the "More smilies" link and its pagination 224 * @since 3.1.0-a1 225 * @changed 3.2.10-RC1 Added base_url 226 */ 227 $vars = [ 228 'mode', 229 'forum_id', 230 'display_link', 231 'base_url', 232 ]; 233 extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars))); 234 235 if ($mode == 'inline' && $display_link) 236 { 237 $template->assign_vars(array( 238 'S_SHOW_SMILEY_LINK' => true, 239 'U_MORE_SMILIES' => $base_url, 240 )); 241 } 242 243 if ($mode == 'window') 244 { 245 page_footer(); 246 } 247 } 248 249 /** 250 * Update last post information 251 * Should be used instead of sync() if only the last post information are out of sync... faster 252 * 253 * @param string $type Can be forum|topic 254 * @param mixed $ids topic/forum ids 255 * @param bool $return_update_sql true: SQL query shall be returned, false: execute SQL 256 */ 257 function update_post_information($type, $ids, $return_update_sql = false) 258 { 259 global $db, $phpbb_dispatcher; 260 261 if (empty($ids)) 262 { 263 return; 264 } 265 if (!is_array($ids)) 266 { 267 $ids = array($ids); 268 } 269 270 $update_sql = $empty_forums = $not_empty_forums = array(); 271 272 if ($type != 'topic') 273 { 274 $topic_join = ', ' . TOPICS_TABLE . ' t'; 275 $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED; 276 } 277 else 278 { 279 $topic_join = ''; 280 $topic_condition = ''; 281 } 282 283 if (count($ids) == 1) 284 { 285 $sql = 'SELECT p.post_id as last_post_id 286 FROM ' . POSTS_TABLE . " p $topic_join 287 WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . " 288 $topic_condition 289 AND p.post_visibility = " . ITEM_APPROVED . " 290 ORDER BY p.post_id DESC"; 291 $result = $db->sql_query_limit($sql, 1); 292 } 293 else 294 { 295 $sql = 'SELECT p.' . $type . '_id, MAX(p.post_id) as last_post_id 296 FROM ' . POSTS_TABLE . " p $topic_join 297 WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . " 298 $topic_condition 299 AND p.post_visibility = " . ITEM_APPROVED . " 300 GROUP BY p.{$type}_id"; 301 $result = $db->sql_query($sql); 302 } 303 304 $last_post_ids = array(); 305 while ($row = $db->sql_fetchrow($result)) 306 { 307 if (count($ids) == 1) 308 { 309 $row[$type . '_id'] = $ids[0]; 310 } 311 312 if ($type == 'forum') 313 { 314 $not_empty_forums[] = $row['forum_id']; 315 316 if (empty($row['last_post_id'])) 317 { 318 $empty_forums[] = $row['forum_id']; 319 } 320 } 321 322 $last_post_ids[] = $row['last_post_id']; 323 } 324 $db->sql_freeresult($result); 325 326 if ($type == 'forum') 327 { 328 $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums)); 329 330 foreach ($empty_forums as $void => $forum_id) 331 { 332 $update_sql[$forum_id][] = 'forum_last_post_id = 0'; 333 $update_sql[$forum_id][] = "forum_last_post_subject = ''"; 334 $update_sql[$forum_id][] = 'forum_last_post_time = 0'; 335 $update_sql[$forum_id][] = 'forum_last_poster_id = 0'; 336 $update_sql[$forum_id][] = "forum_last_poster_name = ''"; 337 $update_sql[$forum_id][] = "forum_last_poster_colour = ''"; 338 } 339 } 340 341 if (count($last_post_ids)) 342 { 343 $sql_ary = array( 344 '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', 345 'FROM' => array( 346 POSTS_TABLE => 'p', 347 USERS_TABLE => 'u', 348 ), 349 'WHERE' => $db->sql_in_set('p.post_id', $last_post_ids) . ' 350 AND p.poster_id = u.user_id', 351 ); 352 353 /** 354 * Event to modify the SQL array to get the post and user data from all last posts 355 * 356 * @event core.update_post_info_modify_posts_sql 357 * @var string type The table being updated (forum or topic) 358 * @var array sql_ary SQL array to get some of the last posts' data 359 * @since 3.3.5-RC1 360 */ 361 $vars = [ 362 'type', 363 'sql_ary', 364 ]; 365 extract($phpbb_dispatcher->trigger_event('core.update_post_info_modify_posts_sql', compact($vars))); 366 $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); 367 368 $rowset = array(); 369 while ($row = $db->sql_fetchrow($result)) 370 { 371 $rowset[] = $row; 372 $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id']; 373 $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; 374 $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time']; 375 $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id']; 376 $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; 377 $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; 378 } 379 $db->sql_freeresult($result); 380 381 /** 382 * Event to modify the update_sql array to add new update data for forum or topic last posts 383 * 384 * @event core.update_post_info_modify_sql 385 * @var string type The table being updated (forum or topic) 386 * @var array rowset Array with the posts data 387 * @var array update_sql Array with SQL data to update the forums or topics table with 388 * @since 3.3.5-RC1 389 */ 390 $vars = [ 391 'type', 392 'rowset', 393 'update_sql', 394 ]; 395 extract($phpbb_dispatcher->trigger_event('core.update_post_info_modify_sql', compact($vars))); 396 unset($rowset); 397 } 398 unset($empty_forums, $ids, $last_post_ids); 399 400 if ($return_update_sql || !count($update_sql)) 401 { 402 return $update_sql; 403 } 404 405 $table = ($type == 'forum') ? FORUMS_TABLE : TOPICS_TABLE; 406 407 foreach ($update_sql as $update_id => $update_sql_ary) 408 { 409 $sql = "UPDATE $table 410 SET " . implode(', ', $update_sql_ary) . " 411 WHERE {$type}_id = $update_id"; 412 $db->sql_query($sql); 413 } 414 415 return; 416 } 417 418 /** 419 * Generate Topic Icons for display 420 */ 421 function posting_gen_topic_icons($mode, $icon_id) 422 { 423 global $phpbb_root_path, $phpbb_path_helper, $config, $template, $cache; 424 425 // Grab icons 426 $icons = $cache->obtain_icons(); 427 428 if (!$icon_id) 429 { 430 $template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"'); 431 } 432 433 if (count($icons)) 434 { 435 $root_path = $phpbb_path_helper->get_web_root_path(); 436 437 foreach ($icons as $id => $data) 438 { 439 if ($data['display']) 440 { 441 $template->assign_block_vars('topic_icon', array( 442 'ICON_ID' => $id, 443 'ICON_IMG' => $root_path . $config['icons_path'] . '/' . $data['img'], 444 'ICON_WIDTH' => $data['width'], 445 'ICON_HEIGHT' => $data['height'], 446 'ICON_ALT' => $data['alt'], 447 448 'S_CHECKED' => ($id == $icon_id) ? true : false, 449 'S_ICON_CHECKED' => ($id == $icon_id) ? ' checked="checked"' : '') 450 ); 451 } 452 } 453 454 return true; 455 } 456 457 return false; 458 } 459 460 /** 461 * Build topic types able to be selected 462 */ 463 function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL) 464 { 465 global $auth, $user, $template; 466 467 $toggle = false; 468 469 $topic_types = array( 470 'sticky' => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'), 471 'announce' => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'), 472 'announce_global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL') 473 ); 474 475 $topic_type_array = array(); 476 477 foreach ($topic_types as $auth_key => $topic_value) 478 { 479 if ($auth->acl_get('f_' . $auth_key, $forum_id)) 480 { 481 $toggle = true; 482 483 $topic_type_array[] = array( 484 'VALUE' => $topic_value['const'], 485 'S_CHECKED' => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '', 486 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']] 487 ); 488 } 489 } 490 491 if ($toggle) 492 { 493 $topic_type_array = array_merge(array(0 => array( 494 'VALUE' => POST_NORMAL, 495 'S_CHECKED' => ($cur_topic_type == POST_NORMAL) ? ' checked="checked"' : '', 496 'L_TOPIC_TYPE' => $user->lang['POST_NORMAL'])), 497 498 $topic_type_array 499 ); 500 501 foreach ($topic_type_array as $array) 502 { 503 $template->assign_block_vars('topic_type', $array); 504 } 505 506 $template->assign_vars(array( 507 'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)), 508 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_gets('f_announce', 'f_announce_global', $forum_id)), 509 )); 510 } 511 512 return $toggle; 513 } 514 515 // 516 // Attachment related functions 517 // 518 /** 519 * Calculate the needed size for Thumbnail 520 */ 521 function get_img_size_format($width, $height) 522 { 523 global $config; 524 525 // Maximum Width the Image can take 526 $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400; 527 528 if ($width > $height) 529 { 530 return array( 531 round($width * ($max_width / $width)), 532 round($height * ($max_width / $width)) 533 ); 534 } 535 else 536 { 537 return array( 538 round($width * ($max_width / $height)), 539 round($height * ($max_width / $height)) 540 ); 541 } 542 } 543 544 /** 545 * Return supported image types 546 */ 547 function get_supported_image_types($type = false) 548 { 549 if (@extension_loaded('gd')) 550 { 551 $format = imagetypes(); 552 $new_type = 0; 553 554 if ($type !== false) 555 { 556 // Type is one of the IMAGETYPE constants - it is fetched from getimagesize() 557 switch ($type) 558 { 559 // GIF 560 case IMAGETYPE_GIF: 561 $new_type = ($format & IMG_GIF) ? IMG_GIF : false; 562 break; 563 564 // JPG, JPC, JP2 565 case IMAGETYPE_JPEG: 566 case IMAGETYPE_JPC: 567 case IMAGETYPE_JPEG2000: 568 case IMAGETYPE_JP2: 569 case IMAGETYPE_JPX: 570 case IMAGETYPE_JB2: 571 $new_type = ($format & IMG_JPG) ? IMG_JPG : false; 572 break; 573 574 // PNG 575 case IMAGETYPE_PNG: 576 $new_type = ($format & IMG_PNG) ? IMG_PNG : false; 577 break; 578 579 // WBMP 580 case IMAGETYPE_WBMP: 581 $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false; 582 break; 583 584 // WEBP 585 case IMAGETYPE_WEBP: 586 $new_type = ($format & IMG_WEBP) ? IMG_WEBP : false; 587 break; 588 } 589 } 590 else 591 { 592 $new_type = []; 593 $go_through_types = [IMG_GIF, IMG_JPG, IMG_PNG, IMG_WBMP, IMG_WEBP]; 594 595 foreach ($go_through_types as $check_type) 596 { 597 if ($format & $check_type) 598 { 599 $new_type[] = $check_type; 600 } 601 } 602 } 603 604 return [ 605 'gd' => ($new_type) ? true : false, 606 'format' => $new_type, 607 'version' => (function_exists('imagecreatetruecolor')) ? 2 : 1 608 ]; 609 } 610 611 return ['gd' => false]; 612 } 613 614 /** 615 * Create Thumbnail 616 */ 617 function create_thumbnail($source, $destination, $mimetype) 618 { 619 global $config, $phpbb_filesystem, $phpbb_dispatcher; 620 621 $min_filesize = (int) $config['img_min_thumb_filesize']; 622 $img_filesize = (file_exists($source)) ? @filesize($source) : false; 623 624 if (!$img_filesize || $img_filesize <= $min_filesize) 625 { 626 return false; 627 } 628 629 $dimension = @getimagesize($source); 630 631 if ($dimension === false) 632 { 633 return false; 634 } 635 636 list($width, $height, $type, ) = $dimension; 637 638 if (empty($width) || empty($height)) 639 { 640 return false; 641 } 642 643 list($new_width, $new_height) = get_img_size_format($width, $height); 644 645 // Do not create a thumbnail if the resulting width/height is bigger than the original one 646 if ($new_width >= $width && $new_height >= $height) 647 { 648 return false; 649 } 650 651 $thumbnail_created = false; 652 653 /** 654 * Create thumbnail event to replace GD thumbnail creation with for example ImageMagick 655 * 656 * @event core.thumbnail_create_before 657 * @var string source Image source path 658 * @var string destination Thumbnail destination path 659 * @var string mimetype Image mime type 660 * @var float new_width Calculated thumbnail width 661 * @var float new_height Calculated thumbnail height 662 * @var bool thumbnail_created Set to true to skip default GD thumbnail creation 663 * @since 3.2.4 664 */ 665 $vars = array( 666 'source', 667 'destination', 668 'mimetype', 669 'new_width', 670 'new_height', 671 'thumbnail_created', 672 ); 673 extract($phpbb_dispatcher->trigger_event('core.thumbnail_create_before', compact($vars))); 674 675 if (!$thumbnail_created) 676 { 677 $type = get_supported_image_types($type); 678 679 if ($type['gd']) 680 { 681 // If the type is not supported, we are not able to create a thumbnail 682 if ($type['format'] === false) 683 { 684 return false; 685 } 686 687 switch ($type['format']) 688 { 689 case IMG_GIF: 690 $image = @imagecreatefromgif($source); 691 break; 692 693 case IMG_JPG: 694 @ini_set('gd.jpeg_ignore_warning', 1); 695 $image = @imagecreatefromjpeg($source); 696 break; 697 698 case IMG_PNG: 699 $image = @imagecreatefrompng($source); 700 break; 701 702 case IMG_WBMP: 703 $image = @imagecreatefromwbmp($source); 704 break; 705 706 case IMG_WEBP: 707 $image = @imagecreatefromwebp($source); 708 break; 709 } 710 711 if (empty($image)) 712 { 713 return false; 714 } 715 716 if ($type['version'] == 1) 717 { 718 $new_image = imagecreate($new_width, $new_height); 719 720 if ($new_image === false) 721 { 722 return false; 723 } 724 725 imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); 726 } 727 else 728 { 729 $new_image = imagecreatetruecolor($new_width, $new_height); 730 731 if ($new_image === false) 732 { 733 return false; 734 } 735 736 // Preserve alpha transparency (png for example) 737 @imagealphablending($new_image, false); 738 @imagesavealpha($new_image, true); 739 740 imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); 741 } 742 743 switch ($type['format']) 744 { 745 case IMG_GIF: 746 imagegif($new_image, $destination); 747 break; 748 749 case IMG_JPG: 750 imagejpeg($new_image, $destination, 90); 751 break; 752 753 case IMG_PNG: 754 imagepng($new_image, $destination); 755 break; 756 757 case IMG_WBMP: 758 imagewbmp($new_image, $destination); 759 break; 760 761 case IMG_WEBP: 762 imagewebp($new_image, $destination); 763 break; 764 } 765 766 imagedestroy($new_image); 767 } 768 else 769 { 770 return false; 771 } 772 } 773 774 if (!file_exists($destination)) 775 { 776 return false; 777 } 778 779 try 780 { 781 $phpbb_filesystem->phpbb_chmod($destination, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); 782 } 783 catch (\phpbb\filesystem\exception\filesystem_exception $e) 784 { 785 // Do nothing 786 } 787 788 return true; 789 } 790 791 /** 792 * Assign Inline attachments (build option fields) 793 */ 794 function posting_gen_inline_attachments(&$attachment_data) 795 { 796 global $template; 797 798 if (count($attachment_data)) 799 { 800 $s_inline_attachment_options = ''; 801 802 foreach ($attachment_data as $i => $attachment) 803 { 804 $s_inline_attachment_options .= '<option value="' . $i . '">' . utf8_basename($attachment['real_filename']) . '</option>'; 805 } 806 807 $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options); 808 809 return true; 810 } 811 812 return false; 813 } 814 815 /** 816 * Generate inline attachment entry 817 * 818 * @param array $attachment_data The attachment data 819 * @param string $filename_data The filename data (filecomment) 820 * @param bool $show_attach_box Whether to show the attach box 821 * @param mixed $forum_id The forum id to check or false if private message 822 * @return int 823 */ 824 function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true, $forum_id = false) 825 { 826 global $template, $cache, $config, $phpbb_root_path, $phpEx, $user, $phpbb_dispatcher; 827 828 $allowed_attachments = array_keys($cache->obtain_attach_extensions($forum_id)['_allowed_']); 829 830 // Some default template variables 831 $default_vars = [ 832 'S_SHOW_ATTACH_BOX' => $show_attach_box, 833 'S_HAS_ATTACHMENTS' => count($attachment_data), 834 'FILESIZE' => $config['max_filesize'], 835 'FILE_COMMENT' => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '', 836 'MAX_ATTACHMENT_FILESIZE' => $config['max_filesize'] > 0 ? $user->lang('MAX_ATTACHMENT_FILESIZE', get_formatted_filesize($config['max_filesize'])) : '', 837 'ALLOWED_ATTACHMENTS' => !empty($allowed_attachments) ? '.' . implode(',.', $allowed_attachments) : '', 838 ]; 839 840 /** 841 * Modify default attachments template vars 842 * 843 * @event core.modify_default_attachments_template_vars 844 * @var array allowed_attachments Array containing allowed attachments data 845 * @var array default_vars Array containing default attachments template vars 846 * @since 3.3.6-RC1 847 */ 848 $vars = ['allowed_attachments', 'default_vars']; 849 extract($phpbb_dispatcher->trigger_event('core.modify_default_attachments_template_vars', compact($vars))); 850 851 $template->assign_vars($default_vars); 852 853 if (count($attachment_data)) 854 { 855 // We display the posted attachments within the desired order. 856 ($config['display_order']) ? krsort($attachment_data) : ksort($attachment_data); 857 858 $attachrow_template_vars = []; 859 860 foreach ($attachment_data as $count => $attach_row) 861 { 862 $hidden = ''; 863 $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']); 864 865 foreach ($attach_row as $key => $value) 866 { 867 $hidden .= '<input type="hidden" name="attachment_data[' . $count . '][' . $key . ']" value="' . $value . '" />'; 868 } 869 870 $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); 871 872 $attachrow_template_vars[(int) $attach_row['attach_id']] = array( 873 'FILENAME' => utf8_basename($attach_row['real_filename']), 874 'A_FILENAME' => addslashes(utf8_basename($attach_row['real_filename'])), 875 'FILE_COMMENT' => $attach_row['attach_comment'], 876 'ATTACH_ID' => $attach_row['attach_id'], 877 'S_IS_ORPHAN' => $attach_row['is_orphan'], 878 'ASSOC_INDEX' => $count, 879 'FILESIZE' => get_formatted_filesize($attach_row['filesize']), 880 881 'U_VIEW_ATTACHMENT' => $download_link, 882 'S_HIDDEN' => $hidden, 883 ); 884 } 885 886 /** 887 * Modify inline attachments template vars 888 * 889 * @event core.modify_inline_attachments_template_vars 890 * @var array attachment_data Array containing attachments data 891 * @var array attachrow_template_vars Array containing attachments template vars 892 * @since 3.2.2-RC1 893 */ 894 $vars = array('attachment_data', 'attachrow_template_vars'); 895 extract($phpbb_dispatcher->trigger_event('core.modify_inline_attachments_template_vars', compact($vars))); 896 897 $template->assign_block_vars_array('attach_row', $attachrow_template_vars); 898 } 899 900 return count($attachment_data); 901 } 902 903 // 904 // General Post functions 905 // 906 907 /** 908 * Load Drafts 909 */ 910 function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0) 911 { 912 global $user, $db, $template, $auth; 913 global $phpbb_root_path, $phpbb_dispatcher, $phpEx; 914 915 $topic_ids = $forum_ids = $draft_rows = array(); 916 917 // Load those drafts not connected to forums/topics 918 // If forum_id == 0 AND topic_id == 0 then this is a PM draft 919 if (!$topic_id && !$forum_id) 920 { 921 $sql_and = ' AND d.forum_id = 0 AND d.topic_id = 0'; 922 } 923 else 924 { 925 $sql_and = ''; 926 $sql_and .= ($forum_id) ? ' AND d.forum_id = ' . (int) $forum_id : ''; 927 $sql_and .= ($topic_id) ? ' AND d.topic_id = ' . (int) $topic_id : ''; 928 } 929 930 $sql = 'SELECT d.*, f.forum_id, f.forum_name 931 FROM ' . DRAFTS_TABLE . ' d 932 LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = d.forum_id) 933 WHERE d.user_id = ' . $user->data['user_id'] . " 934 $sql_and 935 ORDER BY d.save_time DESC"; 936 $result = $db->sql_query($sql); 937 938 while ($row = $db->sql_fetchrow($result)) 939 { 940 if ($row['topic_id']) 941 { 942 $topic_ids[] = (int) $row['topic_id']; 943 } 944 $draft_rows[] = $row; 945 } 946 $db->sql_freeresult($result); 947 948 if (!count($draft_rows)) 949 { 950 return; 951 } 952 953 $topic_rows = array(); 954 if (count($topic_ids)) 955 { 956 $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster 957 FROM ' . TOPICS_TABLE . ' 958 WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids)); 959 $result = $db->sql_query($sql); 960 961 while ($row = $db->sql_fetchrow($result)) 962 { 963 $topic_rows[$row['topic_id']] = $row; 964 } 965 $db->sql_freeresult($result); 966 } 967 968 /** 969 * Drafts found and their topics 970 * Edit $draft_rows in order to add or remove drafts loaded 971 * 972 * @event core.load_drafts_draft_list_result 973 * @var array draft_rows The drafts query result. Includes its forum id and everything about the draft 974 * @var array topic_ids The list of topics got from the topics table 975 * @var array topic_rows The topics that draft_rows references 976 * @since 3.1.0-RC3 977 */ 978 $vars = array('draft_rows', 'topic_ids', 'topic_rows'); 979 extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars))); 980 981 unset($topic_ids); 982 983 $template->assign_var('S_SHOW_DRAFTS', true); 984 985 foreach ($draft_rows as $draft) 986 { 987 $link_topic = $link_forum = $link_pm = false; 988 $view_url = $title = ''; 989 990 if (isset($topic_rows[$draft['topic_id']]) 991 && ( 992 ($topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_get('f_read', $topic_rows[$draft['topic_id']]['forum_id'])) 993 || 994 (!$topic_rows[$draft['topic_id']]['forum_id'] && $auth->acl_getf_global('f_read')) 995 )) 996 { 997 $topic_forum_id = ($topic_rows[$draft['topic_id']]['forum_id']) ? $topic_rows[$draft['topic_id']]['forum_id'] : $forum_id; 998 999 $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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |