[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package acp 5 * @version $Id$ 6 * @copyright (c) 2005 phpBB Group 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * @ignore 13 */ 14 if (!defined('IN_PHPBB')) 15 { 16 exit; 17 } 18 19 /** 20 * Recalculate Nested Sets 21 * 22 * @param int $new_id first left_id (should start with 1) 23 * @param string $pkey primary key-column (containing the id for the parent_id of the children) 24 * @param string $table constant or fullname of the table 25 * @param int $parent_id parent_id of the current set (default = 0) 26 * @param array $where contains strings to compare closer on the where statement (additional) 27 * 28 * @author EXreaction 29 */ 30 function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array()) 31 { 32 global $db; 33 34 $sql = 'SELECT * 35 FROM ' . $table . ' 36 WHERE parent_id = ' . (int) $parent_id . 37 ((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . ' 38 ORDER BY left_id ASC'; 39 $result = $db->sql_query($sql); 40 while ($row = $db->sql_fetchrow($result)) 41 { 42 // First we update the left_id for this module 43 if ($row['left_id'] != $new_id) 44 { 45 $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('left_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); 46 } 47 $new_id++; 48 49 // Then we go through any children and update their left/right id's 50 recalc_nested_sets($new_id, $pkey, $table, $row[$pkey], $where); 51 52 // Then we come back and update the right_id for this module 53 if ($row['right_id'] != $new_id) 54 { 55 $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('right_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); 56 } 57 $new_id++; 58 } 59 $db->sql_freeresult($result); 60 } 61 62 /** 63 * Simple version of jumpbox, just lists authed forums 64 */ 65 function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = false, $ignore_nonpost = false, $ignore_emptycat = true, $only_acl_post = false, $return_array = false) 66 { 67 global $db, $user, $auth; 68 69 // This query is identical to the jumpbox one 70 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id 71 FROM ' . FORUMS_TABLE . ' 72 ORDER BY left_id ASC'; 73 $result = $db->sql_query($sql, 600); 74 75 $right = 0; 76 $padding_store = array('0' => ''); 77 $padding = ''; 78 $forum_list = ($return_array) ? array() : ''; 79 80 // Sometimes it could happen that forums will be displayed here not be displayed within the index page 81 // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions. 82 // If this happens, the padding could be "broken" 83 84 while ($row = $db->sql_fetchrow($result)) 85 { 86 if ($row['left_id'] < $right) 87 { 88 $padding .= ' '; 89 $padding_store[$row['parent_id']] = $padding; 90 } 91 else if ($row['left_id'] > $right + 1) 92 { 93 $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : ''; 94 } 95 96 $right = $row['right_id']; 97 $disabled = false; 98 99 if (!$ignore_acl && $auth->acl_gets(array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'), $row['forum_id'])) 100 { 101 if ($only_acl_post && !$auth->acl_get('f_post', $row['forum_id']) || (!$auth->acl_get('m_approve', $row['forum_id']) && !$auth->acl_get('f_noapprove', $row['forum_id']))) 102 { 103 $disabled = true; 104 } 105 } 106 else if (!$ignore_acl) 107 { 108 continue; 109 } 110 111 if ( 112 ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id) 113 || 114 // Non-postable forum with no subforums, don't display 115 ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat) 116 || 117 ($row['forum_type'] != FORUM_POST && $ignore_nonpost) 118 ) 119 { 120 $disabled = true; 121 } 122 123 if ($return_array) 124 { 125 // Include some more information... 126 $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false); 127 $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row); 128 } 129 else 130 { 131 $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : ''); 132 $forum_list .= '<option value="' . $row['forum_id'] . '"' . (($disabled) ? ' disabled="disabled" class="disabled-option"' : $selected) . '>' . $padding . $row['forum_name'] . '</option>'; 133 } 134 } 135 $db->sql_freeresult($result); 136 unset($padding_store); 137 138 return $forum_list; 139 } 140 141 /** 142 * Generate size select options 143 */ 144 function size_select_options($size_compare) 145 { 146 global $user; 147 148 $size_types_text = array($user->lang['BYTES'], $user->lang['KIB'], $user->lang['MIB']); 149 $size_types = array('b', 'kb', 'mb'); 150 151 $s_size_options = ''; 152 153 for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++) 154 { 155 $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : ''; 156 $s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>'; 157 } 158 159 return $s_size_options; 160 } 161 162 /** 163 * Generate list of groups (option fields without select) 164 * 165 * @param int $group_id The default group id to mark as selected 166 * @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id 167 * @param int $manage_founder If set to false (default) all groups are returned, if 0 only those groups returned not being managed by founders only, if 1 only those groups returned managed by founders only. 168 * 169 * @return string The list of options. 170 */ 171 function group_select_options($group_id, $exclude_ids = false, $manage_founder = false) 172 { 173 global $db, $user, $config; 174 175 $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : ''; 176 $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : ''; 177 $sql_founder = ($manage_founder !== false) ? (($exclude_sql || $sql_and) ? ' AND ' : ' WHERE ') . 'group_founder_manage = ' . (int) $manage_founder : ''; 178 179 $sql = 'SELECT group_id, group_name, group_type 180 FROM ' . GROUPS_TABLE . " 181 $exclude_sql 182 $sql_and 183 $sql_founder 184 ORDER BY group_type DESC, group_name ASC"; 185 $result = $db->sql_query($sql); 186 187 $s_group_options = ''; 188 while ($row = $db->sql_fetchrow($result)) 189 { 190 $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : ''; 191 $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '"' . $selected . '>' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>'; 192 } 193 $db->sql_freeresult($result); 194 195 return $s_group_options; 196 } 197 198 /** 199 * Obtain authed forums list 200 */ 201 function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false) 202 { 203 global $db, $auth; 204 static $forum_rows; 205 206 if (!isset($forum_rows)) 207 { 208 // This query is identical to the jumpbox one 209 $expire_time = ($no_cache) ? 0 : 600; 210 211 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id 212 FROM ' . FORUMS_TABLE . ' 213 ORDER BY left_id ASC'; 214 $result = $db->sql_query($sql, $expire_time); 215 216 $forum_rows = array(); 217 218 $right = $padding = 0; 219 $padding_store = array('0' => 0); 220 221 while ($row = $db->sql_fetchrow($result)) 222 { 223 if ($row['left_id'] < $right) 224 { 225 $padding++; 226 $padding_store[$row['parent_id']] = $padding; 227 } 228 else if ($row['left_id'] > $right + 1) 229 { 230 // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it. 231 // @todo digging deep to find out "how" this can happen. 232 $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding; 233 } 234 235 $right = $row['right_id']; 236 $row['padding'] = $padding; 237 238 $forum_rows[] = $row; 239 } 240 $db->sql_freeresult($result); 241 unset($padding_store); 242 } 243 244 $rowset = array(); 245 foreach ($forum_rows as $row) 246 { 247 if ($postable_only && $row['forum_type'] != FORUM_POST) 248 { 249 continue; 250 } 251 252 if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id']))) 253 { 254 $rowset[] = ($id_only) ? (int) $row['forum_id'] : $row; 255 } 256 } 257 258 return $rowset; 259 } 260 261 /** 262 * Get forum branch 263 */ 264 function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true) 265 { 266 global $db; 267 268 switch ($type) 269 { 270 case 'parents': 271 $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id'; 272 break; 273 274 case 'children': 275 $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id'; 276 break; 277 278 default: 279 $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id'; 280 break; 281 } 282 283 $rows = array(); 284 285 $sql = 'SELECT f2.* 286 FROM ' . FORUMS_TABLE . ' f1 287 LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition) 288 WHERE f1.forum_id = $forum_id 289 ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC'); 290 $result = $db->sql_query($sql); 291 292 while ($row = $db->sql_fetchrow($result)) 293 { 294 if (!$include_forum && $row['forum_id'] == $forum_id) 295 { 296 continue; 297 } 298 299 $rows[] = $row; 300 } 301 $db->sql_freeresult($result); 302 303 return $rows; 304 } 305 306 /** 307 * Copies permissions from one forum to others 308 * 309 * @param int $src_forum_id The source forum we want to copy permissions from 310 * @param array $dest_forum_ids The destination forum(s) we want to copy to 311 * @param bool $clear_dest_perms True if destination permissions should be deleted 312 * @param bool $add_log True if log entry should be added 313 * 314 * @return bool False on error 315 * 316 * @author bantu 317 */ 318 function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true) 319 { 320 global $db; 321 322 // Only one forum id specified 323 if (!is_array($dest_forum_ids)) 324 { 325 $dest_forum_ids = array($dest_forum_ids); 326 } 327 328 // Make sure forum ids are integers 329 $src_forum_id = (int) $src_forum_id; 330 $dest_forum_ids = array_map('intval', $dest_forum_ids); 331 332 // No source forum or no destination forums specified 333 if (empty($src_forum_id) || empty($dest_forum_ids)) 334 { 335 return false; 336 } 337 338 // Check if source forum exists 339 $sql = 'SELECT forum_name 340 FROM ' . FORUMS_TABLE . ' 341 WHERE forum_id = ' . $src_forum_id; 342 $result = $db->sql_query($sql); 343 $src_forum_name = $db->sql_fetchfield('forum_name'); 344 $db->sql_freeresult($result); 345 346 // Source forum doesn't exist 347 if (empty($src_forum_name)) 348 { 349 return false; 350 } 351 352 // Check if destination forums exists 353 $sql = 'SELECT forum_id, forum_name 354 FROM ' . FORUMS_TABLE . ' 355 WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); 356 $result = $db->sql_query($sql); 357 358 $dest_forum_ids = $dest_forum_names = array(); 359 while ($row = $db->sql_fetchrow($result)) 360 { 361 $dest_forum_ids[] = (int) $row['forum_id']; 362 $dest_forum_names[] = $row['forum_name']; 363 } 364 $db->sql_freeresult($result); 365 366 // No destination forum exists 367 if (empty($dest_forum_ids)) 368 { 369 return false; 370 } 371 372 // From the mysql documentation: 373 // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear 374 // in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14. 375 // Due to this we stay on the safe side if we do the insertion "the manual way" 376 377 // Rowsets we're going to insert 378 $users_sql_ary = $groups_sql_ary = array(); 379 380 // Query acl users table for source forum data 381 $sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting 382 FROM ' . ACL_USERS_TABLE . ' 383 WHERE forum_id = ' . $src_forum_id; 384 $result = $db->sql_query($sql); 385 386 while ($row = $db->sql_fetchrow($result)) 387 { 388 $row = array( 389 'user_id' => (int) $row['user_id'], 390 'auth_option_id' => (int) $row['auth_option_id'], 391 'auth_role_id' => (int) $row['auth_role_id'], 392 'auth_setting' => (int) $row['auth_setting'], 393 ); 394 395 foreach ($dest_forum_ids as $dest_forum_id) 396 { 397 $users_sql_ary[] = $row + array('forum_id' => $dest_forum_id); 398 } 399 } 400 $db->sql_freeresult($result); 401 402 // Query acl groups table for source forum data 403 $sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting 404 FROM ' . ACL_GROUPS_TABLE . ' 405 WHERE forum_id = ' . $src_forum_id; 406 $result = $db->sql_query($sql); 407 408 while ($row = $db->sql_fetchrow($result)) 409 { 410 $row = array( 411 'group_id' => (int) $row['group_id'], 412 'auth_option_id' => (int) $row['auth_option_id'], 413 'auth_role_id' => (int) $row['auth_role_id'], 414 'auth_setting' => (int) $row['auth_setting'], 415 ); 416 417 foreach ($dest_forum_ids as $dest_forum_id) 418 { 419 $groups_sql_ary[] = $row + array('forum_id' => $dest_forum_id); 420 } 421 } 422 $db->sql_freeresult($result); 423 424 $db->sql_transaction('begin'); 425 426 // Clear current permissions of destination forums 427 if ($clear_dest_perms) 428 { 429 $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' 430 WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); 431 $db->sql_query($sql); 432 433 $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' 434 WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); 435 $db->sql_query($sql); 436 } 437 438 $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary); 439 $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); 440 441 if ($add_log) 442 { 443 add_log('admin', 'LOG_FORUM_COPIED_PERMISSIONS', $src_forum_name, implode(', ', $dest_forum_names)); 444 } 445 446 $db->sql_transaction('commit'); 447 448 return true; 449 } 450 451 /** 452 * Get physical file listing 453 */ 454 function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png') 455 { 456 $matches = array($dir => array()); 457 458 // Remove initial / if present 459 $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir; 460 // Add closing / if not present 461 $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir; 462 463 // Remove initial / if present 464 $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir; 465 // Add closing / if not present 466 $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir; 467 468 if (!is_dir($rootdir . $dir)) 469 { 470 return $matches; 471 } 472 473 $dh = @opendir($rootdir . $dir); 474 475 if (!$dh) 476 { 477 return $matches; 478 } 479 480 while (($fname = readdir($dh)) !== false) 481 { 482 if (is_file("$rootdir$dir$fname")) 483 { 484 if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname)) 485 { 486 $matches[$dir][] = $fname; 487 } 488 } 489 else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname")) 490 { 491 $matches += filelist($rootdir, "$dir$fname", $type); 492 } 493 } 494 closedir($dh); 495 496 return $matches; 497 } 498 499 /** 500 * Move topic(s) 501 */ 502 function move_topics($topic_ids, $forum_id, $auto_sync = true) 503 { 504 global $db; 505 506 if (empty($topic_ids)) 507 { 508 return; 509 } 510 511 $forum_ids = array($forum_id); 512 513 if (!is_array($topic_ids)) 514 { 515 $topic_ids = array($topic_ids); 516 } 517 518 $sql = 'DELETE FROM ' . TOPICS_TABLE . ' 519 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . ' 520 AND forum_id = ' . $forum_id; 521 $db->sql_query($sql); 522 523 if ($auto_sync) 524 { 525 $sql = 'SELECT DISTINCT forum_id 526 FROM ' . TOPICS_TABLE . ' 527 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 528 $result = $db->sql_query($sql); 529 530 while ($row = $db->sql_fetchrow($result)) 531 { 532 $forum_ids[] = $row['forum_id']; 533 } 534 $db->sql_freeresult($result); 535 } 536 537 $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); 538 foreach ($table_ary as $table) 539 { 540 $sql = "UPDATE $table 541 SET forum_id = $forum_id 542 WHERE " . $db->sql_in_set('topic_id', $topic_ids); 543 $db->sql_query($sql); 544 } 545 unset($table_ary); 546 547 if ($auto_sync) 548 { 549 sync('forum', 'forum_id', $forum_ids, true, true); 550 unset($forum_ids); 551 } 552 } 553 554 /** 555 * Move post(s) 556 */ 557 function move_posts($post_ids, $topic_id, $auto_sync = true) 558 { 559 global $db; 560 561 if (!is_array($post_ids)) 562 { 563 $post_ids = array($post_ids); 564 } 565 566 $forum_ids = array(); 567 $topic_ids = array($topic_id); 568 569 $sql = 'SELECT DISTINCT topic_id, forum_id 570 FROM ' . POSTS_TABLE . ' 571 WHERE ' . $db->sql_in_set('post_id', $post_ids); 572 $result = $db->sql_query($sql); 573 574 while ($row = $db->sql_fetchrow($result)) 575 { 576 $forum_ids[] = (int) $row['forum_id']; 577 $topic_ids[] = (int) $row['topic_id']; 578 } 579 $db->sql_freeresult($result); 580 581 $sql = 'SELECT forum_id 582 FROM ' . TOPICS_TABLE . ' 583 WHERE topic_id = ' . $topic_id; 584 $result = $db->sql_query($sql); 585 $forum_row = $db->sql_fetchrow($result); 586 $db->sql_freeresult($result); 587 588 if (!$forum_row) 589 { 590 trigger_error('NO_TOPIC'); 591 } 592 593 $sql = 'UPDATE ' . POSTS_TABLE . ' 594 SET forum_id = ' . (int) $forum_row['forum_id'] . ", topic_id = $topic_id 595 WHERE " . $db->sql_in_set('post_id', $post_ids); 596 $db->sql_query($sql); 597 598 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " 599 SET topic_id = $topic_id, in_message = 0 600 WHERE " . $db->sql_in_set('post_msg_id', $post_ids); 601 $db->sql_query($sql); 602 603 if ($auto_sync) 604 { 605 $forum_ids[] = (int) $forum_row['forum_id']; 606 607 sync('topic_reported', 'topic_id', $topic_ids); 608 sync('topic_attachment', 'topic_id', $topic_ids); 609 sync('topic', 'topic_id', $topic_ids, true); 610 sync('forum', 'forum_id', $forum_ids, true, true); 611 } 612 613 // Update posted information 614 update_posted_info($topic_ids); 615 } 616 617 /** 618 * Remove topic(s) 619 */ 620 function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true) 621 { 622 global $db, $config; 623 624 $approved_topics = 0; 625 $forum_ids = $topic_ids = array(); 626 627 if ($where_type === 'range') 628 { 629 $where_clause = $where_ids; 630 } 631 else 632 { 633 $where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids); 634 635 if (!sizeof($where_ids)) 636 { 637 return array('topics' => 0, 'posts' => 0); 638 } 639 640 $where_clause = $db->sql_in_set($where_type, $where_ids); 641 } 642 643 // Making sure that delete_posts does not call delete_topics again... 644 $return = array( 645 'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0, 646 ); 647 648 $sql = 'SELECT topic_id, forum_id, topic_approved, topic_moved_id 649 FROM ' . TOPICS_TABLE . ' 650 WHERE ' . $where_clause; 651 $result = $db->sql_query($sql); 652 653 while ($row = $db->sql_fetchrow($result)) 654 { 655 $forum_ids[] = $row['forum_id']; 656 $topic_ids[] = $row['topic_id']; 657 658 if ($row['topic_approved'] && !$row['topic_moved_id']) 659 { 660 $approved_topics++; 661 } 662 } 663 $db->sql_freeresult($result); 664 665 $return['topics'] = sizeof($topic_ids); 666 667 if (!sizeof($topic_ids)) 668 { 669 return $return; 670 } 671 672 $db->sql_transaction('begin'); 673 674 $table_ary = array(BOOKMARKS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE); 675 676 foreach ($table_ary as $table) 677 { 678 $sql = "DELETE FROM $table 679 WHERE " . $db->sql_in_set('topic_id', $topic_ids); 680 $db->sql_query($sql); 681 } 682 unset($table_ary); 683 684 $moved_topic_ids = array(); 685 686 // update the other forums 687 $sql = 'SELECT topic_id, forum_id 688 FROM ' . TOPICS_TABLE . ' 689 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids); 690 $result = $db->sql_query($sql); 691 692 while ($row = $db->sql_fetchrow($result)) 693 { 694 $forum_ids[] = $row['forum_id']; 695 $moved_topic_ids[] = $row['topic_id']; 696 } 697 $db->sql_freeresult($result); 698 699 if (sizeof($moved_topic_ids)) 700 { 701 $sql = 'DELETE FROM ' . TOPICS_TABLE . ' 702 WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids); 703 $db->sql_query($sql); 704 } 705 706 $db->sql_transaction('commit'); 707 708 if ($auto_sync) 709 { 710 sync('forum', 'forum_id', array_unique($forum_ids), true, true); 711 sync('topic_reported', $where_type, $where_ids); 712 } 713 714 if ($approved_topics) 715 { 716 set_config_count('num_topics', $approved_topics * (-1), true); 717 } 718 719 return $return; 720 } 721 722 /** 723 * Remove post(s) 724 */ 725 function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true) 726 { 727 global $db, $config, $phpbb_root_path, $phpEx; 728 729 if ($where_type === 'range') 730 { 731 $where_clause = $where_ids; 732 } 733 else 734 { 735 if (is_array($where_ids)) 736 { 737 $where_ids = array_unique($where_ids); 738 } 739 else 740 { 741 $where_ids = array($where_ids); 742 } 743 744 if (!sizeof($where_ids)) 745 { 746 return false; 747 } 748 749 $where_ids = array_map('intval', $where_ids); 750 751 /* Possible code for splitting post deletion 752 if (sizeof($where_ids) >= 1001) 753 { 754 // Split into chunks of 1000 755 $chunks = array_chunk($where_ids, 1000); 756 757 foreach ($chunks as $_where_ids) 758 { 759 delete_posts($where_type, $_where_ids, $auto_sync, $posted_sync, $post_count_sync, $call_delete_topics); 760 } 761 762 return; 763 }*/ 764 765 $where_clause = $db->sql_in_set($where_type, $where_ids); 766 } 767 768 $approved_posts = 0; 769 $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array(); 770 771 $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id 772 FROM ' . POSTS_TABLE . ' 773 WHERE ' . $where_clause; 774 $result = $db->sql_query($sql); 775 776 while ($row = $db->sql_fetchrow($result)) 777 { 778 $post_ids[] = (int) $row['post_id']; 779 $poster_ids[] = (int) $row['poster_id']; 780 $topic_ids[] = (int) $row['topic_id']; 781 $forum_ids[] = (int) $row['forum_id']; 782 783 if ($row['post_postcount'] && $post_count_sync && $row['post_approved']) 784 { 785 $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; 786 } 787 788 if ($row['post_approved']) 789 { 790 $approved_posts++; 791 } 792 } 793 $db->sql_freeresult($result); 794 795 if (!sizeof($post_ids)) 796 { 797 return false; 798 } 799 800 $db->sql_transaction('begin'); 801 802 $table_ary = array(POSTS_TABLE, REPORTS_TABLE); 803 804 foreach ($table_ary as $table) 805 { 806 $sql = "DELETE FROM $table 807 WHERE " . $db->sql_in_set('post_id', $post_ids); 808 $db->sql_query($sql); 809 } 810 unset($table_ary); 811 812 // Adjust users post counts 813 if (sizeof($post_counts) && $post_count_sync) 814 { 815 foreach ($post_counts as $poster_id => $substract) 816 { 817 $sql = 'UPDATE ' . USERS_TABLE . ' 818 SET user_posts = 0 819 WHERE user_id = ' . $poster_id . ' 820 AND user_posts < ' . $substract; 821 $db->sql_query($sql); 822 823 $sql = 'UPDATE ' . USERS_TABLE . ' 824 SET user_posts = user_posts - ' . $substract . ' 825 WHERE user_id = ' . $poster_id . ' 826 AND user_posts >= ' . $substract; 827 $db->sql_query($sql); 828 } 829 } 830 831 // Remove topics now having no posts? 832 if (sizeof($topic_ids)) 833 { 834 $sql = 'SELECT topic_id 835 FROM ' . POSTS_TABLE . ' 836 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' 837 GROUP BY topic_id'; 838 $result = $db->sql_query($sql); 839 840 while ($row = $db->sql_fetchrow($result)) 841 { 842 $remove_topics[] = $row['topic_id']; 843 } 844 $db->sql_freeresult($result); 845 846 // Actually, those not within remove_topics should be removed. ;) 847 $remove_topics = array_diff($topic_ids, $remove_topics); 848 } 849 850 // Remove the message from the search index 851 $search_type = basename($config['search_type']); 852 853 if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) 854 { 855 trigger_error('NO_SUCH_SEARCH_MODULE'); 856 } 857 858 include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx"); 859 860 $error = false; 861 $search = new $search_type($error); 862 863 if ($error) 864 { 865 trigger_error($error); 866 } 867 868 $search->index_remove($post_ids, $poster_ids, $forum_ids); 869 870 delete_attachments('post', $post_ids, false); 871 872 $db->sql_transaction('commit'); 873 874 // Resync topics_posted table 875 if ($posted_sync) 876 { 877 update_posted_info($topic_ids); 878 } 879 880 if ($auto_sync) 881 { 882 sync('topic_reported', 'topic_id', $topic_ids); 883 sync('topic', 'topic_id', $topic_ids, true); 884 sync('forum', 'forum_id', $forum_ids, true, true); 885 } 886 887 if ($approved_posts) 888 { 889 set_config_count('num_posts', $approved_posts * (-1), true); 890 } 891 892 // We actually remove topics now to not be inconsistent (the delete_topics function calls this function too) 893 if (sizeof($remove_topics) && $call_delete_topics) 894 { 895 delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false); 896 } 897 898 return sizeof($post_ids); 899 } 900 901 /** 902 * Delete Attachments 903 * 904 * @param string $mode can be: post|message|topic|attach|user 905 * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids 906 * @param bool $resync set this to false if you are deleting posts or topics 907 */ 908 function delete_attachments($mode, $ids, $resync = true) 909 { 910 global $db, $config; 911 912 // 0 is as bad as an empty array 913 if (empty($ids)) 914 { 915 return false; 916 } 917 918 if (is_array($ids)) 919 { 920 $ids = array_unique($ids); 921 $ids = array_map('intval', $ids); 922 } 923 else 924 { 925 $ids = array((int) $ids); 926 } 927 928 $sql_where = ''; 929 930 switch ($mode) 931 { 932 case 'post': 933 case 'message': 934 $sql_id = 'post_msg_id'; 935 $sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0); 936 break; 937 938 case 'topic': 939 $sql_id = 'topic_id'; 940 break; 941 942 case 'user': 943 $sql_id = 'poster_id'; 944 break; 945 946 case 'attach': 947 default: 948 $sql_id = 'attach_id'; 949 $mode = 'attach'; 950 break; 951 } 952 953 $post_ids = $message_ids = $topic_ids = $physical = array(); 954 955 // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled) 956 $sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan 957 FROM ' . ATTACHMENTS_TABLE . ' 958 WHERE ' . $db->sql_in_set($sql_id, $ids); 959 960 $sql .= $sql_where; 961 962 $result = $db->sql_query($sql); 963 964 while ($row = $db->sql_fetchrow($result)) 965 { 966 // We only need to store post/message/topic ids if resync is enabled and the file is not orphaned 967 if ($resync && !$row['is_orphan']) 968 { 969 if (!$row['in_message']) 970 { 971 $post_ids[] = $row['post_msg_id']; 972 $topic_ids[] = $row['topic_id']; 973 } 974 else 975 { 976 $message_ids[] = $row['post_msg_id']; 977 } 978 } 979 980 $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']); 981 } 982 $db->sql_freeresult($result); 983 984 // Delete attachments 985 $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . ' 986 WHERE ' . $db->sql_in_set($sql_id, $ids); 987 988 $sql .= $sql_where; 989 990 $db->sql_query($sql); 991 $num_deleted = $db->sql_affectedrows(); 992 993 if (!$num_deleted) 994 { 995 return 0; 996 } 997 998 // Delete attachments from filesystem 999 $space_removed = $files_removed = 0; 1000 foreach ($physical as $file_ary) 1001 { 1002 if (phpbb_unlink($file_ary['filename'], 'file', true) && !$file_ary['is_orphan']) 1003 { 1004 // Only non-orphaned files count to the file size 1005 $space_removed += $file_ary['filesize']; 1006 $files_removed++; 1007 } 1008 1009 if ($file_ary['thumbnail']) 1010 { 1011 phpbb_unlink($file_ary['filename'], 'thumbnail', true); 1012 } 1013 } 1014 1015 if ($space_removed || $files_removed) 1016 { 1017 set_config_count('upload_dir_size', $space_removed * (-1), true); 1018 set_config_count('num_files', $files_removed * (-1), true); 1019 } 1020 1021 // If we do not resync, we do not need to adjust any message, post, topic or user entries 1022 if (!$resync) 1023 { 1024 return $num_deleted; 1025 } 1026 1027 // No more use for the original ids 1028 unset($ids); 1029 1030 // Now, we need to resync posts, messages, topics. We go through every one of them 1031 $post_ids = array_unique($post_ids); 1032 $message_ids = array_unique($message_ids); 1033 $topic_ids = array_unique($topic_ids); 1034 1035 // Update post indicators for posts now no longer having attachments 1036 if (sizeof($post_ids)) 1037 { 1038 // Just check which posts are still having an assigned attachment not orphaned by querying the attachments table 1039 $sql = 'SELECT post_msg_id 1040 FROM ' . ATTACHMENTS_TABLE . ' 1041 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . ' 1042 AND in_message = 0 1043 AND is_orphan = 0'; 1044 $result = $db->sql_query($sql); 1045 1046 $remaining_ids = array(); 1047 while ($row = $db->sql_fetchrow($result)) 1048 { 1049 $remaining_ids[] = $row['post_msg_id']; 1050 } 1051 $db->sql_freeresult($result); 1052 1053 // Now only unset those ids remaining 1054 $post_ids = array_diff($post_ids, $remaining_ids); 1055 1056 if (sizeof($post_ids)) 1057 { 1058 $sql = 'UPDATE ' . POSTS_TABLE . ' 1059 SET post_attachment = 0 1060 WHERE ' . $db->sql_in_set('post_id', $post_ids); 1061 $db->sql_query($sql); 1062 } 1063 } 1064 1065 // Update message table if messages are affected 1066 if (sizeof($message_ids)) 1067 { 1068 // Just check which messages are still having an assigned attachment not orphaned by querying the attachments table 1069 $sql = 'SELECT post_msg_id 1070 FROM ' . ATTACHMENTS_TABLE . ' 1071 WHERE ' . $db->sql_in_set('post_msg_id', $message_ids) . ' 1072 AND in_message = 1 1073 AND is_orphan = 0'; 1074 $result = $db->sql_query($sql); 1075 1076 $remaining_ids = array(); 1077 while ($row = $db->sql_fetchrow($result)) 1078 { 1079 $remaining_ids[] = $row['post_msg_id']; 1080 } 1081 $db->sql_freeresult($result); 1082 1083 // Now only unset those ids remaining 1084 $message_ids = array_diff($message_ids, $remaining_ids); 1085 1086 if (sizeof($message_ids)) 1087 { 1088 $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' 1089 SET message_attachment = 0 1090 WHERE ' . $db->sql_in_set('msg_id', $message_ids); 1091 $db->sql_query($sql); 1092 } 1093 } 1094 1095 // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic 1096 if (sizeof($topic_ids)) 1097 { 1098 // Just check which topics are still having an assigned attachment not orphaned by querying the attachments table (much less entries expected) 1099 $sql = 'SELECT topic_id 1100 FROM ' . ATTACHMENTS_TABLE . ' 1101 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' 1102 AND is_orphan = 0'; 1103 $result = $db->sql_query($sql); 1104 1105 $remaining_ids = array(); 1106 while ($row = $db->sql_fetchrow($result)) 1107 { 1108 $remaining_ids[] = $row['topic_id']; 1109 } 1110 $db->sql_freeresult($result); 1111 1112 // Now only unset those ids remaining 1113 $topic_ids = array_diff($topic_ids, $remaining_ids); 1114 1115 if (sizeof($topic_ids)) 1116 { 1117 $sql = 'UPDATE ' . TOPICS_TABLE . ' 1118 SET topic_attachment = 0 1119 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 1120 $db->sql_query($sql); 1121 } 1122 } 1123 1124 return $num_deleted; 1125 } 1126 1127 /** 1128 * Deletes shadow topics pointing to a specified forum. 1129 * 1130 * @param int $forum_id The forum id 1131 * @param string $sql_more Additional WHERE statement, e.g. t.topic_time < (time() - 1234) 1132 * @param bool $auto_sync Will call sync() if this is true 1133 * 1134 * @return array Array with affected forums 1135 * 1136 * @author bantu 1137 */ 1138 function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true) 1139 { 1140 global $db; 1141 1142 if (!$forum_id) 1143 { 1144 // Nothing to do. 1145 return; 1146 } 1147 1148 // Set of affected forums we have to resync 1149 $sync_forum_ids = array(); 1150 1151 // Amount of topics we select and delete at once. 1152 $batch_size = 500; 1153 1154 do 1155 { 1156 $sql = 'SELECT t2.forum_id, t2.topic_id 1157 FROM ' . TOPICS_TABLE . ' t2, ' . TOPICS_TABLE . ' t 1158 WHERE t2.topic_moved_id = t.topic_id 1159 AND t.forum_id = ' . (int) $forum_id . ' 1160 ' . (($sql_more) ? 'AND ' . $sql_more : ''); 1161 $result = $db->sql_query_limit($sql, $batch_size); 1162 1163 $topic_ids = array(); 1164 while ($row = $db->sql_fetchrow($result)) 1165 { 1166 $topic_ids[] = (int) $row['topic_id']; 1167 1168 $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id']; 1169 } 1170 $db->sql_freeresult($result); 1171 1172 if (!empty($topic_ids)) 1173 { 1174 $sql = 'DELETE FROM ' . TOPICS_TABLE . ' 1175 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 1176 $db->sql_query($sql); 1177 } 1178 } 1179 while (sizeof($topic_ids) == $batch_size); 1180 1181 if ($auto_sync) 1182 { 1183 sync('forum', 'forum_id', $sync_forum_ids, true, true); 1184 } 1185 1186 return $sync_forum_ids; 1187 } 1188 1189 /** 1190 * Update/Sync posted information for topics 1191 */ 1192 function update_posted_info(&$topic_ids) 1193 { 1194 global $db, $config; 1195 1196 if (empty($topic_ids) || !$config['load_db_track']) 1197 { 1198 return; 1199 } 1200 1201 // First of all, let us remove any posted information for these topics 1202 $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . ' 1203 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 1204 $db->sql_query($sql); 1205 1206 // Now, let us collect the user/topic combos for rebuilding the information 1207 $sql = 'SELECT poster_id, topic_id 1208 FROM ' . POSTS_TABLE . ' 1209 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' 1210 AND poster_id <> ' . ANONYMOUS . ' 1211 GROUP BY poster_id, topic_id'; 1212 $result = $db->sql_query($sql); 1213 1214 $posted = array(); 1215 while ($row = $db->sql_fetchrow($result)) 1216 { 1217 // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique 1218 $posted[$row['poster_id']][] = $row['topic_id']; 1219 } 1220 $db->sql_freeresult($result); 1221 1222 // Now add the information... 1223 $sql_ary = array(); 1224 foreach ($posted as $user_id => $topic_row) 1225 { 1226 foreach ($topic_row as $topic_id) 1227 { 1228 $sql_ary[] = array( 1229 'user_id' => (int) $user_id, 1230 'topic_id' => (int) $topic_id, 1231 'topic_posted' => 1, 1232 ); 1233 } 1234 } 1235 unset($posted); 1236 1237 $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); 1238 } 1239 1240 /** 1241 * Delete attached file 1242 */ 1243 function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) 1244 { 1245 global $db, $phpbb_root_path, $config; 1246 1247 // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself. 1248 $sql = 'SELECT COUNT(attach_id) AS num_entries 1249 FROM ' . ATTACHMENTS_TABLE . " 1250 WHERE physical_filename = '" . $db->sql_escape(utf8_basename($filename)) . "'"; 1251 $result = $db->sql_query($sql); 1252 $num_entries = (int) $db->sql_fetchfield('num_entries'); 1253 $db->sql_freeresult($result); 1254 1255 // Do not remove file if at least one additional entry with the same name exist. 1256 if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1)) 1257 { 1258 return false; 1259 } 1260 1261 $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename); 1262 return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename); 1263 } 1264 1265 /** 1266 * All-encompasing sync function 1267 * 1268 * Exaples: 1269 * <code> 1270 * sync('topic', 'topic_id', 123); // resync topic #123 1271 * sync('topic', 'forum_id', array(2, 3)); // resync topics from forum #2 and #3 1272 * sync('topic'); // resync all topics 1273 * sync('topic', 'range', 'topic_id BETWEEN 1 AND 60'); // resync a range of topics/forums (only available for 'topic' and 'forum' modes) 1274 * </code> 1275 * 1276 * Modes: 1277 * - forum Resync complete forum 1278 * - topic Resync topics 1279 * - topic_moved Removes topic shadows that would be in the same forum as the topic they link to 1280 * - topic_approved Resyncs the topic_approved flag according to the status of the first post 1281 * - post_reported Resyncs the post_reported flag, relying on actual reports 1282 * - topic_reported Resyncs the topic_reported flag, relying on post_reported flags 1283 * - post_attachement Same as post_reported, but with attachment flags 1284 * - topic_attachement Same as topic_reported, but with attachment flags 1285 */ 1286 function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false) 1287 { 1288 global $db; 1289 1290 if (is_array($where_ids)) 1291 { 1292 $where_ids = array_unique($where_ids); 1293 $where_ids = array_map('intval', $where_ids); 1294 } 1295 else if ($where_type != 'range') 1296 { 1297 $where_ids = ($where_ids) ? array((int) $where_ids) : array(); 1298 } 1299 1300 if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved' || $mode == 'topic_reported' || $mode == 'post_reported') 1301 { 1302 if (!$where_type) 1303 { 1304 $where_sql = ''; 1305 $where_sql_and = 'WHERE'; 1306 } 1307 else if ($where_type == 'range') 1308 { 1309 // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60' 1310 $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)"; 1311 $where_sql_and = $where_sql . "\n\tAND"; 1312 } 1313 else 1314 { 1315 // Do not sync the "global forum" 1316 $where_ids = array_diff($where_ids, array(0)); 1317 1318 if (!sizeof($where_ids)) 1319 { 1320 // Empty array with IDs. This means that we don't have any work to do. Just return. 1321 return; 1322 } 1323 1324 // Limit the topics/forums we are syncing, use specific topic/forum IDs. 1325 // $where_type contains the field for the where clause (forum_id, topic_id) 1326 $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); 1327 $where_sql_and = $where_sql . "\n\tAND"; 1328 } 1329 } 1330 else 1331 { 1332 if (!sizeof($where_ids)) 1333 { 1334 return; 1335 } 1336 1337 // $where_type contains the field for the where clause (forum_id, topic_id) 1338 $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); 1339 $where_sql_and = $where_sql . "\n\tAND"; 1340 } 1341 1342 switch ($mode) 1343 { 1344 case 'topic_moved': 1345 $db->sql_transaction('begin'); 1346 switch ($db->sql_layer) 1347 { 1348 case 'mysql4': 1349 case 'mysqli': 1350 $sql = 'DELETE FROM ' . TOPICS_TABLE . ' 1351 USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 1352 WHERE t1.topic_moved_id = t2.topic_id 1353 AND t1.forum_id = t2.forum_id"; 1354 $db->sql_query($sql); 1355 break; 1356 1357 default: 1358 $sql = 'SELECT t1.topic_id 1359 FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 1360 WHERE t1.topic_moved_id = t2.topic_id 1361 AND t1.forum_id = t2.forum_id"; 1362 $result = $db->sql_query($sql); 1363 1364 $topic_id_ary = array(); 1365 while ($row = $db->sql_fetchrow($result)) 1366 { 1367 $topic_id_ary[] = $row['topic_id']; 1368 } 1369 $db->sql_freeresult($result); 1370 1371 if (!sizeof($topic_id_ary)) 1372 { 1373 return; 1374 } 1375 1376 $sql = 'DELETE FROM ' . TOPICS_TABLE . ' 1377 WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary); 1378 $db->sql_query($sql); 1379 1380 break; 1381 } 1382 1383 $db->sql_transaction('commit'); 1384 break; 1385 1386 case 'topic_approved': 1387 1388 $db->sql_transaction('begin'); 1389 switch ($db->sql_layer) 1390 { 1391 case 'mysql4': 1392 case 'mysqli': 1393 $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p 1394 SET t.topic_approved = p.post_approved 1395 $where_sql_and t.topic_first_post_id = p.post_id"; 1396 $db->sql_query($sql); 1397 break; 1398 1399 default: 1400 $sql = 'SELECT t.topic_id, p.post_approved 1401 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p 1402 $where_sql_and p.post_id = t.topic_first_post_id 1403 AND p.post_approved <> t.topic_approved"; 1404 $result = $db->sql_query($sql); 1405 1406 $topic_ids = array(); 1407 while ($row = $db->sql_fetchrow($result)) 1408 { 1409 $topic_ids[] = $row['topic_id']; 1410 } 1411 $db->sql_freeresult($result); 1412 1413 if (!sizeof($topic_ids)) 1414 { 1415 return; 1416 } 1417 1418 $sql = 'UPDATE ' . TOPICS_TABLE . ' 1419 SET topic_approved = 1 - topic_approved 1420 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 1421 $db->sql_query($sql); 1422 break; 1423 } 1424 1425 $db->sql_transaction('commit'); 1426 break; 1427 1428 case 'post_reported': 1429 $post_ids = $post_reported = array(); 1430 1431 $db->sql_transaction('begin'); 1432 1433 $sql = 'SELECT p.post_id, p.post_reported 1434 FROM ' . POSTS_TABLE . " p 1435 $where_sql 1436 GROUP BY p.post_id, p.post_reported"; 1437 $result = $db->sql_query($sql); 1438 1439 while ($row = $db->sql_fetchrow($result)) 1440 { 1441 $post_ids[$row['post_id']] = $row['post_id']; 1442 if ($row['post_reported']) 1443 { 1444 $post_reported[$row['post_id']] = 1; 1445 } 1446 } 1447 $db->sql_freeresult($result); 1448 1449 $sql = 'SELECT DISTINCT(post_id) 1450 FROM ' . REPORTS_TABLE . ' 1451 WHERE ' . $db->sql_in_set('post_id', $post_ids) . ' 1452 AND report_closed = 0'; 1453 $result = $db->sql_query($sql); 1454 1455 $post_ids = array(); 1456 while ($row = $db->sql_fetchrow($result)) 1457 { 1458 if (!isset($post_reported[$row['post_id']])) 1459 { 1460 $post_ids[] = $row['post_id']; 1461 } 1462 else 1463 { 1464 unset($post_reported[$row['post_id']]); 1465 } 1466 } 1467 $db->sql_freeresult($result); 1468 1469 // $post_reported should be empty by now, if it's not it contains 1470 // posts that are falsely flagged as reported 1471 foreach ($post_reported as $post_id => $void) 1472 { 1473 $post_ids[] = $post_id; 1474 } 1475 1476 if (sizeof($post_ids)) 1477 { 1478 $sql = 'UPDATE ' . POSTS_TABLE . ' 1479 SET post_reported = 1 - post_reported 1480 WHERE ' . $db->sql_in_set('post_id', $post_ids); 1481 $db->sql_query($sql); 1482 } 1483 1484 $db->sql_transaction('commit'); 1485 break; 1486 1487 case 'topic_reported': 1488 if ($sync_extra) 1489 { 1490 sync('post_reported', $where_type, $where_ids); 1491 } 1492 1493 $topic_ids = $topic_reported = array(); 1494 1495 $db->sql_transaction('begin'); 1496 1497 $sql = 'SELECT DISTINCT(t.topic_id) 1498 FROM ' . POSTS_TABLE . " t 1499 $where_sql_and t.post_reported = 1"; 1500 $result = $db->sql_query($sql); 1501 1502 while ($row = $db->sql_fetchrow($result)) 1503 { 1504 $topic_reported[$row['topic_id']] = 1; 1505 } 1506 $db->sql_freeresult($result); 1507 1508 $sql = 'SELECT t.topic_id, t.topic_reported 1509 FROM ' . TOPICS_TABLE . " t 1510 $where_sql"; 1511 $result = $db->sql_query($sql); 1512 1513 while ($row = $db->sql_fetchrow($result)) 1514 { 1515 if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']])) 1516 { 1517 $topic_ids[] = $row['topic_id']; 1518 } 1519 } 1520 $db->sql_freeresult($result); 1521 1522 if (sizeof($topic_ids)) 1523 { 1524 $sql = 'UPDATE ' . TOPICS_TABLE . ' 1525 SET topic_reported = 1 - topic_reported 1526 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 1527 $db->sql_query($sql); 1528 } 1529 1530 $db->sql_transaction('commit'); 1531 break; 1532 1533 case 'post_attachment': 1534 $post_ids = $post_attachment = array(); 1535 1536 $db->sql_transaction('begin'); 1537 1538 $sql = 'SELECT p.post_id, p.post_attachment 1539 FROM ' . POSTS_TABLE . " p 1540 $where_sql 1541 GROUP BY p.post_id, p.post_attachment"; 1542 $result = $db->sql_query($sql); 1543 1544 while ($row = $db->sql_fetchrow($result)) 1545 { 1546 $post_ids[$row['post_id']] = $row['post_id']; 1547 if ($row['post_attachment']) 1548 { 1549 $post_attachment[$row['post_id']] = 1; 1550 } 1551 } 1552 $db->sql_freeresult($result); 1553 1554 $sql = 'SELECT DISTINCT(post_msg_id) 1555 FROM ' . ATTACHMENTS_TABLE . ' 1556 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . ' 1557 AND in_message = 0'; 1558 $result = $db->sql_query($sql); 1559 1560 $post_ids = array(); 1561 while ($row = $db->sql_fetchrow($result)) 1562 { 1563 if (!isset($post_attachment[$row['post_msg_id']])) 1564 { 1565 $post_ids[] = $row['post_msg_id']; 1566 } 1567 else 1568 { 1569 unset($post_attachment[$row['post_msg_id']]); 1570 } 1571 } 1572 $db->sql_freeresult($result); 1573 1574 // $post_attachment should be empty by now, if it's not it contains 1575 // posts that are falsely flagged as having attachments 1576 foreach ($post_attachment as $post_id => $void) 1577 { 1578 $post_ids[] = $post_id; 1579 } 1580 1581 if (sizeof($post_ids)) 1582 { 1583 $sql = 'UPDATE ' . POSTS_TABLE . ' 1584 SET post_attachment = 1 - post_attachment 1585 WHERE ' . $db->sql_in_set('post_id', $post_ids); 1586 $db->sql_query($sql); 1587 } 1588 1589 $db->sql_transaction('commit'); 1590 break; 1591 1592 case 'topic_attachment': 1593 if ($sync_extra) 1594 { 1595 sync('post_attachment', $where_type, $where_ids); 1596 } 1597 1598 $topic_ids = $topic_attachment = array(); 1599 1600 $db->sql_transaction('begin'); 1601 1602 $sql = 'SELECT DISTINCT(t.topic_id) 1603 FROM ' . POSTS_TABLE . " t 1604 $where_sql_and t.post_attachment = 1"; 1605 $result = $db->sql_query($sql); 1606 1607 while ($row = $db->sql_fetchrow($result)) 1608 { 1609 $topic_attachment[$row['topic_id']] = 1; 1610 } 1611 $db->sql_freeresult($result); 1612 1613 $sql = 'SELECT t.topic_id, t.topic_attachment 1614 FROM ' . TOPICS_TABLE . " t 1615 $where_sql"; 1616 $result = $db->sql_query($sql); 1617 1618 while ($row = $db->sql_fetchrow($result)) 1619 { 1620 if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']])) 1621 { 1622 $topic_ids[] = $row['topic_id']; 1623 } 1624 } 1625 $db->sql_freeresult($result); 1626 1627 if (sizeof($topic_ids)) 1628 { 1629 $sql = 'UPDATE ' . TOPICS_TABLE . ' 1630 SET topic_attachment = 1 - topic_attachment 1631 WHERE ' . $db->sql_in_set('topic_id', $topic_ids); 1632 $db->sql_query($sql); 1633 } 1634 1635 $db->sql_transaction('commit'); 1636 1637 break; 1638 1639 case 'forum': 1640 1641 $db->sql_transaction('begin'); 1642 1643 // 1: Get the list of all forums 1644 $sql = 'SELECT f.* 1645 FROM ' . FORUMS_TABLE . " f 1646 $where_sql"; 1647 $result = $db->sql_query($sql); 1648 1649 $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array(); 1650 while ($row = $db->sql_fetchrow($result)) 1651 { 1652 if ($row['forum_type'] == FORUM_LINK) 1653 { 1654 continue; 1655 } 1656 1657 $forum_id = (int) $row['forum_id']; 1658 $forum_ids[$forum_id] = $forum_id; 1659 1660 $forum_data[$forum_id] = $row; 1661 if ($sync_extra) 1662 { 1663 $forum_data[$forum_id]['posts'] = 0; 1664 $forum_data[$forum_id]['topics'] = 0; 1665 $forum_data[$forum_id]['topics_real'] = 0; 1666 } 1667 $forum_data[$forum_id]['last_post_id'] = 0; 1668 $forum_data[$forum_id]['last_post_subject'] = ''; 1669 $forum_data[$forum_id]['last_post_time'] = 0; 1670 $forum_data[$forum_id]['last_poster_id'] = 0; 1671 $forum_data[$forum_id]['last_poster_name'] = ''; 1672 $forum_data[$forum_id]['last_poster_colour'] = ''; 1673 } 1674 $db->sql_freeresult($result); 1675 1676 if (!sizeof($forum_ids)) 1677 { 1678 break; 1679 } 1680 1681 $forum_ids = array_values($forum_ids); 1682 1683 // 2: Get topic counts for each forum (optional) 1684 if ($sync_extra) 1685 { 1686 $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics 1687 FROM ' . TOPICS_TABLE . ' 1688 WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' 1689 GROUP BY forum_id, topic_approved'; 1690 $result = $db->sql_query($sql); 1691 1692 while ($row = $db->sql_fetchrow($result)) 1693 { 1694 $forum_id = (int) $row['forum_id']; 1695 $forum_data[$forum_id]['topics_real'] += $row['forum_topics']; 1696 1697 if ($row['topic_approved']) 1698 { 1699 $forum_data[$forum_id]['topics'] = $row['forum_topics']; 1700 } 1701 } 1702 $db->sql_freeresult($result); 1703 } 1704 1705 // 3: Get post count for each forum (optional) 1706 if ($sync_extra) 1707 { 1708 if (sizeof($forum_ids) == 1) 1709 { 1710 $sql = 'SELECT SUM(t.topic_replies + 1) AS forum_posts 1711 FROM ' . TOPICS_TABLE . ' t 1712 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' 1713 AND t.topic_approved = 1 1714 AND t.topic_status <> ' . ITEM_MOVED; 1715 } 1716 else 1717 { 1718 $sql = 'SELECT t.forum_id, SUM(t.topic_replies + 1) AS forum_posts 1719 FROM ' . TOPICS_TABLE . ' t 1720 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' 1721 AND t.topic_approved = 1 1722 AND t.topic_status <> ' . ITEM_MOVED . ' 1723 GROUP BY t.forum_id'; 1724 } 1725 1726 $result = $db->sql_query($sql); 1727 1728 while ($row = $db->sql_fetchrow($result)) 1729 { 1730 $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id']; 1731 1732 $forum_data[$forum_id]['posts'] = (int) $row['forum_posts']; 1733 } 1734 $db->sql_freeresult($result); 1735 } 1736 1737 // 4: Get last_post_id for each forum 1738 if (sizeof($forum_ids) == 1) 1739 { 1740 $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id 1741 FROM ' . TOPICS_TABLE . ' t 1742 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' 1743 AND t.topic_approved = 1'; 1744 } 1745 else 1746 { 1747 $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id 1748 FROM ' . TOPICS_TABLE . ' t 1749 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' 1750 AND t.topic_approved = 1 1751 GROUP BY t.forum_id'; 1752 } 1753 1754 $result = $db->sql_query($sql); 1755 1756 while ($row = $db->sql_fetchrow($result)) 1757 { 1758 $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id']; 1759 1760 $forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id']; 1761 1762 $post_ids[] = $row['last_post_id']; 1763 } 1764 $db->sql_freeresult($result); 1765 1766 // 5: Retrieve last_post infos 1767 if (sizeof($post_ids)) 1768 { 1769 $sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour 1770 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u 1771 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' 1772 AND p.poster_id = u.user_id'; 1773 $result = $db->sql_query($sql); 1774 1775 while ($row = $db->sql_fetchrow($result)) 1776 { 1777 $post_info[$row['post_id']] = $row; 1778 } 1779 $db->sql_freeresult($result); 1780 1781 foreach ($forum_data as $forum_id => $data) 1782 { 1783 if ($data['last_post_id']) 1784 { 1785 if (isset($post_info[$data['last_post_id']])) 1786 { 1787 $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject']; 1788 $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time']; 1789 $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id']; 1790 $forum_data[$forum_id]['last_poster_name'] = ($post_info[$data['last_post_id']]['poster_id'] != ANONYMOUS) ? $post_info[$data['last_post_id']]['username'] : $post_info[$data['last_post_id']]['post_username']; 1791 $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour']; 1792 } 1793 else 1794 { 1795 // For some reason we did not find the post in the db 1796 $forum_data[$forum_id]['last_post_id'] = 0; 1797 $forum_data[$forum_id]['last_post_subject'] = ''; 1798 $forum_data[$forum_id]['last_post_time'] = 0; 1799 $forum_data[$forum_id]['last_poster_id'] = 0; 1800 $forum_data[$forum_id]['last_poster_name'] = ''; 1801 $forum_data[$forum_id]['last_poster_colour'] = ''; 1802 } 1803 } 1804 } 1805 unset($post_info); 1806 } 1807 1808 // 6: Now do that thing 1809 $fieldnames = array('last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); 1810 1811 if ($sync_extra) 1812 { 1813 array_push($fieldnames, 'posts', 'topics', 'topics_real'); 1814 } 1815 1816 foreach ($forum_data as $forum_id => $row) 1817 { 1818 $sql_ary = array(); 1819 1820 foreach ($fieldnames as $fieldname) 1821 { 1822 if ($row['forum_' . $fieldname] != $row[$fieldname]) 1823 { 1824 if (preg_match('#(name|colour|subject)$#', $fieldname)) 1825 { 1826 $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname]; 1827 } 1828 else 1829 { 1830 $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname]; 1831 } 1832 } 1833 } 1834 1835 if (sizeof($sql_ary)) 1836 { 1837 $sql = 'UPDATE ' . FORUMS_TABLE . ' 1838 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 1839 WHERE forum_id = ' . $forum_id; 1840 $db->sql_query($sql); 1841 } 1842 } 1843 1844 $db->sql_transaction('commit'); 1845 break; 1846 1847 case 'topic': 1848 $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); 1849 1850 $db->sql_transaction('begin'); 1851 1852 $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_approved, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_replies, t.topic_replies_real, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time 1853 FROM ' . TOPICS_TABLE . " t 1854 $where_sql"; 1855 $result = $db->sql_query($sql); 1856 1857 while ($row = $db->sql_fetchrow($result)) 1858 { 1859 if ($row['topic_moved_id']) 1860 { 1861 $moved_topics[] = $row['topic_id']; 1862 continue; 1863 } 1864 1865 $topic_id = (int) $row['topic_id']; 1866 $topic_data[$topic_id] = $row; 1867 $topic_data[$topic_id]['replies_real'] = -1; 1868 $topic_data[$topic_id]['replies'] = 0; 1869 $topic_data[$topic_id]['first_post_id'] = 0; 1870 $topic_data[$topic_id]['last_post_id'] = 0; 1871 unset($topic_data[$topic_id]['topic_id']); 1872 1873 // This array holds all topic_ids 1874 $delete_topics[$topic_id] = ''; 1875 1876 if ($sync_extra) 1877 { 1878 $topic_data[$topic_id]['reported'] = 0; 1879 $topic_data[$topic_id]['attachment'] = 0; 1880 } 1881 } 1882 $db->sql_freeresult($result); 1883 1884 // Use "t" as table alias because of the $where_sql clause 1885 // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown. 1886 $sql = 'SELECT t.topic_id, t.post_approved, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id 1887 FROM ' . POSTS_TABLE . " t 1888 $where_sql 1889 GROUP BY t.topic_id, t.post_approved"; 1890 $result = $db->sql_query($sql); 1891 1892 while ($row = $db->sql_fetchrow($result)) 1893 { 1894 $topic_id = (int) $row['topic_id']; 1895 1896 $row['first_post_id'] = (int) $row['first_post_id']; 1897 $row['last_post_id'] = (int) $row['last_post_id']; 1898 1899 if (!isset($topic_data[$topic_id])) 1900 { 1901 // Hey, these posts come from a topic that does not exist 1902 $delete_posts[$topic_id] = ''; 1903 } 1904 else 1905 { 1906 // Unset the corresponding entry in $delete_topics 1907 // When we'll be done, only topics with no posts will remain 1908 unset($delete_topics[$topic_id]); 1909 1910 $topic_data[$topic_id]['replies_real'] += $row['total_posts']; 1911 $topic_data[$topic_id]['first_post_id'] = (!$topic_data[$topic_id]['first_post_id']) ? $row['first_post_id'] : min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']); 1912 1913 if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id']) 1914 { 1915 $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1; 1916 $topic_data[$topic_id]['last_post_id'] = $row['last_post_id']; 1917 } 1918 } 1919 } 1920 $db->sql_freeresult($result); 1921 1922 foreach ($topic_data as $topic_id => $row) 1923 { 1924 $post_ids[] = $row['first_post_id']; 1925 if ($row['first_post_id'] != $row['last_post_id']) 1926 { 1927 $post_ids[] = $row['last_post_id']; 1928 } 1929 } 1930 1931 // Now we delete empty topics and orphan posts 1932 if (sizeof($delete_posts)) 1933 { 1934 delete_posts('topic_id', array_keys($delete_posts), false); 1935 unset($delete_posts); 1936 } 1937 1938 if (!sizeof($topic_data)) 1939 { 1940 // If we get there, topic ids were invalid or topics did not contain any posts 1941 delete_topics($where_type, $where_ids, true); 1942 return; 1943 } 1944 1945 if (sizeof($delete_topics)) 1946 { 1947 $delete_topic_ids = array(); 1948 foreach ($delete_topics as $topic_id => $void) 1949 { 1950 unset($topic_data[$topic_id]); 1951 $delete_topic_ids[] = $topic_id; 1952 } 1953 1954 delete_topics('topic_id', $delete_topic_ids, false); 1955 unset($delete_topics, $delete_topic_ids); 1956 } 1957 1958 $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour 1959 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u 1960 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' 1961 AND u.user_id = p.poster_id'; 1962 $result = $db->sql_query($sql); 1963 1964 $post_ids = array(); 1965 while ($row = $db->sql_fetchrow($result)) 1966 { 1967 $topic_id = intval($row['topic_id']); 1968 1969 if ($row['post_id'] == $topic_data[$topic_id]['first_post_id']) 1970 { 1971 if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved']) 1972 { 1973 $approved_unapproved_ids[] = $topic_id; 1974 } 1975 $topic_data[$topic_id]['time'] = $row['post_time']; 1976 $topic_data[$topic_id]['poster'] = $row['poster_id']; 1977 $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; 1978 $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour']; 1979 } 1980 1981 if ($row['post_id'] == $topic_data[$topic_id]['last_post_id']) 1982 { 1983 $topic_data[$topic_id]['last_poster_id'] = $row['poster_id']; 1984 $topic_data[$topic_id]['last_post_subject'] = $row['post_subject']; 1985 $topic_data[$topic_id]['last_post_time'] = $row['post_time']; 1986 $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; 1987 $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour']; 1988 } 1989 } 1990 $db->sql_freeresult($result); 1991 1992 // Make sure shadow topics do link to existing topics 1993 if (sizeof($moved_topics)) 1994 { 1995 $delete_topics = array(); 1996 1997 $sql = 'SELECT t1.topic_id, t1.topic_moved_id 1998 FROM ' . TOPICS_TABLE . ' t1 1999 LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id) 2000 WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . ' 2001 AND t2.topic_id IS NULL'; 2002 $result = $db->sql_query($sql); 2003 2004 while ($row = $db->sql_fetchrow($result)) 2005 { 2006 $delete_topics[] = $row['topic_id']; 2007 } 2008 $db->sql_freeresult($result); 2009 2010 if (sizeof($delete_topics)) 2011 { 2012 delete_topics('topic_id', $delete_topics, false); 2013 } 2014 unset($delete_topics); 2015 2016 // Make sure shadow topics having no last post data being updated (this only rarely happens...) 2017 $sql = 'SELECT topic_id, topic_moved_id, topic_last_post_id, topic_first_post_id 2018 FROM ' . TOPICS_TABLE . ' 2019 WHERE ' . $db->sql_in_set('topic_id', $moved_topics) . ' 2020 AND topic_last_post_time = 0'; 2021 $result = $db->sql_query($sql); 2022 2023 $shadow_topic_data = $post_ids = array(); 2024 while ($row = $db->sql_fetchrow($result)) 2025 { 2026 $shadow_topic_data[$row['topic_moved_id']] = $row; 2027 $post_ids[] = $row['topic_last_post_id']; 2028 $post_ids[] = $row['topic_first_post_id']; 2029 } 2030 $db->sql_freeresult($result); 2031 2032 $sync_shadow_topics = array(); 2033 if (sizeof($post_ids)) 2034 { 2035 $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour 2036 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u 2037 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' 2038 AND u.user_id = p.poster_id'; 2039 $result = $db->sql_query($sql); 2040 2041 $post_ids = array(); 2042 while ($row = $db->sql_fetchrow($result)) 2043 { 2044 $topic_id = (int) $row['topic_id']; 2045 2046 // Ok, there should be a shadow topic. If there isn't, then there's something wrong with the db. 2047 // However, there's not much we can do about it. 2048 if (!empty($shadow_topic_data[$topic_id])) 2049 { 2050 if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_first_post_id']) 2051 { 2052 $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id']; 2053 2054 if (!isset($sync_shadow_topics[$orig_topic_id])) 2055 { 2056 $sync_shadow_topics[$orig_topic_id] = array(); 2057 } 2058 2059 $sync_shadow_topics[$orig_topic_id]['topic_time'] = $row['post_time']; 2060 $sync_shadow_topics[$orig_topic_id]['topic_poster'] = $row['poster_id']; 2061 $sync_shadow_topics[$orig_topic_id]['topic_first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; 2062 $sync_shadow_topics[$orig_topic_id]['topic_first_poster_colour'] = $row['user_colour']; 2063 } 2064 2065 if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_last_post_id']) 2066 { 2067 $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id']; 2068 2069 if (!isset($sync_shadow_topics[$orig_topic_id])) 2070 { 2071 $sync_shadow_topics[$orig_topic_id] = array(); 2072 } 2073 2074 $sync_shadow_topics[$orig_topic_id]['topic_last_poster_id'] = $row['poster_id']; 2075 $sync_shadow_topics[$orig_topic_id]['topic_last_post_subject'] = $row['post_subject']; 2076 $sync_shadow_topics[$orig_topic_id]['topic_last_post_time'] = $row['post_time']; 2077 $sync_shadow_topics[$orig_topic_id]['topic_last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; 2078 $sync_shadow_topics[$orig_topic_id]['topic_last_poster_colour'] = $row['user_colour']; 2079 } 2080 } 2081 } 2082 $db->sql_freeresult($result); 2083 2084 $shadow_topic_data = array(); 2085 2086 // Update the information we collected 2087 if (sizeof($sync_shadow_topics)) 2088 { 2089 foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary) 2090 { 2091 $sql = 'UPDATE ' . TOPICS_TABLE . ' 2092 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 2093 WHERE topic_id = ' . $sync_topic_id; 2094 $db->sql_query($sql); 2095 } 2096 } 2097 } 2098 2099 unset($sync_shadow_topics, $shadow_topic_data); 2100 } 2101 2102 // approved becomes unapproved, and vice-versa 2103 if (sizeof($approved_unapproved_ids)) 2104 { 2105 $sql = 'UPDATE ' . TOPICS_TABLE . ' 2106 SET topic_approved = 1 - topic_approved 2107 WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids); 2108 $db->sql_query($sql); 2109 } 2110 unset($approved_unapproved_ids); 2111 2112 // These are fields that will be synchronised 2113 $fieldnames = array('time', 'replies', 'replies_real', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); 2114 2115 if ($sync_extra) 2116 { 2117 // This routine assumes that post_reported values are correct 2118 // if they are not, use sync('post_reported') first 2119 $sql = 'SELECT t.topic_id, p.post_id 2120 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p 2121 $where_sql_and p.topic_id = t.topic_id 2122 AND p.post_reported = 1 2123 GROUP BY t.topic_id, p.post_id"; 2124 $result = $db->sql_query($sql); 2125 2126 $fieldnames[] = 'reported'; 2127 while ($row = $db->sql_fetchrow($result)) 2128 { 2129 $topic_data[intval($row['topic_id'])]['reported'] = 1; 2130 } 2131 $db->sql_freeresult($result); 2132 2133 // This routine assumes that post_attachment values are correct 2134 // if they are not, use sync('post_attachment') first 2135 $sql = 'SELECT t.topic_id, p.post_id 2136 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p 2137 $where_sql_and p.topic_id = t.topic_id 2138 AND p.post_attachment = 1 2139 GROUP BY t.topic_id, p.post_id"; 2140 $result = $db->sql_query($sql); 2141 2142 $fieldnames[] = 'attachment'; 2143 while ($row = $db->sql_fetchrow($result)) 2144 { 2145 $topic_data[intval($row['topic_id'])]['attachment'] = 1; 2146 } 2147 $db->sql_freeresult($result); 2148 } 2149 2150 foreach ($topic_data as $topic_id => $row) 2151 { 2152 $sql_ary = array(); 2153 2154 foreach ($fieldnames as $fieldname) 2155 { 2156 if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname]) 2157 { 2158 $sql_ary['topic_' . $fieldname] = $row[$fieldname]; 2159 } 2160 } 2161 2162 if (sizeof($sql_ary)) 2163 { 2164 $sql = 'UPDATE ' . TOPICS_TABLE . ' 2165 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 2166 WHERE topic_id = ' . $topic_id; 2167 $db->sql_query($sql); 2168 2169 $resync_forums[$row['forum_id']] = $row['forum_id']; 2170 } 2171 } 2172 unset($topic_data); 2173 2174 $db->sql_transaction('commit'); 2175 2176 // if some topics have been resync'ed then resync parent forums 2177 // except when we're only syncing a range, we don't want to sync forums during 2178 // batch processing. 2179 if ($resync_parents && sizeof($resync_forums) && $where_type != 'range') 2180 { 2181 sync('forum', 'forum_id', array_values($resync_forums), true, true); 2182 } 2183 break; 2184 } 2185 2186 return; 2187 } 2188 2189 /** 2190 * Prune function 2191 */ 2192 function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true) 2193 { 2194 global $db; 2195 2196 if (!is_array($forum_id)) 2197 { 2198 $forum_id = array($forum_id); 2199 } 2200 2201 if (!sizeof($forum_id)) 2202 { 2203 return; 2204 } 2205 2206 $sql_and = ''; 2207 2208 if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE)) 2209 { 2210 $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE; 2211 } 2212 2213 if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY)) 2214 { 2215 $sql_and .= ' AND topic_type <> ' . POST_STICKY; 2216 } 2217 2218 if ($prune_mode == 'posted') 2219 { 2220 $sql_and .= " AND topic_last_post_time < $prune_date"; 2221 } 2222 2223 if ($prune_mode == 'viewed') 2224 { 2225 $sql_and .= " AND topic_last_view_time < $prune_date"; 2226 } 2227 2228 $sql = 'SELECT topic_id 2229 FROM ' . TOPICS_TABLE . ' 2230 WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " 2231 AND poll_start = 0 2232 $sql_and"; 2233 $result = $db->sql_query($sql); 2234 2235 $topic_list = array(); 2236 while ($row = $db->sql_fetchrow($result)) 2237 { 2238 $topic_list[] = $row['topic_id']; 2239 } 2240 $db->sql_freeresult($result); 2241 2242 if ($prune_flags & FORUM_FLAG_PRUNE_POLL) 2243 { 2244 $sql = 'SELECT topic_id 2245 FROM ' . TOPICS_TABLE . ' 2246 WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " 2247 AND poll_start > 0 2248 AND poll_last_vote < $prune_date 2249 $sql_and"; 2250 $result = $db->sql_query($sql); 2251 2252 while ($row = $db->sql_fetchrow($result)) 2253 { 2254 $topic_list[] = $row['topic_id']; 2255 } 2256 $db->sql_freeresult($result); 2257 2258 $topic_list = array_unique($topic_list); 2259 } 2260 2261 return delete_topics('topic_id', $topic_list, $auto_sync, false); 2262 } 2263 2264 /** 2265 * Function auto_prune(), this function now relies on passed vars 2266 */ 2267 function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq) 2268 { 2269 global $db; 2270 2271 $sql = 'SELECT forum_name 2272 FROM ' . FORUMS_TABLE . " 2273 WHERE forum_id = $forum_id"; 2274 $result = $db->sql_query($sql, 3600); 2275 $row = $db->sql_fetchrow($result); 2276 $db->sql_freeresult($result); 2277 2278 if ($row) 2279 { 2280 $prune_date = time() - ($prune_days * 86400); 2281 $next_prune = time() + ($prune_freq * 86400); 2282 2283 prune($forum_id, $prune_mode, $prune_date, $prune_flags, true); 2284 2285 $sql = 'UPDATE ' . FORUMS_TABLE . " 2286 SET prune_next = $next_prune 2287 WHERE forum_id = $forum_id"; 2288 $db->sql_query($sql); 2289 2290 add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']); 2291 } 2292 2293 return; 2294 } 2295 2296 /** 2297 * remove_comments will strip the sql comment lines out of an uploaded sql file 2298 * specifically for mssql and postgres type files in the install.... 2299 * 2300 * @deprecated Use phpbb_remove_comments() instead. 2301 */ 2302 function remove_comments(&$output) 2303 { 2304 // Remove /* */ comments (http://ostermiller.org/findcomment.html) 2305 $output = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $output); 2306 2307 // Return by reference and value. 2308 return $output; 2309 } 2310 2311 /** 2312 * Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username 2313 * and group names must be carried through for the moderators table 2314 */ 2315 function cache_moderators() 2316 { 2317 global $db, $cache, $auth, $phpbb_root_path, $phpEx; 2318 2319 // Remove cached sql results 2320 $cache->destroy('sql', MODERATOR_CACHE_TABLE); 2321 2322 // Clear table 2323 switch ($db->sql_layer) 2324 { 2325 case 'sqlite': 2326 case 'firebird': 2327 $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE); 2328 break; 2329 2330 default: 2331 $db->sql_query('TRUNCATE TABLE ' . MODERATOR_CACHE_TABLE); 2332 break; 2333 } 2334 2335 // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting 2336 $hold_ary = $ug_id_ary = $sql_ary = array(); 2337 2338 // Grab all users having moderative options... 2339 $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false); 2340 2341 // Add users? 2342 if (sizeof($hold_ary)) 2343 { 2344 // At least one moderative option warrants a display 2345 $ug_id_ary = array_keys($hold_ary); 2346 2347 // Remove users who have group memberships with DENY moderator permissions 2348 $sql = $db->sql_build_query('SELECT', array( 2349 'SELECT' => 'a.forum_id, ug.user_id, g.group_id', 2350 2351 'FROM' => array( 2352 ACL_OPTIONS_TABLE => 'o', 2353 USER_GROUP_TABLE => 'ug', 2354 GROUPS_TABLE => 'g', 2355 ACL_GROUPS_TABLE => 'a', 2356 ), 2357 2358 'LEFT_JOIN' => array( 2359 array( 2360 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), 2361 'ON' => 'a.auth_role_id = r.role_id' 2362 ) 2363 ), 2364 2365 'WHERE' => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id) 2366 AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL) 2367 OR r.auth_setting = ' . ACL_NEVER . ') 2368 AND a.group_id = ug.group_id 2369 AND g.group_id = ug.group_id 2370 AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) 2371 AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " 2372 AND ug.user_pending = 0 2373 AND o.auth_option " . $db->sql_like_expression('m_' . $db->any_char), 2374 )); 2375 $result = $db->sql_query($sql); 2376 2377 while ($row = $db->sql_fetchrow($result)) 2378 { 2379 if (isset($hold_ary[$row['user_id']][$row['forum_id']])) 2380 { 2381 unset($hold_ary[$row['user_id']][$row['forum_id']]); 2382 } 2383 } 2384 $db->sql_freeresult($result); 2385 2386 if (sizeof($hold_ary)) 2387 { 2388 // Get usernames... 2389 $sql = 'SELECT user_id, username 2390 FROM ' . USERS_TABLE . ' 2391 WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary)); 2392 $result = $db->sql_query($sql); 2393 2394 $usernames_ary = array(); 2395 while ($row = $db->sql_fetchrow($result)) 2396 { 2397 $usernames_ary[$row['user_id']] = $row['username']; 2398 } 2399 2400 foreach ($hold_ary as $user_id => $forum_id_ary) 2401 { 2402 // Do not continue if user does not exist 2403 if (!isset($usernames_ary[$user_id])) 2404 { 2405 continue; 2406 } 2407 2408 foreach ($forum_id_ary as $forum_id => $auth_ary) 2409 { 2410 $sql_ary[] = array( 2411 'forum_id' => (int) $forum_id, 2412 'user_id' => (int) $user_id, 2413 'username' => (string) $usernames_ary[$user_id], 2414 'group_id' => 0, 2415 'group_name' => '' 2416 ); 2417 } 2418 } 2419 } 2420 } 2421 2422 // Now to the groups... 2423 $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false); 2424 2425 if (sizeof($hold_ary)) 2426 { 2427 $ug_id_ary = array_keys($hold_ary); 2428 2429 // Make sure not hidden or special groups are involved... 2430 $sql = 'SELECT group_name, group_id, group_type 2431 FROM ' . GROUPS_TABLE . ' 2432 WHERE ' . $db->sql_in_set('group_id', $ug_id_ary); 2433 $result = $db->sql_query($sql); 2434 2435 $groupnames_ary = array(); 2436 while ($row = $db->sql_fetchrow($result)) 2437 { 2438 if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL) 2439 { 2440 unset($hold_ary[$row['group_id']]); 2441 } 2442 2443 $groupnames_ary[$row['group_id']] = $row['group_name']; 2444 } 2445 $db->sql_freeresult($result); 2446 2447 foreach ($hold_ary as $group_id => $forum_id_ary) 2448 { 2449 // If there is no group, we do not assign it... 2450 if (!isset($groupnames_ary[$group_id])) 2451 { 2452 continue; 2453 } 2454 2455 foreach ($forum_id_ary as $forum_id => $auth_ary) 2456 { 2457 $flag = false; 2458 foreach ($auth_ary as $auth_option => $setting) 2459 { 2460 // Make sure at least one ACL_YES option is set... 2461 if ($setting == ACL_YES) 2462 { 2463 $flag = true; 2464 break; 2465 } 2466 } 2467 2468 if (!$flag) 2469 { 2470 continue; 2471 } 2472 2473 $sql_ary[] = array( 2474 'forum_id' => (int) $forum_id, 2475 'user_id' => 0, 2476 'username' => '', 2477 'group_id' => (int) $group_id, 2478 'group_name' => (string) $groupnames_ary[$group_id] 2479 ); 2480 } 2481 } 2482 } 2483 2484 $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary); 2485 } 2486 2487 /** 2488 * View log 2489 * If $log_count is set to false, we will skip counting all entries in the database. 2490 */ 2491 function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '') 2492 { 2493 global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path; 2494 2495 $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array(); 2496 2497 $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile'); 2498 2499 switch ($mode) 2500 { 2501 case 'admin': 2502 $log_type = LOG_ADMIN; 2503 $sql_forum = ''; 2504 break; 2505 2506 case 'mod': 2507 $log_type = LOG_MOD; 2508 $sql_forum = ''; 2509 2510 if ($topic_id) 2511 { 2512 $sql_forum = 'AND l.topic_id = ' . (int) $topic_id; 2513 } 2514 else if (is_array($forum_id)) 2515 { 2516 $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id)); 2517 } 2518 else if ($forum_id) 2519 { 2520 $sql_forum = 'AND l.forum_id = ' . (int) $forum_id; 2521 } 2522 break; 2523 2524 case 'user': 2525 $log_type = LOG_USERS; 2526 $sql_forum = 'AND l.reportee_id = ' . (int) $user_id; 2527 break; 2528 2529 case 'users': 2530 $log_type = LOG_USERS; 2531 $sql_forum = ''; 2532 break; 2533 2534 case 'critical': 2535 $log_type = LOG_CRITICAL; 2536 $sql_forum = ''; 2537 break; 2538 2539 default: 2540 return; 2541 } 2542 2543 // Use no preg_quote for $keywords because this would lead to sole backslashes being added 2544 // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later). 2545 $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY); 2546 $sql_keywords = ''; 2547 2548 if (!empty($keywords)) 2549 { 2550 $keywords_pattern = array(); 2551 2552 // Build pattern and keywords... 2553 for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++) 2554 { 2555 $keywords_pattern[] = preg_quote($keywords[$i], '#'); 2556 $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char); 2557 } 2558 2559 $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui'; 2560 2561 $operations = array(); 2562 foreach ($user->lang as $key => $value) 2563 { 2564 if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value)) 2565 { 2566 $operations[] = $key; 2567 } 2568 } 2569 2570 $sql_keywords = 'AND ('; 2571 if (!empty($operations)) 2572 { 2573 $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR '; 2574 } 2575 $sql_lower = $db->sql_lower_text('l.log_data'); 2576 $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')'; 2577 } 2578 2579 if ($log_count !== false) 2580 { 2581 $sql = 'SELECT COUNT(l.log_id) AS total_entries 2582 FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u 2583 WHERE l.log_type = $log_type 2584 AND l.user_id = u.user_id 2585 AND l.log_time >= $limit_days 2586 $sql_keywords 2587 $sql_forum"; 2588 $result = $db->sql_query($sql); 2589 $log_count = (int) $db->sql_fetchfield('total_entries'); 2590 $db->sql_freeresult($result); 2591 } 2592 2593 // $log_count may be false here if false was passed in for it, 2594 // because in this case we did not run the COUNT() query above. 2595 // If we ran the COUNT() query and it returned zero rows, return; 2596 // otherwise query for logs below. 2597 if ($log_count === 0) 2598 { 2599 // Save the queries, because there are no logs to display 2600 return 0; 2601 } 2602 2603 if ($offset >= $log_count) 2604 { 2605 $offset = ($offset - $limit < 0) ? 0 : $offset - $limit; 2606 } 2607 2608 $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour 2609 FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u 2610 WHERE l.log_type = $log_type 2611 AND u.user_id = l.user_id 2612 " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . " 2613 $sql_keywords 2614 $sql_forum 2615 ORDER BY $sort_by"; 2616 $result = $db->sql_query_limit($sql, $limit, $offset); 2617 2618 $i = 0; 2619 $log = array(); 2620 while ($row = $db->sql_fetchrow($result)) 2621 { 2622 if ($row['topic_id']) 2623 { 2624 $topic_id_list[] = $row['topic_id']; 2625 } 2626 2627 if ($row['reportee_id']) 2628 { 2629 $reportee_id_list[] = $row['reportee_id']; 2630 } 2631 2632 $log[$i] = array( 2633 'id' => $row['log_id'], 2634 2635 'reportee_id' => $row['reportee_id'], 2636 'reportee_username' => '', 2637 'reportee_username_full'=> '', 2638 2639 'user_id' => $row['user_id'], 2640 'username' => $row['username'], 2641 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url), 2642 2643 'ip' => $row['log_ip'], 2644 'time' => $row['log_time'], 2645 'forum_id' => $row['forum_id'], 2646 'topic_id' => $row['topic_id'], 2647 2648 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false, 2649 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}', 2650 ); 2651 2652 if (!empty($row['log_data'])) 2653 { 2654 $log_data_ary = @unserialize($row['log_data']); 2655 $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary; 2656 2657 if (isset($user->lang[$row['log_operation']])) 2658 { 2659 // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array 2660 // It doesn't matter if we add more arguments than placeholders 2661 if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0) 2662 { 2663 $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), '')); 2664 } 2665 2666 $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary); 2667 2668 // If within the admin panel we do not censor text out 2669 if (defined('IN_ADMIN')) 2670 { 2671 $log[$i]['action'] = bbcode_nl2br($log[$i]['action']); 2672 } 2673 else 2674 { 2675 $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action'])); 2676 } 2677 } 2678 else if (!empty($log_data_ary)) 2679 { 2680 $log[$i]['action'] .= '<br />' . implode('', $log_data_ary); 2681 } 2682 2683 /* Apply make_clickable... has to be seen if it is for good. :/ 2684 // Seems to be not for the moment, reconsider later... 2685 $log[$i]['action'] = make_clickable($log[$i]['action']); 2686 */ 2687 } 2688 2689 $i++; 2690 } 2691 $db->sql_freeresult($result); 2692 2693 if (sizeof($topic_id_list)) 2694 { 2695 $topic_id_list = array_unique($topic_id_list); 2696 2697 // This query is not really needed if move_topics() updates the forum_id field, 2698 // although it's also used to determine if the topic still exists in the database 2699 $sql = 'SELECT topic_id, forum_id 2700 FROM ' . TOPICS_TABLE . ' 2701 WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list)); 2702 $result = $db->sql_query($sql); 2703 2704 $default_forum_id = 0; 2705 2706 while ($row = $db->sql_fetchrow($result)) 2707 { 2708 if (!$row['forum_id']) 2709 { 2710 if ($auth->acl_getf_global('f_read')) 2711 { 2712 if (!$default_forum_id) 2713 { 2714 $sql = 'SELECT forum_id 2715 FROM ' . FORUMS_TABLE . ' 2716 WHERE forum_type = ' . FORUM_POST; 2717 $f_result = $db->sql_query_limit($sql, 1); 2718 $default_forum_id = (int) $db->sql_fetchfield('forum_id', false, $f_result); 2719 $db->sql_freeresult($f_result); 2720 } 2721 2722 $is_auth[$row['topic_id']] = $default_forum_id; 2723 } 2724 } 2725 else 2726 { 2727 if ($auth->acl_get('f_read', $row['forum_id'])) 2728 { 2729 $is_auth[$row['topic_id']] = $row['forum_id']; 2730 } 2731 } 2732 2733 if ($auth->acl_gets('a_', 'm_', $row['forum_id'])) 2734 { 2735 $is_mod[$row['topic_id']] = $row['forum_id']; 2736 } 2737 } 2738 $db->sql_freeresult($result); 2739 2740 foreach ($log as $key => $row) 2741 { 2742 $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&t=' . $row['topic_id']) : false; 2743 $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&mode=topic_logs&t=' . $row['topic_id'], true, $user->session_id) : false; 2744 } 2745 } 2746 2747 if (sizeof($reportee_id_list)) 2748 { 2749 $reportee_id_list = array_unique($reportee_id_list); 2750 $reportee_names_list = array(); 2751 2752 $sql = 'SELECT user_id, username, user_colour 2753 FROM ' . USERS_TABLE . ' 2754 WHERE ' . $db->sql_in_set('user_id', $reportee_id_list); 2755 $result = $db->sql_query($sql); 2756 2757 while ($row = $db->sql_fetchrow($result)) 2758 { 2759 $reportee_names_list[$row['user_id']] = $row; 2760 } 2761 $db->sql_freeresult($result); 2762 2763 foreach ($log as $key => $row) 2764 { 2765 if (!isset($reportee_names_list[$row['reportee_id']])) 2766 { 2767 continue; 2768 } 2769 2770 $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username']; 2771 $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url); 2772 } 2773 } 2774 2775 return $offset; 2776 } 2777 2778 /** 2779 * Update foes - remove moderators and administrators from foe lists... 2780 */ 2781 function update_foes($group_id = false, $user_id = false) 2782 { 2783 global $db, $auth; 2784 2785 // update foes for some user 2786 if (is_array($user_id) && sizeof($user_id)) 2787 { 2788 $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' 2789 WHERE ' . $db->sql_in_set('zebra_id', $user_id) . ' 2790 AND foe = 1'; 2791 $db->sql_query($sql); 2792 return; 2793 } 2794 2795 // update foes for some group 2796 if (is_array($group_id) && sizeof($group_id)) 2797 { 2798 // Grab group settings... 2799 $sql = $db->sql_build_query('SELECT', array( 2800 'SELECT' => 'a.group_id', 2801 2802 'FROM' => array( 2803 ACL_OPTIONS_TABLE => 'ao', 2804 ACL_GROUPS_TABLE => 'a' 2805 ), 2806 2807 'LEFT_JOIN' => array( 2808 array( 2809 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), 2810 'ON' => 'a.auth_role_id = r.role_id' 2811 ), 2812 ), 2813 2814 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id) 2815 AND ' . $db->sql_in_set('a.group_id', $group_id) . " 2816 AND ao.auth_option IN ('a_', 'm_')", 2817 2818 'GROUP_BY' => 'a.group_id' 2819 )); 2820 $result = $db->sql_query($sql); 2821 2822 $groups = array(); 2823 while ($row = $db->sql_fetchrow($result)) 2824 { 2825 $groups[] = (int) $row['group_id']; 2826 } 2827 $db->sql_freeresult($result); 2828 2829 if (!sizeof($groups)) 2830 { 2831 return; 2832 } 2833 2834 switch ($db->sql_layer) 2835 { 2836 case 'mysqli': 2837 case 'mysql4': 2838 $sql = 'DELETE ' . (($db->sql_layer === 'mysqli' || version_compare($db->sql_server_info(true), '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . ' 2839 FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug 2840 WHERE z.zebra_id = ug.user_id 2841 AND z.foe = 1 2842 AND ' . $db->sql_in_set('ug.group_id', $groups); 2843 $db->sql_query($sql); 2844 break; 2845 2846 default: 2847 $sql = 'SELECT user_id 2848 FROM ' . USER_GROUP_TABLE . ' 2849 WHERE ' . $db->sql_in_set('group_id', $groups); 2850 $result = $db->sql_query($sql); 2851 2852 $users = array(); 2853 while ($row = $db->sql_fetchrow($result)) 2854 { 2855 $users[] = (int) $row['user_id']; 2856 } 2857 $db->sql_freeresult($result); 2858 2859 if (sizeof($users)) 2860 { 2861 $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' 2862 WHERE ' . $db->sql_in_set('zebra_id', $users) . ' 2863 AND foe = 1'; 2864 $db->sql_query($sql); 2865 } 2866 break; 2867 } 2868 2869 return; 2870 } 2871 2872 // update foes for everyone 2873 $perms = array(); 2874 foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary) 2875 { 2876 foreach ($forum_ary as $auth_option => $user_ary) 2877 { 2878 $perms = array_merge($perms, $user_ary); 2879 } 2880 } 2881 2882 if (sizeof($perms)) 2883 { 2884 $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' 2885 WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . ' 2886 AND foe = 1'; 2887 $db->sql_query($sql); 2888 } 2889 unset($perms); 2890 } 2891 2892 /** 2893 * Lists inactive users 2894 */ 2895 function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC') 2896 { 2897 global $db, $user; 2898 2899 $sql = 'SELECT COUNT(user_id) AS user_count 2900 FROM ' . USERS_TABLE . ' 2901 WHERE user_type = ' . USER_INACTIVE . 2902 (($limit_days) ? " AND user_inactive_time >= $limit_days" : ''); 2903 $result = $db->sql_query($sql); 2904 $user_count = (int) $db->sql_fetchfield('user_count'); 2905 $db->sql_freeresult($result); 2906 2907 if ($user_count == 0) 2908 { 2909 // Save the queries, because there are no users to display 2910 return 0; 2911 } 2912 2913 if ($offset >= $user_count) 2914 { 2915 $offset = ($offset - $limit < 0) ? 0 : $offset - $limit; 2916 } 2917 2918 $sql = 'SELECT * 2919 FROM ' . USERS_TABLE . ' 2920 WHERE user_type = ' . USER_INACTIVE . 2921 (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . " 2922 ORDER BY $sort_by"; 2923 $result = $db->sql_query_limit($sql, $limit, $offset); 2924 2925 while ($row = $db->sql_fetchrow($result)) 2926 { 2927 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN']; 2928 switch ($row['user_inactive_reason']) 2929 { 2930 case INACTIVE_REGISTER: 2931 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER']; 2932 break; 2933 2934 case INACTIVE_PROFILE: 2935 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE']; 2936 break; 2937 2938 case INACTIVE_MANUAL: 2939 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL']; 2940 break; 2941 2942 case INACTIVE_REMIND: 2943 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND']; 2944 break; 2945 } 2946 2947 $users[] = $row; 2948 } 2949 2950 return $offset; 2951 } 2952 2953 /** 2954 * Lists warned users 2955 */ 2956 function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC') 2957 { 2958 global $db; 2959 2960 $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning 2961 FROM ' . USERS_TABLE . ' 2962 WHERE user_warnings > 0 2963 ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . " 2964 ORDER BY $sort_by"; 2965 $result = $db->sql_query_limit($sql, $limit, $offset); 2966 $users = $db->sql_fetchrowset($result); 2967 $db->sql_freeresult($result); 2968 2969 $sql = 'SELECT count(user_id) AS user_count 2970 FROM ' . USERS_TABLE . ' 2971 WHERE user_warnings > 0 2972 ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : ''); 2973 $result = $db->sql_query($sql); 2974 $user_count = (int) $db->sql_fetchfield('user_count'); 2975 $db->sql_freeresult($result); 2976 2977 return; 2978 } 2979 2980 /** 2981 * Get database size 2982 * Currently only mysql and mssql are supported 2983 */ 2984 function get_database_size() 2985 { 2986 global $db, $user, $table_prefix; 2987 2988 $database_size = false; 2989 2990 // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0 2991 switch ($db->sql_layer) 2992 { 2993 case 'mysql': 2994 case 'mysql4': 2995 case 'mysqli': 2996 $sql = 'SELECT VERSION() AS mysql_version'; 2997 $result = $db->sql_query($sql); 2998 $row = $db->sql_fetchrow($result); 2999 $db->sql_freeresult($result); 3000 3001 if ($row) 3002 { 3003 $version = $row['mysql_version']; 3004 3005 if (preg_match('#(3\.23|[45]\.)#', $version)) 3006 { 3007 $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->dbname}`" : $db->dbname; 3008 3009 $sql = 'SHOW TABLE STATUS 3010 FROM ' . $db_name; 3011 $result = $db->sql_query($sql, 7200); 3012 3013 $database_size = 0; 3014 while ($row = $db->sql_fetchrow($result)) 3015 { 3016 if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB'))) 3017 { 3018 if ($table_prefix != '') 3019 { 3020 if (strpos($row['Name'], $table_prefix) !== false) 3021 { 3022 $database_size += $row['Data_length'] + $row['Index_length']; 3023 } 3024 } 3025 else 3026 { 3027 $database_size += $row['Data_length'] + $row['Index_length']; 3028 } 3029 } 3030 } 3031 $db->sql_freeresult($result); 3032 } 3033 } 3034 break; 3035 3036 case 'firebird': 3037 global $dbname; 3038 3039 // if it on the local machine, we can get lucky 3040 if (file_exists($dbname)) 3041 { 3042 $database_size = filesize($dbname); 3043 } 3044 3045 break; 3046 3047 case 'sqlite': 3048 global $dbhost; 3049 3050 if (file_exists($dbhost)) 3051 { 3052 $database_size = filesize($dbhost); 3053 } 3054 3055 break; 3056 3057 case 'mssql': 3058 case 'mssql_odbc': 3059 case 'mssqlnative': 3060 $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize 3061 FROM sysfiles'; 3062 $result = $db->sql_query($sql, 7200); 3063 $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false; 3064 $db->sql_freeresult($result); 3065 break; 3066 3067 case 'postgres': 3068 $sql = "SELECT proname 3069 FROM pg_proc 3070 WHERE proname = 'pg_database_size'"; 3071 $result = $db->sql_query($sql); 3072 $row = $db->sql_fetchrow($result); 3073 $db->sql_freeresult($result); 3074 3075 if ($row['proname'] == 'pg_database_size') 3076 { 3077 $database = $db->dbname; 3078 if (strpos($database, '.') !== false) 3079 { 3080 list($database, ) = explode('.', $database); 3081 } 3082 3083 $sql = "SELECT oid 3084 FROM pg_database 3085 WHERE datname = '$database'"; 3086 $result = $db->sql_query($sql); 3087 $row = $db->sql_fetchrow($result); 3088 $db->sql_freeresult($result); 3089 3090 $oid = $row['oid']; 3091 3092 $sql = 'SELECT pg_database_size(' . $oid . ') as size'; 3093 $result = $db->sql_query($sql); 3094 $row = $db->sql_fetchrow($result); 3095 $db->sql_freeresult($result); 3096 3097 $database_size = $row['size']; 3098 } 3099 break; 3100 3101 case 'oracle': 3102 $sql = 'SELECT SUM(bytes) as dbsize 3103 FROM user_segments'; 3104 $result = $db->sql_query($sql, 7200); 3105 $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false; 3106 $db->sql_freeresult($result); 3107 break; 3108 } 3109 3110 $database_size = ($database_size !== false) ? get_formatted_filesize($database_size) : $user->lang['NOT_AVAILABLE']; 3111 3112 return $database_size; 3113 } 3114 3115 /** 3116 * Retrieve contents from remotely stored file 3117 */ 3118 function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6) 3119 { 3120 global $user; 3121 3122 if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout)) 3123 { 3124 @fputs($fsock, "GET $directory/$filename HTTP/1.0\r\n"); 3125 @fputs($fsock, "HOST: $host\r\n"); 3126 @fputs($fsock, "Connection: close\r\n\r\n"); 3127 3128 $timer_stop = time() + $timeout; 3129 stream_set_timeout($fsock, $timeout); 3130 3131 $file_info = ''; 3132 $get_info = false; 3133 3134 while (!@feof($fsock)) 3135 { 3136 if ($get_info) 3137 { 3138 $file_info .= @fread($fsock, 1024); 3139 } 3140 else 3141 { 3142 $line = @fgets($fsock, 1024); 3143 if ($line == "\r\n") 3144 { 3145 $get_info = true; 3146 } 3147 else if (stripos($line, '404 not found') !== false) 3148 { 3149 $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename; 3150 return false; 3151 } 3152 } 3153 3154 $stream_meta_data = stream_get_meta_data($fsock); 3155 3156 if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop) 3157 { 3158 $errstr = $user->lang['FSOCK_TIMEOUT']; 3159 return false; 3160 } 3161 } 3162 @fclose($fsock); 3163 } 3164 else 3165 { 3166 if ($errstr) 3167 { 3168 $errstr = utf8_convert_message($errstr); 3169 return false; 3170 } 3171 else 3172 { 3173 $errstr = $user->lang['FSOCK_DISABLED']; 3174 return false; 3175 } 3176 } 3177 3178 return $file_info; 3179 } 3180 3181 /** 3182 * Tidy Warnings 3183 * Remove all warnings which have now expired from the database 3184 * The duration of a warning can be defined by the administrator 3185 * This only removes the warning and reduces the associated count, 3186 * it does not remove the user note recording the contents of the warning 3187 */ 3188 function tidy_warnings() 3189 { 3190 global $db, $config; 3191 3192 $expire_date = time() - ($config['warnings_expire_days'] * 86400); 3193 $warning_list = $user_list = array(); 3194 3195 $sql = 'SELECT * FROM ' . WARNINGS_TABLE . " 3196 WHERE warning_time < $expire_date"; 3197 $result = $db->sql_query($sql); 3198 3199 while ($row = $db->sql_fetchrow($result)) 3200 { 3201 $warning_list[] = $row['warning_id']; 3202 $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? ++$user_list[$row['user_id']] : 1; 3203 } 3204 $db->sql_freeresult($result); 3205 3206 if (sizeof($warning_list)) 3207 { 3208 $db->sql_transaction('begin'); 3209 3210 $sql = 'DELETE FROM ' . WARNINGS_TABLE . ' 3211 WHERE ' . $db->sql_in_set('warning_id', $warning_list); 3212 $db->sql_query($sql); 3213 3214 foreach ($user_list as $user_id => $value) 3215 { 3216 $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value 3217 WHERE user_id = $user_id"; 3218 $db->sql_query($sql); 3219 } 3220 3221 $db->sql_transaction('commit'); 3222 } 3223 3224 set_config('warnings_last_gc', time(), true); 3225 } 3226 3227 /** 3228 * Tidy database, doing some maintanance tasks 3229 */ 3230 function tidy_database() 3231 { 3232 global $db; 3233 3234 // Here we check permission consistency 3235 3236 // Sometimes, it can happen permission tables having forums listed which do not exist 3237 $sql = 'SELECT forum_id 3238 FROM ' . FORUMS_TABLE; 3239 $result = $db->sql_query($sql); 3240 3241 $forum_ids = array(0); 3242 while ($row = $db->sql_fetchrow($result)) 3243 { 3244 $forum_ids[] = $row['forum_id']; 3245 } 3246 $db->sql_freeresult($result); 3247 3248 // Delete those rows from the acl tables not having listed the forums above 3249 $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' 3250 WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true); 3251 $db->sql_query($sql); 3252 3253 $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' 3254 WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true); 3255 $db->sql_query($sql); 3256 3257 set_config('database_last_gc', time(), true); 3258 } 3259 3260 /** 3261 * Add permission language - this will make sure custom files will be included 3262 */ 3263 function add_permission_language() 3264 { 3265 global $user, $phpEx; 3266 3267 // First of all, our own file. We need to include it as the first file because it presets all relevant variables. 3268 $user->add_lang('acp/permissions_phpbb'); 3269 3270 $files_to_add = array(); 3271 3272 // Now search in acp and mods folder for permissions_ files. 3273 foreach (array('acp/', 'mods/') as $path) 3274 { 3275 $dh = @opendir($user->lang_path . $user->lang_name . '/' . $path); 3276 3277 if ($dh) 3278 { 3279 while (($file = readdir($dh)) !== false) 3280 { 3281 if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx) 3282 { 3283 $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1)); 3284 } 3285 } 3286 closedir($dh); 3287 } 3288 } 3289 3290 if (!sizeof($files_to_add)) 3291 { 3292 return false; 3293 } 3294 3295 $user->add_lang($files_to_add); 3296 return true; 3297 } 3298 3299 /** 3300 * Obtains the latest version information 3301 * 3302 * @param bool $force_update Ignores cached data. Defaults to false. 3303 * @param bool $warn_fail Trigger a warning if obtaining the latest version information fails. Defaults to false. 3304 * @param int $ttl Cache version information for $ttl seconds. Defaults to 86400 (24 hours). 3305 * 3306 * @return string | false Version info on success, false on failure. 3307 */ 3308 function obtain_latest_version_info($force_update = false, $warn_fail = false, $ttl = 86400) 3309 { 3310 global $cache; 3311 3312 $info = $cache->get('versioncheck'); 3313 3314 if ($info === false || $force_update) 3315 { 3316 $errstr = ''; 3317 $errno = 0; 3318 3319 $info = get_remote_file('version.phpbb.com', '/phpbb', 3320 ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno); 3321 3322 if (empty($info)) 3323 { 3324 $cache->destroy('versioncheck'); 3325 if ($warn_fail) 3326 { 3327 trigger_error($errstr, E_USER_WARNING); 3328 } 3329 return false; 3330 } 3331 3332 $cache->put('versioncheck', $info, $ttl); 3333 } 3334 3335 return $info; 3336 } 3337 3338 /** 3339 * Enables a particular flag in a bitfield column of a given table. 3340 * 3341 * @param string $table_name The table to update 3342 * @param string $column_name The column containing a bitfield to update 3343 * @param int $flag The binary flag which is OR-ed with the current column value 3344 * @param string $sql_more This string is attached to the sql query generated to update the table. 3345 * 3346 * @return null 3347 */ 3348 function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') 3349 { 3350 global $db; 3351 3352 $sql = 'UPDATE ' . $table_name . ' 3353 SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . ' 3354 ' . $sql_more; 3355 $db->sql_query($sql); 3356 } 3357 3358 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Oct 2 15:03:47 2013 | Cross-referenced by PHPXref 0.7.1 |