Verzeichnisstruktur phpBB-3.0.0
- Veröffentlicht
- 12.12.2007
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
functions_admin.php
0001 <?php
0002 /**
0003 *
0004 * @package acp
0005 * @version $Id$
0006 * @copyright (c) 2005 phpBB Group
0007 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
0008 *
0009 */
0010
0011 /**
0012 * @ignore
0013 */
0014 if (!defined('IN_PHPBB'))
0015 {
0016 exit;
0017 }
0018
0019 /**
0020 * Recalculate Binary Tree
0021 function recalc_btree($sql_id, $sql_table, $module_class = '')
0022 {
0023 global $db;
0024
0025 if (!$sql_id || !$sql_table)
0026 {
0027 return;
0028 }
0029
0030 $sql_where = ($module_class) ? " WHERE module_class = '" . $db->sql_escape($module_class) . "'" : '';
0031
0032 // Reset to minimum possible left and right id
0033 $sql = "SELECT MIN(left_id) as min_left_id, MIN(right_id) as min_right_id
0034 FROM $sql_table
0035 $sql_where";
0036 $result = $db->sql_query($sql);
0037 $row = $db->sql_fetchrow($result);
0038 $db->sql_freeresult($result);
0039
0040 $substract = (int) (min($row['min_left_id'], $row['min_right_id']) - 1);
0041
0042 if ($substract > 0)
0043 {
0044 $sql = "UPDATE $sql_table
0045 SET left_id = left_id - $substract, right_id = right_id - $substract
0046 $sql_where";
0047 $db->sql_query($sql);
0048 }
0049
0050 $sql = "SELECT $sql_id, parent_id, left_id, right_id
0051 FROM $sql_table
0052 $sql_where
0053 ORDER BY left_id ASC, parent_id ASC, $sql_id ASC";
0054 $f_result = $db->sql_query($sql);
0055
0056 while ($item_data = $db->sql_fetchrow($f_result))
0057 {
0058 if ($item_data['parent_id'])
0059 {
0060 $sql = "SELECT left_id, right_id
0061 FROM $sql_table
0062 $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
0063 $sql_id = {$item_data['parent_id']}";
0064 $result = $db->sql_query($sql);
0065
0066 if (!$row = $db->sql_fetchrow($result))
0067 {
0068 $sql = "UPDATE $sql_table SET parent_id = 0 WHERE $sql_id = " . $item_data[$sql_id];
0069 $db->sql_query($sql);
0070 }
0071 $db->sql_freeresult($result);
0072
0073 $sql = "UPDATE $sql_table
0074 SET left_id = left_id + 2, right_id = right_id + 2
0075 $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
0076 left_id > {$row['right_id']}";
0077 $db->sql_query($sql);
0078
0079 $sql = "UPDATE $sql_table
0080 SET right_id = right_id + 2
0081 $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
0082 {$row['left_id']} BETWEEN left_id AND right_id";
0083 $db->sql_query($sql);
0084
0085 $item_data['left_id'] = $row['right_id'];
0086 $item_data['right_id'] = $row['right_id'] + 1;
0087 }
0088 else
0089 {
0090 $sql = "SELECT MAX(right_id) AS right_id
0091 FROM $sql_table
0092 $sql_where";
0093 $result = $db->sql_query($sql);
0094 $row = $db->sql_fetchrow($result);
0095 $db->sql_freeresult($result);
0096
0097 $item_data['left_id'] = $row['right_id'] + 1;
0098 $item_data['right_id'] = $row['right_id'] + 2;
0099 }
0100
0101 $sql = "UPDATE $sql_table
0102 SET left_id = {$item_data['left_id']}, right_id = {$item_data['right_id']}
0103 WHERE $sql_id = " . $item_data[$sql_id];
0104 $db->sql_query($sql);
0105 }
0106 $db->sql_freeresult($f_result);
0107 }
0108 */
0109
0110 /**
0111 * Simple version of jumpbox, just lists authed forums
0112 */
0113 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)
0114 {
0115 global $db, $user, $auth;
0116
0117 $acl = ($ignore_acl) ? '' : (($only_acl_post) ? 'f_post' : array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'));
0118
0119 // This query is identical to the jumpbox one
0120 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
0121 FROM ' . FORUMS_TABLE . '
0122 ORDER BY left_id ASC';
0123 $result = $db->sql_query($sql, 600);
0124
0125 $right = 0;
0126 $padding_store = array('0' => '');
0127 $padding = '';
0128 $forum_list = ($return_array) ? array() : '';
0129
0130 // Sometimes it could happen that forums will be displayed here not be displayed within the index page
0131 // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
0132 // If this happens, the padding could be "broken"
0133
0134 while ($row = $db->sql_fetchrow($result))
0135 {
0136 if ($row['left_id'] < $right)
0137 {
0138 $padding .= ' ';
0139 $padding_store[$row['parent_id']] = $padding;
0140 }
0141 else if ($row['left_id'] > $right + 1)
0142 {
0143 $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : '';
0144 }
0145
0146 $right = $row['right_id'];
0147 $disabled = false;
0148
0149 if ($acl && !$auth->acl_gets($acl, $row['forum_id']))
0150 {
0151 // List permission?
0152 if ($auth->acl_get('f_list', $row['forum_id']))
0153 {
0154 $disabled = true;
0155 }
0156 else
0157 {
0158 continue;
0159 }
0160 }
0161
0162 if (
0163 ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id)
0164 ||
0165 // Non-postable forum with no subforums, don't display
0166 ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat)
0167 ||
0168 ($row['forum_type'] != FORUM_POST && $ignore_nonpost)
0169 )
0170 {
0171 $disabled = true;
0172 }
0173
0174 if ($return_array)
0175 {
0176 // Include some more information...
0177 $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false);
0178 $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row);
0179 }
0180 else
0181 {
0182 $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : '');
0183 $forum_list .= '<option value="' . $row['forum_id'] . '"' . (($disabled) ? ' disabled="disabled" class="disabled-option"' : $selected) . '>' . $padding . $row['forum_name'] . '</option>';
0184 }
0185 }
0186 $db->sql_freeresult($result);
0187 unset($padding_store);
0188
0189 return $forum_list;
0190 }
0191
0192 /**
0193 * Generate size select options
0194 */
0195 function size_select_options($size_compare)
0196 {
0197 global $user;
0198
0199 $size_types_text = array($user->lang['BYTES'], $user->lang['KB'], $user->lang['MB']);
0200 $size_types = array('b', 'kb', 'mb');
0201
0202 $s_size_options = '';
0203
0204 for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++)
0205 {
0206 $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : '';
0207 $s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>';
0208 }
0209
0210 return $s_size_options;
0211 }
0212
0213 /**
0214 * Generate list of groups (option fields without select)
0215 *
0216 * @param int $group_id The default group id to mark as selected
0217 * @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id
0218 * @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.
0219 *
0220 * @return string The list of options.
0221 */
0222 function group_select_options($group_id, $exclude_ids = false, $manage_founder = false)
0223 {
0224 global $db, $user, $config;
0225
0226 $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
0227 $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : '';
0228 $sql_founder = ($manage_founder !== false) ? (($exclude_sql || $sql_and) ? ' AND ' : ' WHERE ') . 'group_founder_manage = ' . (int) $manage_founder : '';
0229
0230 $sql = 'SELECT group_id, group_name, group_type
0231 FROM ' . GROUPS_TABLE . "
0232 $exclude_sql
0233 $sql_and
0234 $sql_founder
0235 ORDER BY group_type DESC, group_name ASC";
0236 $result = $db->sql_query($sql);
0237
0238 $s_group_options = '';
0239 while ($row = $db->sql_fetchrow($result))
0240 {
0241 $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : '';
0242 $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>';
0243 }
0244 $db->sql_freeresult($result);
0245
0246 return $s_group_options;
0247 }
0248
0249 /**
0250 * Obtain authed forums list
0251 */
0252 function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false)
0253 {
0254 global $db, $auth;
0255 static $forum_rows;
0256
0257 if (!isset($forum_rows))
0258 {
0259 // This query is identical to the jumpbox one
0260 $expire_time = ($no_cache) ? 0 : 600;
0261
0262 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
0263 FROM ' . FORUMS_TABLE . '
0264 ORDER BY left_id ASC';
0265 $result = $db->sql_query($sql, $expire_time);
0266
0267 $forum_rows = array();
0268
0269 $right = $padding = 0;
0270 $padding_store = array('0' => 0);
0271
0272 while ($row = $db->sql_fetchrow($result))
0273 {
0274 if ($row['left_id'] < $right)
0275 {
0276 $padding++;
0277 $padding_store[$row['parent_id']] = $padding;
0278 }
0279 else if ($row['left_id'] > $right + 1)
0280 {
0281 // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it.
0282 // @todo digging deep to find out "how" this can happen.
0283 $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding;
0284 }
0285
0286 $right = $row['right_id'];
0287 $row['padding'] = $padding;
0288
0289 $forum_rows[] = $row;
0290 }
0291 $db->sql_freeresult($result);
0292 unset($padding_store);
0293 }
0294
0295 $rowset = array();
0296 foreach ($forum_rows as $row)
0297 {
0298 if ($postable_only && $row['forum_type'] != FORUM_POST)
0299 {
0300 continue;
0301 }
0302
0303 if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id'])))
0304 {
0305 $rowset[] = ($id_only) ? $row['forum_id'] : $row;
0306 }
0307 }
0308
0309 return $rowset;
0310 }
0311
0312 /**
0313 * Get forum branch
0314 */
0315 function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true)
0316 {
0317 global $db;
0318
0319 switch ($type)
0320 {
0321 case 'parents':
0322 $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id';
0323 break;
0324
0325 case 'children':
0326 $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id';
0327 break;
0328
0329 default:
0330 $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id';
0331 break;
0332 }
0333
0334 $rows = array();
0335
0336 $sql = 'SELECT f2.*
0337 FROM ' . FORUMS_TABLE . ' f1
0338 LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition)
0339 WHERE f1.forum_id = $forum_id
0340 ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC');
0341 $result = $db->sql_query($sql);
0342
0343 while ($row = $db->sql_fetchrow($result))
0344 {
0345 if (!$include_forum && $row['forum_id'] == $forum_id)
0346 {
0347 continue;
0348 }
0349
0350 $rows[] = $row;
0351 }
0352 $db->sql_freeresult($result);
0353
0354 return $rows;
0355 }
0356
0357 /**
0358 * Get physical file listing
0359 */
0360 function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png')
0361 {
0362 $matches = array();
0363
0364 // Remove initial / if present
0365 $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir;
0366 // Add closing / if not present
0367 $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir;
0368
0369 // Remove initial / if present
0370 $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir;
0371 // Add closing / if not present
0372 $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir;
0373
0374 if (!is_dir($rootdir . $dir))
0375 {
0376 return $matches;
0377 }
0378
0379 $dh = @opendir($rootdir . $dir);
0380
0381 if (!$dh)
0382 {
0383 return $matches;
0384 }
0385
0386 while (($fname = readdir($dh)) !== false)
0387 {
0388 if (is_file("$rootdir$dir$fname"))
0389 {
0390 if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname))
0391 {
0392 $matches[$dir][] = $fname;
0393 }
0394 }
0395 else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname"))
0396 {
0397 $matches += filelist($rootdir, "$dir$fname", $type);
0398 }
0399 }
0400 closedir($dh);
0401
0402 return $matches;
0403 }
0404
0405 /**
0406 * Move topic(s)
0407 */
0408 function move_topics($topic_ids, $forum_id, $auto_sync = true)
0409 {
0410 global $db;
0411
0412 if (empty($topic_ids))
0413 {
0414 return;
0415 }
0416
0417 $forum_ids = array($forum_id);
0418
0419 if (!is_array($topic_ids))
0420 {
0421 $topic_ids = array($topic_ids);
0422 }
0423
0424 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
0425 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . '
0426 AND forum_id = ' . $forum_id;
0427 $db->sql_query($sql);
0428
0429 if ($auto_sync)
0430 {
0431 $sql = 'SELECT DISTINCT forum_id
0432 FROM ' . TOPICS_TABLE . '
0433 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
0434 $result = $db->sql_query($sql);
0435
0436 while ($row = $db->sql_fetchrow($result))
0437 {
0438 $forum_ids[] = $row['forum_id'];
0439 }
0440 $db->sql_freeresult($result);
0441 }
0442
0443 $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
0444 foreach ($table_ary as $table)
0445 {
0446 $sql = "UPDATE $table
0447 SET forum_id = $forum_id
0448 WHERE " . $db->sql_in_set('topic_id', $topic_ids);
0449 $db->sql_query($sql);
0450 }
0451 unset($table_ary);
0452
0453 if ($auto_sync)
0454 {
0455 sync('forum', 'forum_id', $forum_ids, true, true);
0456 unset($forum_ids);
0457 }
0458 }
0459
0460 /**
0461 * Move post(s)
0462 */
0463 function move_posts($post_ids, $topic_id, $auto_sync = true)
0464 {
0465 global $db;
0466
0467 if (!is_array($post_ids))
0468 {
0469 $post_ids = array($post_ids);
0470 }
0471
0472 $forum_ids = array();
0473 $topic_ids = array($topic_id);
0474
0475 $sql = 'SELECT DISTINCT topic_id, forum_id
0476 FROM ' . POSTS_TABLE . '
0477 WHERE ' . $db->sql_in_set('post_id', $post_ids);
0478 $result = $db->sql_query($sql);
0479
0480 while ($row = $db->sql_fetchrow($result))
0481 {
0482 $forum_ids[] = $row['forum_id'];
0483 $topic_ids[] = $row['topic_id'];
0484 }
0485 $db->sql_freeresult($result);
0486
0487 $sql = 'SELECT forum_id
0488 FROM ' . TOPICS_TABLE . '
0489 WHERE topic_id = ' . $topic_id;
0490 $result = $db->sql_query($sql);
0491 $forum_row = $db->sql_fetchrow($result);
0492 $db->sql_freeresult($result);
0493
0494 if (!$forum_row)
0495 {
0496 trigger_error('NO_TOPIC');
0497 }
0498
0499 $sql = 'UPDATE ' . POSTS_TABLE . '
0500 SET forum_id = ' . $forum_row['forum_id'] . ", topic_id = $topic_id
0501 WHERE " . $db->sql_in_set('post_id', $post_ids);
0502 $db->sql_query($sql);
0503
0504 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
0505 SET topic_id = $topic_id, in_message = 0
0506 WHERE " . $db->sql_in_set('post_msg_id', $post_ids);
0507 $db->sql_query($sql);
0508
0509 if ($auto_sync)
0510 {
0511 $forum_ids[] = $forum_row['forum_id'];
0512
0513 sync('topic_reported', 'topic_id', $topic_ids);
0514 sync('topic_attachment', 'topic_id', $topic_ids);
0515 sync('topic', 'topic_id', $topic_ids, true);
0516 sync('forum', 'forum_id', $forum_ids, true, true);
0517 }
0518
0519 // Update posted information
0520 update_posted_info($topic_ids);
0521 }
0522
0523 /**
0524 * Remove topic(s)
0525 */
0526 function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true)
0527 {
0528 global $db, $config;
0529
0530 $approved_topics = 0;
0531 $forum_ids = $topic_ids = array();
0532
0533 if ($where_type === 'range')
0534 {
0535 $where_clause = $where_ids;
0536 }
0537 else
0538 {
0539 $where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids);
0540
0541 if (!sizeof($where_ids))
0542 {
0543 return array('topics' => 0, 'posts' => 0);
0544 }
0545
0546 $where_clause = $db->sql_in_set($where_type, $where_ids);
0547 }
0548
0549 // Making sure that delete_posts does not call delete_topics again...
0550 $return = array(
0551 'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0,
0552 );
0553
0554 $sql = 'SELECT topic_id, forum_id, topic_approved
0555 FROM ' . TOPICS_TABLE . '
0556 WHERE ' . $where_clause;
0557 $result = $db->sql_query($sql);
0558
0559 while ($row = $db->sql_fetchrow($result))
0560 {
0561 $forum_ids[] = $row['forum_id'];
0562 $topic_ids[] = $row['topic_id'];
0563
0564 if ($row['topic_approved'])
0565 {
0566 $approved_topics++;
0567 }
0568 }
0569 $db->sql_freeresult($result);
0570
0571 $return['topics'] = sizeof($topic_ids);
0572
0573 if (!sizeof($topic_ids))
0574 {
0575 return $return;
0576 }
0577
0578 $db->sql_transaction('begin');
0579
0580 $table_ary = array(TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE);
0581
0582 foreach ($table_ary as $table)
0583 {
0584 $sql = "DELETE FROM $table
0585 WHERE " . $db->sql_in_set('topic_id', $topic_ids);
0586 $db->sql_query($sql);
0587 }
0588 unset($table_ary);
0589
0590 $moved_topic_ids = array();
0591
0592 // update the other forums
0593 $sql = 'SELECT topic_id, forum_id
0594 FROM ' . TOPICS_TABLE . '
0595 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids);
0596 $result = $db->sql_query($sql);
0597
0598 while ($row = $db->sql_fetchrow($result))
0599 {
0600 $forum_ids[] = $row['forum_id'];
0601 $moved_topic_ids[] = $row['topic_id'];
0602 }
0603 $db->sql_freeresult($result);
0604
0605 if (sizeof($moved_topic_ids))
0606 {
0607 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
0608 WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids);
0609 $db->sql_query($sql);
0610 }
0611
0612 $db->sql_transaction('commit');
0613
0614 if ($auto_sync)
0615 {
0616 sync('forum', 'forum_id', array_unique($forum_ids), true, true);
0617 sync('topic_reported', $where_type, $where_ids);
0618 }
0619
0620 if ($approved_topics)
0621 {
0622 set_config('num_topics', $config['num_topics'] - $approved_topics, true);
0623 }
0624
0625 return $return;
0626 }
0627
0628 /**
0629 * Remove post(s)
0630 */
0631 function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true)
0632 {
0633 global $db, $config, $phpbb_root_path, $phpEx;
0634
0635 if ($where_type === 'range')
0636 {
0637 $where_clause = $where_ids;
0638 }
0639 else
0640 {
0641 if (is_array($where_ids))
0642 {
0643 $where_ids = array_unique($where_ids);
0644 }
0645 else
0646 {
0647 $where_ids = array($where_ids);
0648 }
0649
0650 if (!sizeof($where_ids))
0651 {
0652 return false;
0653 }
0654
0655 $where_clause = $db->sql_in_set($where_type, array_map('intval', $where_ids));
0656 }
0657
0658 $approved_posts = 0;
0659 $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array();
0660
0661 $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id
0662 FROM ' . POSTS_TABLE . '
0663 WHERE ' . $where_clause;
0664 $result = $db->sql_query($sql);
0665
0666 while ($row = $db->sql_fetchrow($result))
0667 {
0668 $post_ids[] = $row['post_id'];
0669 $poster_ids[] = $row['poster_id'];
0670 $topic_ids[] = $row['topic_id'];
0671 $forum_ids[] = $row['forum_id'];
0672
0673 if ($row['post_postcount'] && $post_count_sync)
0674 {
0675 $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
0676 }
0677
0678 if ($row['post_approved'])
0679 {
0680 $approved_posts++;
0681 }
0682 }
0683 $db->sql_freeresult($result);
0684
0685 if (!sizeof($post_ids))
0686 {
0687 return false;
0688 }
0689
0690 $db->sql_transaction('begin');
0691
0692 $table_ary = array(POSTS_TABLE, REPORTS_TABLE);
0693
0694 foreach ($table_ary as $table)
0695 {
0696 $sql = "DELETE FROM $table
0697 WHERE " . $db->sql_in_set('post_id', $post_ids);
0698 $db->sql_query($sql);
0699 }
0700 unset($table_ary);
0701
0702 // Adjust users post counts
0703 if (sizeof($post_counts) && $post_count_sync)
0704 {
0705 foreach ($post_counts as $poster_id => $substract)
0706 {
0707 $sql = 'UPDATE ' . USERS_TABLE . '
0708 SET user_posts = 0
0709 WHERE user_id = ' . $poster_id . '
0710 AND user_posts < ' . $substract;
0711 $db->sql_query($sql);
0712 $sql = 'UPDATE ' . USERS_TABLE . '
0713 SET user_posts = user_posts - ' . $substract . '
0714 WHERE user_id = ' . $poster_id . '
0715 AND user_posts >= ' . $substract;
0716 $db->sql_query($sql);
0717 }
0718 }
0719
0720 // Remove topics now having no posts?
0721 if (sizeof($topic_ids))
0722 {
0723 $sql = 'SELECT topic_id
0724 FROM ' . POSTS_TABLE . '
0725 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
0726 GROUP BY topic_id';
0727 $result = $db->sql_query($sql);
0728
0729 while ($row = $db->sql_fetchrow($result))
0730 {
0731 $remove_topics[] = $row['topic_id'];
0732 }
0733 $db->sql_freeresult($result);
0734
0735 // Actually, those not within remove_topics should be removed. ;)
0736 $remove_topics = array_diff($topic_ids, $remove_topics);
0737 }
0738
0739 // Remove the message from the search index
0740 $search_type = basename($config['search_type']);
0741
0742 if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
0743 {
0744 trigger_error('NO_SUCH_SEARCH_MODULE');
0745 }
0746
0747 include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx");
0748
0749 $error = false;
0750 $search = new $search_type($error);
0751
0752 if ($error)
0753 {
0754 trigger_error($error);
0755 }
0756
0757 $search->index_remove($post_ids, $poster_ids, $forum_ids);
0758
0759 delete_attachments('post', $post_ids, false);
0760
0761 $db->sql_transaction('commit');
0762
0763 // Resync topics_posted table
0764 if ($posted_sync)
0765 {
0766 update_posted_info($topic_ids);
0767 }
0768
0769 if ($auto_sync)
0770 {
0771 sync('topic_reported', 'topic_id', $topic_ids);
0772 sync('topic', 'topic_id', $topic_ids, true);
0773 sync('forum', 'forum_id', $forum_ids, true, true);
0774 }
0775
0776 if ($approved_posts)
0777 {
0778 set_config('num_posts', $config['num_posts'] - $approved_posts, true);
0779 }
0780
0781 // We actually remove topics now to not be inconsistent (the delete_topics function calls this function too)
0782 if (sizeof($remove_topics) && $call_delete_topics)
0783 {
0784 delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false);
0785 }
0786
0787 return sizeof($post_ids);
0788 }
0789
0790 /**
0791 * Delete Attachments
0792 *
0793 * @param string $mode can be: post|topic|attach|user
0794 * @param mixed $ids can be: post_ids, topic_ids, attach_ids, user_ids
0795 * @param bool $resync set this to false if you are deleting posts or topics
0796 */
0797 function delete_attachments($mode, $ids, $resync = true)
0798 {
0799 global $db, $config;
0800
0801 if (is_array($ids) && sizeof($ids))
0802 {
0803 $ids = array_unique($ids);
0804 $ids = array_map('intval', $ids);
0805 }
0806 else
0807 {
0808 $ids = array((int) $ids);
0809 }
0810
0811 if (!sizeof($ids))
0812 {
0813 return false;
0814 }
0815
0816 $sql_id = ($mode == 'user') ? 'poster_id' : (($mode == 'post') ? 'post_msg_id' : (($mode == 'topic') ? 'topic_id' : 'attach_id'));
0817
0818 $post_ids = $topic_ids = $physical = array();
0819
0820 // Collect post and topics ids for later use
0821 if ($mode == 'attach' || $mode == 'user' || ($mode == 'topic' && $resync))
0822 {
0823 $sql = 'SELECT post_msg_id as post_id, topic_id, physical_filename, thumbnail, filesize
0824 FROM ' . ATTACHMENTS_TABLE . '
0825 WHERE ' . $db->sql_in_set($sql_id, $ids);
0826 $result = $db->sql_query($sql);
0827
0828 while ($row = $db->sql_fetchrow($result))
0829 {
0830 $post_ids[] = $row['post_id'];
0831 $topic_ids[] = $row['topic_id'];
0832 $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize']);
0833 }
0834 $db->sql_freeresult($result);
0835 }
0836
0837 if ($mode == 'post')
0838 {
0839 $sql = 'SELECT topic_id, physical_filename, thumbnail, filesize
0840 FROM ' . ATTACHMENTS_TABLE . '
0841 WHERE ' . $db->sql_in_set('post_msg_id', $ids) . '
0842 AND in_message = 0';
0843 $result = $db->sql_query($sql);
0844
0845 while ($row = $db->sql_fetchrow($result))
0846 {
0847 $topic_ids[] = $row['topic_id'];
0848 $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize']);
0849 }
0850 $db->sql_freeresult($result);
0851 }
0852
0853 // Delete attachments
0854 $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
0855 WHERE ' . $db->sql_in_set($sql_id, $ids);
0856 $db->sql_query($sql);
0857 $num_deleted = $db->sql_affectedrows();
0858
0859 if (!$num_deleted)
0860 {
0861 return 0;
0862 }
0863
0864 // Delete attachments from filesystem
0865 $space_removed = $files_removed = 0;
0866 foreach ($physical as $file_ary)
0867 {
0868 if (phpbb_unlink($file_ary['filename'], 'file', true))
0869 {
0870 $space_removed += $file_ary['filesize'];
0871 $files_removed++;
0872 }
0873
0874 if ($file_ary['thumbnail'])
0875 {
0876 phpbb_unlink($file_ary['filename'], 'thumbnail', true);
0877 }
0878 }
0879 set_config('upload_dir_size', $config['upload_dir_size'] - $space_removed, true);
0880 set_config('num_files', $config['num_files'] - $files_removed, true);
0881
0882 if ($mode == 'topic' && !$resync)
0883 {
0884 return $num_deleted;
0885 }
0886
0887 if ($mode == 'post')
0888 {
0889 $post_ids = $ids;
0890 }
0891 unset($ids);
0892
0893 $post_ids = array_unique($post_ids);
0894 $topic_ids = array_unique($topic_ids);
0895
0896 // Update post indicators
0897 if (sizeof($post_ids))
0898 {
0899 if ($mode == 'post' || $mode == 'topic')
0900 {
0901 $sql = 'UPDATE ' . POSTS_TABLE . '
0902 SET post_attachment = 0
0903 WHERE ' . $db->sql_in_set('post_id', $post_ids);
0904 $db->sql_query($sql);
0905 }
0906
0907 if ($mode == 'user' || $mode == 'attach')
0908 {
0909 $remaining = array();
0910
0911 $sql = 'SELECT post_msg_id
0912 FROM ' . ATTACHMENTS_TABLE . '
0913 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
0914 AND in_message = 0';
0915 $result = $db->sql_query($sql);
0916
0917 while ($row = $db->sql_fetchrow($result))
0918 {
0919 $remaining[] = $row['post_msg_id'];
0920 }
0921 $db->sql_freeresult($result);
0922
0923 $unset_ids = array_diff($post_ids, $remaining);
0924
0925 if (sizeof($unset_ids))
0926 {
0927 $sql = 'UPDATE ' . POSTS_TABLE . '
0928 SET post_attachment = 0
0929 WHERE ' . $db->sql_in_set('post_id', $unset_ids);
0930 $db->sql_query($sql);
0931 }
0932
0933 $remaining = array();
0934
0935 $sql = 'SELECT post_msg_id
0936 FROM ' . ATTACHMENTS_TABLE . '
0937 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
0938 AND in_message = 1';
0939 $result = $db->sql_query($sql);
0940
0941 while ($row = $db->sql_fetchrow($result))
0942 {
0943 $remaining[] = $row['post_msg_id'];
0944 }
0945 $db->sql_freeresult($result);
0946
0947 $unset_ids = array_diff($post_ids, $remaining);
0948
0949 if (sizeof($unset_ids))
0950 {
0951 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
0952 SET message_attachment = 0
0953 WHERE ' . $db->sql_in_set('msg_id', $unset_ids);
0954 $db->sql_query($sql);
0955 }
0956 }
0957 }
0958
0959 if (sizeof($topic_ids))
0960 {
0961 // Update topic indicator
0962 if ($mode == 'topic')
0963 {
0964 $sql = 'UPDATE ' . TOPICS_TABLE . '
0965 SET topic_attachment = 0
0966 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
0967 $db->sql_query($sql);
0968 }
0969
0970 if ($mode == 'post' || $mode == 'user' || $mode == 'attach')
0971 {
0972 $remaining = array();
0973
0974 $sql = 'SELECT topic_id
0975 FROM ' . ATTACHMENTS_TABLE . '
0976 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
0977 $result = $db->sql_query($sql);
0978
0979 while ($row = $db->sql_fetchrow($result))
0980 {
0981 $remaining[] = $row['topic_id'];
0982 }
0983 $db->sql_freeresult($result);
0984
0985 $unset_ids = array_diff($topic_ids, $remaining);
0986
0987 if (sizeof($unset_ids))
0988 {
0989 $sql = 'UPDATE ' . TOPICS_TABLE . '
0990 SET topic_attachment = 0
0991 WHERE ' . $db->sql_in_set('topic_id', $unset_ids);
0992 $db->sql_query($sql);
0993 }
0994 }
0995 }
0996
0997 return $num_deleted;
0998 }
0999
1000 /**
1001 * Remove topic shadows
1002 */
1003 function delete_topic_shadows($max_age, $forum_id = '', $auto_sync = true)
1004 {
1005 $where = (is_array($forum_id)) ? 'AND ' . $db->sql_in_set('t.forum_id', array_map('intval', $forum_id)) : (($forum_id) ? 'AND t.forum_id = ' . (int) $forum_id : '');
1006
1007 switch ($db->sql_layer)
1008 {
1009 case 'mysql4':
1010 case 'mysqli':
1011 $sql = 'DELETE t.*
1012 FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2
1013 WHERE t.topic_moved_id = t2.topic_id
1014 AND t.topic_time < ' . (time() - $max_age)
1015 . $where;
1016 $db->sql_query($sql);
1017 break;
1018
1019 default:
1020 $sql = 'SELECT t.topic_id
1021 FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2
1022 WHERE t.topic_moved_id = t2.topic_id
1023 AND t.topic_time < ' . (time() - $max_age)
1024 . $where;
1025 $result = $db->sql_query($sql);
1026
1027 $topic_ids = array();
1028 while ($row = $db->sql_fetchrow($result))
1029 {
1030 $topic_ids[] = $row['topic_id'];
1031 }
1032 $db->sql_freeresult($result);
1033
1034 if (sizeof($topic_ids))
1035 {
1036 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1037 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1038 $db->sql_query($sql);
1039 }
1040 break;
1041 }
1042
1043 if ($auto_sync)
1044 {
1045 $where_type = ($forum_id) ? 'forum_id' : '';
1046 sync('forum', $where_type, $forum_id, true, true);
1047 }
1048 }
1049
1050 /**
1051 * Update/Sync posted information for topics
1052 */
1053 function update_posted_info(&$topic_ids)
1054 {
1055 global $db, $config;
1056
1057 if (empty($topic_ids) || !$config['load_db_track'])
1058 {
1059 return;
1060 }
1061
1062 // First of all, let us remove any posted information for these topics
1063 $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
1064 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1065 $db->sql_query($sql);
1066
1067 // Now, let us collect the user/topic combos for rebuilding the information
1068 $sql = 'SELECT poster_id, topic_id
1069 FROM ' . POSTS_TABLE . '
1070 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
1071 AND poster_id <> ' . ANONYMOUS . '
1072 GROUP BY poster_id, topic_id';
1073 $result = $db->sql_query($sql);
1074
1075 $posted = array();
1076 while ($row = $db->sql_fetchrow($result))
1077 {
1078 // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique
1079 $posted[$row['poster_id']][] = $row['topic_id'];
1080 }
1081 $db->sql_freeresult($result);
1082
1083 // Now add the information...
1084 $sql_ary = array();
1085 foreach ($posted as $user_id => $topic_row)
1086 {
1087 foreach ($topic_row as $topic_id)
1088 {
1089 $sql_ary[] = array(
1090 'user_id' => (int) $user_id,
1091 'topic_id' => (int) $topic_id,
1092 'topic_posted' => 1,
1093 );
1094 }
1095 }
1096 unset($posted);
1097
1098 $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
1099 }
1100
1101 /**
1102 * Delete attached file
1103 */
1104 function phpbb_unlink($filename, $mode = 'file', $entry_removed = false)
1105 {
1106 global $db, $phpbb_root_path, $config;
1107
1108 // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
1109 $sql = 'SELECT COUNT(attach_id) AS num_entries
1110 FROM ' . ATTACHMENTS_TABLE . "
1111 WHERE physical_filename = '" . $db->sql_escape(basename($filename)) . "'";
1112 $result = $db->sql_query($sql);
1113 $num_entries = (int) $db->sql_fetchfield('num_entries');
1114 $db->sql_freeresult($result);
1115
1116 // Do not remove file if at least one additional entry with the same name exist.
1117 if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
1118 {
1119 return false;
1120 }
1121
1122 $filename = ($mode == 'thumbnail') ? 'thumb_' . basename($filename) : basename($filename);
1123 return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename);
1124 }
1125
1126 /**
1127 * All-encompasing sync function
1128 *
1129 * Exaples:
1130 * <code>
1131 * sync('topic', 'topic_id', 123); // resync topic #123
1132 * sync('topic', 'forum_id', array(2, 3)); // resync topics from forum #2 and #3
1133 * sync('topic'); // resync all topics
1134 * sync('topic', 'range', 'topic_id BETWEEN 1 AND 60'); // resync a range of topics/forums (only available for 'topic' and 'forum' modes)
1135 * </code>
1136 *
1137 * Modes:
1138 * - forum Resync complete forum
1139 * - topic Resync topics
1140 * - topic_moved Removes topic shadows that would be in the same forum as the topic they link to
1141 * - topic_approved Resyncs the topic_approved flag according to the status of the first post
1142 * - post_reported Resyncs the post_reported flag, relying on actual reports
1143 * - topic_reported Resyncs the topic_reported flag, relying on post_reported flags
1144 * - post_attachement Same as post_reported, but with attachment flags
1145 * - topic_attachement Same as topic_reported, but with attachment flags
1146 */
1147 function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false)
1148 {
1149 global $db;
1150
1151 if (is_array($where_ids))
1152 {
1153 $where_ids = array_unique($where_ids);
1154 $where_ids = array_map('intval', $where_ids);
1155 }
1156 else if ($where_type != 'range')
1157 {
1158 $where_ids = ($where_ids) ? array((int) $where_ids) : array();
1159 }
1160
1161 if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved' || $mode == 'topic_reported' || $mode == 'post_reported')
1162 {
1163 if (!$where_type)
1164 {
1165 $where_sql = '';
1166 $where_sql_and = 'WHERE';
1167 }
1168 else if ($where_type == 'range')
1169 {
1170 // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60'
1171 $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)";
1172 $where_sql_and = $where_sql . "\n\tAND";
1173 }
1174 else
1175 {
1176 // Do not sync the "global forum"
1177 $where_ids = array_diff($where_ids, array(0));
1178
1179 if (!sizeof($where_ids))
1180 {
1181 // Empty array with IDs. This means that we don't have any work to do. Just return.
1182 return;
1183 }
1184
1185 // Limit the topics/forums we are syncing, use specific topic/forum IDs.
1186 // $where_type contains the field for the where clause (forum_id, topic_id)
1187 $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
1188 $where_sql_and = $where_sql . "\n\tAND";
1189 }
1190 }
1191 else
1192 {
1193 if (!sizeof($where_ids))
1194 {
1195 return;
1196 }
1197
1198 // $where_type contains the field for the where clause (forum_id, topic_id)
1199 $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
1200 $where_sql_and = $where_sql . "\n\tAND";
1201 }
1202
1203 switch ($mode)
1204 {
1205 case 'topic_moved':
1206 switch ($db->sql_layer)
1207 {
1208 case 'mysql4':
1209 case 'mysqli':
1210 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1211 USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
1212 WHERE t1.topic_moved_id = t2.topic_id
1213 AND t1.forum_id = t2.forum_id";
1214 $db->sql_query($sql);
1215 break;
1216
1217 default:
1218 $sql = 'SELECT t1.topic_id
1219 FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
1220 WHERE t1.topic_moved_id = t2.topic_id
1221 AND t1.forum_id = t2.forum_id";
1222 $result = $db->sql_query($sql);
1223
1224 $topic_id_ary = array();
1225 while ($row = $db->sql_fetchrow($result))
1226 {
1227 $topic_id_ary[] = $row['topic_id'];
1228 }
1229 $db->sql_freeresult($result);
1230
1231 if (!sizeof($topic_id_ary))
1232 {
1233 return;
1234 }
1235
1236 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1237 WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary);
1238 $db->sql_query($sql);
1239
1240 break;
1241 }
1242 break;
1243
1244 case 'topic_approved':
1245 switch ($db->sql_layer)
1246 {
1247 case 'mysql4':
1248 case 'mysqli':
1249 $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1250 SET t.topic_approved = p.post_approved
1251 $where_sql_and t.topic_first_post_id = p.post_id";
1252 $db->sql_query($sql);
1253 break;
1254
1255 default:
1256 $sql = 'SELECT t.topic_id, p.post_approved
1257 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1258 $where_sql_and p.post_id = t.topic_first_post_id
1259 AND p.post_approved <> t.topic_approved";
1260 $result = $db->sql_query($sql);
1261
1262 $topic_ids = array();
1263 while ($row = $db->sql_fetchrow($result))
1264 {
1265 $topic_ids[] = $row['topic_id'];
1266 }
1267 $db->sql_freeresult($result);
1268
1269 if (!sizeof($topic_ids))
1270 {
1271 return;
1272 }
1273
1274 $sql = 'UPDATE ' . TOPICS_TABLE . '
1275 SET topic_approved = 1 - topic_approved
1276 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1277 $db->sql_query($sql);
1278 break;
1279 }
1280 break;
1281
1282 case 'post_reported':
1283 $post_ids = $post_reported = array();
1284
1285 $sql = 'SELECT p.post_id, p.post_reported
1286 FROM ' . POSTS_TABLE . " p
1287 $where_sql
1288 GROUP BY p.post_id, p.post_reported";
1289 $result = $db->sql_query($sql);
1290
1291 while ($row = $db->sql_fetchrow($result))
1292 {
1293 $post_ids[$row['post_id']] = $row['post_id'];
1294 if ($row['post_reported'])
1295 {
1296 $post_reported[$row['post_id']] = 1;
1297 }
1298 }
1299 $db->sql_freeresult($result);
1300
1301 $sql = 'SELECT DISTINCT(post_id)
1302 FROM ' . REPORTS_TABLE . '
1303 WHERE ' . $db->sql_in_set('post_id', $post_ids) . '
1304 AND report_closed = 0';
1305 $result = $db->sql_query($sql);
1306
1307 $post_ids = array();
1308 while ($row = $db->sql_fetchrow($result))
1309 {
1310 if (!isset($post_reported[$row['post_id']]))
1311 {
1312 $post_ids[] = $row['post_id'];
1313 }
1314 else
1315 {
1316 unset($post_reported[$row['post_id']]);
1317 }
1318 }
1319 $db->sql_freeresult($result);
1320
1321 // $post_reported should be empty by now, if it's not it contains
1322 // posts that are falsely flagged as reported
1323 foreach ($post_reported as $post_id => $void)
1324 {
1325 $post_ids[] = $post_id;
1326 }
1327
1328 if (sizeof($post_ids))
1329 {
1330 $sql = 'UPDATE ' . POSTS_TABLE . '
1331 SET post_reported = 1 - post_reported
1332 WHERE ' . $db->sql_in_set('post_id', $post_ids);
1333 $db->sql_query($sql);
1334 }
1335 break;
1336
1337 case 'topic_reported':
1338 if ($sync_extra)
1339 {
1340 sync('post_reported', $where_type, $where_ids);
1341 }
1342
1343 $topic_ids = $topic_reported = array();
1344
1345 $sql = 'SELECT DISTINCT(t.topic_id)
1346 FROM ' . POSTS_TABLE . " t
1347 $where_sql_and t.post_reported = 1";
1348 $result = $db->sql_query($sql);
1349
1350 while ($row = $db->sql_fetchrow($result))
1351 {
1352 $topic_reported[$row['topic_id']] = 1;
1353 }
1354 $db->sql_freeresult($result);
1355
1356 $sql = 'SELECT t.topic_id, t.topic_reported
1357 FROM ' . TOPICS_TABLE . " t
1358 $where_sql";
1359 $result = $db->sql_query($sql);
1360
1361 while ($row = $db->sql_fetchrow($result))
1362 {
1363 if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']]))
1364 {
1365 $topic_ids[] = $row['topic_id'];
1366 }
1367 }
1368 $db->sql_freeresult($result);
1369
1370 if (sizeof($topic_ids))
1371 {
1372 $sql = 'UPDATE ' . TOPICS_TABLE . '
1373 SET topic_reported = 1 - topic_reported
1374 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1375 $db->sql_query($sql);
1376 }
1377 break;
1378
1379 case 'post_attachment':
1380 $post_ids = $post_attachment = array();
1381
1382 $sql = 'SELECT p.post_id, p.post_attachment
1383 FROM ' . POSTS_TABLE . " p
1384 $where_sql
1385 GROUP BY p.post_id, p.post_attachment";
1386 $result = $db->sql_query($sql);
1387
1388 while ($row = $db->sql_fetchrow($result))
1389 {
1390 $post_ids[$row['post_id']] = $row['post_id'];
1391 if ($row['post_attachment'])
1392 {
1393 $post_attachment[$row['post_id']] = 1;
1394 }
1395 }
1396 $db->sql_freeresult($result);
1397
1398 $sql = 'SELECT DISTINCT(post_msg_id)
1399 FROM ' . ATTACHMENTS_TABLE . '
1400 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
1401 AND in_message = 0';
1402 $result = $db->sql_query($sql);
1403
1404 $post_ids = array();
1405 while ($row = $db->sql_fetchrow($result))
1406 {
1407 if (!isset($post_attachment[$row['post_msg_id']]))
1408 {
1409 $post_ids[] = $row['post_msg_id'];
1410 }
1411 else
1412 {
1413 unset($post_attachment[$row['post_msg_id']]);
1414 }
1415 }
1416 $db->sql_freeresult($result);
1417
1418 // $post_attachment should be empty by now, if it's not it contains
1419 // posts that are falsely flagged as having attachments
1420 foreach ($post_attachment as $post_id => $void)
1421 {
1422 $post_ids[] = $post_id;
1423 }
1424
1425 if (sizeof($post_ids))
1426 {
1427 $sql = 'UPDATE ' . POSTS_TABLE . '
1428 SET post_attachment = 1 - post_attachment
1429 WHERE ' . $db->sql_in_set('post_id', $post_ids);
1430 $db->sql_query($sql);
1431 }
1432 break;
1433
1434 case 'topic_attachment':
1435 if ($sync_extra)
1436 {
1437 sync('post_attachment', $where_type, $where_ids);
1438 }
1439
1440 $topic_ids = $topic_attachment = array();
1441
1442 $sql = 'SELECT DISTINCT(t.topic_id)
1443 FROM ' . POSTS_TABLE . " t
1444 $where_sql_and t.post_attachment = 1";
1445 $result = $db->sql_query($sql);
1446
1447 while ($row = $db->sql_fetchrow($result))
1448 {
1449 $topic_attachment[$row['topic_id']] = 1;
1450 }
1451 $db->sql_freeresult($result);
1452
1453 $sql = 'SELECT t.topic_id, t.topic_attachment
1454 FROM ' . TOPICS_TABLE . " t
1455 $where_sql";
1456 $result = $db->sql_query($sql);
1457
1458 while ($row = $db->sql_fetchrow($result))
1459 {
1460 if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']]))
1461 {
1462 $topic_ids[] = $row['topic_id'];
1463 }
1464 }
1465 $db->sql_freeresult($result);
1466
1467 if (sizeof($topic_ids))
1468 {
1469 $sql = 'UPDATE ' . TOPICS_TABLE . '
1470 SET topic_attachment = 1 - topic_attachment
1471 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1472 $db->sql_query($sql);
1473 }
1474 break;
1475
1476 case 'forum':
1477
1478 // 1: Get the list of all forums
1479 $sql = 'SELECT f.*
1480 FROM ' . FORUMS_TABLE . " f
1481 $where_sql";
1482 $result = $db->sql_query($sql);
1483
1484 $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array();
1485 while ($row = $db->sql_fetchrow($result))
1486 {
1487 if ($row['forum_type'] == FORUM_LINK)
1488 {
1489 continue;
1490 }
1491
1492 $forum_id = (int) $row['forum_id'];
1493 $forum_ids[$forum_id] = $forum_id;
1494
1495 $forum_data[$forum_id] = $row;
1496 if ($sync_extra)
1497 {
1498 $forum_data[$forum_id]['posts'] = 0;
1499 $forum_data[$forum_id]['topics'] = 0;
1500 $forum_data[$forum_id]['topics_real'] = 0;
1501 }
1502 $forum_data[$forum_id]['last_post_id'] = 0;
1503 $forum_data[$forum_id]['last_post_subject'] = '';
1504 $forum_data[$forum_id]['last_post_time'] = 0;
1505 $forum_data[$forum_id]['last_poster_id'] = 0;
1506 $forum_data[$forum_id]['last_poster_name'] = '';
1507 $forum_data[$forum_id]['last_poster_colour'] = '';
1508 }
1509 $db->sql_freeresult($result);
1510
1511 if (!sizeof($forum_ids))
1512 {
1513 break;
1514 }
1515
1516 $forum_ids = array_values($forum_ids);
1517
1518 // 2: Get topic counts for each forum (optional)
1519 if ($sync_extra)
1520 {
1521 $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics
1522 FROM ' . TOPICS_TABLE . '
1523 WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
1524 GROUP BY forum_id, topic_approved';
1525 $result = $db->sql_query($sql);
1526
1527 while ($row = $db->sql_fetchrow($result))
1528 {
1529 $forum_id = (int) $row['forum_id'];
1530 $forum_data[$forum_id]['topics_real'] += $row['forum_topics'];
1531
1532 if ($row['topic_approved'])
1533 {
1534 $forum_data[$forum_id]['topics'] = $row['forum_topics'];
1535 }
1536 }
1537 $db->sql_freeresult($result);
1538 }
1539
1540 // 3: Get post count for each forum (optional)
1541 if ($sync_extra)
1542 {
1543 if (sizeof($forum_ids) == 1)
1544 {
1545 $sql = 'SELECT SUM(t.topic_replies + 1) AS forum_posts
1546 FROM ' . TOPICS_TABLE . ' t
1547 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1548 AND t.topic_approved = 1';
1549 }
1550 else
1551 {
1552 $sql = 'SELECT t.forum_id, SUM(t.topic_replies + 1) AS forum_posts
1553 FROM ' . TOPICS_TABLE . ' t
1554 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1555 AND t.topic_approved = 1
1556 GROUP BY t.forum_id';
1557 }
1558
1559 $result = $db->sql_query($sql);
1560
1561 while ($row = $db->sql_fetchrow($result))
1562 {
1563 $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
1564
1565 $forum_data[$forum_id]['posts'] = (int) $row['forum_posts'];
1566 }
1567 $db->sql_freeresult($result);
1568 }
1569
1570 // 4: Get last_post_id for each forum
1571 if (sizeof($forum_ids) == 1)
1572 {
1573 $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id
1574 FROM ' . TOPICS_TABLE . ' t
1575 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1576 AND t.topic_approved = 1';
1577 }
1578 else
1579 {
1580 $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id
1581 FROM ' . TOPICS_TABLE . ' t
1582 WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
1583 AND t.topic_approved = 1
1584 GROUP BY t.forum_id';
1585 }
1586
1587 $result = $db->sql_query($sql);
1588
1589 while ($row = $db->sql_fetchrow($result))
1590 {
1591 $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
1592
1593 $forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id'];
1594
1595 $post_ids[] = $row['last_post_id'];
1596 }
1597 $db->sql_freeresult($result);
1598
1599 // 5: Retrieve last_post infos
1600 if (sizeof($post_ids))
1601 {
1602 $sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour
1603 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1604 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1605 AND p.poster_id = u.user_id';
1606 $result = $db->sql_query($sql);
1607
1608 while ($row = $db->sql_fetchrow($result))
1609 {
1610 $post_info[$row['post_id']] = $row;
1611 }
1612 $db->sql_freeresult($result);
1613
1614 foreach ($forum_data as $forum_id => $data)
1615 {
1616 if ($data['last_post_id'])
1617 {
1618 if (isset($post_info[$data['last_post_id']]))
1619 {
1620 $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject'];
1621 $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time'];
1622 $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id'];
1623 $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'];
1624 $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour'];
1625 }
1626 else
1627 {
1628 // For some reason we did not find the post in the db
1629 $forum_data[$forum_id]['last_post_id'] = 0;
1630 $forum_data[$forum_id]['last_post_subject'] = '';
1631 $forum_data[$forum_id]['last_post_time'] = 0;
1632 $forum_data[$forum_id]['last_poster_id'] = 0;
1633 $forum_data[$forum_id]['last_poster_name'] = '';
1634 $forum_data[$forum_id]['last_poster_colour'] = '';
1635 }
1636 }
1637 }
1638 unset($post_info);
1639 }
1640
1641 // 6: Now do that thing
1642 $fieldnames = array('last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
1643
1644 if ($sync_extra)
1645 {
1646 array_push($fieldnames, 'posts', 'topics', 'topics_real');
1647 }
1648
1649 foreach ($forum_data as $forum_id => $row)
1650 {
1651 $sql_ary = array();
1652
1653 foreach ($fieldnames as $fieldname)
1654 {
1655 if ($row['forum_' . $fieldname] != $row[$fieldname])
1656 {
1657 if (preg_match('#(name|colour|subject)$#', $fieldname))
1658 {
1659 $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname];
1660 }
1661 else
1662 {
1663 $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname];
1664 }
1665 }
1666 }
1667
1668 if (sizeof($sql_ary))
1669 {
1670 $sql = 'UPDATE ' . FORUMS_TABLE . '
1671 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1672 WHERE forum_id = ' . $forum_id;
1673 $db->sql_query($sql);
1674 }
1675 }
1676 break;
1677
1678 case 'topic':
1679 $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array();
1680
1681 $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
1682 FROM ' . TOPICS_TABLE . " t
1683 $where_sql";
1684 $result = $db->sql_query($sql);
1685
1686 while ($row = $db->sql_fetchrow($result))
1687 {
1688 if ($row['topic_moved_id'])
1689 {
1690 $moved_topics[] = $row['topic_id'];
1691 continue;
1692 }
1693
1694 $topic_id = (int) $row['topic_id'];
1695 $topic_data[$topic_id] = $row;
1696 $topic_data[$topic_id]['replies_real'] = -1;
1697 $topic_data[$topic_id]['replies'] = 0;
1698 $topic_data[$topic_id]['first_post_id'] = 0;
1699 $topic_data[$topic_id]['last_post_id'] = 0;
1700 unset($topic_data[$topic_id]['topic_id']);
1701
1702 // This array holds all topic_ids
1703 $delete_topics[$topic_id] = '';
1704
1705 if ($sync_extra)
1706 {
1707 $topic_data[$topic_id]['reported'] = 0;
1708 $topic_data[$topic_id]['attachment'] = 0;
1709 }
1710 }
1711 $db->sql_freeresult($result);
1712
1713 // Use "t" as table alias because of the $where_sql clause
1714 // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown.
1715 $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
1716 FROM ' . POSTS_TABLE . " t
1717 $where_sql
1718 GROUP BY t.topic_id, t.post_approved";
1719 $result = $db->sql_query($sql);
1720
1721 while ($row = $db->sql_fetchrow($result))
1722 {
1723 $topic_id = (int) $row['topic_id'];
1724
1725 $row['first_post_id'] = (int) $row['first_post_id'];
1726 $row['last_post_id'] = (int) $row['last_post_id'];
1727
1728 if (!isset($topic_data[$topic_id]))
1729 {
1730 // Hey, these posts come from a topic that does not exist
1731 $delete_posts[$topic_id] = '';
1732 }
1733 else
1734 {
1735 // Unset the corresponding entry in $delete_topics
1736 // When we'll be done, only topics with no posts will remain
1737 unset($delete_topics[$topic_id]);
1738
1739 $topic_data[$topic_id]['replies_real'] += $row['total_posts'];
1740 $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']);
1741
1742 if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id'])
1743 {
1744 $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1;
1745 $topic_data[$topic_id]['last_post_id'] = $row['last_post_id'];
1746 }
1747 }
1748 }
1749 $db->sql_freeresult($result);
1750
1751 foreach ($topic_data as $topic_id => $row)
1752 {
1753 $post_ids[] = $row['first_post_id'];
1754 if ($row['first_post_id'] != $row['last_post_id'])
1755 {
1756 $post_ids[] = $row['last_post_id'];
1757 }
1758 }
1759
1760 // Now we delete empty topics and orphan posts
1761 if (sizeof($delete_posts))
1762 {
1763 delete_posts('topic_id', array_keys($delete_posts), false);
1764 unset($delete_posts);
1765 }
1766
1767 if (!sizeof($topic_data))
1768 {
1769 // If we get there, topic ids were invalid or topics did not contain any posts
1770 delete_topics($where_type, $where_ids, true);
1771 return;
1772 }
1773
1774 if (sizeof($delete_topics))
1775 {
1776 $delete_topic_ids = array();
1777 foreach ($delete_topics as $topic_id => $void)
1778 {
1779 unset($topic_data[$topic_id]);
1780 $delete_topic_ids[] = $topic_id;
1781 }
1782
1783 delete_topics('topic_id', $delete_topic_ids, false);
1784 unset($delete_topics, $delete_topic_ids);
1785 }
1786
1787 $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
1788 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1789 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1790 AND u.user_id = p.poster_id';
1791 $result = $db->sql_query($sql);
1792
1793 $post_ids = array();
1794 while ($row = $db->sql_fetchrow($result))
1795 {
1796 $topic_id = intval($row['topic_id']);
1797
1798 if ($row['post_id'] == $topic_data[$topic_id]['first_post_id'])
1799 {
1800 if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved'])
1801 {
1802 $approved_unapproved_ids[] = $topic_id;
1803 }
1804 $topic_data[$topic_id]['time'] = $row['post_time'];
1805 $topic_data[$topic_id]['poster'] = $row['poster_id'];
1806 $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1807 $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour'];
1808 }
1809
1810 if ($row['post_id'] == $topic_data[$topic_id]['last_post_id'])
1811 {
1812 $topic_data[$topic_id]['last_poster_id'] = $row['poster_id'];
1813 $topic_data[$topic_id]['last_post_subject'] = $row['post_subject'];
1814 $topic_data[$topic_id]['last_post_time'] = $row['post_time'];
1815 $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1816 $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour'];
1817 }
1818 }
1819 $db->sql_freeresult($result);
1820
1821 // Make sure shadow topics do link to existing topics
1822 if (sizeof($moved_topics))
1823 {
1824 $delete_topics = array();
1825
1826 $sql = 'SELECT t1.topic_id, t1.topic_moved_id
1827 FROM ' . TOPICS_TABLE . ' t1
1828 LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id)
1829 WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . '
1830 AND t2.topic_id IS NULL';
1831 $result = $db->sql_query($sql);
1832
1833 while ($row = $db->sql_fetchrow($result))
1834 {
1835 $delete_topics[] = $row['topic_id'];
1836 }
1837 $db->sql_freeresult($result);
1838
1839 if (sizeof($delete_topics))
1840 {
1841 delete_topics('topic_id', $delete_topics, false);
1842 }
1843 unset($delete_topics);
1844
1845 // Make sure shadow topics having no last post data being updated (this only rarely happens...)
1846 $sql = 'SELECT topic_id, topic_moved_id, topic_last_post_id, topic_first_post_id
1847 FROM ' . TOPICS_TABLE . '
1848 WHERE ' . $db->sql_in_set('topic_id', $moved_topics) . '
1849 AND topic_last_post_time = 0';
1850 $result = $db->sql_query($sql);
1851
1852 $shadow_topic_data = $post_ids = array();
1853 while ($row = $db->sql_fetchrow($result))
1854 {
1855 $shadow_topic_data[$row['topic_moved_id']] = $row;
1856 $post_ids[] = $row['topic_last_post_id'];
1857 $post_ids[] = $row['topic_first_post_id'];
1858 }
1859 $db->sql_freeresult($result);
1860
1861 $sync_shadow_topics = array();
1862 if (sizeof($post_ids))
1863 {
1864 $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
1865 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1866 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1867 AND u.user_id = p.poster_id';
1868 $result = $db->sql_query($sql);
1869
1870 $post_ids = array();
1871 while ($row = $db->sql_fetchrow($result))
1872 {
1873 $topic_id = (int) $row['topic_id'];
1874
1875 // Ok, there should be a shadow topic. If there isn't, then there's something wrong with the db.
1876 // However, there's not much we can do about it.
1877 if (!empty($shadow_topic_data[$topic_id]))
1878 {
1879 if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_first_post_id'])
1880 {
1881 $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id'];
1882
1883 if (!isset($sync_shadow_topics[$orig_topic_id]))
1884 {
1885 $sync_shadow_topics[$orig_topic_id] = array();
1886 }
1887
1888 $sync_shadow_topics[$orig_topic_id]['topic_time'] = $row['post_time'];
1889 $sync_shadow_topics[$orig_topic_id]['topic_poster'] = $row['poster_id'];
1890 $sync_shadow_topics[$orig_topic_id]['topic_first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1891 $sync_shadow_topics[$orig_topic_id]['topic_first_poster_colour'] = $row['user_colour'];
1892 }
1893
1894 if ($row['post_id'] == $shadow_topic_data[$topic_id]['topic_last_post_id'])
1895 {
1896 $orig_topic_id = $shadow_topic_data[$topic_id]['topic_id'];
1897
1898 if (!isset($sync_shadow_topics[$orig_topic_id]))
1899 {
1900 $sync_shadow_topics[$orig_topic_id] = array();
1901 }
1902
1903 $sync_shadow_topics[$orig_topic_id]['topic_last_poster_id'] = $row['poster_id'];
1904 $sync_shadow_topics[$orig_topic_id]['topic_last_post_subject'] = $row['post_subject'];
1905 $sync_shadow_topics[$orig_topic_id]['topic_last_post_time'] = $row['post_time'];
1906 $sync_shadow_topics[$orig_topic_id]['topic_last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1907 $sync_shadow_topics[$orig_topic_id]['topic_last_poster_colour'] = $row['user_colour'];
1908 }
1909 }
1910 }
1911 $db->sql_freeresult($result);
1912
1913 $shadow_topic_data = array();
1914
1915 // Update the information we collected
1916 if (sizeof($sync_shadow_topics))
1917 {
1918 foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary)
1919 {
1920 $sql = 'UPDATE ' . TOPICS_TABLE . '
1921 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1922 WHERE topic_id = ' . $sync_topic_id;
1923 $db->sql_query($sql);
1924 }
1925 }
1926 }
1927
1928 unset($sync_shadow_topics, $shadow_topic_data);
1929 }
1930
1931 // approved becomes unapproved, and vice-versa
1932 if (sizeof($approved_unapproved_ids))
1933 {
1934 $sql = 'UPDATE ' . TOPICS_TABLE . '
1935 SET topic_approved = 1 - topic_approved
1936 WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids);
1937 $db->sql_query($sql);
1938 }
1939 unset($approved_unapproved_ids);
1940
1941 // These are fields that will be synchronised
1942 $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');
1943
1944 if ($sync_extra)
1945 {
1946 // This routine assumes that post_reported values are correct
1947 // if they are not, use sync('post_reported') first
1948 $sql = 'SELECT t.topic_id, p.post_id
1949 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1950 $where_sql_and p.topic_id = t.topic_id
1951 AND p.post_reported = 1
1952 GROUP BY t.topic_id, p.post_id";
1953 $result = $db->sql_query($sql);
1954
1955 $fieldnames[] = 'reported';
1956 while ($row = $db->sql_fetchrow($result))
1957 {
1958 $topic_data[intval($row['topic_id'])]['reported'] = 1;
1959 }
1960 $db->sql_freeresult($result);
1961
1962 // This routine assumes that post_attachment values are correct
1963 // if they are not, use sync('post_attachment') first
1964 $sql = 'SELECT t.topic_id, p.post_id
1965 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1966 $where_sql_and p.topic_id = t.topic_id
1967 AND p.post_attachment = 1
1968 GROUP BY t.topic_id, p.post_id";
1969 $result = $db->sql_query($sql);
1970
1971 $fieldnames[] = 'attachment';
1972 while ($row = $db->sql_fetchrow($result))
1973 {
1974 $topic_data[intval($row['topic_id'])]['attachment'] = 1;
1975 }
1976 $db->sql_freeresult($result);
1977 }
1978
1979 foreach ($topic_data as $topic_id => $row)
1980 {
1981 $sql_ary = array();
1982
1983 foreach ($fieldnames as $fieldname)
1984 {
1985 if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname])
1986 {
1987 $sql_ary['topic_' . $fieldname] = $row[$fieldname];
1988 }
1989 }
1990
1991 if (sizeof($sql_ary))
1992 {
1993 $sql = 'UPDATE ' . TOPICS_TABLE . '
1994 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1995 WHERE topic_id = ' . $topic_id;
1996 $db->sql_query($sql);
1997
1998 $resync_forums[$row['forum_id']] = $row['forum_id'];
1999 }
2000 }
2001 unset($topic_data);
2002
2003 // if some topics have been resync'ed then resync parent forums
2004 // except when we're only syncing a range, we don't want to sync forums during
2005 // batch processing.
2006 if ($resync_parents && sizeof($resync_forums) && $where_type != 'range')
2007 {
2008 sync('forum', 'forum_id', array_values($resync_forums), true, true);
2009 }
2010 break;
2011 }
2012
2013 return;
2014 }
2015
2016 /**
2017 * Prune function
2018 */
2019 function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true)
2020 {
2021 global $db;
2022
2023 if (!is_array($forum_id))
2024 {
2025 $forum_id = array($forum_id);
2026 }
2027
2028 if (!sizeof($forum_id))
2029 {
2030 return;
2031 }
2032
2033 $sql_and = '';
2034
2035 if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE))
2036 {
2037 $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE;
2038 }
2039
2040 if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY))
2041 {
2042 $sql_and .= ' AND topic_type <> ' . POST_STICKY;
2043 }
2044
2045 if ($prune_mode == 'posted')
2046 {
2047 $sql_and .= " AND topic_last_post_time < $prune_date";
2048 }
2049
2050 if ($prune_mode == 'viewed')
2051 {
2052 $sql_and .= " AND topic_last_view_time < $prune_date";
2053 }
2054
2055 $sql = 'SELECT topic_id
2056 FROM ' . TOPICS_TABLE . '
2057 WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
2058 AND poll_start = 0
2059 $sql_and";
2060 $result = $db->sql_query($sql);
2061
2062 $topic_list = array();
2063 while ($row = $db->sql_fetchrow($result))
2064 {
2065 $topic_list[] = $row['topic_id'];
2066 }
2067 $db->sql_freeresult($result);
2068
2069 if ($prune_flags & FORUM_FLAG_PRUNE_POLL)
2070 {
2071 $sql = 'SELECT topic_id
2072 FROM ' . TOPICS_TABLE . '
2073 WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
2074 AND poll_start > 0
2075 AND poll_last_vote < $prune_date
2076 $sql_and";
2077 $result = $db->sql_query($sql);
2078
2079 while ($row = $db->sql_fetchrow($result))
2080 {
2081 $topic_list[] = $row['topic_id'];
2082 }
2083 $db->sql_freeresult($result);
2084
2085 $topic_list = array_unique($topic_list);
2086 }
2087
2088 return delete_topics('topic_id', $topic_list, $auto_sync, false);
2089 }
2090
2091 /**
2092 * Function auto_prune(), this function now relies on passed vars
2093 */
2094 function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq)
2095 {
2096 global $db;
2097
2098 $sql = 'SELECT forum_name
2099 FROM ' . FORUMS_TABLE . "
2100 WHERE forum_id = $forum_id";
2101 $result = $db->sql_query($sql, 3600);
2102 $row = $db->sql_fetchrow($result);
2103 $db->sql_freeresult($result);
2104
2105 if ($row)
2106 {
2107 $prune_date = time() - ($prune_days * 86400);
2108 $next_prune = time() + ($prune_freq * 86400);
2109
2110 prune($forum_id, $prune_mode, $prune_date, $prune_flags, true);
2111
2112 $sql = 'UPDATE ' . FORUMS_TABLE . "
2113 SET prune_next = $next_prune
2114 WHERE forum_id = $forum_id";
2115 $db->sql_query($sql);
2116
2117 add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']);
2118 }
2119
2120 return;
2121 }
2122
2123 /**
2124 * remove_comments will strip the sql comment lines out of an uploaded sql file
2125 * specifically for mssql and postgres type files in the install....
2126 */
2127 function remove_comments(&$output)
2128 {
2129 $lines = explode("\n", $output);
2130 $output = '';
2131
2132 // try to keep mem. use down
2133 $linecount = sizeof($lines);
2134
2135 $in_comment = false;
2136 for ($i = 0; $i < $linecount; $i++)
2137 {
2138 if (trim($lines[$i]) == '/*')
2139 {
2140 $in_comment = true;
2141 }
2142
2143 if (!$in_comment)
2144 {
2145 $output .= $lines[$i] . "\n";
2146 }
2147
2148 if (trim($lines[$i]) == '*/')
2149 {
2150 $in_comment = false;
2151 }
2152 }
2153
2154 unset($lines);
2155 return $output;
2156 }
2157
2158 /**
2159 * Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username
2160 * and group names must be carried through for the moderators table
2161 */
2162 function cache_moderators()
2163 {
2164 global $db, $cache, $auth, $phpbb_root_path, $phpEx;
2165
2166 // Remove cached sql results
2167 $cache->destroy('sql', MODERATOR_CACHE_TABLE);
2168
2169 // Clear table
2170 switch ($db->sql_layer)
2171 {
2172 case 'sqlite':
2173 case 'firebird':
2174 $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE);
2175 break;
2176
2177 default:
2178 $db->sql_query('TRUNCATE TABLE ' . MODERATOR_CACHE_TABLE);
2179 break;
2180 }
2181
2182 // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting
2183 $hold_ary = $ug_id_ary = $sql_ary = array();
2184
2185 // Grab all users having moderative options...
2186 $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false);
2187
2188 // Add users?
2189 if (sizeof($hold_ary))
2190 {
2191 // At least one moderative option warrants a display
2192 $ug_id_ary = array_keys($hold_ary);
2193
2194 // Remove users who have group memberships with DENY moderator permissions
2195 $sql = $db->sql_build_query('SELECT', array(
2196 'SELECT' => 'a.forum_id, ug.user_id',
2197
2198 'FROM' => array(
2199 ACL_OPTIONS_TABLE => 'o',
2200 USER_GROUP_TABLE => 'ug',
2201 ACL_GROUPS_TABLE => 'a'
2202 ),
2203
2204 'LEFT_JOIN' => array(
2205 array(
2206 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'),
2207 'ON' => 'a.auth_role_id = r.role_id'
2208 )
2209 ),
2210
2211 'WHERE' => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id)
2212 AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL)
2213 OR r.auth_setting = ' . ACL_NEVER . ')
2214 AND a.group_id = ug.group_id
2215 AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . "
2216 AND ug.user_pending = 0
2217 AND o.auth_option " . $db->sql_like_expression('m_' . $db->any_char),
2218 ));
2219 $result = $db->sql_query($sql);
2220
2221 while ($row = $db->sql_fetchrow($result))
2222 {
2223 if (isset($hold_ary[$row['user_id']][$row['forum_id']]))
2224 {
2225 unset($hold_ary[$row['user_id']][$row['forum_id']]);
2226 }
2227 }
2228 $db->sql_freeresult($result);
2229
2230 if (sizeof($hold_ary))
2231 {
2232 // Get usernames...
2233 $sql = 'SELECT user_id, username
2234 FROM ' . USERS_TABLE . '
2235 WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary));
2236 $result = $db->sql_query($sql);
2237
2238 $usernames_ary = array();
2239 while ($row = $db->sql_fetchrow($result))
2240 {
2241 $usernames_ary[$row['user_id']] = $row['username'];
2242 }
2243
2244 foreach ($hold_ary as $user_id => $forum_id_ary)
2245 {
2246 // Do not continue if user does not exist
2247 if (!isset($usernames_ary[$user_id]))
2248 {
2249 continue;
2250 }
2251
2252 foreach ($forum_id_ary as $forum_id => $auth_ary)
2253 {
2254 $sql_ary[] = array(
2255 'forum_id' => (int) $forum_id,
2256 'user_id' => (int) $user_id,
2257 'username' => (string) $usernames_ary[$user_id],
2258 'group_id' => 0,
2259 'group_name' => ''
2260 );
2261 }
2262 }
2263 }
2264 }
2265
2266 // Now to the groups...
2267 $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false);
2268
2269 if (sizeof($hold_ary))
2270 {
2271 $ug_id_ary = array_keys($hold_ary);
2272
2273 // Make sure not hidden or special groups are involved...
2274 $sql = 'SELECT group_name, group_id, group_type
2275 FROM ' . GROUPS_TABLE . '
2276 WHERE ' . $db->sql_in_set('group_id', $ug_id_ary);
2277 $result = $db->sql_query($sql);
2278
2279 $groupnames_ary = array();
2280 while ($row = $db->sql_fetchrow($result))
2281 {
2282 if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL)
2283 {
2284 unset($hold_ary[$row['group_id']]);
2285 }
2286
2287 $groupnames_ary[$row['group_id']] = $row['group_name'];
2288 }
2289 $db->sql_freeresult($result);
2290
2291 foreach ($hold_ary as $group_id => $forum_id_ary)
2292 {
2293 // If there is no group, we do not assign it...
2294 if (!isset($groupnames_ary[$group_id]))
2295 {
2296 continue;
2297 }
2298
2299 foreach ($forum_id_ary as $forum_id => $auth_ary)
2300 {
2301 $flag = false;
2302 foreach ($auth_ary as $auth_option => $setting)
2303 {
2304 // Make sure at least one ACL_YES option is set...
2305 if ($setting == ACL_YES)
2306 {
2307 $flag = true;
2308 break;
2309 }
2310 }
2311
2312 if (!$flag)
2313 {
2314 continue;
2315 }
2316
2317 $sql_ary[] = array(
2318 'forum_id' => (int) $forum_id,
2319 'user_id' => 0,
2320 'username' => '',
2321 'group_id' => (int) $group_id,
2322 'group_name' => (string) $groupnames_ary[$group_id]
2323 );
2324 }
2325 }
2326 }
2327
2328 $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary);
2329 }
2330
2331 /**
2332 * View log
2333 */
2334 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')
2335 {
2336 global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
2337
2338 $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
2339
2340 $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');
2341
2342 switch ($mode)
2343 {
2344 case 'admin':
2345 $log_type = LOG_ADMIN;
2346 $sql_forum = '';
2347 break;
2348
2349 case 'mod':
2350 $log_type = LOG_MOD;
2351
2352 if ($topic_id)
2353 {
2354 $sql_forum = 'AND l.topic_id = ' . intval($topic_id);
2355 }
2356 else if (is_array($forum_id))
2357 {
2358 $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
2359 }
2360 else
2361 {
2362 $sql_forum = ($forum_id) ? 'AND l.forum_id = ' . intval($forum_id) : '';
2363 }
2364 break;
2365
2366 case 'user':
2367 $log_type = LOG_USERS;
2368 $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
2369 break;
2370
2371 case 'users':
2372 $log_type = LOG_USERS;
2373 $sql_forum = '';
2374 break;
2375
2376 case 'critical':
2377 $log_type = LOG_CRITICAL;
2378 $sql_forum = '';
2379 break;
2380
2381 default:
2382 return;
2383 }
2384
2385 $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
2386 FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
2387 WHERE l.log_type = $log_type
2388 AND u.user_id = l.user_id
2389 " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
2390 $sql_forum
2391 ORDER BY $sort_by";
2392 $result = $db->sql_query_limit($sql, $limit, $offset);
2393
2394 $i = 0;
2395 $log = array();
2396 while ($row = $db->sql_fetchrow($result))
2397 {
2398 if ($row['topic_id'])
2399 {
2400 $topic_id_list[] = $row['topic_id'];
2401 }
2402
2403 if ($row['reportee_id'])
2404 {
2405 $reportee_id_list[] = $row['reportee_id'];
2406 }
2407
2408 $log[$i] = array(
2409 'id' => $row['log_id'],
2410
2411 'reportee_id' => $row['reportee_id'],
2412 'reportee_username' => '',
2413 'reportee_username_full'=> '',
2414
2415 'user_id' => $row['user_id'],
2416 'username' => $row['username'],
2417 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
2418
2419 'ip' => $row['log_ip'],
2420 'time' => $row['log_time'],
2421 'forum_id' => $row['forum_id'],
2422 'topic_id' => $row['topic_id'],
2423
2424 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
2425 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
2426 );
2427
2428 if (!empty($row['log_data']))
2429 {
2430 $log_data_ary = unserialize($row['log_data']);
2431
2432 if (isset($user->lang[$row['log_operation']]))
2433 {
2434 // We supress the warning about inappropriate number of passed parameters here due to possible changes within LOG strings from one version to another.
2435 $log[$i]['action'] = @vsprintf($log[$i]['action'], $log_data_ary);
2436
2437 // If within the admin panel we do not censor text out
2438 if (defined('IN_ADMIN'))
2439 {
2440 $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
2441 }
2442 else
2443 {
2444 $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
2445 }
2446 }
2447 else
2448 {
2449 $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
2450 }
2451
2452 /* Apply make_clickable... has to be seen if it is for good. :/
2453 // Seems to be not for the moment, reconsider later...
2454 $log[$i]['action'] = make_clickable($log[$i]['action']);
2455 */
2456 }
2457
2458 $i++;
2459 }
2460 $db->sql_freeresult($result);
2461
2462 if (sizeof($topic_id_list))
2463 {
2464 $topic_id_list = array_unique($topic_id_list);
2465
2466 // This query is not really needed if move_topics() updates the forum_id field,
2467 // although it's also used to determine if the topic still exists in the database
2468 $sql = 'SELECT topic_id, forum_id
2469 FROM ' . TOPICS_TABLE . '
2470 WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
2471 $result = $db->sql_query($sql);
2472
2473 $default_forum_id = 0;
2474
2475 while ($row = $db->sql_fetchrow($result))
2476 {
2477 if (!$row['forum_id'])
2478 {
2479 if ($auth->acl_getf_global('f_read'))
2480 {
2481 if (!$default_forum_id)
2482 {
2483 $sql = 'SELECT forum_id
2484 FROM ' . FORUMS_TABLE . '
2485 WHERE forum_type = ' . FORUM_POST;
2486 $f_result = $db->sql_query_limit($sql, 1);
2487 $default_forum_id = (int) $db->sql_fetchfield('forum_id', false, $f_result);
2488 $db->sql_freeresult($f_result);
2489 }
2490
2491 $is_auth[$row['topic_id']] = $default_forum_id;
2492 }
2493 }
2494 else
2495 {
2496 if ($auth->acl_get('f_read', $row['forum_id']))
2497 {
2498 $is_auth[$row['topic_id']] = $row['forum_id'];
2499 }
2500 }
2501
2502 if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
2503 {
2504 $is_mod[$row['topic_id']] = $row['forum_id'];
2505 }
2506 }
2507 $db->sql_freeresult($result);
2508
2509 foreach ($log as $key => $row)
2510 {
2511 $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;
2512 $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;
2513 }
2514 }
2515
2516 if (sizeof($reportee_id_list))
2517 {
2518 $reportee_id_list = array_unique($reportee_id_list);
2519 $reportee_names_list = array();
2520
2521 $sql = 'SELECT user_id, username, user_colour
2522 FROM ' . USERS_TABLE . '
2523 WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
2524 $result = $db->sql_query($sql);
2525
2526 while ($row = $db->sql_fetchrow($result))
2527 {
2528 $reportee_names_list[$row['user_id']] = $row;
2529 }
2530 $db->sql_freeresult($result);
2531
2532 foreach ($log as $key => $row)
2533 {
2534 if (!isset($reportee_names_list[$row['reportee_id']]))
2535 {
2536 continue;
2537 }
2538
2539 $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
2540 $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);
2541 }
2542 }
2543
2544 $sql = 'SELECT COUNT(l.log_id) AS total_entries
2545 FROM ' . LOG_TABLE . " l
2546 WHERE l.log_type = $log_type
2547 AND l.log_time >= $limit_days
2548 $sql_forum";
2549 $result = $db->sql_query($sql);
2550 $log_count = (int) $db->sql_fetchfield('total_entries');
2551 $db->sql_freeresult($result);
2552
2553 return;
2554 }
2555
2556 /**
2557 * Update foes - remove moderators and administrators from foe lists...
2558 */
2559 function update_foes($group_id = false, $user_id = false)
2560 {
2561 global $db, $auth;
2562
2563 // update foes for some user
2564 if (is_array($user_id) && sizeof($user_id))
2565 {
2566 $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2567 WHERE ' . $db->sql_in_set('zebra_id', $user_id) . '
2568 AND foe = 1';
2569 $db->sql_query($sql);
2570 return;
2571 }
2572
2573 // update foes for some group
2574 if (is_array($group_id) && sizeof($group_id))
2575 {
2576 // Grab group settings...
2577 $sql = $db->sql_build_query('SELECT', array(
2578 'SELECT' => 'a.group_id',
2579
2580 'FROM' => array(
2581 ACL_OPTIONS_TABLE => 'ao',
2582 ACL_GROUPS_TABLE => 'a'
2583 ),
2584
2585 'LEFT_JOIN' => array(
2586 array(
2587 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'),
2588 'ON' => 'a.auth_role_id = r.role_id'
2589 ),
2590 ),
2591
2592 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id)
2593 AND ' . $db->sql_in_set('a.group_id', $group_id) . "
2594 AND ao.auth_option IN ('a_', 'm_')",
2595
2596 'GROUP_BY' => 'a.group_id'
2597 ));
2598 $result = $db->sql_query($sql);
2599
2600 $groups = array();
2601 while ($row = $db->sql_fetchrow($result))
2602 {
2603 $groups[] = (int) $row['group_id'];
2604 }
2605 $db->sql_freeresult($result);
2606
2607 if (!sizeof($groups))
2608 {
2609 return;
2610 }
2611
2612 switch ($db->sql_layer)
2613 {
2614 case 'mysqli':
2615 case 'mysql4':
2616 $sql = 'DELETE ' . (($db->sql_layer === 'mysqli' || version_compare($db->mysql_version, '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . '
2617 FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug
2618 WHERE z.zebra_id = ug.user_id
2619 AND z.foe = 1
2620 AND ' . $db->sql_in_set('ug.group_id', $groups);
2621 $db->sql_query($sql);
2622 break;
2623
2624 default:
2625 $sql = 'SELECT user_id
2626 FROM ' . USER_GROUP_TABLE . '
2627 WHERE ' . $db->sql_in_set('group_id', $groups);
2628 $result = $db->sql_query($sql);
2629
2630 $users = array();
2631 while ($row = $db->sql_fetchrow($result))
2632 {
2633 $users[] = (int) $row['user_id'];
2634 }
2635 $db->sql_freeresult($result);
2636
2637 if (sizeof($users))
2638 {
2639 $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2640 WHERE ' . $db->sql_in_set('zebra_id', $users) . '
2641 AND foe = 1';
2642 $db->sql_query($sql);
2643 }
2644 break;
2645 }
2646
2647 return;
2648 }
2649
2650 // update foes for everyone
2651 $perms = array();
2652 foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary)
2653 {
2654 foreach ($forum_ary as $auth_option => $user_ary)
2655 {
2656 $perms = array_merge($perms, $user_ary);
2657 }
2658 }
2659
2660 if (sizeof($perms))
2661 {
2662 $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2663 WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . '
2664 AND foe = 1';
2665 $db->sql_query($sql);
2666 }
2667 unset($perms);
2668 }
2669
2670 /**
2671 * Lists inactive users
2672 */
2673 function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC')
2674 {
2675 global $db, $user;
2676
2677 $sql = 'SELECT COUNT(user_id) AS user_count
2678 FROM ' . USERS_TABLE . '
2679 WHERE user_type = ' . USER_INACTIVE .
2680 (($limit_days) ? " AND user_inactive_time >= $limit_days" : '');
2681 $result = $db->sql_query($sql);
2682 $user_count = (int) $db->sql_fetchfield('user_count');
2683 $db->sql_freeresult($result);
2684
2685 if ($offset >= $user_count)
2686 {
2687 $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
2688 }
2689
2690 $sql = 'SELECT user_id, username, user_regdate, user_lastvisit, user_inactive_time, user_inactive_reason
2691 FROM ' . USERS_TABLE . '
2692 WHERE user_type = ' . USER_INACTIVE .
2693 (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . "
2694 ORDER BY $sort_by";
2695 $result = $db->sql_query_limit($sql, $limit, $offset);
2696
2697 while ($row = $db->sql_fetchrow($result))
2698 {
2699 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN'];
2700 switch ($row['user_inactive_reason'])
2701 {
2702 case INACTIVE_REGISTER:
2703 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER'];
2704 break;
2705
2706 case INACTIVE_PROFILE:
2707 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE'];
2708 break;
2709
2710 case INACTIVE_MANUAL:
2711 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL'];
2712 break;
2713
2714 case INACTIVE_REMIND:
2715 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND'];
2716 break;
2717 }
2718
2719 $users[] = $row;
2720 }
2721
2722 return $offset;
2723 }
2724
2725 /**
2726 * Lists warned users
2727 */
2728 function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC')
2729 {
2730 global $db;
2731
2732 $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning
2733 FROM ' . USERS_TABLE . '
2734 WHERE user_warnings > 0
2735 ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . "
2736 ORDER BY $sort_by";
2737 $result = $db->sql_query_limit($sql, $limit, $offset);
2738 $users = $db->sql_fetchrowset($result);
2739 $db->sql_freeresult($result);
2740
2741 $sql = 'SELECT count(user_id) AS user_count
2742 FROM ' . USERS_TABLE . '
2743 WHERE user_warnings > 0
2744 ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '');
2745 $result = $db->sql_query($sql);
2746 $user_count = (int) $db->sql_fetchfield('user_count');
2747 $db->sql_freeresult($result);
2748
2749 return;
2750 }
2751
2752 /**
2753 * Get database size
2754 * Currently only mysql and mssql are supported
2755 */
2756 function get_database_size()
2757 {
2758 global $db, $user, $table_prefix;
2759
2760 $database_size = false;
2761
2762 // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0
2763 switch ($db->sql_layer)
2764 {
2765 case 'mysql':
2766 case 'mysql4':
2767 case 'mysqli':
2768 $sql = 'SELECT VERSION() AS mysql_version';
2769 $result = $db->sql_query($sql);
2770 $row = $db->sql_fetchrow($result);
2771 $db->sql_freeresult($result);
2772
2773 if ($row)
2774 {
2775 $version = $row['mysql_version'];
2776
2777 if (preg_match('#(3\.23|[45]\.)#', $version))
2778 {
2779 $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->dbname}`" : $db->dbname;
2780
2781 $sql = 'SHOW TABLE STATUS
2782 FROM ' . $db_name;
2783 $result = $db->sql_query($sql, 7200);
2784
2785 $database_size = 0;
2786 while ($row = $db->sql_fetchrow($result))
2787 {
2788 if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB')))
2789 {
2790 if ($table_prefix != '')
2791 {
2792 if (strpos($row['Name'], $table_prefix) !== false)
2793 {
2794 $database_size += $row['Data_length'] + $row['Index_length'];
2795 }
2796 }
2797 else
2798 {
2799 $database_size += $row['Data_length'] + $row['Index_length'];
2800 }
2801 }
2802 }
2803 $db->sql_freeresult($result);
2804 }
2805 }
2806 break;
2807
2808 case 'firebird':
2809 global $dbname;
2810
2811 // if it on the local machine, we can get lucky
2812 if (file_exists($dbname))
2813 {
2814 $database_size = filesize($dbname);
2815 }
2816
2817 break;
2818
2819 case 'sqlite':
2820 global $dbhost;
2821
2822 if (file_exists($dbhost))
2823 {
2824 $database_size = filesize($dbhost);
2825 }
2826
2827 break;
2828
2829 case 'mssql':
2830 case 'mssql_odbc':
2831 $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize
2832 FROM sysfiles';
2833 $result = $db->sql_query($sql, 7200);
2834 $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
2835 $db->sql_freeresult($result);
2836 break;
2837
2838 case 'postgres':
2839 $sql = "SELECT proname
2840 FROM pg_proc
2841 WHERE proname = 'pg_database_size'";
2842 $result = $db->sql_query($sql);
2843 $row = $db->sql_fetchrow($result);
2844 $db->sql_freeresult($result);
2845
2846 if ($row['proname'] == 'pg_database_size')
2847 {
2848 $database = $db->dbname;
2849 if (strpos($database, '.') !== false)
2850 {
2851 list($database, ) = explode('.', $database);
2852 }
2853
2854 $sql = "SELECT oid
2855 FROM pg_database
2856 WHERE datname = '$database'";
2857 $result = $db->sql_query($sql);
2858 $row = $db->sql_fetchrow($result);
2859 $db->sql_freeresult($result);
2860
2861 $oid = $row['oid'];
2862
2863 $sql = 'SELECT pg_database_size(' . $oid . ') as size';
2864 $result = $db->sql_query($sql);
2865 $row = $db->sql_fetchrow($result);
2866 $db->sql_freeresult($result);
2867
2868 $database_size = $row['size'];
2869 }
2870 break;
2871
2872 case 'oracle':
2873 $sql = 'SELECT SUM(bytes) as dbsize
2874 FROM user_segments';
2875 $result = $db->sql_query($sql, 7200);
2876 $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
2877 $db->sql_freeresult($result);
2878 break;
2879 }
2880
2881 if ($database_size !== false)
2882 {
2883 $database_size = ($database_size >= 1048576) ? sprintf('%.2f ' . $user->lang['MB'], ($database_size / 1048576)) : (($database_size >= 1024) ? sprintf('%.2f ' . $user->lang['KB'], ($database_size / 1024)) : sprintf('%.2f ' . $user->lang['BYTES'], $database_size));
2884 }
2885 else
2886 {
2887 $database_size = $user->lang['NOT_AVAILABLE'];
2888 }
2889
2890 return $database_size;
2891 }
2892
2893 /**
2894 * Retrieve contents from remotely stored file
2895 */
2896 function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 10)
2897 {
2898 global $user;
2899
2900 if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout))
2901 {
2902 @fputs($fsock, "GET $directory/$filename HTTP/1.1\r\n");
2903 @fputs($fsock, "HOST: $host\r\n");
2904 @fputs($fsock, "Connection: close\r\n\r\n");
2905
2906 $file_info = '';
2907 $get_info = false;
2908
2909 while (!@feof($fsock))
2910 {
2911 if ($get_info)
2912 {
2913 $file_info .= @fread($fsock, 1024);
2914 }
2915 else
2916 {
2917 $line = @fgets($fsock, 1024);
2918 if ($line == "\r\n")
2919 {
2920 $get_info = true;
2921 }
2922 else if (stripos($line, '404 not found') !== false)
2923 {
2924 $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename;
2925 return false;
2926 }
2927 }
2928 }
2929 @fclose($fsock);
2930 }
2931 else
2932 {
2933 if ($errstr)
2934 {
2935 $errstr = utf8_convert_message($errstr);
2936 return false;
2937 }
2938 else
2939 {
2940 $errstr = $user->lang['FSOCK_DISABLED'];
2941 return false;
2942 }
2943 }
2944
2945 return $file_info;
2946 }
2947
2948 /**
2949 * Tidy Warnings
2950 * Remove all warnings which have now expired from the database
2951 * The duration of a warning can be defined by the administrator
2952 * This only removes the warning and reduces the associated count,
2953 * it does not remove the user note recording the contents of the warning
2954 */
2955 function tidy_warnings()
2956 {
2957 global $db, $config;
2958
2959 $expire_date = time() - ($config['warnings_expire_days'] * 86400);
2960 $warning_list = $user_list = array();
2961
2962 $sql = 'SELECT * FROM ' . WARNINGS_TABLE . "
2963 WHERE warning_time < $expire_date";
2964 $result = $db->sql_query($sql);
2965
2966 while ($row = $db->sql_fetchrow($result))
2967 {
2968 $warning_list[] = $row['warning_id'];
2969 $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? ++$user_list[$row['user_id']] : 1;
2970 }
2971 $db->sql_freeresult($result);
2972
2973 if (sizeof($warning_list))
2974 {
2975 $db->sql_transaction('begin');
2976
2977 $sql = 'DELETE FROM ' . WARNINGS_TABLE . '
2978 WHERE ' . $db->sql_in_set('warning_id', $warning_list);
2979 $db->sql_query($sql);
2980
2981 foreach ($user_list as $user_id => $value)
2982 {
2983 $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value
2984 WHERE user_id = $user_id";
2985 $db->sql_query($sql);
2986 }
2987
2988 $db->sql_transaction('commit');
2989 }
2990
2991 set_config('warnings_last_gc', time(), true);
2992 }
2993
2994 /**
2995 * Tidy database, doing some maintanance tasks
2996 */
2997 function tidy_database()
2998 {
2999 global $db;
3000
3001 set_config('database_last_gc', time(), true);
3002 }
3003
3004 /**
3005 * Add permission language - this will make sure custom files will be included
3006 */
3007 function add_permission_language()
3008 {
3009 global $user, $phpEx;
3010
3011 // First of all, our own file. We need to include it as the first file because it presets all relevant variables.
3012 $user->add_lang('acp/permissions_phpbb');
3013
3014 $files_to_add = array();
3015
3016 // Now search in acp and mods folder for permissions_ files.
3017 foreach (array('acp/', 'mods/') as $path)
3018 {
3019 $dh = @opendir($user->lang_path . $path);
3020
3021 if ($dh)
3022 {
3023 while (($file = readdir($dh)) !== false)
3024 {
3025 if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
3026 {
3027 $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1));
3028 }
3029 }
3030 closedir($dh);
3031 }
3032 }
3033
3034 if (!sizeof($files_to_add))
3035 {
3036 return false;
3037 }
3038
3039 $user->add_lang($files_to_add);
3040 return true;
3041 }
3042
3043 ?>