- a bunch of fixes
[phpbb.git] / phpBB / includes / functions_admin.php
blob23f243168f24bdf6e19467bc85cb6e27c1065a33
1 <?php
2 /**
4 * @package acp
5 * @version $Id$
6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
12 * Recalculate Binary Tree
13 function recalc_btree($sql_id, $sql_table, $module_class = '')
15 global $db;
17 if (!$sql_id || !$sql_table)
19 return;
22 $sql_where = ($module_class) ? " WHERE module_class = '" . $db->sql_escape($module_class) . "'" : '';
24 // Reset to minimum possible left and right id
25 $sql = "SELECT MIN(left_id) as min_left_id, MIN(right_id) as min_right_id
26 FROM $sql_table
27 $sql_where";
28 $result = $db->sql_query($sql);
29 $row = $db->sql_fetchrow($result);
30 $db->sql_freeresult($result);
32 $substract = (int) (min($row['min_left_id'], $row['min_right_id']) - 1);
34 if ($substract > 0)
36 $sql = "UPDATE $sql_table
37 SET left_id = left_id - $substract, right_id = right_id - $substract
38 $sql_where";
39 $db->sql_query($sql);
42 $sql = "SELECT $sql_id, parent_id, left_id, right_id
43 FROM $sql_table
44 $sql_where
45 ORDER BY left_id ASC, parent_id ASC, $sql_id ASC";
46 $f_result = $db->sql_query($sql);
48 while ($item_data = $db->sql_fetchrow($f_result))
50 if ($item_data['parent_id'])
52 $sql = "SELECT left_id, right_id
53 FROM $sql_table
54 $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
55 $sql_id = {$item_data['parent_id']}";
56 $result = $db->sql_query($sql);
58 if (!$row = $db->sql_fetchrow($result))
60 $sql = "UPDATE $sql_table SET parent_id = 0 WHERE $sql_id = " . $item_data[$sql_id];
61 $db->sql_query($sql);
63 $db->sql_freeresult($result);
65 $sql = "UPDATE $sql_table
66 SET left_id = left_id + 2, right_id = right_id + 2
67 $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
68 left_id > {$row['right_id']}";
69 $db->sql_query($sql);
71 $sql = "UPDATE $sql_table
72 SET right_id = right_id + 2
73 $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . "
74 {$row['left_id']} BETWEEN left_id AND right_id";
75 $db->sql_query($sql);
77 $item_data['left_id'] = $row['right_id'];
78 $item_data['right_id'] = $row['right_id'] + 1;
80 else
82 $sql = "SELECT MAX(right_id) AS right_id
83 FROM $sql_table
84 $sql_where";
85 $result = $db->sql_query($sql);
86 $row = $db->sql_fetchrow($result);
87 $db->sql_freeresult($result);
89 $item_data['left_id'] = $row['right_id'] + 1;
90 $item_data['right_id'] = $row['right_id'] + 2;
93 $sql = "UPDATE $sql_table
94 SET left_id = {$item_data['left_id']}, right_id = {$item_data['right_id']}
95 WHERE $sql_id = " . $item_data[$sql_id];
96 $db->sql_query($sql);
98 $db->sql_freeresult($f_result);
103 * Simple version of jumpbox, just lists authed forums
105 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)
107 global $db, $user, $auth;
109 $acl = ($ignore_acl) ? '' : (($only_acl_post) ? 'f_post' : array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'));
111 // This query is identical to the jumpbox one
112 $sql = 'SELECT forum_id, parent_id, forum_name, forum_type, forum_status, left_id, right_id
113 FROM ' . FORUMS_TABLE . '
114 ORDER BY left_id ASC';
115 $result = $db->sql_query($sql);
117 $right = $iteration = 0;
118 $padding_store = array('0' => '');
119 $padding = '';
120 $forum_list = ($return_array) ? array() : '';
122 // Sometimes it could happen that forums will be displayed here not be displayed within the index page
123 // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
124 // If this happens, the padding could be "broken"
126 while ($row = $db->sql_fetchrow($result))
128 if ($row['left_id'] < $right)
130 $padding .= '&nbsp; &nbsp;';
131 $padding_store[$row['parent_id']] = $padding;
133 else if ($row['left_id'] > $right + 1)
135 $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : '';
138 $right = $row['right_id'];
140 if ($acl && !$auth->acl_gets($acl, $row['forum_id']))
142 continue;
145 if ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id)
147 continue;
150 if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat)
152 // Non-postable forum with no subforums, don't display
153 continue;
156 if ($row['forum_type'] != FORUM_POST && $ignore_nonpost)
158 continue;
161 if ($return_array)
163 // Include some more information...
164 $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false);
165 $forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => $selected), $row);
167 else
169 $selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : '');
170 $forum_list .= '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>';
173 $iteration++;
175 $db->sql_freeresult($result);
176 unset($padding_store);
178 return $forum_list;
182 * Generate size select options
184 function size_select_options($size_compare)
186 global $user;
188 $size_types_text = array($user->lang['BYTES'], $user->lang['KB'], $user->lang['MB']);
189 $size_types = array('b', 'kb', 'mb');
191 $s_size_options = '';
193 for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++)
195 $selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : '';
196 $s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>';
199 return $s_size_options;
203 * Generate list of groups
205 function group_select_options($group_id, $exclude_ids = false)
207 global $db, $user, $config;
209 $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
210 $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : '';
212 $sql = 'SELECT group_id, group_name, group_type
213 FROM ' . GROUPS_TABLE . "
214 $exclude_sql
215 $sql_and
216 ORDER BY group_type DESC, group_name ASC";
217 $result = $db->sql_query($sql);
219 $s_group_options = '';
220 while ($row = $db->sql_fetchrow($result))
222 $selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : '';
223 $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>';
225 $db->sql_freeresult($result);
227 return $s_group_options;
231 * Obtain authed forums list
233 function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false)
235 global $db, $auth;
236 static $forum_rows;
238 if (!isset($forum_rows))
240 // This query is identical to the jumpbox one
241 $expire_time = ($no_cache) ? 0 : 120;
243 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
244 FROM ' . FORUMS_TABLE . '
245 ORDER BY left_id ASC';
246 $result = $db->sql_query($sql, $expire_time);
248 $forum_rows = array();
249 while ($row = $db->sql_fetchrow($result))
251 $forum_rows[] = $row;
253 $db->sql_freeresult($result);
256 $rowset = array();
257 foreach ($forum_rows as $row)
259 if ($postable_only && $row['forum_type'] != FORUM_POST)
261 continue;
264 if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id'])))
266 $rowset[] = ($id_only) ? $row['forum_id'] : $row;
270 return $rowset;
274 * Get forum branch
276 function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true)
278 global $db;
280 switch ($type)
282 case 'parents':
283 $condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id';
284 break;
286 case 'children':
287 $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id';
288 break;
290 default:
291 $condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id';
292 break;
295 $rows = array();
297 $sql = 'SELECT f2.*
298 FROM ' . FORUMS_TABLE . ' f1
299 LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition)
300 WHERE f1.forum_id = $forum_id
301 ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC');
302 $result = $db->sql_query($sql);
304 while ($row = $db->sql_fetchrow($result))
306 if (!$include_forum && $row['forum_id'] == $forum_id)
308 continue;
311 $rows[] = $row;
313 $db->sql_freeresult($result);
315 return $rows;
319 * Get physical file listing
321 function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png')
323 $matches = array();
325 // Remove initial / if present
326 $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir;
327 // Add closing / if not present
328 $rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir;
330 // Remove initial / if present
331 $dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir;
332 // Add closing / if not present
333 $dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir;
335 if (!is_dir($rootdir . $dir))
337 return false;
340 $dh = opendir($rootdir . $dir);
341 while (($fname = readdir($dh)) !== false)
343 if (is_file("$rootdir$dir$fname"))
345 if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname))
347 $matches[$dir][] = $fname;
350 else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname"))
352 $matches += filelist($rootdir, "$dir$fname", $type);
355 closedir($dh);
357 return $matches;
361 * Move topic(s)
363 function move_topics($topic_ids, $forum_id, $auto_sync = true)
365 global $db;
367 if (empty($topic_ids))
369 return;
372 $forum_ids = array($forum_id);
374 if (!is_array($topic_ids))
376 $topic_ids = array($topic_ids);
379 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
380 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . '
381 AND forum_id = ' . $forum_id;
382 $db->sql_query($sql);
384 if ($auto_sync)
386 $sql = 'SELECT DISTINCT forum_id
387 FROM ' . TOPICS_TABLE . '
388 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
389 $result = $db->sql_query($sql);
391 while ($row = $db->sql_fetchrow($result))
393 $forum_ids[] = $row['forum_id'];
395 $db->sql_freeresult($result);
398 $table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
399 foreach ($table_ary as $table)
401 $sql = "UPDATE $table
402 SET forum_id = $forum_id
403 WHERE " . $db->sql_in_set('topic_id', $topic_ids);
404 $db->sql_query($sql);
406 unset($table_ary);
408 if ($auto_sync)
410 sync('forum', 'forum_id', $forum_ids, true);
411 unset($forum_ids);
416 * Move post(s)
418 function move_posts($post_ids, $topic_id, $auto_sync = true)
420 global $db;
422 if (!is_array($post_ids))
424 $post_ids = array($post_ids);
427 $forum_ids = array();
428 $topic_ids = array($topic_id);
430 $sql = 'SELECT DISTINCT topic_id, forum_id
431 FROM ' . POSTS_TABLE . '
432 WHERE ' . $db->sql_in_set('post_id', $post_ids);
433 $result = $db->sql_query($sql);
435 while ($row = $db->sql_fetchrow($result))
437 $forum_ids[] = $row['forum_id'];
438 $topic_ids[] = $row['topic_id'];
440 $db->sql_freeresult($result);
442 $sql = 'SELECT forum_id
443 FROM ' . TOPICS_TABLE . '
444 WHERE topic_id = ' . $topic_id;
445 $result = $db->sql_query($sql);
446 $forum_row = $db->sql_fetchrow($result);
447 $db->sql_freeresult($result);
449 if (!$forum_row)
451 trigger_error('NO_TOPIC');
454 $sql = 'UPDATE ' . POSTS_TABLE . '
455 SET forum_id = ' . $forum_row['forum_id'] . ", topic_id = $topic_id
456 WHERE " . $db->sql_in_set('post_id', $post_ids);
457 $db->sql_query($sql);
459 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
460 SET topic_id = $topic_id, in_message = 0
461 WHERE " . $db->sql_in_set('post_msg_id', $post_ids);
462 $db->sql_query($sql);
464 if ($auto_sync)
466 $forum_ids[] = $forum_row['forum_id'];
468 sync('topic_reported', 'topic_id', $topic_ids);
469 sync('topic_attachment', 'topic_id', $topic_ids);
470 sync('topic', 'topic_id', $topic_ids, true);
471 sync('forum', 'forum_id', $forum_ids, true);
474 // Update posted information
475 update_posted_info($topic_ids);
479 * Remove topic(s)
481 function delete_topics($where_type, $where_ids, $auto_sync = true)
483 global $db, $config;
485 $approved_topics = 0;
486 $forum_ids = $topic_ids = array();
488 if (is_array($where_ids))
490 $where_ids = array_unique($where_ids);
492 else
494 $where_ids = array($where_ids);
497 if (!sizeof($where_ids))
499 return array('topics' => 0, 'posts' => 0);
502 $return = array(
503 'posts' => delete_posts($where_type, $where_ids, false, true)
506 $sql = 'SELECT topic_id, forum_id, topic_approved
507 FROM ' . TOPICS_TABLE . '
508 WHERE ' . $db->sql_in_set($where_type, $where_ids);
509 $result = $db->sql_query($sql);
511 while ($row = $db->sql_fetchrow($result))
513 $forum_ids[] = $row['forum_id'];
514 $topic_ids[] = $row['topic_id'];
516 if ($row['topic_approved'])
518 $approved_topics++;
521 $db->sql_freeresult($result);
523 $return['topics'] = sizeof($topic_ids);
525 if (!sizeof($topic_ids))
527 return $return;
530 $db->sql_transaction('begin');
532 $table_ary = array(TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE);
534 foreach ($table_ary as $table)
536 $sql = "DELETE FROM $table
537 WHERE " . $db->sql_in_set('topic_id', $topic_ids);
538 $db->sql_query($sql);
540 unset($table_ary);
542 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
543 WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids);
544 $db->sql_query($sql);
546 $db->sql_transaction('commit');
548 if ($auto_sync)
550 sync('forum', 'forum_id', $forum_ids, true);
551 sync('topic_reported', $where_type, $where_ids);
554 if ($approved_topics)
556 set_config('num_topics', $config['num_topics'] - $approved_topics, true);
559 return $return;
563 * Remove post(s)
565 function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true)
567 global $db, $config, $phpbb_root_path, $phpEx;
569 if (is_array($where_ids))
571 $where_ids = array_unique($where_ids);
573 else
575 $where_ids = array($where_ids);
578 if (!sizeof($where_ids))
580 return false;
583 $approved_posts = 0;
584 $post_ids = $topic_ids = $forum_ids = $post_counts = array();
586 $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id
587 FROM ' . POSTS_TABLE . '
588 WHERE ' . $db->sql_in_set($where_type, array_map('intval', $where_ids));
589 $result = $db->sql_query($sql);
591 while ($row = $db->sql_fetchrow($result))
593 $post_ids[] = $row['post_id'];
594 $poster_ids[] = $row['poster_id'];
595 $topic_ids[] = $row['topic_id'];
596 $forum_ids[] = $row['forum_id'];
598 if ($row['post_postcount'])
600 $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
603 if ($row['post_approved'])
605 $approved_posts++;
608 $db->sql_freeresult($result);
610 if (!sizeof($post_ids))
612 return false;
615 $db->sql_transaction('begin');
617 $table_ary = array(POSTS_TABLE, REPORTS_TABLE);
619 foreach ($table_ary as $table)
621 $sql = "DELETE FROM $table
622 WHERE " . $db->sql_in_set('post_id', $post_ids);
623 $db->sql_query($sql);
625 unset($table_ary);
627 // Adjust users post counts
628 if (sizeof($post_counts))
630 foreach ($post_counts as $poster_id => $substract)
632 $sql = 'UPDATE ' . USERS_TABLE . '
633 SET user_posts = user_posts - ' . $substract . '
634 WHERE user_id = ' . $poster_id;
635 $db->sql_query($sql);
639 // Remove the message from the search index
640 $search_type = basename($config['search_type']);
642 if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx))
644 trigger_error('NO_SUCH_SEARCH_MODULE');
647 include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx");
649 $error = false;
650 $search = new $search_type($error);
652 if ($error)
654 trigger_error($error);
657 $search->index_remove($post_ids, $poster_ids, $forum_ids);
659 delete_attachments('post', $post_ids, false);
661 $db->sql_transaction('commit');
663 // Resync topics_posted table
664 if ($posted_sync)
666 update_posted_info($topic_ids);
669 if ($auto_sync)
671 sync('topic_reported', 'topic_id', $topic_ids);
672 sync('topic', 'topic_id', $topic_ids, true);
673 sync('forum', 'forum_id', $forum_ids, true);
676 if ($approved_posts)
678 set_config('num_posts', $config['num_posts'] - $approved_posts, true);
681 return sizeof($post_ids);
685 * Delete Attachments
687 * @param string $mode can be: post|topic|attach|user
688 * @param mixed $ids can be: post_ids, topic_ids, attach_ids, user_ids
689 * @param bool $resync set this to false if you are deleting posts or topics
691 function delete_attachments($mode, $ids, $resync = true)
693 global $db, $config;
695 if (is_array($ids))
697 $ids = array_unique($ids);
698 $ids = array_map('intval', $ids);
700 else
702 $ids = array((int) $ids);
705 if (!sizeof($ids))
707 return false;
710 $sql_id = ($mode == 'user') ? 'poster_id' : (($mode == 'post') ? 'post_msg_id' : (($mode == 'topic') ? 'topic_id' : 'attach_id'));
712 $post_ids = $topic_ids = $physical = array();
714 // Collect post and topics ids for later use
715 if ($mode == 'attach' || $mode == 'user' || ($mode == 'topic' && $resync))
717 $sql = 'SELECT post_msg_id as post_id, topic_id, physical_filename, thumbnail, filesize
718 FROM ' . ATTACHMENTS_TABLE . '
719 WHERE ' . $db->sql_in_set($sql_id, $ids);
720 $result = $db->sql_query($sql);
722 while ($row = $db->sql_fetchrow($result))
724 $post_ids[] = $row['post_id'];
725 $topic_ids[] = $row['topic_id'];
726 $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize']);
728 $db->sql_freeresult($result);
731 if ($mode == 'post')
733 $sql = 'SELECT topic_id, physical_filename, thumbnail, filesize
734 FROM ' . ATTACHMENTS_TABLE . '
735 WHERE ' . $db->sql_in_set('post_msg_id', $ids) . '
736 AND in_message = 0';
737 $result = $db->sql_query($sql);
739 while ($row = $db->sql_fetchrow($result))
741 $topic_ids[] = $row['topic_id'];
742 $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize']);
744 $db->sql_freeresult($result);
747 // Delete attachments
748 $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
749 WHERE ' . $db->sql_in_set($sql_id, $ids);
750 $db->sql_query($sql);
751 $num_deleted = $db->sql_affectedrows();
753 if (!$num_deleted)
755 return 0;
758 // Delete attachments from filesystem
759 $space_removed = $files_removed = 0;
760 foreach ($physical as $file_ary)
762 if (phpbb_unlink($file_ary['filename'], 'file'))
764 $space_removed += $file_ary['filesize'];
765 $files_removed++;
768 if ($file_ary['thumbnail'])
770 phpbb_unlink($file_ary['filename'], 'thumbnail');
773 set_config('upload_dir_size', $config['upload_dir_size'] - $space_removed, true);
774 set_config('num_files', $config['num_files'] - $files_removed, true);
776 if ($mode == 'topic' && !$resync)
778 return $num_deleted;
781 if ($mode == 'post')
783 $post_ids = $ids;
785 unset($ids);
787 $post_ids = array_unique($post_ids);
788 $topic_ids = array_unique($topic_ids);
790 // Update post indicators
791 if (sizeof($post_ids))
793 if ($mode == 'post' || $mode == 'topic')
795 $sql = 'UPDATE ' . POSTS_TABLE . '
796 SET post_attachment = 0
797 WHERE ' . $db->sql_in_set('post_id', $post_ids);
798 $db->sql_query($sql);
801 if ($mode == 'user' || $mode == 'attach')
803 $remaining = array();
805 $sql = 'SELECT post_msg_id
806 FROM ' . ATTACHMENTS_TABLE . '
807 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
808 AND in_message = 0';
809 $result = $db->sql_query($sql);
811 while ($row = $db->sql_fetchrow($result))
813 $remaining[] = $row['post_msg_id'];
815 $db->sql_freeresult($result);
817 $unset_ids = array_diff($post_ids, $remaining);
819 if (sizeof($unset_ids))
821 $sql = 'UPDATE ' . POSTS_TABLE . '
822 SET post_attachment = 0
823 WHERE ' . $db->sql_in_set('post_id', $unset_ids);
824 $db->sql_query($sql);
827 $remaining = array();
829 $sql = 'SELECT post_msg_id
830 FROM ' . ATTACHMENTS_TABLE . '
831 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
832 AND in_message = 1';
833 $result = $db->sql_query($sql);
835 while ($row = $db->sql_fetchrow($result))
837 $remaining[] = $row['post_msg_id'];
839 $db->sql_freeresult($result);
841 $unset_ids = array_diff($post_ids, $remaining);
843 if (sizeof($unset_ids))
845 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
846 SET message_attachment = 0
847 WHERE ' . $db->sql_in_set('msg_id', $unset_ids);
848 $db->sql_query($sql);
853 if (sizeof($topic_ids))
855 // Update topic indicator
856 if ($mode == 'topic')
858 $sql = 'UPDATE ' . TOPICS_TABLE . '
859 SET topic_attachment = 0
860 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
861 $db->sql_query($sql);
864 if ($mode == 'post' || $mode == 'user' || $mode == 'attach')
866 $remaining = array();
868 $sql = 'SELECT topic_id
869 FROM ' . ATTACHMENTS_TABLE . '
870 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
871 $result = $db->sql_query($sql);
873 while ($row = $db->sql_fetchrow($result))
875 $remaining[] = $row['topic_id'];
877 $db->sql_freeresult($result);
879 $unset_ids = array_diff($topic_ids, $remaining);
881 if (sizeof($unset_ids))
883 $sql = 'UPDATE ' . TOPICS_TABLE . '
884 SET topic_attachment = 0
885 WHERE ' . $db->sql_in_set('topic_id', $unset_ids);
886 $db->sql_query($sql);
891 return $num_deleted;
895 * Remove topic shadows
897 function delete_topic_shadows($max_age, $forum_id = '', $auto_sync = true)
899 $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 : '');
901 switch ($db->sql_layer)
903 case 'mysql4':
904 case 'mysqli':
905 $sql = 'DELETE t.*
906 FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2
907 WHERE t.topic_moved_id = t2.topic_id
908 AND t.topic_time < ' . (time() - $max_age)
909 . $where;
910 $db->sql_query($sql);
911 break;
913 default:
914 $sql = 'SELECT t.topic_id
915 FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2
916 WHERE t.topic_moved_id = t2.topic_id
917 AND t.topic_time < ' . (time() - $max_age)
918 . $where;
919 $result = $db->sql_query($sql);
921 $topic_ids = array();
922 while ($row = $db->sql_fetchrow($result))
924 $topic_ids[] = $row['topic_id'];
926 $db->sql_freeresult($result);
928 if (sizeof($topic_ids))
930 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
931 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
932 $db->sql_query($sql);
934 break;
937 if ($auto_sync)
939 $where_type = ($forum_id) ? 'forum_id' : '';
940 sync('forum', $where_type, $forum_id, true);
945 * Update/Sync posted information for topics
947 function update_posted_info(&$topic_ids)
949 global $db, $config;
951 if (empty($topic_ids) || !$config['load_db_track'])
953 return;
956 // First of all, let us remove any posted information for these topics
957 $sql = 'DELETE FROM ' . TOPICS_POSTED_TABLE . '
958 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
959 $db->sql_query($sql);
961 // Now, let us collect the user/topic combos for rebuilding the information
962 $sql = 'SELECT poster_id, topic_id
963 FROM ' . POSTS_TABLE . '
964 WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
965 AND poster_id <> ' . ANONYMOUS . '
966 GROUP BY poster_id, topic_id';
967 $result = $db->sql_query($sql);
969 $posted = array();
970 while ($row = $db->sql_fetchrow($result))
972 // Add as key to make them unique (grouping by) and circumvent empty keys on array_unique
973 $posted[$row['poster_id']][] = $row['topic_id'];
975 $db->sql_freeresult($result);
977 // Now add the information...
978 $sql_ary = array();
979 foreach ($posted as $user_id => $topic_row)
981 foreach ($topic_row as $topic_id)
983 $sql_ary[] = array(
984 'user_id' => $user_id,
985 'topic_id' => $topic_id,
986 'topic_posted' => 1,
990 unset($posted);
992 $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
996 * Delete File
998 function phpbb_unlink($filename, $mode = 'file')
1000 global $config, $user, $phpbb_root_path;
1002 $filename = ($mode == 'thumbnail') ? $phpbb_root_path . $config['upload_path'] . '/thumb_' . basename($filename) : $phpbb_root_path . $config['upload_path'] . '/' . basename($filename);
1003 return @unlink($filename);
1007 * All-encompasing sync function
1009 * Exaples:
1010 * <code>
1011 * sync('topic', 'topic_id', 123); // resync topic #123
1012 * sync('topic', 'forum_id', array(2, 3)); // resync topics from forum #2 and #3
1013 * sync('topic'); // resync all topics
1014 * sync('topic', 'range', 'topic_id BETWEEN 1 AND 60'); // resync a range of topics/forums (only available for 'topic' and 'forum' modes)
1015 * </code>
1017 * Modes:
1018 * - forum Resync complete forum
1019 * - topic Resync topics
1020 * - topic_moved Removes topic shadows that would be in the same forum as the topic they link to
1021 * - topic_approved Resyncs the topic_approved flag according to the status of the first post
1022 * - post_reported Resyncs the post_reported flag, relying on actual reports
1023 * - topic_reported Resyncs the topic_reported flag, relying on post_reported flags
1024 * - post_attachement Same as post_reported, but with attachment flags
1025 * - topic_attachement Same as topic_reported, but with attachment flags
1027 function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_extra = false)
1029 global $db;
1031 if (is_array($where_ids))
1033 $where_ids = array_unique($where_ids);
1034 $where_ids = array_map('intval', $where_ids);
1036 else if ($where_type != 'range')
1038 $where_ids = ($where_ids) ? array((int) $where_ids) : array();
1041 if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved')
1043 if (!$where_type)
1045 $where_sql = '';
1046 $where_sql_and = 'WHERE';
1048 else if ($where_type == 'range')
1050 // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60'
1051 $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)";
1052 $where_sql_and = $where_sql . "\n\tAND";
1054 else
1056 // Do not sync the "global forum"
1057 $where_ids = array_diff($where_ids, array(0));
1059 if (!sizeof($where_ids))
1061 // Empty array with IDs. This means that we don't have any work to do. Just return.
1062 return;
1065 // Limit the topics/forums we are syncing, use specific topic/forum IDs.
1066 // $where_type contains the field for the where clause (forum_id, topic_id)
1067 $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
1068 $where_sql_and = $where_sql . "\n\tAND";
1071 else
1073 if (!sizeof($where_ids))
1075 return;
1078 // $where_type contains the field for the where clause (forum_id, topic_id)
1079 $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids);
1080 $where_sql_and = $where_sql . "\n\tAND";
1083 switch ($mode)
1085 case 'topic_moved':
1086 switch ($db->sql_layer)
1088 case 'mysql4':
1089 case 'mysqli':
1090 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1091 USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
1092 WHERE t1.topic_moved_id = t2.topic_id
1093 AND t1.forum_id = t2.forum_id";
1094 $db->sql_query($sql);
1095 break;
1097 default:
1098 $sql = 'SELECT t1.topic_id
1099 FROM ' .TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2
1100 WHERE t1.topic_moved_id = t2.topic_id
1101 AND t1.forum_id = t2.forum_id";
1102 $result = $db->sql_query($sql);
1104 $topic_id_ary = array();
1105 while ($row = $db->sql_fetchrow($result))
1107 $topic_id_ary[] = $row['topic_id'];
1109 $db->sql_freeresult($result);
1111 if (!sizeof($topic_id_ary))
1113 return;
1116 $sql = 'DELETE FROM ' . TOPICS_TABLE . '
1117 WHERE ' . $db->sql_in_set('topic_id', $topic_id_ary);
1118 $db->sql_query($sql);
1120 break;
1122 break;
1124 case 'topic_approved':
1125 switch ($db->sql_layer)
1127 case 'mysql4':
1128 case 'mysqli':
1129 $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1130 SET t.topic_approved = p.post_approved
1131 $where_sql_and t.topic_first_post_id = p.post_id";
1132 $db->sql_query($sql);
1133 break;
1135 default:
1136 $sql = 'SELECT t.topic_id, p.post_approved
1137 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1138 $where_sql_and p.post_id = t.topic_first_post_id
1139 AND p.post_approved <> t.topic_approved";
1140 $result = $db->sql_query($sql);
1142 $topic_ids = array();
1143 while ($row = $db->sql_fetchrow($result))
1145 $topic_ids[] = $row['topic_id'];
1147 $db->sql_freeresult($result);
1149 if (!sizeof($topic_ids))
1151 return;
1154 $sql = 'UPDATE ' . TOPICS_TABLE . '
1155 SET topic_approved = 1 - topic_approved
1156 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1157 $db->sql_query($sql);
1158 break;
1160 break;
1162 case 'post_reported':
1163 $post_ids = $post_reported = array();
1165 $sql = 'SELECT p.post_id, p.post_reported
1166 FROM ' . POSTS_TABLE . " p
1167 $where_sql
1168 GROUP BY p.post_id, p.post_reported";
1169 $result = $db->sql_query($sql);
1171 while ($row = $db->sql_fetchrow($result))
1173 $post_ids[$row['post_id']] = $row['post_id'];
1174 if ($row['post_reported'])
1176 $post_reported[$row['post_id']] = 1;
1179 $db->sql_freeresult($result);
1181 $sql = 'SELECT DISTINCT(post_id)
1182 FROM ' . REPORTS_TABLE . '
1183 WHERE ' . $db->sql_in_set('post_id', $post_ids) . '
1184 AND report_closed = 0';
1185 $result = $db->sql_query($sql);
1187 $post_ids = array();
1188 while ($row = $db->sql_fetchrow($result))
1190 if (!isset($post_reported[$row['post_id']]))
1192 $post_ids[] = $row['post_id'];
1194 else
1196 unset($post_reported[$row['post_id']]);
1199 $db->sql_freeresult($result);
1201 // $post_reported should be empty by now, if it's not it contains
1202 // posts that are falsely flagged as reported
1203 foreach ($post_reported as $post_id => $void)
1205 $post_ids[] = $post_id;
1208 if (sizeof($post_ids))
1210 $sql = 'UPDATE ' . POSTS_TABLE . '
1211 SET post_reported = 1 - post_reported
1212 WHERE ' . $db->sql_in_set('post_id', $post_ids);
1213 $db->sql_query($sql);
1215 break;
1217 case 'topic_reported':
1218 if ($sync_extra)
1220 sync('post_reported', $where_type, $where_ids);
1223 $topic_ids = $topic_reported = array();
1225 $sql = 'SELECT DISTINCT(t.topic_id)
1226 FROM ' . POSTS_TABLE . " t
1227 $where_sql_and t.post_reported = 1";
1228 $result = $db->sql_query($sql);
1230 while ($row = $db->sql_fetchrow($result))
1232 $topic_reported[$row['topic_id']] = 1;
1234 $db->sql_freeresult($result);
1236 $sql = 'SELECT t.topic_id, t.topic_reported
1237 FROM ' . TOPICS_TABLE . " t
1238 $where_sql";
1239 $result = $db->sql_query($sql);
1241 while ($row = $db->sql_fetchrow($result))
1243 if ($row['topic_reported'] ^ isset($topic_reported[$row['topic_id']]))
1245 $topic_ids[] = $row['topic_id'];
1248 $db->sql_freeresult($result);
1250 if (sizeof($topic_ids))
1252 $sql = 'UPDATE ' . TOPICS_TABLE . '
1253 SET topic_reported = 1 - topic_reported
1254 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1255 $db->sql_query($sql);
1257 break;
1259 case 'post_attachment':
1260 $post_ids = $post_attachment = array();
1262 $sql = 'SELECT p.post_id, p.post_attachment
1263 FROM ' . POSTS_TABLE . " p
1264 $where_sql
1265 GROUP BY p.post_id, p.post_attachment";
1266 $result = $db->sql_query($sql);
1268 while ($row = $db->sql_fetchrow($result))
1270 $post_ids[$row['post_id']] = $row['post_id'];
1271 if ($row['post_attachment'])
1273 $post_attachment[$row['post_id']] = 1;
1276 $db->sql_freeresult($result);
1278 $sql = 'SELECT DISTINCT(post_msg_id)
1279 FROM ' . ATTACHMENTS_TABLE . '
1280 WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
1281 AND in_message = 0';
1282 $result = $db->sql_query($sql);
1284 $post_ids = array();
1285 while ($row = $db->sql_fetchrow($result))
1287 if (!isset($post_attachment[$row['post_id']]))
1289 $post_ids[] = $row['post_id'];
1291 else
1293 unset($post_attachment[$row['post_id']]);
1296 $db->sql_freeresult($result);
1298 // $post_attachment should be empty by now, if it's not it contains
1299 // posts that are falsely flagged as having attachments
1300 foreach ($post_attachment as $post_id => $void)
1302 $post_ids[] = $post_id;
1305 if (sizeof($post_ids))
1307 $sql = 'UPDATE ' . POSTS_TABLE . '
1308 SET post_attachment = 1 - post_attachment
1309 WHERE ' . $db->sql_in_set('post_id', $post_ids);
1310 $db->sql_query($sql);
1312 break;
1314 case 'topic_attachment':
1315 if ($sync_extra)
1317 sync('post_attachment', $where_type, $where_ids);
1320 $topic_ids = $topic_attachment = array();
1322 $sql = 'SELECT DISTINCT(t.topic_id)
1323 FROM ' . POSTS_TABLE . " t
1324 $where_sql_and t.post_attachment = 1";
1325 $result = $db->sql_query($sql);
1327 while ($row = $db->sql_fetchrow($result))
1329 $topic_attachment[$row['topic_id']] = 1;
1331 $db->sql_freeresult($result);
1333 $sql = 'SELECT t.topic_id, t.topic_attachment
1334 FROM ' . TOPICS_TABLE . " t
1335 $where_sql";
1336 $result = $db->sql_query($sql);
1338 while ($row = $db->sql_fetchrow($result))
1340 if ($row['topic_attachment'] ^ isset($topic_attachment[$row['topic_id']]))
1342 $topic_ids[] = $row['topic_id'];
1345 $db->sql_freeresult($result);
1347 if (sizeof($topic_ids))
1349 $sql = 'UPDATE ' . TOPICS_TABLE . '
1350 SET topic_attachment = 1 - topic_attachment
1351 WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
1352 $db->sql_query($sql);
1354 break;
1356 case 'forum':
1358 // 1: Get the list of all forums
1359 $sql = 'SELECT f.*
1360 FROM ' . FORUMS_TABLE . " f
1361 $where_sql";
1362 $result = $db->sql_query($sql);
1364 $forum_data = $forum_ids = $post_ids = $last_post_id = $post_info = array();
1365 while ($row = $db->sql_fetchrow($result))
1367 if ($row['forum_type'] == FORUM_LINK)
1369 continue;
1372 $forum_id = (int) $row['forum_id'];
1373 $forum_ids[$forum_id] = $forum_id;
1375 $forum_data[$forum_id] = $row;
1376 $forum_data[$forum_id]['posts'] = 0;
1377 $forum_data[$forum_id]['topics'] = 0;
1378 $forum_data[$forum_id]['topics_real'] = 0;
1379 $forum_data[$forum_id]['last_post_id'] = 0;
1380 $forum_data[$forum_id]['last_post_subject'] = '';
1381 $forum_data[$forum_id]['last_post_time'] = 0;
1382 $forum_data[$forum_id]['last_poster_id'] = 0;
1383 $forum_data[$forum_id]['last_poster_name'] = '';
1384 $forum_data[$forum_id]['last_poster_colour'] = '';
1386 $db->sql_freeresult($result);
1388 if (!sizeof($forum_ids))
1390 break;
1393 $forum_ids = array_values($forum_ids);
1395 // 2: Get topic counts for each forum
1396 $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics
1397 FROM ' . TOPICS_TABLE . '
1398 WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
1399 GROUP BY forum_id, topic_approved';
1400 $result = $db->sql_query($sql);
1402 while ($row = $db->sql_fetchrow($result))
1404 $forum_id = (int) $row['forum_id'];
1405 $forum_data[$forum_id]['topics_real'] += $row['forum_topics'];
1407 if ($row['topic_approved'])
1409 $forum_data[$forum_id]['topics'] = $row['forum_topics'];
1412 $db->sql_freeresult($result);
1414 // 3: Get post count and last_post_id for each forum
1415 if (sizeof($forum_ids) == 1)
1417 $sql = 'SELECT COUNT(post_id) AS forum_posts, MAX(post_id) AS last_post_id
1418 FROM ' . POSTS_TABLE . '
1419 WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
1420 AND post_approved = 1';
1422 else
1424 $sql = 'SELECT forum_id, COUNT(post_id) AS forum_posts, MAX(post_id) AS last_post_id
1425 FROM ' . POSTS_TABLE . '
1426 WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
1427 AND post_approved = 1
1428 GROUP BY forum_id';
1431 $result = $db->sql_query($sql);
1433 while ($row = $db->sql_fetchrow($result))
1435 $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
1437 $forum_data[$forum_id]['posts'] = (int) $row['forum_posts'];
1438 $forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id'];
1440 $post_ids[] = $row['last_post_id'];
1442 $db->sql_freeresult($result);
1444 // 4: Retrieve last_post infos
1445 if (sizeof($post_ids))
1447 $sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour
1448 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1449 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1450 AND p.poster_id = u.user_id';
1451 $result = $db->sql_query($sql);
1453 while ($row = $db->sql_fetchrow($result))
1455 $post_info[$row['post_id']] = $row;
1457 $db->sql_freeresult($result);
1459 foreach ($forum_data as $forum_id => $data)
1461 if ($data['last_post_id'])
1463 if (isset($post_info[$data['last_post_id']]))
1465 $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject'];
1466 $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time'];
1467 $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id'];
1468 $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'];
1469 $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour'];
1471 else
1473 // For some reason we did not find the post in the db
1474 $forum_data[$forum_id]['last_post_id'] = 0;
1475 $forum_data[$forum_id]['last_post_subject'] = '';
1476 $forum_data[$forum_id]['last_post_time'] = 0;
1477 $forum_data[$forum_id]['last_poster_id'] = 0;
1478 $forum_data[$forum_id]['last_poster_name'] = '';
1479 $forum_data[$forum_id]['last_poster_colour'] = '';
1483 unset($post_info);
1486 // 5: Now do that thing
1487 $fieldnames = array('posts', 'topics', 'topics_real', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
1489 foreach ($forum_data as $forum_id => $row)
1491 $sql_ary = array();
1493 foreach ($fieldnames as $fieldname)
1495 if ($row['forum_' . $fieldname] != $row[$fieldname])
1497 if (preg_match('#(name|colour|subject)$#', $fieldname))
1499 $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname];
1501 else
1503 $sql_ary['forum_' . $fieldname] = (int) $row[$fieldname];
1508 if (sizeof($sql_ary))
1510 $sql = 'UPDATE ' . FORUMS_TABLE . '
1511 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1512 WHERE forum_id = ' . $forum_id;
1513 $db->sql_query($sql);
1516 break;
1518 case 'topic':
1519 $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array();
1521 $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
1522 FROM ' . TOPICS_TABLE . " t
1523 $where_sql";
1524 $result = $db->sql_query($sql);
1526 while ($row = $db->sql_fetchrow($result))
1528 if ($row['topic_moved_id'])
1530 $moved_topics[] = $row['topic_id'];
1531 continue;
1534 $topic_id = (int) $row['topic_id'];
1535 $topic_data[$topic_id] = $row;
1536 $topic_data[$topic_id]['replies_real'] = -1;
1537 $topic_data[$topic_id]['replies'] = 0;
1538 $topic_data[$topic_id]['first_post_id'] = 0;
1539 $topic_data[$topic_id]['last_post_id'] = 0;
1540 unset($topic_data[$topic_id]['topic_id']);
1542 // This array holds all topic_ids
1543 $delete_topics[$topic_id] = '';
1545 if ($sync_extra)
1547 $topic_data[$topic_id]['reported'] = 0;
1548 $topic_data[$topic_id]['attachment'] = 0;
1551 $db->sql_freeresult($result);
1553 // Use "t" as table alias because of the $where_sql clause
1554 // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown.
1555 $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
1556 FROM ' . POSTS_TABLE . " t
1557 $where_sql
1558 GROUP BY t.topic_id, t.post_approved";
1559 $result = $db->sql_query($sql);
1561 while ($row = $db->sql_fetchrow($result))
1563 $topic_id = (int) $row['topic_id'];
1565 $row['first_post_id'] = (int) $row['first_post_id'];
1566 $row['last_post_id'] = (int) $row['last_post_id'];
1568 if (!isset($topic_data[$topic_id]))
1570 // Hey, these posts come from a topic that does not exist
1571 $delete_posts[$topic_id] = '';
1573 else
1575 // Unset the corresponding entry in $delete_topics
1576 // When we'll be done, only topics with no posts will remain
1577 unset($delete_topics[$topic_id]);
1579 $topic_data[$topic_id]['replies_real'] += $row['total_posts'];
1580 $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']);
1582 if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id'])
1584 $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1;
1585 $topic_data[$topic_id]['last_post_id'] = $row['last_post_id'];
1589 $db->sql_freeresult($result);
1591 foreach ($topic_data as $topic_id => $row)
1593 $post_ids[] = $row['first_post_id'];
1594 if ($row['first_post_id'] != $row['last_post_id'])
1596 $post_ids[] = $row['last_post_id'];
1600 // Now we delete empty topics and orphan posts
1601 if (sizeof($delete_posts))
1603 delete_posts('topic_id', array_keys($delete_posts), false);
1604 unset($delete_posts);
1607 if (!sizeof($topic_data))
1609 // If we get there, topic ids were invalid or topics did not contain any posts
1610 delete_topics($where_type, $where_ids, true);
1611 return;
1614 if (sizeof($delete_topics))
1616 $delete_topic_ids = array();
1617 foreach ($delete_topics as $topic_id => $void)
1619 unset($topic_data[$topic_id]);
1620 $delete_topic_ids[] = $topic_id;
1623 delete_topics('topic_id', $delete_topic_ids, false);
1624 unset($delete_topics, $delete_topic_ids);
1627 // Make sure shadow topics do link to existing topics
1628 if (sizeof($moved_topics))
1630 $delete_topics = array();
1632 $sql = 'SELECT t1.topic_id, t1.topic_moved_id
1633 FROM ' . TOPICS_TABLE . ' t1
1634 LEFT JOIN ' . TOPICS_TABLE . ' t2 ON (t2.topic_id = t1.topic_moved_id)
1635 WHERE ' . $db->sql_in_set('t1.topic_id', $moved_topics) . '
1636 AND t2.topic_id IS NULL';
1637 $result = $db->sql_query($sql);
1639 while ($row = $db->sql_fetchrow($result))
1641 $delete_topics[] = $row['topic_id'];
1643 $db->sql_freeresult($result);
1645 if (sizeof($delete_topics))
1647 delete_topics('topic_id', $delete_topics, false);
1649 unset($delete_topics);
1652 $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
1653 FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
1654 WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
1655 AND u.user_id = p.poster_id';
1656 $result = $db->sql_query($sql);
1658 $post_ids = array();
1659 while ($row = $db->sql_fetchrow($result))
1661 $topic_id = intval($row['topic_id']);
1663 if ($row['post_id'] == $topic_data[$topic_id]['first_post_id'])
1665 if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved'])
1667 $approved_unapproved_ids[] = $topic_id;
1669 $topic_data[$topic_id]['time'] = $row['post_time'];
1670 $topic_data[$topic_id]['poster'] = $row['poster_id'];
1671 $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1672 $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour'];
1675 if ($row['post_id'] == $topic_data[$topic_id]['last_post_id'])
1677 $topic_data[$topic_id]['last_poster_id'] = $row['poster_id'];
1678 $topic_data[$topic_id]['last_post_subject'] = $row['post_subject'];
1679 $topic_data[$topic_id]['last_post_time'] = $row['post_time'];
1680 $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
1681 $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour'];
1684 $db->sql_freeresult($result);
1686 // approved becomes unapproved, and vice-versa
1687 if (sizeof($approved_unapproved_ids))
1689 $sql = 'UPDATE ' . TOPICS_TABLE . '
1690 SET topic_approved = 1 - topic_approved
1691 WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids);
1692 $db->sql_query($sql);
1694 unset($approved_unapproved_ids);
1696 // These are fields that will be synchronised
1697 $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');
1699 if ($sync_extra)
1701 // This routine assumes that post_reported values are correct
1702 // if they are not, use sync('post_reported') first
1703 $sql = 'SELECT t.topic_id, p.post_id
1704 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1705 $where_sql_and p.topic_id = t.topic_id
1706 AND p.post_reported = 1
1707 GROUP BY t.topic_id, p.post_id";
1708 $result = $db->sql_query($sql);
1710 $fieldnames[] = 'reported';
1711 while ($row = $db->sql_fetchrow($result))
1713 $topic_data[intval($row['topic_id'])]['reported'] = 1;
1715 $db->sql_freeresult($result);
1717 // This routine assumes that post_attachment values are correct
1718 // if they are not, use sync('post_attachment') first
1719 $sql = 'SELECT t.topic_id, p.post_id
1720 FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
1721 $where_sql_and p.topic_id = t.topic_id
1722 AND p.post_attachment = 1
1723 GROUP BY t.topic_id, p.post_id";
1724 $result = $db->sql_query($sql);
1726 $fieldnames[] = 'attachment';
1727 while ($row = $db->sql_fetchrow($result))
1729 $topic_data[intval($row['topic_id'])]['attachment'] = 1;
1731 $db->sql_freeresult($result);
1734 foreach ($topic_data as $topic_id => $row)
1736 $sql_ary = array();
1738 foreach ($fieldnames as $fieldname)
1740 if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname])
1742 $sql_ary['topic_' . $fieldname] = $row[$fieldname];
1746 if (sizeof($sql_ary))
1748 $sql = 'UPDATE ' . TOPICS_TABLE . '
1749 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
1750 WHERE topic_id = ' . $topic_id;
1751 $db->sql_query($sql);
1753 $resync_forums[$row['forum_id']] = $row['forum_id'];
1756 unset($topic_data);
1758 // if some topics have been resync'ed then resync parent forums
1759 // except when we're only syncing a range, we don't want to sync forums during
1760 // batch processing.
1761 if ($resync_parents && sizeof($resync_forums) && $where_type != 'range')
1763 sync('forum', 'forum_id', array_values($resync_forums), true);
1765 break;
1768 return;
1772 * Prune function
1774 function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true)
1776 global $db;
1778 if (!is_array($forum_id))
1780 $forum_id = array($forum_id);
1783 if (!sizeof($forum_id))
1785 return;
1788 $sql_and = '';
1790 if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE))
1792 $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE;
1795 if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY))
1797 $sql_and .= ' AND topic_type <> ' . POST_STICKY;
1800 if ($prune_mode == 'posted')
1802 $sql_and .= " AND topic_last_post_time < $prune_date";
1805 if ($prune_mode == 'viewed')
1807 $sql_and .= " AND topic_last_view_time < $prune_date";
1810 $sql = 'SELECT topic_id
1811 FROM ' . TOPICS_TABLE . '
1812 WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
1813 AND poll_start = 0
1814 $sql_and";
1815 $result = $db->sql_query($sql);
1817 $topic_list = array();
1818 while ($row = $db->sql_fetchrow($result))
1820 $topic_list[] = $row['topic_id'];
1822 $db->sql_freeresult($result);
1824 if ($prune_flags & FORUM_FLAG_PRUNE_POLL)
1826 $sql = 'SELECT topic_id
1827 FROM ' . TOPICS_TABLE . '
1828 WHERE ' . $db->sql_in_set('forum_id', $forum_id) . "
1829 AND poll_start > 0
1830 AND poll_last_vote < $prune_date
1831 $sql_and";
1832 $result = $db->sql_query($sql);
1834 while ($row = $db->sql_fetchrow($result))
1836 $topic_list[] = $row['topic_id'];
1838 $db->sql_freeresult($result);
1840 $topic_list = array_unique($topic_list);
1843 return delete_topics('topic_id', $topic_list, $auto_sync);
1847 * Function auto_prune(), this function now relies on passed vars
1849 function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq)
1851 global $db;
1853 $sql = 'SELECT forum_name
1854 FROM ' . FORUMS_TABLE . "
1855 WHERE forum_id = $forum_id";
1856 $result = $db->sql_query($sql, 3600);
1857 $row = $db->sql_fetchrow($result);
1858 $db->sql_freeresult($result);
1860 if ($row)
1862 $prune_date = time() - ($prune_days * 86400);
1863 $next_prune = time() + ($prune_freq * 86400);
1865 prune($forum_id, $prune_mode, $prune_date, $prune_flags, true);
1867 $sql = 'UPDATE ' . FORUMS_TABLE . "
1868 SET prune_next = $next_prune
1869 WHERE forum_id = $forum_id";
1870 $db->sql_query($sql);
1872 add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']);
1875 return;
1879 * remove_comments will strip the sql comment lines out of an uploaded sql file
1880 * specifically for mssql and postgres type files in the install....
1882 function remove_comments(&$output)
1884 $lines = explode("\n", $output);
1885 $output = '';
1887 // try to keep mem. use down
1888 $linecount = sizeof($lines);
1890 $in_comment = false;
1891 for ($i = 0; $i < $linecount; $i++)
1893 if (trim($lines[$i]) == '/*')
1895 $in_comment = true;
1898 if (!$in_comment)
1900 $output .= $lines[$i] . "\n";
1903 if (trim($lines[$i]) == '*/')
1905 $in_comment = false;
1909 unset($lines);
1910 return $output;
1914 * remove_remarks will strip the sql comment lines out of an uploaded sql file
1916 function remove_remarks(&$sql)
1918 $sql = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql));
1922 * split_sql_file will split an uploaded sql file into single sql statements.
1923 * Note: expects trim() to have already been run on $sql.
1925 function split_sql_file($sql, $delimiter)
1927 $sql = str_replace("\r" , '', $sql);
1928 $data = preg_split('/' . preg_quote($delimiter, '/') . '$/m', $sql);
1930 foreach ($data as $key => $value)
1932 $data[$key] = trim($value);
1935 // The empty case
1936 $end_data = end($data);
1938 if (empty($end_data))
1940 unset($data[key($data)]);
1943 return $data;
1947 * Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username
1948 * and group names must be carried through for the moderators table
1950 function cache_moderators()
1952 global $db, $cache, $auth, $phpbb_root_path, $phpEx;
1954 // Remove cached sql results
1955 $cache->destroy('sql', MODERATOR_CACHE_TABLE);
1957 // Clear table
1958 $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . MODERATOR_CACHE_TABLE);
1960 // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting
1961 $hold_ary = $ug_id_ary = $sql_ary = array();
1963 // Grab all users having moderative options...
1964 $hold_ary = $auth->acl_user_raw_data(false, 'm_%', false);
1966 // Add users?
1967 if (sizeof($hold_ary))
1969 // At least one moderative option warrants a display
1970 $ug_id_ary = array_keys($hold_ary);
1972 // Remove users who have group memberships with DENY moderator permissions
1973 $sql = $db->sql_build_query('SELECT', array(
1974 'SELECT' => 'a.forum_id, ug.user_id',
1976 'FROM' => array(
1977 ACL_OPTIONS_TABLE => 'o',
1978 USER_GROUP_TABLE => 'ug',
1979 ACL_GROUPS_TABLE => 'a'
1982 'LEFT_JOIN' => array(
1983 array(
1984 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'),
1985 'ON' => 'a.auth_role_id = r.role_id'
1989 'WHERE' => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id)
1990 AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL)
1991 OR r.auth_setting = ' . ACL_NEVER . ')
1992 AND a.group_id = ug.group_id
1993 AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . "
1994 AND ug.user_pending = 0
1995 AND o.auth_option LIKE 'm\_%'" .
1996 (($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : ''),
1998 $result = $db->sql_query($sql);
2000 while ($row = $db->sql_fetchrow($result))
2002 if (isset($hold_ary[$row['user_id']][$row['forum_id']]))
2004 unset($hold_ary[$row['user_id']][$row['forum_id']]);
2007 $db->sql_freeresult($result);
2009 if (sizeof($hold_ary))
2011 // Get usernames...
2012 $sql = 'SELECT user_id, username
2013 FROM ' . USERS_TABLE . '
2014 WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary));
2015 $result = $db->sql_query($sql);
2017 $usernames_ary = array();
2018 while ($row = $db->sql_fetchrow($result))
2020 $usernames_ary[$row['user_id']] = $row['username'];
2023 foreach ($hold_ary as $user_id => $forum_id_ary)
2025 // Do not continue if user does not exist
2026 if (!isset($usernames_ary[$user_id]))
2028 continue;
2031 foreach ($forum_id_ary as $forum_id => $auth_ary)
2033 $sql_ary[] = array(
2034 'forum_id' => $forum_id,
2035 'user_id' => $user_id,
2036 'username' => $usernames_ary[$user_id],
2037 'group_id' => 0,
2038 'group_name' => ''
2045 // Now to the groups...
2046 $hold_ary = $auth->acl_group_raw_data(false, 'm_%', false);
2048 if (sizeof($hold_ary))
2050 $ug_id_ary = array_keys($hold_ary);
2052 // Make sure not hidden or special groups are involved...
2053 $sql = 'SELECT group_name, group_id, group_type
2054 FROM ' . GROUPS_TABLE . '
2055 WHERE ' . $db->sql_in_set('group_id', $ug_id_ary);
2056 $result = $db->sql_query($sql);
2058 $groupnames_ary = array();
2059 while ($row = $db->sql_fetchrow($result))
2061 if ($row['group_type'] == GROUP_HIDDEN || $row['group_type'] == GROUP_SPECIAL)
2063 unset($hold_ary[$row['group_id']]);
2066 $groupnames_ary[$row['group_id']] = $row['group_name'];
2068 $db->sql_freeresult($result);
2070 foreach ($hold_ary as $group_id => $forum_id_ary)
2072 // If there is no group, we do not assign it...
2073 if (!isset($groupnames_ary[$group_id]))
2075 continue;
2078 foreach ($forum_id_ary as $forum_id => $auth_ary)
2080 $flag = false;
2081 foreach ($auth_ary as $auth_option => $setting)
2083 // Make sure at least one ACL_YES option is set...
2084 if ($setting == ACL_YES)
2086 $flag = true;
2087 break;
2091 if (!$flag)
2093 continue;
2096 $sql_ary[] = array(
2097 'forum_id' => $forum_id,
2098 'user_id' => 0,
2099 'username' => '',
2100 'group_id' => $group_id,
2101 'group_name' => $groupnames_ary[$group_id]
2107 $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary);
2111 * View log
2113 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')
2115 global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
2117 $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
2119 $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile');
2121 switch ($mode)
2123 case 'admin':
2124 $log_type = LOG_ADMIN;
2125 $sql_forum = '';
2126 break;
2128 case 'mod':
2129 $log_type = LOG_MOD;
2131 if ($topic_id)
2133 $sql_forum = 'AND l.topic_id = ' . intval($topic_id);
2135 else if (is_array($forum_id))
2137 $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
2139 else
2141 $sql_forum = ($forum_id) ? 'AND l.forum_id = ' . intval($forum_id) : '';
2143 break;
2145 case 'user':
2146 $log_type = LOG_USERS;
2147 $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
2148 break;
2150 case 'users':
2151 $log_type = LOG_USERS;
2152 $sql_forum = '';
2153 break;
2155 case 'critical':
2156 $log_type = LOG_CRITICAL;
2157 $sql_forum = '';
2158 break;
2160 default:
2161 return;
2164 $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
2165 FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
2166 WHERE l.log_type = $log_type
2167 AND u.user_id = l.user_id
2168 " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
2169 $sql_forum
2170 ORDER BY $sort_by";
2171 $result = $db->sql_query_limit($sql, $limit, $offset);
2173 $i = 0;
2174 $log = array();
2175 while ($row = $db->sql_fetchrow($result))
2177 if ($row['topic_id'])
2179 $topic_id_list[] = $row['topic_id'];
2182 if ($row['reportee_id'])
2184 $reportee_id_list[] = $row['reportee_id'];
2187 $log[$i] = array(
2188 'id' => $row['log_id'],
2190 'reportee_id' => $row['reportee_id'],
2191 'reportee_username' => '',
2192 'reportee_username_full'=> '',
2194 'user_id' => $row['user_id'],
2195 'username' => $row['username'],
2196 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
2198 'ip' => $row['log_ip'],
2199 'time' => $row['log_time'],
2200 'forum_id' => $row['forum_id'],
2201 'topic_id' => $row['topic_id'],
2203 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
2204 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
2207 if (!empty($row['log_data']))
2209 $log_data_ary = unserialize($row['log_data']);
2211 if (isset($user->lang[$row['log_operation']]))
2213 $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
2214 $log[$i]['action'] = str_replace("\n", '<br />', censor_text($log[$i]['action']));
2216 else
2218 $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
2222 $i++;
2224 $db->sql_freeresult($result);
2226 if (sizeof($topic_id_list))
2228 $topic_id_list = array_unique($topic_id_list);
2230 // This query is not really needed if move_topics() updates the forum_id field,
2231 // although it's also used to determine if the topic still exists in the database
2232 $sql = 'SELECT topic_id, forum_id
2233 FROM ' . TOPICS_TABLE . '
2234 WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
2235 $result = $db->sql_query($sql);
2237 $default_forum_id = 0;
2239 while ($row = $db->sql_fetchrow($result))
2241 if (!$row['forum_id'])
2243 if ($auth->acl_getf_global('f_read'))
2245 if (!$default_forum_id)
2247 $sql = 'SELECT forum_id
2248 FROM ' . FORUMS_TABLE . '
2249 WHERE forum_type = ' . FORUM_POST;
2250 $f_result = $db->sql_query_limit($sql, 1);
2251 $default_forum_id = (int) $db->sql_fetchfield('forum_id', false, $f_result);
2252 $db->sql_freeresult($f_result);
2255 $is_auth[$row['topic_id']] = $default_forum_id;
2258 else
2260 if ($auth->acl_get('f_read', $row['forum_id']))
2262 $is_auth[$row['topic_id']] = $row['forum_id'];
2266 if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
2268 $is_mod[$row['topic_id']] = $row['forum_id'];
2271 $db->sql_freeresult($result);
2273 foreach ($log as $key => $row)
2275 $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
2276 $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $user->session_id) : false;
2280 if (sizeof($reportee_id_list))
2282 $reportee_id_list = array_unique($reportee_id_list);
2283 $reportee_names_list = array();
2285 $sql = 'SELECT user_id, username, user_colour
2286 FROM ' . USERS_TABLE . '
2287 WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
2288 $result = $db->sql_query($sql);
2290 while ($row = $db->sql_fetchrow($result))
2292 $reportee_names_list[$row['user_id']] = $row;
2294 $db->sql_freeresult($result);
2296 foreach ($log as $key => $row)
2298 if (!isset($reportee_names_list[$row['reportee_id']]))
2300 continue;
2303 $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
2304 $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);
2308 $sql = 'SELECT COUNT(l.log_id) AS total_entries
2309 FROM ' . LOG_TABLE . " l
2310 WHERE l.log_type = $log_type
2311 AND l.log_time >= $limit_days
2312 $sql_forum";
2313 $result = $db->sql_query($sql);
2314 $log_count = (int) $db->sql_fetchfield('total_entries');
2315 $db->sql_freeresult($result);
2317 return;
2321 * Update foes - remove moderators and administrators from foe lists...
2323 function update_foes()
2325 global $db, $auth;
2327 $perms = array();
2328 foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary)
2330 foreach ($forum_ary as $auth_option => $user_ary)
2332 $perms = array_merge($perms, $user_ary);
2336 if (sizeof($perms))
2338 $sql = 'DELETE FROM ' . ZEBRA_TABLE . '
2339 WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . '
2340 AND foe = 1';
2341 $db->sql_query($sql);
2343 unset($perms);
2347 * Lists inactive users
2349 function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC')
2351 global $db, $user;
2353 $sql = 'SELECT user_id, username, user_regdate, user_lastvisit, user_inactive_time, user_inactive_reason
2354 FROM ' . USERS_TABLE . '
2355 WHERE user_type = ' . USER_INACTIVE .
2356 (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . "
2357 ORDER BY $sort_by";
2358 $result = $db->sql_query_limit($sql, $limit, $offset);
2360 while ($row = $db->sql_fetchrow($result))
2362 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN'];
2363 switch ($row['user_inactive_reason'])
2365 case INACTIVE_REGISTER:
2366 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER'];
2367 break;
2369 case INACTIVE_PROFILE:
2370 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE'];
2371 break;
2373 case INACTIVE_MANUAL:
2374 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL'];
2375 break;
2377 case INACTIVE_REMIND:
2378 $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND'];
2379 break;
2382 $users[] = $row;
2385 $sql = 'SELECT COUNT(user_id) AS user_count
2386 FROM ' . USERS_TABLE . '
2387 WHERE user_type = ' . USER_INACTIVE .
2388 (($limit_days) ? " AND user_inactive_time >= $limit_days" : '');
2389 $result = $db->sql_query($sql);
2390 $user_count = (int) $db->sql_fetchfield('user_count');
2391 $db->sql_freeresult($result);
2393 return;
2397 * Lists warned users
2399 function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC')
2401 global $db;
2403 $sql = 'SELECT user_id, username, user_colour, user_warnings, user_last_warning
2404 FROM ' . USERS_TABLE . '
2405 WHERE user_warnings > 0
2406 ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '') . "
2407 ORDER BY $sort_by";
2408 $result = $db->sql_query_limit($sql, $limit, $offset);
2409 $users = $db->sql_fetchrowset($result);
2410 $db->sql_freeresult($result);
2412 $sql = 'SELECT count(user_id) AS user_count
2413 FROM ' . USERS_TABLE . '
2414 WHERE user_warnings > 0
2415 ' . (($limit_days) ? "AND user_last_warning >= $limit_days" : '');
2416 $result = $db->sql_query($sql);
2417 $user_count = (int) $db->sql_fetchfield('user_count');
2418 $db->sql_freeresult($result);
2420 return;
2424 * Get database size
2425 * Currently only mysql and mssql are supported
2427 function get_database_size()
2429 global $db, $user, $table_prefix;
2431 $database_size = false;
2433 // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0
2434 switch ($db->sql_layer)
2436 case 'mysql':
2437 case 'mysql4':
2438 case 'mysqli':
2440 $sql = 'SELECT VERSION() AS mysql_version';
2441 $result = $db->sql_query($sql);
2442 $row = $db->sql_fetchrow($result);
2443 $db->sql_freeresult($result);
2445 if ($row)
2447 $version = $row['mysql_version'];
2449 if (preg_match('#(3\.23|[45]\.)#', $version))
2451 $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->dbname}`" : $db->dbname;
2453 $sql = 'SHOW TABLE STATUS
2454 FROM ' . $db_name;
2455 $result = $db->sql_query($sql);
2457 $database_size = 0;
2458 while ($row = $db->sql_fetchrow($result))
2460 if ((isset($row['Type']) && $row['Type'] != 'MRG_MyISAM') || (isset($row['Engine']) && ($row['Engine'] == 'MyISAM' || $row['Engine'] == 'InnoDB')))
2462 if ($table_prefix != '')
2464 if (strpos($row['Name'], $table_prefix) !== false)
2466 $database_size += $row['Data_length'] + $row['Index_length'];
2469 else
2471 $database_size += $row['Data_length'] + $row['Index_length'];
2475 $db->sql_freeresult($result);
2479 break;
2481 case 'mssql':
2482 case 'mssql_odbc':
2484 $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize
2485 FROM sysfiles';
2486 $result = $db->sql_query($sql);
2487 $database_size = ($row = $db->sql_fetchrow($result)) ? $row['dbsize'] : false;
2488 $db->sql_freeresult($result);
2490 break;
2492 case 'postgres':
2494 $sql = "SELECT proname
2495 FROM pg_proc
2496 WHERE proname = 'pg_database_size'";
2497 $result = $db->sql_query($sql);
2498 $row = $db->sql_fetchrow($result);
2499 $db->sql_freeresult($result);
2501 if ($row['proname'] == 'pg_database_size')
2503 $sql = "SELECT oid
2504 FROM pg_database
2505 WHERE datname = '" . $db->dbname . "'";
2506 $result = $db->sql_query($sql);
2507 $row = $db->sql_fetchrow($result);
2508 $db->sql_freeresult($result);
2510 $oid = $row['oid'];
2512 $sql = 'SELECT pg_database_size(' . $oid . ') as size';
2513 $result = $db->sql_query($sql);
2514 $row = $db->sql_fetchrow($result);
2515 $db->sql_freeresult($result);
2517 $database_size = $row['size'];
2520 break;
2523 if ($database_size !== false)
2525 $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));
2527 else
2529 $database_size = $user->lang['NOT_AVAILABLE'];
2532 return $database_size;
2536 * Retrieve contents from remotely stored file
2538 function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 10)
2540 global $user;
2542 if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout))
2544 @fputs($fsock, "GET $directory/$filename HTTP/1.1\r\n");
2545 @fputs($fsock, "HOST: $host\r\n");
2546 @fputs($fsock, "Connection: close\r\n\r\n");
2548 $file_info = '';
2549 $get_info = false;
2551 while (!@feof($fsock))
2553 if ($get_info)
2555 $file_info .= @fread($fsock, 1024);
2557 else
2559 $line = @fgets($fsock, 1024);
2560 if ($line == "\r\n")
2562 $get_info = true;
2564 else if (strpos($line, '404 Not Found') !== false)
2566 $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename;
2567 return false;
2571 @fclose($fsock);
2573 else
2575 if ($errstr)
2577 return false;
2579 else
2581 $errstr = 'fsock disabled';
2582 return false;
2586 return $file_info;
2590 * Tidy Warnings
2591 * Remove all warnings which have now expired from the database
2592 * The duration of a warning can be defined by the administrator
2593 * This only removes the warning and reduces the assosciated count,
2594 * it does not remove the user note recording the contents of the warning
2596 function tidy_warnings()
2598 global $db, $config;
2600 $expire_date = time() - ($config['warnings_expire_days'] * 86400);
2601 $warning_list = $user_list = array();
2603 $sql = 'SELECT * FROM ' . WARNINGS_TABLE . "
2604 WHERE warning_time < $expire_date";
2605 $result = $db->sql_query($sql);
2607 while ($row = $db->sql_fetchrow($result))
2609 $warning_list[] = $row['warning_id'];
2610 $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? $user_list[$row['user_id']]++ : 1;
2612 $db->sql_freeresult($result);
2614 if (sizeof($warning_list))
2616 $db->sql_transaction('begin');
2618 $sql = 'DELETE FROM ' . WARNINGS_TABLE . '
2619 WHERE ' . $db->sql_in_set('warning_id', $warning_list);
2620 $db->sql_query($sql);
2622 foreach ($user_list as $user_id => $value)
2624 $sql = 'UPDATE ' . USERS_TABLE . " SET user_warnings = user_warnings - $value
2625 WHERE user_id = $user_id";
2626 $db->sql_query($sql);
2629 $db->sql_transaction('commit');
2632 set_config('warnings_last_gc', time(), true);
2636 * Tidy database, doing some maintanance tasks
2638 function tidy_database()
2640 global $db;
2642 set_config('database_last_gc', time(), true);
2646 * Add permission language - this will make sure custom files will be included
2648 function add_permission_language()
2650 global $user, $phpEx;
2652 // First of all, our own file.
2653 $user->add_lang('acp/permissions_phpbb');
2655 $files_to_add = array();
2657 // Now search in acp and mods folder for permissions_ files.
2658 foreach (array('acp/', 'mods/') as $path)
2660 $dh = opendir($user->lang_path . $path);
2662 if ($dh !== false)
2664 while (($file = readdir($dh)) !== false)
2666 if (strpos($file, 'permissions_') === 0 && strpos($file, 'permissions_phpbb') === false && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
2668 $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1));
2671 closedir($dh);
2675 if (!sizeof($files_to_add))
2677 return false;
2680 $user->add_lang($files_to_add);
2681 return true;