<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* Recalculate Nested Sets
*
* @param int $new_id first left_id (should start with 1)
* @param string $pkey primary key-column (containing the id for the parent_id of the children)
* @param string $table constant or fullname of the table
* @param int $parent_id parent_id of the current set (default = 0)
* @param array $where contains strings to compare closer on the where statement (additional)
*/
function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array())
{
global $db;
$sql = 'SELECT *
FROM ' . $table . '
WHERE parent_id = ' . (int) $parent_id .
((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . '
ORDER BY left_id ASC';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
// First we update the left_id for this module
if ($row['left_id'] != $new_id)
{
$db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('left_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}");
}
$new_id++;
// Then we go through any children and update their left/right id's
recalc_nested_sets($new_id, $pkey, $table, $row[$pkey], $where);
// Then we come back and update the right_id for this module
if ($row['right_id'] != $new_id)
{
$db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('right_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}");
}
$new_id++;
}
$db->sql_freeresult($result);
}
/**
* Simple version of jumpbox, just lists authed forums
*/
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)
{
global $db, $user, $auth;
// This query is identical to the jumpbox one
$sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id
FROM ' . FORUMS_TABLE . '
ORDER BY left_id ASC';
$result = $db->sql_query($sql, 600);
$right = 0;
$padding_store = array('0' => '');
$padding = '';
$forum_list = ($return_array) ? array() : '';
// Sometimes it could happen that forums will be displayed here not be displayed within the index page
// This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
// If this happens, the padding could be "broken"
while ($row = $db->sql_fetchrow($result))
{
if ($row['left_id'] < $right)
{
$padding .= ' ';
$padding_store[$row['parent_id']] = $padding;
}
else if ($row['left_id'] > $right + 1)
{
$padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : '';
}
$right = $row['right_id'];
$disabled = false;
if (!$ignore_acl && $auth->acl_gets(array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'), $row['forum_id']))
{
if ($only_acl_post && !$auth->acl_get('f_post', $row['forum_id']) || (!$auth->acl_get('m_approve', $row['forum_id']) && !$auth->acl_get('f_noapprove', $row['forum_id'])))
{
$disabled = true;
}
}
else if (!$ignore_acl)
{
continue;
}
if (
((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id)
||
// Non-postable forum with no subforums, don't display
($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat)
||
($row['forum_type'] != FORUM_POST && $ignore_nonpost)
)
{
$disabled = true;
}
if ($return_array)
{
// Include some more information...
$selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? true : false) : (($row['forum_id'] == $select_id) ? true : false);
$forum_list[$row['forum_id']] = array_merge(array('padding' => $padding, 'selected' => ($selected && !$disabled), 'disabled' => $disabled), $row);
}
else
{
$selected = (is_array($select_id)) ? ((in_array($row['forum_id'], $select_id)) ? ' selected="selected"' : '') : (($row['forum_id'] == $select_id) ? ' selected="selected"' : '');
$forum_list .= '<option value="' . $row['forum_id'] . '"' . (($disabled) ? ' disabled="disabled" class="disabled-option"' : $selected) . '>' . $padding . $row['forum_name'] . '</option>';
}
}
$db->sql_freeresult($result);
unset($padding_store);
return $forum_list;
}
/**
* Generate size select options
*/
function size_select_options($size_compare)
{
global $user;
$size_types_text = array($user->lang['BYTES'], $user->lang['KIB'], $user->lang['MIB']);
$size_types = array('b', 'kb', 'mb');
$s_size_options = '';
for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++)
{
$selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : '';
$s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>';
}
return $s_size_options;
}
/**
* Generate list of groups (option fields without select)
*
* @param int $group_id The default group id to mark as selected
* @param array $exclude_ids The group ids to exclude from the list, false (default) if you whish to exclude no id
* @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.
*
* @return string The list of options.
*/
function group_select_options($group_id, $exclude_ids = false, $manage_founder = false)
{
global $db, $user, $config;
$exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
$sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : '';
$sql_founder = ($manage_founder !== false) ? (($exclude_sql || $sql_and) ? ' AND ' : ' WHERE ') . 'group_founder_manage = ' . (int) $manage_founder : '';
$sql = 'SELECT group_id, group_name, group_type
FROM ' . GROUPS_TABLE . "
$exclude_sql
$sql_and
$sql_founder
ORDER BY group_type DESC, group_name ASC";
$result = $db->sql_query($sql);
$s_group_options = '';
while ($row = $db->sql_fetchrow($result))
{
$selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : '';
$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>';
}
$db->sql_freeresult($result);
return $s_group_options;
}
/**
* Obtain authed forums list
*/
function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = false, $no_cache = false)
{
global $db, $auth;
static $forum_rows;
if (!isset($forum_rows))
{
// This query is identical to the jumpbox one
$expire_time = ($no_cache) ? 0 : 600;
$sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
FROM ' . FORUMS_TABLE . '
ORDER BY left_id ASC';
$result = $db->sql_query($sql, $expire_time);
$forum_rows = array();
$right = $padding = 0;
$padding_store = array('0' => 0);
while ($row = $db->sql_fetchrow($result))
{
if ($row['left_id'] < $right)
{
$padding++;
$padding_store[$row['parent_id']] = $padding;
}
else if ($row['left_id'] > $right + 1)
{
// Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it.
// @todo digging deep to find out "how" this can happen.
$padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding;
}
$right = $row['right_id'];
$row['padding'] = $padding;
$forum_rows[] = $row;
}
$db->sql_freeresult($result);
unset($padding_store);
}
$rowset = array();
foreach ($forum_rows as $row)
{
if ($postable_only && $row['forum_type'] != FORUM_POST)
{
continue;
}
if ($acl_list == '' || ($acl_list != '' && $auth->acl_gets($acl_list, $row['forum_id'])))
{
$rowset[] = ($id_only) ? (int) $row['forum_id'] : $row;
}
}
return $rowset;
}
/**
* Get forum branch
*/
function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $include_forum = true)
{
global $db;
switch ($type)
{
case 'parents':
$condition = 'f1.left_id BETWEEN f2.left_id AND f2.right_id';
break;
case 'children':
$condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id';
break;
default:
$condition = 'f2.left_id BETWEEN f1.left_id AND f1.right_id OR f1.left_id BETWEEN f2.left_id AND f2.right_id';
break;
}
$rows = array();
$sql = 'SELECT f2.*
FROM ' . FORUMS_TABLE . ' f1
LEFT JOIN ' . FORUMS_TABLE . " f2 ON ($condition)
WHERE f1.forum_id = $forum_id
ORDER BY f2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC');
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
if (!$include_forum && $row['forum_id'] == $forum_id)
{
continue;
}
$rows[] = $row;
}
$db->sql_freeresult($result);
return $rows;
}
/**
* Copies permissions from one forum to others
*
* @param int $src_forum_id The source forum we want to copy permissions from
* @param array $dest_forum_ids The destination forum(s) we want to copy to
* @param bool $clear_dest_perms True if destination permissions should be deleted
* @param bool $add_log True if log entry should be added
*
* @return bool False on error
*/
function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true)
{
global $db;
// Only one forum id specified
if (!is_array($dest_forum_ids))
{
$dest_forum_ids = array($dest_forum_ids);
}
// Make sure forum ids are integers
$src_forum_id = (int) $src_forum_id;
$dest_forum_ids = array_map('intval', $dest_forum_ids);
// No source forum or no destination forums specified
if (empty($src_forum_id) || empty($dest_forum_ids))
{
return false;
}
// Check if source forum exists
$sql = 'SELECT forum_name
FROM ' . FORUMS_TABLE . '
WHERE forum_id = ' . $src_forum_id;
$result = $db->sql_query($sql);
$src_forum_name = $db->sql_fetchfield('forum_name');
$db->sql_freeresult($result);
// Source forum doesn't exist
if (empty($src_forum_name))
{
return false;
}
// Check if destination forums exists
$sql = 'SELECT forum_id, forum_name
FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids);
$result = $db->sql_query($sql);
$dest_forum_ids = $dest_forum_names = array();
while ($row = $db->sql_fetchrow($result))
{
$dest_forum_ids[] = (int) $row['forum_id'];
$dest_forum_names[] = $row['forum_name'];
}
$db->sql_freeresult($result);
// No destination forum exists
if (empty($dest_forum_ids))
{
return false;
}
// From the mysql documentation:
// Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear
// in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14.
// Due to this we stay on the safe side if we do the insertion "the manual way"
// Rowsets we're going to insert
$users_sql_ary = $groups_sql_ary = array();
// Query acl users table for source forum data
$sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting
FROM ' . ACL_USERS_TABLE . '
WHERE forum_id = ' . $src_forum_id;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$row = array(
'user_id' => (int) $row['user_id'],
'auth_option_id' => (int) $row['auth_option_id'],
'auth_role_id' => (int) $row['auth_role_id'],
'auth_setting' => (int) $row['auth_setting'],
);
foreach ($dest_forum_ids as $dest_forum_id)
{
$users_sql_ary[] = $row + array('forum_id' => $dest_forum_id);
}
}
$db->sql_freeresult($result);
// Query acl groups table for source forum data
$sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting
FROM ' . ACL_GROUPS_TABLE . '
WHERE forum_id = ' . $src_forum_id;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$row = array(
'group_id' => (int) $row['group_id'],
'auth_option_id' => (int) $row['auth_option_id'],
'auth_role_id' => (int) $row['auth_role_id'],
'auth_setting' => (int) $row['auth_setting'],
);
foreach ($dest_forum_ids as $dest_forum_id)
{
$groups_sql_ary[] = $row + array('forum_id' => $dest_forum_id);
}
}
$db->sql_freeresult($result);
$db->sql_transaction('begin');
// Clear current permissions of destination forums
if ($clear_dest_perms)
{
$sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids);
$db->sql_query($sql);
$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids);
$db->sql_query($sql);
}
$db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary);
$db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary);
if ($add_log)
{
add_log('admin', 'LOG_FORUM_COPIED_PERMISSIONS', $src_forum_name, implode(', ', $dest_forum_names));
}
$db->sql_transaction('commit');
return true;
}
/**
* Get physical file listing
*/
function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png')
{
$matches = array($dir => array());
// Remove initial / if present
$rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir;
// Add closing / if not present
$rootdir = ($rootdir && substr($rootdir, -1) != '/') ? $rootdir . '/' : $rootdir;
// Remove initial / if present
$dir = (substr($dir, 0, 1) == '/') ? substr($dir, 1) : $dir;
// Add closing / if not present
$dir = ($dir && substr($dir, -1) != '/') ? $dir . '/' : $dir;
if (!is_dir($rootdir . $dir))
{
return $matches;
}
$dh = @opendir($rootdir . $dir);
if (!$dh)
{
return $matches;
}
while (($fname = readdir($dh)) !== false)
{
if (is_file("$rootdir$dir$fname"))
{
if (filesize("$rootdir$dir$fname") && preg_match('#\.' . $type . '$#i', $fname))
{
$matches[$dir][] = $fname;
}
}
else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname"))
{
$matches += filelist($rootdir, "$dir$fname", $type);
}
}
closedir($dh);
return $matches;
}
/**
* Move topic(s)
*/
function move_topics($topic_ids, $forum_id, $auto_sync = true)
{
global $db, $phpbb_dispatcher;
if (empty($topic_ids))
{
return;
}
$forum_ids = array($forum_id);
if (!is_array($topic_ids))
{
$topic_ids = array($topic_ids);
}
$sql = 'DELETE FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . '
AND forum_id = ' . $forum_id;
$db->sql_query($sql);
if ($auto_sync)
{
$sql = 'SELECT DISTINCT forum_id
FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$forum_ids[] = $row['forum_id'];
}
$db->sql_freeresult($result);
}
$table_ary = array(TOPICS_TABLE, POSTS_TABLE, LOG_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
/**
* Perform additional actions before topics move
*
* @event core.move_topics_before_query
* @var array table_ary Array of tables from which forum_id will be updated for all rows that hold the moved topics
|