first commit

This commit is contained in:
gauvainboiche
2020-03-03 22:45:25 +01:00
commit 058c2110e9
4420 changed files with 598645 additions and 0 deletions

File diff suppressed because it is too large Load Diff

298
includes/acp/acp_ban.php Normal file
View File

@@ -0,0 +1,298 @@
<?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;
}
class acp_ban
{
var $u_action;
function main($id, $mode)
{
global $user, $template, $request, $phpbb_dispatcher;
global $phpbb_root_path, $phpEx;
if (!function_exists('user_ban'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
$bansubmit = $request->is_set_post('bansubmit');
$unbansubmit = $request->is_set_post('unbansubmit');
$user->add_lang(array('acp/ban', 'acp/users'));
$this->tpl_name = 'acp_ban';
$form_key = 'acp_ban';
add_form_key($form_key);
if (($bansubmit || $unbansubmit) && !check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Ban submitted?
if ($bansubmit)
{
// Grab the list of entries
$ban = $request->variable('ban', '', true);
$ban_length = $request->variable('banlength', 0);
$ban_length_other = $request->variable('banlengthother', '');
$ban_exclude = $request->variable('banexclude', 0);
$ban_reason = $request->variable('banreason', '', true);
$ban_give_reason = $request->variable('bangivereason', '', true);
if ($ban)
{
$abort_ban = false;
/**
* Use this event to modify the ban details before the ban is performed
*
* @event core.acp_ban_before
* @var string mode One of the following: user, ip, email
* @var string ban Either string or array with usernames, ips or email addresses
* @var int ban_length Ban length in minutes
* @var string ban_length_other Ban length as a date (YYYY-MM-DD)
* @var bool ban_exclude Are we banning or excluding from another ban
* @var string ban_reason Ban reason displayed to moderators
* @var string ban_give_reason Ban reason displayed to the banned user
* @var mixed abort_ban Either false, or an error message that is displayed to the user.
* If a string is given the bans are not issued.
* @since 3.1.0-RC5
*/
$vars = array(
'mode',
'ban',
'ban_length',
'ban_length_other',
'ban_exclude',
'ban_reason',
'ban_give_reason',
'abort_ban',
);
extract($phpbb_dispatcher->trigger_event('core.acp_ban_before', compact($vars)));
if ($abort_ban)
{
trigger_error($abort_ban . adm_back_link($this->u_action));
}
user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason);
/**
* Use this event to perform actions after the ban has been performed
*
* @event core.acp_ban_after
* @var string mode One of the following: user, ip, email
* @var string ban Either string or array with usernames, ips or email addresses
* @var int ban_length Ban length in minutes
* @var string ban_length_other Ban length as a date (YYYY-MM-DD)
* @var bool ban_exclude Are we banning or excluding from another ban
* @var string ban_reason Ban reason displayed to moderators
* @var string ban_give_reason Ban reason displayed to the banned user
* @since 3.1.0-RC5
*/
$vars = array(
'mode',
'ban',
'ban_length',
'ban_length_other',
'ban_exclude',
'ban_reason',
'ban_give_reason',
);
extract($phpbb_dispatcher->trigger_event('core.acp_ban_after', compact($vars)));
trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . adm_back_link($this->u_action));
}
}
else if ($unbansubmit)
{
$ban = $request->variable('unban', array(''));
if ($ban)
{
user_unban($mode, $ban);
trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . adm_back_link($this->u_action));
}
}
// Define language vars
$this->page_title = $user->lang[strtoupper($mode) . '_BAN'];
$l_ban_explain = $user->lang[strtoupper($mode) . '_BAN_EXPLAIN'];
$l_ban_exclude_explain = $user->lang[strtoupper($mode) . '_BAN_EXCLUDE_EXPLAIN'];
$l_unban_title = $user->lang[strtoupper($mode) . '_UNBAN'];
$l_unban_explain = $user->lang[strtoupper($mode) . '_UNBAN_EXPLAIN'];
$l_no_ban_cell = $user->lang[strtoupper($mode) . '_NO_BANNED'];
switch ($mode)
{
case 'user':
$l_ban_cell = $user->lang['USERNAME'];
break;
case 'ip':
$l_ban_cell = $user->lang['IP_HOSTNAME'];
break;
case 'email':
$l_ban_cell = $user->lang['EMAIL_ADDRESS'];
break;
}
self::display_ban_options($mode);
$template->assign_vars(array(
'L_TITLE' => $this->page_title,
'L_EXPLAIN' => $l_ban_explain,
'L_UNBAN_TITLE' => $l_unban_title,
'L_UNBAN_EXPLAIN' => $l_unban_explain,
'L_BAN_CELL' => $l_ban_cell,
'L_BAN_EXCLUDE_EXPLAIN' => $l_ban_exclude_explain,
'L_NO_BAN_CELL' => $l_no_ban_cell,
'S_USERNAME_BAN' => ($mode == 'user') ? true : false,
'U_ACTION' => $this->u_action,
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=acp_ban&amp;field=ban'),
));
}
/**
* Display ban options
*/
static public function display_ban_options($mode)
{
global $user, $db, $template;
// Ban length options
$ban_end_text = array(0 => $user->lang['PERMANENT'], 30 => $user->lang['30_MINS'], 60 => $user->lang['1_HOUR'], 360 => $user->lang['6_HOURS'], 1440 => $user->lang['1_DAY'], 10080 => $user->lang['7_DAYS'], 20160 => $user->lang['2_WEEKS'], 40320 => $user->lang['1_MONTH'], -1 => $user->lang['UNTIL'] . ' -&gt; ');
$ban_end_options = '';
foreach ($ban_end_text as $length => $text)
{
$ban_end_options .= '<option value="' . $length . '">' . $text . '</option>';
}
switch ($mode)
{
case 'user':
$field = 'username';
$sql = 'SELECT b.*, u.user_id, u.username, u.username_clean
FROM ' . BANLIST_TABLE . ' b, ' . USERS_TABLE . ' u
WHERE (b.ban_end >= ' . time() . '
OR b.ban_end = 0)
AND u.user_id = b.ban_userid
ORDER BY u.username_clean ASC';
break;
case 'ip':
$field = 'ban_ip';
$sql = 'SELECT *
FROM ' . BANLIST_TABLE . '
WHERE (ban_end >= ' . time() . "
OR ban_end = 0)
AND ban_ip <> ''
ORDER BY ban_ip";
break;
case 'email':
$field = 'ban_email';
$sql = 'SELECT *
FROM ' . BANLIST_TABLE . '
WHERE (ban_end >= ' . time() . "
OR ban_end = 0)
AND ban_email <> ''
ORDER BY ban_email";
break;
}
$result = $db->sql_query($sql);
$banned_options = $excluded_options = array();
while ($row = $db->sql_fetchrow($result))
{
$option = '<option value="' . $row['ban_id'] . '">' . $row[$field] . '</option>';
if ($row['ban_exclude'])
{
$excluded_options[] = $option;
}
else
{
$banned_options[] = $option;
}
$time_length = ($row['ban_end']) ? ($row['ban_end'] - $row['ban_start']) / 60 : 0;
if ($time_length == 0)
{
// Banned permanently
$ban_length = $user->lang['PERMANENT'];
}
else if (isset($ban_end_text[$time_length]))
{
// Banned for a given duration
$ban_length = $user->lang('BANNED_UNTIL_DURATION', $ban_end_text[$time_length], $user->format_date($row['ban_end'], false, true));
}
else
{
// Banned until given date
$ban_length = $user->lang('BANNED_UNTIL_DATE', $user->format_date($row['ban_end'], false, true));
}
$template->assign_block_vars('bans', array(
'BAN_ID' => (int) $row['ban_id'],
'LENGTH' => $ban_length,
'A_LENGTH' => addslashes($ban_length),
'REASON' => $row['ban_reason'],
'A_REASON' => addslashes($row['ban_reason']),
'GIVE_REASON' => $row['ban_give_reason'],
'A_GIVE_REASON' => addslashes($row['ban_give_reason']),
));
}
$db->sql_freeresult($result);
$options = '';
if ($excluded_options)
{
$options .= '<optgroup label="' . $user->lang['OPTIONS_EXCLUDED'] . '">';
$options .= implode('', $excluded_options);
$options .= '</optgroup>';
}
if ($banned_options)
{
$options .= '<optgroup label="' . $user->lang['OPTIONS_BANNED'] . '">';
$options .= implode('', $banned_options);
$options .= '</optgroup>';
}
$template->assign_vars(array(
'S_BAN_END_OPTIONS' => $ban_end_options,
'S_BANNED_OPTIONS' => ($banned_options || $excluded_options) ? true : false,
'BANNED_OPTIONS' => $options,
));
}
}

View File

@@ -0,0 +1,620 @@
<?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;
}
class acp_bbcodes
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $cache, $request, $phpbb_dispatcher, $phpbb_container;
global $phpbb_log;
$user->add_lang('acp/posting');
// Set up general vars
$action = $request->variable('action', '');
$bbcode_id = $request->variable('bbcode', 0);
$submit = $request->is_set_post('submit');
$this->tpl_name = 'acp_bbcodes';
$this->page_title = 'ACP_BBCODES';
$form_key = 'acp_bbcodes';
add_form_key($form_key);
if ($submit && !check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Set up mode-specific vars
switch ($action)
{
case 'add':
$bbcode_match = $bbcode_tpl = $bbcode_helpline = '';
$display_on_posting = 0;
break;
case 'edit':
$sql = 'SELECT bbcode_match, bbcode_tpl, display_on_posting, bbcode_helpline
FROM ' . BBCODES_TABLE . '
WHERE bbcode_id = ' . $bbcode_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$row)
{
trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$bbcode_match = $row['bbcode_match'];
$bbcode_tpl = htmlspecialchars($row['bbcode_tpl']);
$display_on_posting = $row['display_on_posting'];
$bbcode_helpline = $row['bbcode_helpline'];
break;
case 'modify':
$sql = 'SELECT bbcode_id, bbcode_tag
FROM ' . BBCODES_TABLE . '
WHERE bbcode_id = ' . $bbcode_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$row)
{
trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// No break here
case 'create':
$display_on_posting = $request->variable('display_on_posting', 0);
$bbcode_match = $request->variable('bbcode_match', '');
$bbcode_tpl = htmlspecialchars_decode($request->variable('bbcode_tpl', '', true));
$bbcode_helpline = $request->variable('bbcode_helpline', '', true);
break;
}
// Do major work
switch ($action)
{
case 'edit':
case 'add':
$tpl_ary = array(
'S_EDIT_BBCODE' => true,
'U_BACK' => $this->u_action,
'U_ACTION' => $this->u_action . '&amp;action=' . (($action == 'add') ? 'create' : 'modify') . (($bbcode_id) ? "&amp;bbcode=$bbcode_id" : ''),
'L_BBCODE_USAGE_EXPLAIN'=> sprintf($user->lang['BBCODE_USAGE_EXPLAIN'], '<a href="#down">', '</a>'),
'BBCODE_MATCH' => $bbcode_match,
'BBCODE_TPL' => $bbcode_tpl,
'BBCODE_HELPLINE' => $bbcode_helpline,
'DISPLAY_ON_POSTING' => $display_on_posting,
);
$bbcode_tokens = array('TEXT', 'SIMPLETEXT', 'INTTEXT', 'IDENTIFIER', 'NUMBER', 'EMAIL', 'URL', 'LOCAL_URL', 'RELATIVE_URL', 'COLOR');
/**
* Modify custom bbcode template data before we display the add/edit form
*
* @event core.acp_bbcodes_edit_add
* @var string action Type of the action: add|edit
* @var array tpl_ary Array with custom bbcode add/edit data
* @var int bbcode_id When editing: the bbcode id,
* when creating: 0
* @var array bbcode_tokens Array of bbcode tokens
* @since 3.1.0-a3
*/
$vars = array('action', 'tpl_ary', 'bbcode_id', 'bbcode_tokens');
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_edit_add', compact($vars)));
$template->assign_vars($tpl_ary);
foreach ($bbcode_tokens as $token)
{
$template->assign_block_vars('token', array(
'TOKEN' => '{' . $token . '}',
'EXPLAIN' => ($token === 'LOCAL_URL') ? $user->lang(array('tokens', $token), generate_board_url() . '/') : $user->lang(array('tokens', $token)),
));
}
return;
break;
case 'modify':
case 'create':
$sql_ary = $hidden_fields = array();
/**
* Modify custom bbcode data before the modify/create action
*
* @event core.acp_bbcodes_modify_create
* @var string action Type of the action: modify|create
* @var array sql_ary Array with new bbcode data
* @var int bbcode_id When editing: the bbcode id,
* when creating: 0
* @var bool display_on_posting Display bbcode on posting form
* @var string bbcode_match The bbcode usage string to match
* @var string bbcode_tpl The bbcode HTML replacement string
* @var string bbcode_helpline The bbcode help line string
* @var array hidden_fields Array of hidden fields for use when
* submitting form when $warn_text is true
* @since 3.1.0-a3
*/
$vars = array(
'action',
'sql_ary',
'bbcode_id',
'display_on_posting',
'bbcode_match',
'bbcode_tpl',
'bbcode_helpline',
'hidden_fields',
);
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create', compact($vars)));
$warn_text = preg_match('%<[^>]*\{text[\d]*\}[^>]*>%i', $bbcode_tpl);
if (!$warn_text || confirm_box(true))
{
$data = $this->build_regexp($bbcode_match, $bbcode_tpl);
// Make sure the user didn't pick a "bad" name for the BBCode tag.
$hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash=');
if (($action == 'modify' && strtolower($data['bbcode_tag']) !== strtolower($row['bbcode_tag'])) || ($action == 'create'))
{
$sql = 'SELECT 1 as test
FROM ' . BBCODES_TABLE . "
WHERE LOWER(bbcode_tag) = '" . $db->sql_escape(strtolower($data['bbcode_tag'])) . "'";
$result = $db->sql_query($sql);
$info = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
// Grab the end, interrogate the last closing tag
if ($info['test'] === '1' || in_array(strtolower($data['bbcode_tag']), $hard_coded) || (preg_match('#\[/([^[]*)]$#', $bbcode_match, $regs) && in_array(strtolower($regs[1]), $hard_coded)))
{
trigger_error($user->lang['BBCODE_INVALID_TAG_NAME'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
if (substr($data['bbcode_tag'], -1) === '=')
{
$test = substr($data['bbcode_tag'], 0, -1);
}
else
{
$test = $data['bbcode_tag'];
}
if (!preg_match('%\\[' . $test . '[^]]*].*?\\[/' . $test . ']%s', $bbcode_match))
{
trigger_error($user->lang['BBCODE_OPEN_ENDED_TAG'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (strlen($data['bbcode_tag']) > 16)
{
trigger_error($user->lang['BBCODE_TAG_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (strlen($bbcode_match) > 4000)
{
trigger_error($user->lang['BBCODE_TAG_DEF_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (strlen($bbcode_helpline) > 255)
{
trigger_error($user->lang['BBCODE_HELPLINE_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql_ary = array_merge($sql_ary, array(
'bbcode_tag' => $data['bbcode_tag'],
'bbcode_match' => $bbcode_match,
'bbcode_tpl' => $bbcode_tpl,
'display_on_posting' => $display_on_posting,
'bbcode_helpline' => $bbcode_helpline,
'first_pass_match' => $data['first_pass_match'],
'first_pass_replace' => $data['first_pass_replace'],
'second_pass_match' => $data['second_pass_match'],
'second_pass_replace' => $data['second_pass_replace']
));
if ($action == 'create')
{
$sql = 'SELECT MAX(bbcode_id) as max_bbcode_id
FROM ' . BBCODES_TABLE;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($row)
{
$bbcode_id = (int) $row['max_bbcode_id'] + 1;
// Make sure it is greater than the core bbcode ids...
if ($bbcode_id <= NUM_CORE_BBCODES)
{
$bbcode_id = NUM_CORE_BBCODES + 1;
}
}
else
{
$bbcode_id = NUM_CORE_BBCODES + 1;
}
if ($bbcode_id > BBCODE_LIMIT)
{
trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql_ary['bbcode_id'] = (int) $bbcode_id;
$db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary));
$cache->destroy('sql', BBCODES_TABLE);
$phpbb_container->get('text_formatter.cache')->invalidate();
$lang = 'BBCODE_ADDED';
$log_action = 'LOG_BBCODE_ADD';
}
else
{
$sql = 'UPDATE ' . BBCODES_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE bbcode_id = ' . $bbcode_id;
$db->sql_query($sql);
$cache->destroy('sql', BBCODES_TABLE);
$phpbb_container->get('text_formatter.cache')->invalidate();
$lang = 'BBCODE_EDITED';
$log_action = 'LOG_BBCODE_EDIT';
}
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_action, false, array($data['bbcode_tag']));
/**
* Event after a BBCode has been added or updated
*
* @event core.acp_bbcodes_modify_create_after
* @var string action Type of the action: modify|create
* @var int bbcode_id The id of the added or updated bbcode
* @var array sql_ary Array with bbcode data (read only)
* @since 3.2.4-RC1
*/
$vars = array(
'action',
'bbcode_id',
'sql_ary',
);
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create_after', compact($vars)));
trigger_error($user->lang[$lang] . adm_back_link($this->u_action));
}
else
{
confirm_box(false, $user->lang['BBCODE_DANGER'], build_hidden_fields(array_merge($hidden_fields, array(
'action' => $action,
'bbcode' => $bbcode_id,
'bbcode_match' => $bbcode_match,
'bbcode_tpl' => htmlspecialchars($bbcode_tpl),
'bbcode_helpline' => $bbcode_helpline,
'display_on_posting' => $display_on_posting,
)))
, 'confirm_bbcode.html');
}
break;
case 'delete':
$sql = 'SELECT bbcode_tag
FROM ' . BBCODES_TABLE . "
WHERE bbcode_id = $bbcode_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($row)
{
if (confirm_box(true))
{
$bbcode_tag = $row['bbcode_tag'];
$db->sql_query('DELETE FROM ' . BBCODES_TABLE . " WHERE bbcode_id = $bbcode_id");
$cache->destroy('sql', BBCODES_TABLE);
$phpbb_container->get('text_formatter.cache')->invalidate();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_BBCODE_DELETE', false, array($bbcode_tag));
/**
* Event after a BBCode has been deleted
*
* @event core.acp_bbcodes_delete_after
* @var string action Type of the action: delete
* @var int bbcode_id The id of the deleted bbcode
* @var string bbcode_tag The tag of the deleted bbcode
* @since 3.2.4-RC1
*/
$vars = array(
'action',
'bbcode_id',
'bbcode_tag',
);
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_delete_after', compact($vars)));
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'MESSAGE_TITLE' => $user->lang['INFORMATION'],
'MESSAGE_TEXT' => $user->lang['BBCODE_DELETED'],
'REFRESH_DATA' => array(
'time' => 3
)
));
}
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'bbcode' => $bbcode_id,
'i' => $id,
'mode' => $mode,
'action' => $action))
);
}
}
break;
}
$u_action = $this->u_action;
$template_data = array(
'U_ACTION' => $this->u_action . '&amp;action=add',
);
$sql_ary = array(
'SELECT' => 'b.*',
'FROM' => array(BBCODES_TABLE => 'b'),
'ORDER_BY' => 'b.bbcode_tag',
);
/**
* Modify custom bbcode template data before we display the form
*
* @event core.acp_bbcodes_display_form
* @var string action Type of the action: modify|create
* @var array sql_ary The SQL array to get custom bbcode data
* @var array template_data Array with form template data
* @var string u_action The u_action link
* @since 3.1.0-a3
*/
$vars = array('action', 'sql_ary', 'template_data', 'u_action');
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_form', compact($vars)));
$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
$template->assign_vars($template_data);
while ($row = $db->sql_fetchrow($result))
{
$bbcodes_array = array(
'BBCODE_TAG' => $row['bbcode_tag'],
'U_EDIT' => $u_action . '&amp;action=edit&amp;bbcode=' . $row['bbcode_id'],
'U_DELETE' => $u_action . '&amp;action=delete&amp;bbcode=' . $row['bbcode_id'],
);
/**
* Modify display of custom bbcodes in the form
*
* @event core.acp_bbcodes_display_bbcodes
* @var array row Array with current bbcode data
* @var array bbcodes_array Array of bbcodes template data
* @var string u_action The u_action link
* @since 3.1.0-a3
*/
$vars = array('bbcodes_array', 'row', 'u_action');
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_bbcodes', compact($vars)));
$template->assign_block_vars('bbcodes', $bbcodes_array);
}
$db->sql_freeresult($result);
}
/*
* Build regular expression for custom bbcode
*/
function build_regexp(&$bbcode_match, &$bbcode_tpl)
{
$bbcode_match = trim($bbcode_match);
$bbcode_tpl = trim($bbcode_tpl);
// Allow unicode characters for URL|LOCAL_URL|RELATIVE_URL|INTTEXT tokens
$utf8 = preg_match('/(URL|LOCAL_URL|RELATIVE_URL|INTTEXT)/', $bbcode_match);
$fp_match = preg_quote($bbcode_match, '!');
$fp_replace = preg_replace('#^\[(.*?)\]#', '[$1:$uid]', $bbcode_match);
$fp_replace = preg_replace('#\[/(.*?)\]$#', '[/$1:$uid]', $fp_replace);
$sp_match = preg_quote($bbcode_match, '!');
$sp_match = preg_replace('#^\\\\\[(.*?)\\\\\]#', '\[$1:$uid\]', $sp_match);
$sp_match = preg_replace('#\\\\\[/(.*?)\\\\\]$#', '\[/$1:$uid\]', $sp_match);
$sp_replace = $bbcode_tpl;
// @todo Make sure to change this too if something changed in message parsing
$tokens = array(
'URL' => array(
'!(?:(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('url')) . ')|(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('www_url')) . '))!ie' => "\$this->bbcode_specialchars(('\$1') ? '\$1' : 'http://\$2')"
),
'LOCAL_URL' => array(
'!(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')!e' => "\$this->bbcode_specialchars('$1')"
),
'RELATIVE_URL' => array(
'!(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')!e' => "\$this->bbcode_specialchars('$1')"
),
'EMAIL' => array(
'!(' . get_preg_expression('email') . ')!ie' => "\$this->bbcode_specialchars('$1')"
),
'TEXT' => array(
'!(.*?)!es' => "str_replace(array(\"\\r\\n\", '\\\"', '\\'', '(', ')'), array(\"\\n\", '\"', '&#39;', '&#40;', '&#41;'), trim('\$1'))"
),
'SIMPLETEXT' => array(
'!([a-zA-Z0-9-+.,_ ]+)!' => "$1"
),
'INTTEXT' => array(
'!([\p{L}\p{N}\-+,_. ]+)!u' => "$1"
),
'IDENTIFIER' => array(
'!([a-zA-Z0-9-_]+)!' => "$1"
),
'COLOR' => array(
'!([a-z]+|#[0-9abcdef]+)!i' => '$1'
),
'NUMBER' => array(
'!([0-9]+)!' => '$1'
)
);
$sp_tokens = array(
'URL' => '(?i)((?:' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('url')) . ')|(?:' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('www_url')) . '))(?-i)',
'LOCAL_URL' => '(?i)(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')(?-i)',
'RELATIVE_URL' => '(?i)(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')(?-i)',
'EMAIL' => '(' . get_preg_expression('email') . ')',
'TEXT' => '(.*?)',
'SIMPLETEXT' => '([a-zA-Z0-9-+.,_ ]+)',
'INTTEXT' => '([\p{L}\p{N}\-+,_. ]+)',
'IDENTIFIER' => '([a-zA-Z0-9-_]+)',
'COLOR' => '([a-zA-Z]+|#[0-9abcdefABCDEF]+)',
'NUMBER' => '([0-9]+)',
);
$pad = 0;
$modifiers = 'i';
$modifiers .= ($utf8) ? 'u' : '';
if (preg_match_all('/\{(' . implode('|', array_keys($tokens)) . ')[0-9]*\}/i', $bbcode_match, $m))
{
foreach ($m[0] as $n => $token)
{
$token_type = $m[1][$n];
reset($tokens[strtoupper($token_type)]);
list($match, $replace) = each($tokens[strtoupper($token_type)]);
// Pad backreference numbers from tokens
if (preg_match_all('/(?<!\\\\)\$([0-9]+)/', $replace, $repad))
{
$repad = $pad + count(array_unique($repad[0]));
$replace = preg_replace_callback('/(?<!\\\\)\$([0-9]+)/', function ($match) use ($pad) {
return '${' . ($match[1] + $pad) . '}';
}, $replace);
$pad = $repad;
}
// Obtain pattern modifiers to use and alter the regex accordingly
$regex = preg_replace('/!(.*)!([a-z]*)/', '$1', $match);
$regex_modifiers = preg_replace('/!(.*)!([a-z]*)/', '$2', $match);
for ($i = 0, $size = strlen($regex_modifiers); $i < $size; ++$i)
{
if (strpos($modifiers, $regex_modifiers[$i]) === false)
{
$modifiers .= $regex_modifiers[$i];
if ($regex_modifiers[$i] == 'e')
{
$fp_replace = "'" . str_replace("'", "\\'", $fp_replace) . "'";
}
}
if ($regex_modifiers[$i] == 'e')
{
$replace = "'.$replace.'";
}
}
$fp_match = str_replace(preg_quote($token, '!'), $regex, $fp_match);
$fp_replace = str_replace($token, $replace, $fp_replace);
$sp_match = str_replace(preg_quote($token, '!'), $sp_tokens[$token_type], $sp_match);
// Prepend the board url to local relative links
$replace_prepend = ($token_type === 'LOCAL_URL') ? generate_board_url() . '/' : '';
$sp_replace = str_replace($token, $replace_prepend . '${' . ($n + 1) . '}', $sp_replace);
}
$fp_match = '!' . $fp_match . '!' . $modifiers;
$sp_match = '!' . $sp_match . '!s' . (($utf8) ? 'u' : '');
if (strpos($fp_match, 'e') !== false)
{
$fp_replace = str_replace("'.'", '', $fp_replace);
$fp_replace = str_replace(".''.", '.', $fp_replace);
}
}
else
{
// No replacement is present, no need for a second-pass pattern replacement
// A simple str_replace will suffice
$fp_match = '!' . $fp_match . '!' . $modifiers;
$sp_match = $fp_replace;
$sp_replace = '';
}
// Lowercase tags
$bbcode_tag = preg_replace('/.*?\[([a-z0-9_-]+).*/i', '$1', $bbcode_match);
$bbcode_search = preg_replace('/.*?\[([a-z0-9_-]+).*/i', '$1', $bbcode_match);
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $bbcode_tag))
{
global $user;
trigger_error($user->lang['BBCODE_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$fp_match = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
return strtolower($match[0]);
}, $fp_match);
$fp_replace = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
return strtolower($match[0]);
}, $fp_replace);
$sp_match = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
return strtolower($match[0]);
}, $sp_match);
$sp_replace = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
return strtolower($match[0]);
}, $sp_replace);
return array(
'bbcode_tag' => $bbcode_tag,
'first_pass_match' => $fp_match,
'first_pass_replace' => $fp_replace,
'second_pass_match' => $sp_match,
'second_pass_replace' => $sp_replace
);
}
}

1178
includes/acp/acp_board.php Normal file

File diff suppressed because it is too large Load Diff

427
includes/acp/acp_bots.php Normal file
View File

@@ -0,0 +1,427 @@
<?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;
}
class acp_bots
{
var $u_action;
function main($id, $mode)
{
global $config, $db, $user, $template, $cache, $request, $phpbb_log;
global $phpbb_root_path, $phpEx;
$action = $request->variable('action', '');
$submit = (isset($_POST['submit'])) ? true : false;
$mark = $request->variable('mark', array(0));
$bot_id = $request->variable('id', 0);
if (isset($_POST['add']))
{
$action = 'add';
}
$error = array();
$user->add_lang('acp/bots');
$this->tpl_name = 'acp_bots';
$this->page_title = 'ACP_BOTS';
$form_key = 'acp_bots';
add_form_key($form_key);
if ($submit && !check_form_key($form_key))
{
$error[] = $user->lang['FORM_INVALID'];
}
// User wants to do something, how inconsiderate of them!
switch ($action)
{
case 'activate':
if ($bot_id || count($mark))
{
$sql_id = ($bot_id) ? " = $bot_id" : ' IN (' . implode(', ', $mark) . ')';
$sql = 'UPDATE ' . BOTS_TABLE . "
SET bot_active = 1
WHERE bot_id $sql_id";
$db->sql_query($sql);
}
$cache->destroy('_bots');
break;
case 'deactivate':
if ($bot_id || count($mark))
{
$sql_id = ($bot_id) ? " = $bot_id" : ' IN (' . implode(', ', $mark) . ')';
$sql = 'UPDATE ' . BOTS_TABLE . "
SET bot_active = 0
WHERE bot_id $sql_id";
$db->sql_query($sql);
}
$cache->destroy('_bots');
break;
case 'delete':
if ($bot_id || count($mark))
{
if (confirm_box(true))
{
// We need to delete the relevant user, usergroup and bot entries ...
$sql_id = ($bot_id) ? " = $bot_id" : ' IN (' . implode(', ', $mark) . ')';
$sql = 'SELECT bot_name, user_id
FROM ' . BOTS_TABLE . "
WHERE bot_id $sql_id";
$result = $db->sql_query($sql);
$user_id_ary = $bot_name_ary = array();
while ($row = $db->sql_fetchrow($result))
{
$user_id_ary[] = (int) $row['user_id'];
$bot_name_ary[] = $row['bot_name'];
}
$db->sql_freeresult($result);
$db->sql_transaction('begin');
$sql = 'DELETE FROM ' . BOTS_TABLE . "
WHERE bot_id $sql_id";
$db->sql_query($sql);
if (count($user_id_ary))
{
$_tables = array(USERS_TABLE, USER_GROUP_TABLE);
foreach ($_tables as $table)
{
$sql = "DELETE FROM $table
WHERE " . $db->sql_in_set('user_id', $user_id_ary);
$db->sql_query($sql);
}
}
$db->sql_transaction('commit');
$cache->destroy('_bots');
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_BOT_DELETE', false, array(implode(', ', $bot_name_ary)));
trigger_error($user->lang['BOT_DELETED'] . adm_back_link($this->u_action));
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'mark' => $mark,
'id' => $bot_id,
'mode' => $mode,
'action' => $action))
);
}
}
break;
case 'edit':
case 'add':
if (!function_exists('user_update_name'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
$bot_row = array(
'bot_name' => $request->variable('bot_name', '', true),
'bot_agent' => $request->variable('bot_agent', ''),
'bot_ip' => $request->variable('bot_ip', ''),
'bot_active' => $request->variable('bot_active', true),
'bot_lang' => $request->variable('bot_lang', $config['default_lang']),
'bot_style' => $request->variable('bot_style' , $config['default_style']),
);
if ($submit)
{
if (!$bot_row['bot_agent'] && !$bot_row['bot_ip'])
{
$error[] = $user->lang['ERR_BOT_NO_MATCHES'];
}
if ($bot_row['bot_ip'] && !preg_match('#^[\d\.,:]+$#', $bot_row['bot_ip']))
{
if (!$ip_list = gethostbynamel($bot_row['bot_ip']))
{
$error[] = $user->lang['ERR_BOT_NO_IP'];
}
else
{
$bot_row['bot_ip'] = implode(',', $ip_list);
}
}
$bot_row['bot_ip'] = str_replace(' ', '', $bot_row['bot_ip']);
// Make sure the admin is not adding a bot with an user agent similar to his one
if ($bot_row['bot_agent'] && substr($user->data['session_browser'], 0, 149) === substr($bot_row['bot_agent'], 0, 149))
{
$error[] = $user->lang['ERR_BOT_AGENT_MATCHES_UA'];
}
$bot_name = false;
if ($bot_id)
{
$sql = 'SELECT u.username_clean
FROM ' . BOTS_TABLE . ' b, ' . USERS_TABLE . " u
WHERE b.bot_id = $bot_id
AND u.user_id = b.user_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$bot_row)
{
$error[] = $user->lang['NO_BOT'];
}
else
{
$bot_name = $row['username_clean'];
}
}
if (!$this->validate_botname($bot_row['bot_name'], $bot_name))
{
$error[] = $user->lang['BOT_NAME_TAKEN'];
}
if (!count($error))
{
// New bot? Create a new user and group entry
if ($action == 'add')
{
$sql = 'SELECT group_id, group_colour
FROM ' . GROUPS_TABLE . "
WHERE group_name = 'BOTS'
AND group_type = " . GROUP_SPECIAL;
$result = $db->sql_query($sql);
$group_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$group_row)
{
trigger_error($user->lang['NO_BOT_GROUP'] . adm_back_link($this->u_action . "&amp;id=$bot_id&amp;action=$action"), E_USER_WARNING);
}
$user_id = user_add(array(
'user_type' => (int) USER_IGNORE,
'group_id' => (int) $group_row['group_id'],
'username' => (string) $bot_row['bot_name'],
'user_regdate' => time(),
'user_password' => '',
'user_colour' => (string) $group_row['group_colour'],
'user_email' => '',
'user_lang' => (string) $bot_row['bot_lang'],
'user_style' => (int) $bot_row['bot_style'],
'user_allow_massemail' => 0,
));
$sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => (int) $user_id,
'bot_name' => (string) $bot_row['bot_name'],
'bot_active' => (int) $bot_row['bot_active'],
'bot_agent' => (string) $bot_row['bot_agent'],
'bot_ip' => (string) $bot_row['bot_ip'])
);
$db->sql_query($sql);
$log = 'ADDED';
}
else if ($bot_id)
{
$sql = 'SELECT user_id, bot_name
FROM ' . BOTS_TABLE . "
WHERE bot_id = $bot_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$row)
{
trigger_error($user->lang['NO_BOT'] . adm_back_link($this->u_action . "&amp;id=$bot_id&amp;action=$action"), E_USER_WARNING);
}
$sql_ary = array(
'user_style' => (int) $bot_row['bot_style'],
'user_lang' => (string) $bot_row['bot_lang'],
);
if ($bot_row['bot_name'] !== $row['bot_name'])
{
$sql_ary['username'] = (string) $bot_row['bot_name'];
$sql_ary['username_clean'] = (string) utf8_clean_string($bot_row['bot_name']);
}
$sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " WHERE user_id = {$row['user_id']}";
$db->sql_query($sql);
$sql = 'UPDATE ' . BOTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
'bot_name' => (string) $bot_row['bot_name'],
'bot_active' => (int) $bot_row['bot_active'],
'bot_agent' => (string) $bot_row['bot_agent'],
'bot_ip' => (string) $bot_row['bot_ip'])
) . " WHERE bot_id = $bot_id";
$db->sql_query($sql);
// Updated username?
if ($bot_row['bot_name'] !== $row['bot_name'])
{
user_update_name($row['bot_name'], $bot_row['bot_name']);
}
$log = 'UPDATED';
}
$cache->destroy('_bots');
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_BOT_' . $log, false, array($bot_row['bot_name']));
trigger_error($user->lang['BOT_' . $log] . adm_back_link($this->u_action));
}
}
else if ($bot_id)
{
$sql = 'SELECT b.*, u.user_lang, u.user_style
FROM ' . BOTS_TABLE . ' b, ' . USERS_TABLE . " u
WHERE b.bot_id = $bot_id
AND u.user_id = b.user_id";
$result = $db->sql_query($sql);
$bot_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$bot_row)
{
trigger_error($user->lang['NO_BOT'] . adm_back_link($this->u_action . "&amp;id=$bot_id&amp;action=$action"), E_USER_WARNING);
}
$bot_row['bot_lang'] = $bot_row['user_lang'];
$bot_row['bot_style'] = $bot_row['user_style'];
unset($bot_row['user_lang'], $bot_row['user_style']);
}
$s_active_options = '';
$_options = array('0' => 'NO', '1' => 'YES');
foreach ($_options as $value => $lang)
{
$selected = ($bot_row['bot_active'] == $value) ? ' selected="selected"' : '';
$s_active_options .= '<option value="' . $value . '"' . $selected . '>' . $user->lang[$lang] . '</option>';
}
$style_select = style_select($bot_row['bot_style'], true);
$lang_select = language_select($bot_row['bot_lang']);
$l_title = ($action == 'edit') ? 'EDIT' : 'ADD';
$template->assign_vars(array(
'L_TITLE' => $user->lang['BOT_' . $l_title],
'U_ACTION' => $this->u_action . "&amp;id=$bot_id&amp;action=$action",
'U_BACK' => $this->u_action,
'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
'BOT_NAME' => $bot_row['bot_name'],
'BOT_IP' => $bot_row['bot_ip'],
'BOT_AGENT' => $bot_row['bot_agent'],
'S_EDIT_BOT' => true,
'S_ACTIVE_OPTIONS' => $s_active_options,
'S_STYLE_OPTIONS' => $style_select,
'S_LANG_OPTIONS' => $lang_select,
'S_ERROR' => (count($error)) ? true : false,
)
);
return;
break;
}
if ($request->is_ajax() && ($action == 'activate' || $action == 'deactivate'))
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'text' => $user->lang['BOT_' . (($action == 'activate') ? 'DE' : '') . 'ACTIVATE'],
));
}
$s_options = '';
$_options = array('activate' => 'BOT_ACTIVATE', 'deactivate' => 'BOT_DEACTIVATE', 'delete' => 'DELETE');
foreach ($_options as $value => $lang)
{
$s_options .= '<option value="' . $value . '">' . $user->lang[$lang] . '</option>';
}
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
'S_BOT_OPTIONS' => $s_options)
);
$sql = 'SELECT b.bot_id, b.bot_name, b.bot_active, u.user_lastvisit
FROM ' . BOTS_TABLE . ' b, ' . USERS_TABLE . ' u
WHERE u.user_id = b.user_id
ORDER BY u.user_lastvisit DESC, b.bot_name ASC';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$active_lang = (!$row['bot_active']) ? 'BOT_ACTIVATE' : 'BOT_DEACTIVATE';
$active_value = (!$row['bot_active']) ? 'activate' : 'deactivate';
$template->assign_block_vars('bots', array(
'BOT_NAME' => $row['bot_name'],
'BOT_ID' => $row['bot_id'],
'LAST_VISIT' => ($row['user_lastvisit']) ? $user->format_date($row['user_lastvisit']) : $user->lang['BOT_NEVER'],
'U_ACTIVATE_DEACTIVATE' => $this->u_action . "&amp;id={$row['bot_id']}&amp;action=$active_value",
'L_ACTIVATE_DEACTIVATE' => $user->lang[$active_lang],
'U_EDIT' => $this->u_action . "&amp;id={$row['bot_id']}&amp;action=edit",
'U_DELETE' => $this->u_action . "&amp;id={$row['bot_id']}&amp;action=delete")
);
}
$db->sql_freeresult($result);
}
/**
* Validate bot name against username table
*/
function validate_botname($newname, $oldname = false)
{
global $db;
if ($oldname && utf8_clean_string($newname) === $oldname)
{
return true;
}
// Admins might want to use names otherwise forbidden, thus we only check for duplicates.
$sql = 'SELECT username
FROM ' . USERS_TABLE . "
WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($newname)) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
return ($row) ? false : true;
}
}

View File

@@ -0,0 +1,190 @@
<?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;
}
class acp_captcha
{
var $u_action;
function main($id, $mode)
{
global $user, $template, $phpbb_log, $request;
global $config, $phpbb_container;
$user->add_lang('acp/board');
/* @var $factory \phpbb\captcha\factory */
$factory = $phpbb_container->get('captcha.factory');
$captchas = $factory->get_captcha_types();
$selected = $request->variable('select_captcha', $config['captcha_plugin']);
$selected = (isset($captchas['available'][$selected]) || isset($captchas['unavailable'][$selected])) ? $selected : $config['captcha_plugin'];
$configure = $request->variable('configure', false);
// Oh, they are just here for the view
if (isset($_GET['captcha_demo']))
{
$this->deliver_demo($selected);
}
// Delegate
if ($configure)
{
$config_captcha = $factory->get_instance($selected);
$config_captcha->acp_page($id, $this);
}
else
{
$config_vars = array(
'enable_confirm' => array(
'tpl' => 'REG_ENABLE',
'default' => false,
'validate' => 'bool',
'lang' => 'VISUAL_CONFIRM_REG',
),
'enable_post_confirm' => array(
'tpl' => 'POST_ENABLE',
'default' => false,
'validate' => 'bool',
'lang' => 'VISUAL_CONFIRM_POST',
),
'confirm_refresh' => array(
'tpl' => 'CONFIRM_REFRESH',
'default' => false,
'validate' => 'bool',
'lang' => 'VISUAL_CONFIRM_REFRESH',
),
'max_reg_attempts' => array(
'tpl' => 'REG_LIMIT',
'default' => 0,
'validate' => 'int:0:99999',
'lang' => 'REG_LIMIT',
),
'max_login_attempts' => array(
'tpl' => 'MAX_LOGIN_ATTEMPTS',
'default' => 0,
'validate' => 'int:0:99999',
'lang' => 'MAX_LOGIN_ATTEMPTS',
),
);
$this->tpl_name = 'acp_captcha';
$this->page_title = 'ACP_VC_SETTINGS';
$form_key = 'acp_captcha';
add_form_key($form_key);
$submit = $request->variable('main_submit', false);
$error = $cfg_array = array();
if ($submit)
{
foreach ($config_vars as $config_var => $options)
{
$cfg_array[$config_var] = $request->variable($config_var, $options['default']);
}
validate_config_vars($config_vars, $cfg_array, $error);
if (!check_form_key($form_key))
{
$error[] = $user->lang['FORM_INVALID'];
}
if ($error)
{
$submit = false;
}
}
if ($submit)
{
foreach ($cfg_array as $key => $value)
{
$config->set($key, $value);
}
if ($selected !== $config['captcha_plugin'])
{
// sanity check
if (isset($captchas['available'][$selected]))
{
$old_captcha = $factory->get_instance($config['captcha_plugin']);
$old_captcha->uninstall();
$config->set('captcha_plugin', $selected);
$new_captcha = $factory->get_instance($config['captcha_plugin']);
$new_captcha->install();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
}
else
{
trigger_error($user->lang['CAPTCHA_UNAVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
}
else
{
$captcha_select = '';
foreach ($captchas['available'] as $value => $title)
{
$current = ($selected !== false && $value == $selected) ? ' selected="selected"' : '';
$captcha_select .= '<option value="' . $value . '"' . $current . '>' . $user->lang($title) . '</option>';
}
foreach ($captchas['unavailable'] as $value => $title)
{
$current = ($selected !== false && $value == $selected) ? ' selected="selected"' : '';
$captcha_select .= '<option value="' . $value . '"' . $current . ' class="disabled-option">' . $user->lang($title) . '</option>';
}
$demo_captcha = $factory->get_instance($selected);
foreach ($config_vars as $config_var => $options)
{
$template->assign_var($options['tpl'], (isset($_POST[$config_var])) ? $request->variable($config_var, $options['default']) : $config[$config_var]) ;
}
$template->assign_vars(array(
'CAPTCHA_PREVIEW_TPL' => $demo_captcha->get_demo_template($id),
'S_CAPTCHA_HAS_CONFIG' => $demo_captcha->has_config(),
'CAPTCHA_SELECT' => $captcha_select,
'ERROR_MSG' => implode('<br />', $error),
'U_ACTION' => $this->u_action,
));
}
}
}
/**
* Entry point for delivering image CAPTCHAs in the ACP.
*/
function deliver_demo($selected)
{
global $phpbb_container;
$captcha = $phpbb_container->get('captcha.factory')->get_instance($selected);
$captcha->init(CONFIRM_REG);
$captcha->execute_demo();
garbage_collection();
exit_handler();
}
}

View File

@@ -0,0 +1,138 @@
<?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;
}
/**
* @package acp
*/
class acp_contact
{
public $u_action;
public function main($id, $mode)
{
global $user, $request, $template;
global $config, $phpbb_root_path, $phpEx, $phpbb_container;
$user->add_lang(array('acp/board', 'posting'));
$this->tpl_name = 'acp_contact';
$this->page_title = 'ACP_CONTACT_SETTINGS';
$form_name = 'acp_contact';
add_form_key($form_name);
$error = '';
if (!function_exists('display_custom_bbcodes'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
if (!class_exists('parse_message'))
{
include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
}
/* @var $config_text \phpbb\config\db_text */
$config_text = $phpbb_container->get('config_text');
$contact_admin_data = $config_text->get_array(array(
'contact_admin_info',
'contact_admin_info_uid',
'contact_admin_info_bitfield',
'contact_admin_info_flags',
));
$contact_admin_info = $contact_admin_data['contact_admin_info'];
$contact_admin_info_uid = $contact_admin_data['contact_admin_info_uid'];
$contact_admin_info_bitfield= $contact_admin_data['contact_admin_info_bitfield'];
$contact_admin_info_flags = $contact_admin_data['contact_admin_info_flags'];
if ($request->is_set_post('submit') || $request->is_set_post('preview'))
{
if (!check_form_key($form_name))
{
$error = $user->lang('FORM_INVALID');
}
$contact_admin_info = $request->variable('contact_admin_info', '', true);
generate_text_for_storage(
$contact_admin_info,
$contact_admin_info_uid,
$contact_admin_info_bitfield,
$contact_admin_info_flags,
!$request->variable('disable_bbcode', false),
!$request->variable('disable_magic_url', false),
!$request->variable('disable_smilies', false)
);
if (empty($error) && $request->is_set_post('submit'))
{
$config->set('contact_admin_form_enable', $request->variable('contact_admin_form_enable', false));
$config_text->set_array(array(
'contact_admin_info' => $contact_admin_info,
'contact_admin_info_uid' => $contact_admin_info_uid,
'contact_admin_info_bitfield' => $contact_admin_info_bitfield,
'contact_admin_info_flags' => $contact_admin_info_flags,
));
trigger_error($user->lang['CONTACT_US_INFO_UPDATED'] . adm_back_link($this->u_action));
}
}
$contact_admin_info_preview = '';
if ($request->is_set_post('preview'))
{
$contact_admin_info_preview = generate_text_for_display($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_bitfield, $contact_admin_info_flags);
}
$contact_admin_edit = generate_text_for_edit($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_flags);
/** @var \phpbb\controller\helper $controller_helper */
$controller_helper = $phpbb_container->get('controller.helper');
$template->assign_vars(array(
'ERRORS' => $error,
'CONTACT_ENABLED' => $config['contact_admin_form_enable'],
'CONTACT_US_INFO' => $contact_admin_edit['text'],
'CONTACT_US_INFO_PREVIEW' => $contact_admin_info_preview,
'S_BBCODE_DISABLE_CHECKED' => !$contact_admin_edit['allow_bbcode'],
'S_SMILIES_DISABLE_CHECKED' => !$contact_admin_edit['allow_smilies'],
'S_MAGIC_URL_DISABLE_CHECKED' => !$contact_admin_edit['allow_urls'],
'BBCODE_STATUS' => $user->lang('BBCODE_IS_ON', '<a href="' . $controller_helper->route('phpbb_help_bbcode_controller') . '">', '</a>'),
'SMILIES_STATUS' => $user->lang['SMILIES_ARE_ON'],
'IMG_STATUS' => $user->lang['IMAGES_ARE_ON'],
'FLASH_STATUS' => $user->lang['FLASH_IS_ON'],
'URL_STATUS' => $user->lang['URL_IS_ON'],
'S_BBCODE_ALLOWED' => true,
'S_SMILIES_ALLOWED' => true,
'S_BBCODE_IMG' => true,
'S_BBCODE_FLASH' => true,
'S_LINKS_ALLOWED' => true,
));
// Assigning custom bbcodes
display_custom_bbcodes();
}
}

View File

@@ -0,0 +1,622 @@
<?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;
}
class acp_database
{
var $db_tools;
var $u_action;
public $page_title;
function main($id, $mode)
{
global $cache, $db, $user, $template, $table_prefix, $request;
global $phpbb_root_path, $phpbb_container, $phpbb_log;
$this->db_tools = $phpbb_container->get('dbal.tools');
$user->add_lang('acp/database');
$this->tpl_name = 'acp_database';
$this->page_title = 'ACP_DATABASE';
$action = $request->variable('action', '');
$form_key = 'acp_database';
add_form_key($form_key);
$template->assign_vars(array(
'MODE' => $mode
));
switch ($mode)
{
case 'backup':
$this->page_title = 'ACP_BACKUP';
switch ($action)
{
case 'download':
$type = $request->variable('type', '');
$table = array_intersect($this->db_tools->sql_list_tables(), $request->variable('table', array('')));
$format = $request->variable('method', '');
$where = $request->variable('where', '');
if (!count($table))
{
trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (!check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$store = $structure = $schema_data = false;
if ($where == 'store')
{
$store = true;
}
if ($type == 'full' || $type == 'structure')
{
$structure = true;
}
if ($type == 'full' || $type == 'data')
{
$schema_data = true;
}
@set_time_limit(1200);
@set_time_limit(0);
$time = time();
$filename = 'backup_' . $time . '_' . unique_id();
/** @var phpbb\db\extractor\extractor_interface $extractor Database extractor */
$extractor = $phpbb_container->get('dbal.extractor');
$extractor->init_extractor($format, $filename, $time, false, $store);
$extractor->write_start($table_prefix);
foreach ($table as $table_name)
{
// Get the table structure
if ($structure)
{
$extractor->write_table($table_name);
}
else
{
// We might wanna empty out all that junk :D
switch ($db->get_sql_layer())
{
case 'sqlite3':
$extractor->flush('DELETE FROM ' . $table_name . ";\n");
break;
case 'mssql_odbc':
case 'mssqlnative':
$extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n");
break;
case 'oracle':
$extractor->flush('TRUNCATE TABLE ' . $table_name . "/\n");
break;
default:
$extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n");
break;
}
}
// Data
if ($schema_data)
{
$extractor->write_data($table_name);
}
}
$extractor->write_end();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_BACKUP');
trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action));
break;
default:
$tables = $this->db_tools->sql_list_tables();
asort($tables);
foreach ($tables as $table_name)
{
if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0)
{
$template->assign_block_vars('tables', array(
'TABLE' => $table_name
));
}
}
unset($tables);
$template->assign_vars(array(
'U_ACTION' => $this->u_action . '&amp;action=download'
));
$available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2');
foreach ($available_methods as $type => $module)
{
if (!@extension_loaded($module))
{
continue;
}
$template->assign_block_vars('methods', array(
'TYPE' => $type
));
}
$template->assign_block_vars('methods', array(
'TYPE' => 'text'
));
break;
}
break;
case 'restore':
$this->page_title = 'ACP_RESTORE';
switch ($action)
{
case 'submit':
$delete = $request->variable('delete', '');
$file = $request->variable('file', '');
$backup_info = $this->get_backup_file($phpbb_root_path . 'store/', $file);
if (empty($backup_info) || !is_readable($backup_info['file_name']))
{
trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($delete)
{
if (confirm_box(true))
{
unlink($backup_info['file_name']);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_DELETE');
trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action));
}
else
{
confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file)));
}
}
else if (confirm_box(true))
{
switch ($backup_info['extensions'])
{
case 'sql':
$fp = fopen($backup_info['file_name'], 'rb');
$read = 'fread';
$seek = 'fseek';
$eof = 'feof';
$close = 'fclose';
$fgetd = 'fgetd';
break;
case 'sql.bz2':
$fp = bzopen($backup_info['file_name'], 'r');
$read = 'bzread';
$seek = '';
$eof = 'feof';
$close = 'bzclose';
$fgetd = 'fgetd_seekless';
break;
case 'sql.gz':
$fp = gzopen($backup_info['file_name'], 'rb');
$read = 'gzread';
$seek = 'gzseek';
$eof = 'gzeof';
$close = 'gzclose';
$fgetd = 'fgetd';
break;
default:
trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
return;
}
switch ($db->get_sql_layer())
{
case 'mysql':
case 'mysql4':
case 'mysqli':
case 'sqlite3':
while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false)
{
$db->sql_query($sql);
}
break;
case 'postgres':
$delim = ";\n";
while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false)
{
$query = trim($sql);
if (substr($query, 0, 13) == 'CREATE DOMAIN')
{
list(, , $domain) = explode(' ', $query);
$sql = "SELECT domain_name
FROM information_schema.domains
WHERE domain_name = '$domain';";
$result = $db->sql_query($sql);
if (!$db->sql_fetchrow($result))
{
$db->sql_query($query);
}
$db->sql_freeresult($result);
}
else
{
$db->sql_query($query);
}
if (substr($query, 0, 4) == 'COPY')
{
while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.')
{
if ($sub === false)
{
trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
pg_put_line($db->get_db_connect_id(), $sub . "\n");
}
pg_put_line($db->get_db_connect_id(), "\\.\n");
pg_end_copy($db->get_db_connect_id());
}
}
break;
case 'oracle':
while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false)
{
$db->sql_query($sql);
}
break;
case 'mssql_odbc':
case 'mssqlnative':
while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false)
{
$db->sql_query($sql);
}
break;
}
$close($fp);
// Purge the cache due to updated data
$cache->purge();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_RESTORE');
trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action));
break;
}
else
{
confirm_box(false, $user->lang['RESTORE_SELECTED_BACKUP'], build_hidden_fields(array('file' => $file)));
}
default:
$backup_files = $this->get_file_list($phpbb_root_path . 'store/');
if (!empty($backup_files))
{
krsort($backup_files);
foreach ($backup_files as $name => $file)
{
$template->assign_block_vars('files', array(
'FILE' => sha1($file),
'NAME' => $user->format_date($name, 'd-m-Y H:i', true),
'SUPPORTED' => true,
));
}
}
$template->assign_vars(array(
'U_ACTION' => $this->u_action . '&amp;action=submit'
));
break;
}
break;
}
}
/**
* Get backup file from file hash
*
* @param string $directory Relative path to directory
* @param string $file_hash Hash of selected file
*
* @return array Backup file data or empty array if unable to find file
*/
protected function get_backup_file($directory, $file_hash)
{
$backup_data = [];
$file_list = $this->get_file_list($directory);
$supported_extensions = $this->get_supported_extensions();
foreach ($file_list as $file)
{
preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches);
if (sha1($file) === $file_hash && in_array($matches[2], $supported_extensions))
{
$backup_data = [
'file_name' => $directory . $file,
'extension' => $matches[2],
];
break;
}
}
return $backup_data;
}
/**
* Get backup file list for directory
*
* @param string $directory Relative path to backup directory
*
* @return array List of backup files in specified directory
*/
protected function get_file_list($directory)
{
$supported_extensions = $this->get_supported_extensions();
$dh = @opendir($directory);
$backup_files = [];
if ($dh)
{
while (($file = readdir($dh)) !== false)
{
if (preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches))
{
if (in_array($matches[2], $supported_extensions))
{
$backup_files[(int) $matches[1]] = $file;
}
}
}
closedir($dh);
}
return $backup_files;
}
/**
* Get supported extensions for backup
*
* @return array List of supported extensions
*/
protected function get_supported_extensions()
{
$extensions = ['sql'];
$available_methods = ['sql.gz' => 'zlib', 'sql.bz2' => 'bz2'];
foreach ($available_methods as $type => $module)
{
if (!@extension_loaded($module))
{
continue;
}
$extensions[] = $type;
}
return $extensions;
}
}
// get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P)
function get_usable_memory()
{
$val = trim(@ini_get('memory_limit'));
if (preg_match('/(\\d+)([mkg]?)/i', $val, $regs))
{
$memory_limit = (int) $regs[1];
switch ($regs[2])
{
case 'k':
case 'K':
$memory_limit *= 1024;
break;
case 'm':
case 'M':
$memory_limit *= 1048576;
break;
case 'g':
case 'G':
$memory_limit *= 1073741824;
break;
}
// how much memory PHP requires at the start of export (it is really a little less)
if ($memory_limit > 6100000)
{
$memory_limit -= 6100000;
}
// allow us to consume half of the total memory available
$memory_limit /= 2;
}
else
{
// set the buffer to 1M if we have no clue how much memory PHP will give us :P
$memory_limit = 1048576;
}
return $memory_limit;
}
function sanitize_data_mssql($text)
{
$data = preg_split('/[\n\t\r\b\f]/', $text);
preg_match_all('/[\n\t\r\b\f]/', $text, $matches);
$val = array();
foreach ($data as $value)
{
if (strlen($value))
{
$val[] = "'" . $value . "'";
}
if (count($matches[0]))
{
$val[] = 'char(' . ord(array_shift($matches[0])) . ')';
}
}
return implode('+', $val);
}
function sanitize_data_oracle($text)
{
// $data = preg_split('/[\0\n\t\r\b\f\'"\/\\\]/', $text);
// preg_match_all('/[\0\n\t\r\b\f\'"\/\\\]/', $text, $matches);
$data = preg_split('/[\0\b\f\'\/]/', $text);
preg_match_all('/[\0\r\b\f\'\/]/', $text, $matches);
$val = array();
foreach ($data as $value)
{
if (strlen($value))
{
$val[] = "'" . $value . "'";
}
if (count($matches[0]))
{
$val[] = 'chr(' . ord(array_shift($matches[0])) . ')';
}
}
return implode('||', $val);
}
function sanitize_data_generic($text)
{
$data = preg_split('/[\n\t\r\b\f]/', $text);
preg_match_all('/[\n\t\r\b\f]/', $text, $matches);
$val = array();
foreach ($data as $value)
{
if (strlen($value))
{
$val[] = "'" . $value . "'";
}
if (count($matches[0]))
{
$val[] = "'" . array_shift($matches[0]) . "'";
}
}
return implode('||', $val);
}
// modified from PHP.net
function fgetd(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
{
$record = '';
$delim_len = strlen($delim);
while (!$eof($fp))
{
$pos = strpos($record, $delim);
if ($pos === false)
{
$record .= $read($fp, $buffer);
if ($eof($fp) && ($pos = strpos($record, $delim)) !== false)
{
$seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR);
return substr($record, 0, $pos);
}
}
else
{
$seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR);
return substr($record, 0, $pos);
}
}
return false;
}
function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
{
static $array = array();
static $record = '';
if (!count($array))
{
while (!$eof($fp))
{
if (strpos($record, $delim) !== false)
{
$array = explode($delim, $record);
$record = array_pop($array);
break;
}
else
{
$record .= $read($fp, $buffer);
}
}
if ($eof($fp) && strpos($record, $delim) !== false)
{
$array = explode($delim, $record);
$record = array_pop($array);
}
}
if (count($array))
{
return array_shift($array);
}
return false;
}

View File

@@ -0,0 +1,115 @@
<?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;
}
class acp_disallow
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $cache, $phpbb_log, $request;
$user->add_lang('acp/posting');
// Set up general vars
$this->tpl_name = 'acp_disallow';
$this->page_title = 'ACP_DISALLOW_USERNAMES';
$form_key = 'acp_disallow';
add_form_key($form_key);
$disallow = (isset($_POST['disallow'])) ? true : false;
$allow = (isset($_POST['allow'])) ? true : false;
if (($allow || $disallow) && !check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($disallow)
{
$disallowed_user = str_replace('*', '%', $request->variable('disallowed_user', '', true));
if (!$disallowed_user)
{
trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT disallow_id
FROM ' . DISALLOW_TABLE . "
WHERE disallow_username = '" . $db->sql_escape($disallowed_user) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($row)
{
trigger_error($user->lang['DISALLOWED_ALREADY'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'INSERT INTO ' . DISALLOW_TABLE . ' ' . $db->sql_build_array('INSERT', array('disallow_username' => $disallowed_user));
$db->sql_query($sql);
$cache->destroy('_disallowed_usernames');
$message = $user->lang['DISALLOW_SUCCESSFUL'];
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DISALLOW_ADD', false, array(str_replace('%', '*', $disallowed_user)));
trigger_error($message . adm_back_link($this->u_action));
}
else if ($allow)
{
$disallowed_id = $request->variable('disallowed_id', 0);
if (!$disallowed_id)
{
trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'DELETE FROM ' . DISALLOW_TABLE . '
WHERE disallow_id = ' . $disallowed_id;
$db->sql_query($sql);
$cache->destroy('_disallowed_usernames');
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DISALLOW_DELETE');
trigger_error($user->lang['DISALLOWED_DELETED'] . adm_back_link($this->u_action));
}
// Grab the current list of disallowed usernames...
$sql = 'SELECT *
FROM ' . DISALLOW_TABLE;
$result = $db->sql_query($sql);
$disallow_select = '';
while ($row = $db->sql_fetchrow($result))
{
$disallow_select .= '<option value="' . $row['disallow_id'] . '">' . str_replace('%', '*', $row['disallow_username']) . '</option>';
}
$db->sql_freeresult($result);
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
'S_DISALLOWED_NAMES' => $disallow_select)
);
}
}

351
includes/acp/acp_email.php Normal file
View File

@@ -0,0 +1,351 @@
<?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;
}
class acp_email
{
var $u_action;
function main($id, $mode)
{
global $config, $db, $user, $template, $phpbb_log, $request;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_dispatcher;
$user->add_lang('acp/email');
$this->tpl_name = 'acp_email';
$this->page_title = 'ACP_MASS_EMAIL';
$form_key = 'acp_email';
add_form_key($form_key);
// Set some vars
$submit = (isset($_POST['submit'])) ? true : false;
$error = array();
$usernames = $request->variable('usernames', '', true);
$usernames = (!empty($usernames)) ? explode("\n", $usernames) : array();
$group_id = $request->variable('g', 0);
$subject = $request->variable('subject', '', true);
$message = $request->variable('message', '', true);
// Do the job ...
if ($submit)
{
// Error checking needs to go here ... if no subject and/or no message then skip
// over the send and return to the form
$use_queue = (isset($_POST['send_immediately'])) ? false : true;
$priority = $request->variable('mail_priority_flag', MAIL_NORMAL_PRIORITY);
if (!check_form_key($form_key))
{
$error[] = $user->lang['FORM_INVALID'];
}
if (!$subject)
{
$error[] = $user->lang['NO_EMAIL_SUBJECT'];
}
if (!$message)
{
$error[] = $user->lang['NO_EMAIL_MESSAGE'];
}
if (!count($error))
{
if (!empty($usernames))
{
// If giving usernames the admin is able to email inactive users too...
$sql_ary = array(
'SELECT' => 'username, user_email, user_jabber, user_notify_type, user_lang',
'FROM' => array(
USERS_TABLE => '',
),
'WHERE' => $db->sql_in_set('username_clean', array_map('utf8_clean_string', $usernames)) . '
AND user_allow_massemail = 1',
'ORDER_BY' => 'user_lang, user_notify_type',
);
}
else
{
if ($group_id)
{
$sql_ary = array(
'SELECT' => 'u.user_email, u.username, u.username_clean, u.user_lang, u.user_jabber, u.user_notify_type',
'FROM' => array(
USERS_TABLE => 'u',
USER_GROUP_TABLE => 'ug',
),
'WHERE' => 'ug.group_id = ' . $group_id . '
AND ug.user_pending = 0
AND u.user_id = ug.user_id
AND u.user_allow_massemail = 1
AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')',
'ORDER_BY' => 'u.user_lang, u.user_notify_type',
);
}
else
{
$sql_ary = array(
'SELECT' => 'u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type',
'FROM' => array(
USERS_TABLE => 'u',
),
'WHERE' => 'u.user_allow_massemail = 1
AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')',
'ORDER_BY' => 'u.user_lang, u.user_notify_type',
);
}
// Mail banned or not
if (!isset($_REQUEST['mail_banned_flag']))
{
$sql_ary['WHERE'] .= ' AND (b.ban_id IS NULL
OR b.ban_exclude = 1)';
$sql_ary['LEFT_JOIN'] = array(
array(
'FROM' => array(
BANLIST_TABLE => 'b',
),
'ON' => 'u.user_id = b.ban_userid',
),
);
}
}
/**
* Modify sql query to change the list of users the email is sent to
*
* @event core.acp_email_modify_sql
* @var array sql_ary Array which is used to build the sql query
* @since 3.1.2-RC1
*/
$vars = array('sql_ary');
extract($phpbb_dispatcher->trigger_event('core.acp_email_modify_sql', compact($vars)));
$sql = $db->sql_build_query('SELECT', $sql_ary);
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
if (!$row)
{
$db->sql_freeresult($result);
trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$i = $j = 0;
// Send with BCC
// Maximum number of bcc recipients
$max_chunk_size = (int) $config['email_max_chunk_size'];
$email_list = array();
$old_lang = $row['user_lang'];
$old_notify_type = $row['user_notify_type'];
do
{
if (($row['user_notify_type'] == NOTIFY_EMAIL && $row['user_email']) ||
($row['user_notify_type'] == NOTIFY_IM && $row['user_jabber']) ||
($row['user_notify_type'] == NOTIFY_BOTH && ($row['user_email'] || $row['user_jabber'])))
{
if ($i == $max_chunk_size || $row['user_lang'] != $old_lang || $row['user_notify_type'] != $old_notify_type)
{
$i = 0;
if (count($email_list))
{
$j++;
}
$old_lang = $row['user_lang'];
$old_notify_type = $row['user_notify_type'];
}
$email_list[$j][$i]['lang'] = $row['user_lang'];
$email_list[$j][$i]['method'] = $row['user_notify_type'];
$email_list[$j][$i]['email'] = $row['user_email'];
$email_list[$j][$i]['name'] = $row['username'];
$email_list[$j][$i]['jabber'] = $row['user_jabber'];
$i++;
}
}
while ($row = $db->sql_fetchrow($result));
$db->sql_freeresult($result);
// Send the messages
if (!class_exists('messenger'))
{
include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
}
if (!function_exists('get_group_name'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
$messenger = new messenger($use_queue);
$errored = false;
$email_template = 'admin_send_email';
$template_data = array(
'CONTACT_EMAIL' => phpbb_get_board_contact($config, $phpEx),
'MESSAGE' => htmlspecialchars_decode($message),
);
$generate_log_entry = true;
/**
* Modify email template data before the emails are sent
*
* @event core.acp_email_send_before
* @var string email_template The template to be used for sending the email
* @var string subject The subject of the email
* @var array template_data Array with template data assigned to email template
* @var bool generate_log_entry If false, no log entry will be created
* @var array usernames Usernames which will be displayed in log entry, if it will be created
* @var int group_id The group this email will be sent to
* @var bool use_queue If true, email queue will be used for sending
* @var int priority Priority of sent emails
* @since 3.1.3-RC1
*/
$vars = array(
'email_template',
'subject',
'template_data',
'generate_log_entry',
'usernames',
'group_id',
'use_queue',
'priority',
);
extract($phpbb_dispatcher->trigger_event('core.acp_email_send_before', compact($vars)));
for ($i = 0, $size = count($email_list); $i < $size; $i++)
{
$used_lang = $email_list[$i][0]['lang'];
$used_method = $email_list[$i][0]['method'];
for ($j = 0, $list_size = count($email_list[$i]); $j < $list_size; $j++)
{
$email_row = $email_list[$i][$j];
$messenger->{((count($email_list[$i]) == 1) ? 'to' : 'bcc')}($email_row['email'], $email_row['name']);
$messenger->im($email_row['jabber'], $email_row['name']);
}
$messenger->template($email_template, $used_lang);
$messenger->anti_abuse_headers($config, $user);
$messenger->subject(htmlspecialchars_decode($subject));
$messenger->set_mail_priority($priority);
$messenger->assign_vars($template_data);
if (!($messenger->send($used_method)))
{
$errored = true;
}
}
unset($email_list);
$messenger->save_queue();
if ($generate_log_entry)
{
if (!empty($usernames))
{
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MASS_EMAIL', false, array(implode(', ', utf8_normalize_nfc($usernames))));
}
else
{
if ($group_id)
{
$group_name = get_group_name($group_id);
}
else
{
// Not great but the logging routine doesn't cope well with localising on the fly
$group_name = $user->lang['ALL_USERS'];
}
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MASS_EMAIL', false, array($group_name));
}
}
if (!$errored)
{
$message = ($use_queue) ? $user->lang['EMAIL_SENT_QUEUE'] : $user->lang['EMAIL_SENT'];
trigger_error($message . adm_back_link($this->u_action));
}
else
{
$message = sprintf($user->lang['EMAIL_SEND_ERROR'], '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&amp;mode=critical') . '">', '</a>');
trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
}
}
// Exclude bots and guests...
$sql = 'SELECT group_id
FROM ' . GROUPS_TABLE . "
WHERE group_name IN ('BOTS', 'GUESTS')";
$result = $db->sql_query($sql);
$exclude = array();
while ($row = $db->sql_fetchrow($result))
{
$exclude[] = $row['group_id'];
}
$db->sql_freeresult($result);
$select_list = '<option value="0"' . ((!$group_id) ? ' selected="selected"' : '') . '>' . $user->lang['ALL_USERS'] . '</option>';
$select_list .= group_select_options($group_id, $exclude);
$s_priority_options = '<option value="' . MAIL_LOW_PRIORITY . '">' . $user->lang['MAIL_LOW_PRIORITY'] . '</option>';
$s_priority_options .= '<option value="' . MAIL_NORMAL_PRIORITY . '" selected="selected">' . $user->lang['MAIL_NORMAL_PRIORITY'] . '</option>';
$s_priority_options .= '<option value="' . MAIL_HIGH_PRIORITY . '">' . $user->lang['MAIL_HIGH_PRIORITY'] . '</option>';
$template_data = array(
'S_WARNING' => (count($error)) ? true : false,
'WARNING_MSG' => (count($error)) ? implode('<br />', $error) : '',
'U_ACTION' => $this->u_action,
'S_GROUP_OPTIONS' => $select_list,
'USERNAMES' => implode("\n", $usernames),
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=acp_email&amp;field=usernames'),
'SUBJECT' => $subject,
'MESSAGE' => $message,
'S_PRIORITY_OPTIONS' => $s_priority_options,
);
/**
* Modify custom email template data before we display the form
*
* @event core.acp_email_display
* @var array template_data Array with template data assigned to email template
* @var array exclude Array with groups which are excluded from group selection
* @var array usernames Usernames which will be displayed in form
*
* @since 3.1.4-RC1
*/
$vars = array('template_data', 'exclude', 'usernames');
extract($phpbb_dispatcher->trigger_event('core.acp_email_display', compact($vars)));
$template->assign_vars($template_data);
}
}

View File

@@ -0,0 +1,665 @@
<?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.
*
*/
use phpbb\exception\exception_interface;
use phpbb\exception\version_check_exception;
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
class acp_extensions
{
var $u_action;
var $tpl_name;
var $page_title;
private $config;
private $template;
private $user;
private $log;
private $request;
private $phpbb_dispatcher;
private $ext_manager;
private $phpbb_container;
private $php_ini;
function main()
{
// Start the page
global $config, $user, $template, $request, $phpbb_extension_manager, $phpbb_root_path, $phpbb_log, $phpbb_dispatcher, $phpbb_container;
$this->config = $config;
$this->template = $template;
$this->user = $user;
$this->request = $request;
$this->log = $phpbb_log;
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->ext_manager = $phpbb_extension_manager;
$this->phpbb_container = $phpbb_container;
$this->php_ini = $this->phpbb_container->get('php_ini');
$this->user->add_lang(array('install', 'acp/extensions', 'migrator'));
$this->page_title = 'ACP_EXTENSIONS';
$action = $this->request->variable('action', 'list');
$ext_name = $this->request->variable('ext_name', '');
// What is a safe limit of execution time? Half the max execution time should be safe.
$safe_time_limit = ($this->php_ini->getNumeric('max_execution_time') / 2);
$start_time = time();
// Cancel action
if ($this->request->is_set_post('cancel'))
{
$action = 'list';
$ext_name = '';
}
if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($this->request->variable('hash', ''), $action . '.' . $ext_name))
{
trigger_error('FORM_INVALID', E_USER_WARNING);
}
/**
* Event to run a specific action on extension
*
* @event core.acp_extensions_run_action_before
* @var string action Action to run; if the event completes execution of the action, should be set to 'none'
* @var string u_action Url we are at
* @var string ext_name Extension name from request
* @var int safe_time_limit Safe limit of execution time
* @var int start_time Start time
* @var string tpl_name Template file to load
* @since 3.1.11-RC1
* @changed 3.2.1-RC1 Renamed to core.acp_extensions_run_action_before, added tpl_name, added action 'none'
*/
$u_action = $this->u_action;
$tpl_name = '';
$vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name');
extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_before', compact($vars)));
// In case they have been updated by the event
$this->u_action = $u_action;
$this->tpl_name = $tpl_name;
// If they've specified an extension, let's load the metadata manager and validate it.
if ($ext_name)
{
$md_manager = $this->ext_manager->create_extension_metadata_manager($ext_name);
try
{
$md_manager->get_metadata('all');
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
}
// What are we doing?
switch ($action)
{
case 'none':
// Intentionally empty, used by extensions that execute additional actions in the prior event
break;
case 'set_config_version_check_force_unstable':
$force_unstable = $this->request->variable('force_unstable', false);
if ($force_unstable)
{
$s_hidden_fields = build_hidden_fields(array(
'force_unstable' => $force_unstable,
));
confirm_box(false, $this->user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields);
}
else
{
$this->config->set('extension_force_unstable', false);
trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
}
break;
case 'list':
default:
if (confirm_box(true))
{
$this->config->set('extension_force_unstable', true);
trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
}
$this->list_enabled_exts();
$this->list_disabled_exts();
$this->list_available_exts();
$this->template->assign_vars(array(
'U_VERSIONCHECK_FORCE' => $this->u_action . '&amp;action=list&amp;versioncheck_force=1',
'FORCE_UNSTABLE' => $this->config['extension_force_unstable'],
'U_ACTION' => $this->u_action,
));
$this->tpl_name = 'acp_ext_list';
break;
case 'enable_pre':
try
{
$md_manager->validate_enable();
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
$extension = $this->ext_manager->get_extension($ext_name);
if (!$extension->is_enableable())
{
trigger_error($this->user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($this->ext_manager->is_enabled($ext_name))
{
redirect($this->u_action);
}
$this->tpl_name = 'acp_ext_enable';
$this->template->assign_vars(array(
'PRE' => true,
'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_ENABLE_CONFIRM', $md_manager->get_metadata('display-name')),
'U_ENABLE' => $this->u_action . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name) . '&amp;hash=' . generate_link_hash('enable.' . $ext_name),
));
break;
case 'enable':
try
{
$md_manager->validate_enable();
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
$extension = $this->ext_manager->get_extension($ext_name);
if (!$extension->is_enableable())
{
trigger_error($this->user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
try
{
while ($this->ext_manager->enable_step($ext_name))
{
// Are we approaching the time limit? If so we want to pause the update and continue after refreshing
if ((time() - $start_time) >= $safe_time_limit)
{
$this->template->assign_var('S_NEXT_STEP', true);
meta_refresh(0, $this->u_action . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name) . '&amp;hash=' . generate_link_hash('enable.' . $ext_name));
}
}
// Update custom style for admin area
$this->template->set_custom_style(array(
array(
'name' => 'adm',
'ext_path' => 'adm/style/',
),
), array($phpbb_root_path . 'adm/style'));
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name));
}
catch (\phpbb\db\migration\exception $e)
{
$this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user));
}
$this->tpl_name = 'acp_ext_enable';
$this->template->assign_vars(array(
'U_RETURN' => $this->u_action . '&amp;action=list',
));
break;
case 'disable_pre':
if (!$this->ext_manager->is_enabled($ext_name))
{
redirect($this->u_action);
}
$this->tpl_name = 'acp_ext_disable';
$this->template->assign_vars(array(
'PRE' => true,
'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DISABLE_CONFIRM', $md_manager->get_metadata('display-name')),
'U_DISABLE' => $this->u_action . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name) . '&amp;hash=' . generate_link_hash('disable.' . $ext_name),
));
break;
case 'disable':
if (!$this->ext_manager->is_enabled($ext_name))
{
redirect($this->u_action);
}
while ($this->ext_manager->disable_step($ext_name))
{
// Are we approaching the time limit? If so we want to pause the update and continue after refreshing
if ((time() - $start_time) >= $safe_time_limit)
{
$this->template->assign_var('S_NEXT_STEP', true);
meta_refresh(0, $this->u_action . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name) . '&amp;hash=' . generate_link_hash('disable.' . $ext_name));
}
}
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name));
$this->tpl_name = 'acp_ext_disable';
$this->template->assign_vars(array(
'U_RETURN' => $this->u_action . '&amp;action=list',
));
break;
case 'delete_data_pre':
if ($this->ext_manager->is_enabled($ext_name))
{
redirect($this->u_action);
}
$this->tpl_name = 'acp_ext_delete_data';
$this->template->assign_vars(array(
'PRE' => true,
'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DELETE_DATA_CONFIRM', $md_manager->get_metadata('display-name')),
'U_PURGE' => $this->u_action . '&amp;action=delete_data&amp;ext_name=' . urlencode($ext_name) . '&amp;hash=' . generate_link_hash('delete_data.' . $ext_name),
));
break;
case 'delete_data':
if ($this->ext_manager->is_enabled($ext_name))
{
redirect($this->u_action);
}
try
{
while ($this->ext_manager->purge_step($ext_name))
{
// Are we approaching the time limit? If so we want to pause the update and continue after refreshing
if ((time() - $start_time) >= $safe_time_limit)
{
$this->template->assign_var('S_NEXT_STEP', true);
meta_refresh(0, $this->u_action . '&amp;action=delete_data&amp;ext_name=' . urlencode($ext_name) . '&amp;hash=' . generate_link_hash('delete_data.' . $ext_name));
}
}
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_PURGE', time(), array($ext_name));
}
catch (\phpbb\db\migration\exception $e)
{
$this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user));
}
$this->tpl_name = 'acp_ext_delete_data';
$this->template->assign_vars(array(
'U_RETURN' => $this->u_action . '&amp;action=list',
));
break;
case 'details':
// Output it to the template
$meta = $md_manager->get_metadata('all');
$this->output_metadata_to_template($meta);
if (isset($meta['extra']['version-check']))
{
try
{
$updates_available = $this->ext_manager->version_check($md_manager, $this->request->variable('versioncheck_force', false), false, $this->config['extension_force_unstable'] ? 'unstable' : null);
$this->template->assign_vars(array(
'S_UP_TO_DATE' => empty($updates_available),
'UP_TO_DATE_MSG' => $this->user->lang(empty($updates_available) ? 'UP_TO_DATE' : 'NOT_UP_TO_DATE', $md_manager->get_metadata('display-name')),
));
$this->template->assign_block_vars('updates_available', $updates_available);
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_vars(array(
'S_VERSIONCHECK_FAIL' => true,
'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '',
));
}
$this->template->assign_var('S_VERSIONCHECK', true);
}
else
{
$this->template->assign_var('S_VERSIONCHECK', false);
}
$this->template->assign_vars(array(
'U_BACK' => $this->u_action . '&amp;action=list',
'U_VERSIONCHECK_FORCE' => $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name')),
));
$this->tpl_name = 'acp_ext_details';
break;
}
/**
* Event to run after a specific action on extension has completed
*
* @event core.acp_extensions_run_action_after
* @var string action Action that has run
* @var string u_action Url we are at
* @var string ext_name Extension name from request
* @var int safe_time_limit Safe limit of execution time
* @var int start_time Start time
* @var string tpl_name Template file to load
* @since 3.1.11-RC1
*/
$u_action = $this->u_action;
$tpl_name = $this->tpl_name;
$vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name');
extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_after', compact($vars)));
// In case they have been updated by the event
$this->u_action = $u_action;
$this->tpl_name = $tpl_name;
}
/**
* Lists all the enabled extensions and dumps to the template
*
* @return null
*/
public function list_enabled_exts()
{
$enabled_extension_meta_data = array();
foreach ($this->ext_manager->all_enabled() as $name => $location)
{
$md_manager = $this->ext_manager->create_extension_metadata_manager($name);
try
{
$meta = $md_manager->get_metadata('all');
$enabled_extension_meta_data[$name] = array(
'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'),
'META_VERSION' => $meta['version'],
);
if (isset($meta['extra']['version-check']))
{
try
{
$force_update = $this->request->variable('versioncheck_force', false);
$updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update);
$enabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
$enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
$enabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
}
catch (exception_interface $e)
{
// Ignore exceptions due to the version check
}
}
else
{
$enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_block_vars('disabled', array(
'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message),
'S_VERSIONCHECK' => false,
));
}
catch (\RuntimeException $e)
{
$enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
}
uasort($enabled_extension_meta_data, array($this, 'sort_extension_meta_data_table'));
foreach ($enabled_extension_meta_data as $name => $block_vars)
{
$block_vars['NAME'] = $name;
$block_vars['U_DETAILS'] = $this->u_action . '&amp;action=details&amp;ext_name=' . urlencode($name);
$this->template->assign_block_vars('enabled', $block_vars);
$this->output_actions('enabled', array(
'DISABLE' => $this->u_action . '&amp;action=disable_pre&amp;ext_name=' . urlencode($name),
));
}
}
/**
* Lists all the disabled extensions and dumps to the template
*
* @return null
*/
public function list_disabled_exts()
{
$disabled_extension_meta_data = array();
foreach ($this->ext_manager->all_disabled() as $name => $location)
{
$md_manager = $this->ext_manager->create_extension_metadata_manager($name);
try
{
$meta = $md_manager->get_metadata('all');
$disabled_extension_meta_data[$name] = array(
'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'),
'META_VERSION' => $meta['version'],
);
if (isset($meta['extra']['version-check']))
{
$force_update = $this->request->variable('versioncheck_force', false);
$updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update);
$disabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
$disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
$disabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
}
else
{
$disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
}
catch (version_check_exception $e)
{
$disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_block_vars('disabled', array(
'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message),
'S_VERSIONCHECK' => false,
));
}
catch (\RuntimeException $e)
{
$disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
}
uasort($disabled_extension_meta_data, array($this, 'sort_extension_meta_data_table'));
foreach ($disabled_extension_meta_data as $name => $block_vars)
{
$block_vars['NAME'] = $name;
$block_vars['U_DETAILS'] = $this->u_action . '&amp;action=details&amp;ext_name=' . urlencode($name);
$this->template->assign_block_vars('disabled', $block_vars);
$this->output_actions('disabled', array(
'ENABLE' => $this->u_action . '&amp;action=enable_pre&amp;ext_name=' . urlencode($name),
'DELETE_DATA' => $this->u_action . '&amp;action=delete_data_pre&amp;ext_name=' . urlencode($name),
));
}
}
/**
* Lists all the available extensions and dumps to the template
*
* @return null
*/
public function list_available_exts()
{
$uninstalled = array_diff_key($this->ext_manager->all_available(), $this->ext_manager->all_configured());
$available_extension_meta_data = array();
foreach ($uninstalled as $name => $location)
{
$md_manager = $this->ext_manager->create_extension_metadata_manager($name);
try
{
$meta = $md_manager->get_metadata('all');
$available_extension_meta_data[$name] = array(
'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'),
'META_VERSION' => $meta['version'],
);
if (isset($meta['extra']['version-check']))
{
$force_update = $this->request->variable('versioncheck_force', false);
$updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update);
$available_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
$available_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
$available_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
}
else
{
$available_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
}
catch (version_check_exception $e)
{
$available_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
catch (exception_interface $e)
{
$message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_block_vars('disabled', array(
'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message),
'S_VERSIONCHECK' => false,
));
}
}
uasort($available_extension_meta_data, array($this, 'sort_extension_meta_data_table'));
foreach ($available_extension_meta_data as $name => $block_vars)
{
$block_vars['NAME'] = $name;
$block_vars['U_DETAILS'] = $this->u_action . '&amp;action=details&amp;ext_name=' . urlencode($name);
$this->template->assign_block_vars('disabled', $block_vars);
$this->output_actions('disabled', array(
'ENABLE' => $this->u_action . '&amp;action=enable_pre&amp;ext_name=' . urlencode($name),
));
}
}
/**
* Output actions to a block
*
* @param string $block
* @param array $actions
*/
private function output_actions($block, $actions)
{
foreach ($actions as $lang => $url)
{
$this->template->assign_block_vars($block . '.actions', array(
'L_ACTION' => $this->user->lang('EXTENSION_' . $lang),
'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $lang . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $lang . '_EXPLAIN') : '',
'U_ACTION' => $url,
));
}
}
/**
* Sort helper for the table containing the metadata about the extensions.
*/
protected function sort_extension_meta_data_table($val1, $val2)
{
return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']);
}
/**
* Outputs extension metadata into the template
*
* @param array $metadata Array with all metadata for the extension
* @return null
*/
public function output_metadata_to_template($metadata)
{
$this->template->assign_vars(array(
'META_NAME' => $metadata['name'],
'META_TYPE' => $metadata['type'],
'META_DESCRIPTION' => (isset($metadata['description'])) ? $metadata['description'] : '',
'META_HOMEPAGE' => (isset($metadata['homepage'])) ? $metadata['homepage'] : '',
'META_VERSION' => $metadata['version'],
'META_TIME' => (isset($metadata['time'])) ? $metadata['time'] : '',
'META_LICENSE' => $metadata['license'],
'META_REQUIRE_PHP' => (isset($metadata['require']['php'])) ? $metadata['require']['php'] : '',
'META_REQUIRE_PHP_FAIL' => (isset($metadata['require']['php'])) ? false : true,
'META_REQUIRE_PHPBB' => (isset($metadata['extra']['soft-require']['phpbb/phpbb'])) ? $metadata['extra']['soft-require']['phpbb/phpbb'] : '',
'META_REQUIRE_PHPBB_FAIL' => (isset($metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true,
'META_DISPLAY_NAME' => (isset($metadata['extra']['display-name'])) ? $metadata['extra']['display-name'] : '',
));
foreach ($metadata['authors'] as $author)
{
$this->template->assign_block_vars('meta_authors', array(
'AUTHOR_NAME' => $author['name'],
'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '',
'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '',
'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '',
));
}
}
}

2179
includes/acp/acp_forums.php Normal file

File diff suppressed because it is too large Load Diff

1228
includes/acp/acp_groups.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
<?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;
}
class acp_help_phpbb
{
var $u_action;
function main($id, $mode)
{
global $config, $request, $template, $user, $phpbb_dispatcher, $phpbb_admin_path, $phpbb_root_path, $phpEx;
if (!class_exists('phpbb_questionnaire_data_collector'))
{
include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx);
}
$collect_url = "https://www.phpbb.com/stats/receive_stats.php";
$this->tpl_name = 'acp_help_phpbb';
$this->page_title = 'ACP_HELP_PHPBB';
$submit = ($request->is_set_post('submit')) ? true : false;
$form_key = 'acp_help_phpbb';
add_form_key($form_key);
$error = array();
if ($submit && !check_form_key($form_key))
{
$error[] = $user->lang['FORM_INVALID'];
}
// Do not write values if there is an error
if (count($error))
{
$submit = false;
}
// generate a unique id if necessary
if (!isset($config['questionnaire_unique_id']))
{
$install_id = unique_id();
$config->set('questionnaire_unique_id', $install_id);
}
else
{
$install_id = $config['questionnaire_unique_id'];
}
$collector = new phpbb_questionnaire_data_collector($install_id);
// Add data provider
$collector->add_data_provider(new phpbb_questionnaire_php_data_provider());
$collector->add_data_provider(new phpbb_questionnaire_system_data_provider());
$collector->add_data_provider(new phpbb_questionnaire_phpbb_data_provider($config));
/**
* Event to modify ACP help phpBB page and/or listen to submit
*
* @event core.acp_help_phpbb_submit_before
* @var boolean submit Do we display the form or process the submission
* @since 3.2.0-RC2
*/
$vars = array('submit');
extract($phpbb_dispatcher->trigger_event('core.acp_help_phpbb_submit_before', compact($vars)));
if ($submit)
{
$config->set('help_send_statistics', $request->variable('help_send_statistics', false));
$response = $request->variable('send_statistics_response', '');
$config->set('help_send_statistics_time', time());
if (!empty($response))
{
if ((strpos($response, 'Thank you') !== false || strpos($response, 'Flood protection') !== false))
{
trigger_error($user->lang('THANKS_SEND_STATISTICS') . adm_back_link($this->u_action));
}
else
{
trigger_error($user->lang('FAIL_SEND_STATISTICS') . adm_back_link($this->u_action));
}
}
trigger_error($user->lang('CONFIG_UPDATED') . adm_back_link($this->u_action));
}
$template->assign_vars(array(
'U_COLLECT_STATS' => $collect_url,
'S_COLLECT_STATS' => (!empty($config['help_send_statistics'])) ? true : false,
'RAW_DATA' => $collector->get_data_for_form(),
'U_ACP_MAIN' => append_sid("{$phpbb_admin_path}index.$phpEx"),
'U_ACTION' => $this->u_action,
// Pass earliest time we should try to send stats again
'COLLECT_STATS_TIME' => intval($config['help_send_statistics_time']) + 86400,
));
$raw = $collector->get_data_raw();
foreach ($raw as $provider => $data)
{
if ($provider == 'install_id')
{
$data = array($provider => $data);
}
$template->assign_block_vars('providers', array(
'NAME' => htmlspecialchars($provider),
));
foreach ($data as $key => $value)
{
if (is_array($value))
{
$value = utf8_wordwrap(serialize($value), 75, "\n", true);
}
$template->assign_block_vars('providers.values', array(
'KEY' => utf8_htmlspecialchars($key),
'VALUE' => utf8_htmlspecialchars($value),
));
}
}
}
}

999
includes/acp/acp_icons.php Normal file
View File

@@ -0,0 +1,999 @@
<?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;
}
/**
* @todo [smilies] check regular expressions for special char replacements (stored specialchared in db)
*/
class acp_icons
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $cache;
global $config, $phpbb_root_path;
global $request, $phpbb_container;
$user->add_lang('acp/posting');
// Set up general vars
$action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : $action;
$action = (isset($_POST['edit'])) ? 'edit' : $action;
$action = (isset($_POST['import'])) ? 'import' : $action;
$icon_id = $request->variable('id', 0);
$submit = $request->is_set_post('submit', false);
$form_key = 'acp_icons';
add_form_key($form_key);
$mode = ($mode == 'smilies') ? 'smilies' : 'icons';
$this->tpl_name = 'acp_icons';
// What are we working on?
switch ($mode)
{
case 'smilies':
$table = SMILIES_TABLE;
$lang = 'SMILIES';
$fields = 'smiley';
$img_path = $config['smilies_path'];
break;
case 'icons':
$table = ICONS_TABLE;
$lang = 'ICONS';
$fields = 'icons';
$img_path = $config['icons_path'];
break;
}
$this->page_title = 'ACP_' . $lang;
// Clear some arrays
$_images = $_paks = array();
$notice = '';
// Grab file list of paks and images
if ($action == 'edit' || $action == 'add' || $action == 'import')
{
$imglist = filelist($phpbb_root_path . $img_path, '');
foreach ($imglist as $path => $img_ary)
{
if (empty($img_ary))
{
continue;
}
asort($img_ary, SORT_STRING);
foreach ($img_ary as $img)
{
$img_size = getimagesize($phpbb_root_path . $img_path . '/' . $path . $img);
if (!$img_size[0] || !$img_size[1] || strlen($img) > 255)
{
continue;
}
// adjust the width and height to be lower than 128px while perserving the aspect ratio (for icons)
if ($mode == 'icons')
{
if ($img_size[0] > 127 && $img_size[0] > $img_size[1])
{
$img_size[1] = (int) ($img_size[1] * (127 / $img_size[0]));
$img_size[0] = 127;
}
else if ($img_size[1] > 127)
{
$img_size[0] = (int) ($img_size[0] * (127 / $img_size[1]));
$img_size[1] = 127;
}
}
$_images[$path . $img]['file'] = $path . $img;
$_images[$path . $img]['width'] = $img_size[0];
$_images[$path . $img]['height'] = $img_size[1];
}
}
unset($imglist);
if ($dir = @opendir($phpbb_root_path . $img_path))
{
while (($file = readdir($dir)) !== false)
{
if (is_file($phpbb_root_path . $img_path . '/' . $file) && preg_match('#\.pak$#i', $file))
{
$_paks[] = $file;
}
}
closedir($dir);
if (!empty($_paks))
{
asort($_paks, SORT_STRING);
}
}
}
// What shall we do today? Oops, I believe that's trademarked ...
switch ($action)
{
case 'edit':
unset($_images);
$_images = array();
// no break;
case 'add':
$smilies = $default_row = array();
$smiley_options = $order_list = $add_order_list = '';
if ($action == 'add' && $mode == 'smilies')
{
$sql = 'SELECT *
FROM ' . SMILIES_TABLE . '
ORDER BY smiley_order';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
if (empty($smilies[$row['smiley_url']]))
{
$smilies[$row['smiley_url']] = $row;
}
}
$db->sql_freeresult($result);
if (count($smilies))
{
foreach ($smilies as $row)
{
$selected = false;
if (!$smiley_options)
{
$selected = true;
$default_row = $row;
}
$smiley_options .= '<option value="' . $row['smiley_url'] . '"' . (($selected) ? ' selected="selected"' : '') . '>' . $row['smiley_url'] . '</option>';
$template->assign_block_vars('smile', array(
'SMILEY_URL' => addslashes($row['smiley_url']),
'CODE' => addslashes($row['code']),
'EMOTION' => addslashes($row['emotion']),
'WIDTH' => $row['smiley_width'],
'HEIGHT' => $row['smiley_height'],
'ORDER' => $row['smiley_order'] + 1,
));
}
}
}
$sql = "SELECT *
FROM $table
ORDER BY {$fields}_order " . (($icon_id || $action == 'add') ? 'DESC' : 'ASC');
$result = $db->sql_query($sql);
$data = array();
$after = false;
$order_lists = array('', '');
$add_order_lists = array('', '');
$display_count = 0;
while ($row = $db->sql_fetchrow($result))
{
if ($action == 'add')
{
unset($_images[$row[$fields . '_url']]);
}
if ($row[$fields . '_id'] == $icon_id)
{
$after = true;
$data[$row[$fields . '_url']] = $row;
}
else
{
if ($action == 'edit' && !$icon_id)
{
$data[$row[$fields . '_url']] = $row;
}
$selected = '';
if (!empty($after))
{
$selected = ' selected="selected"';
$after = false;
}
if ($row['display_on_posting'])
{
$display_count++;
}
$after_txt = ($mode == 'smilies') ? $row['code'] : $row['icons_url'];
$order_lists[$row['display_on_posting']] = '<option value="' . ($row[$fields . '_order'] + 1) . '"' . $selected . '>' . sprintf($user->lang['AFTER_' . $lang], ' -&gt; ' . $after_txt) . '</option>' . $order_lists[$row['display_on_posting']];
if (!empty($default_row))
{
$add_order_lists[$row['display_on_posting']] = '<option value="' . ($row[$fields . '_order'] + 1) . '"' . (($row[$fields . '_id'] == $default_row['smiley_id']) ? ' selected="selected"' : '') . '>' . sprintf($user->lang['AFTER_' . $lang], ' -&gt; ' . $after_txt) . '</option>' . $add_order_lists[$row['display_on_posting']];
}
}
}
$db->sql_freeresult($result);
$order_list = '<option value="1"' . ((!isset($after)) ? ' selected="selected"' : '') . '>' . $user->lang['FIRST'] . '</option>';
$add_order_list = '<option value="1">' . $user->lang['FIRST'] . '</option>';
if ($action == 'add')
{
$data = $_images;
}
$colspan = (($mode == 'smilies') ? 7 : 6);
$colspan += ($icon_id) ? 1 : 0;
$colspan += ($action == 'add') ? 2 : 0;
$template->assign_vars(array(
'S_EDIT' => true,
'S_SMILIES' => ($mode == 'smilies') ? true : false,
'S_ADD' => ($action == 'add') ? true : false,
'S_ORDER_LIST_DISPLAY' => $order_list . $order_lists[1],
'S_ORDER_LIST_UNDISPLAY' => $order_list . $order_lists[0],
'S_ORDER_LIST_DISPLAY_COUNT' => $display_count + 1,
'L_TITLE' => $user->lang['ACP_' . $lang],
'L_EXPLAIN' => $user->lang['ACP_' . $lang . '_EXPLAIN'],
'L_CONFIG' => $user->lang[$lang . '_CONFIG'],
'L_URL' => $user->lang[$lang . '_URL'],
'L_LOCATION' => $user->lang[$lang . '_LOCATION'],
'L_WIDTH' => $user->lang[$lang . '_WIDTH'],
'L_HEIGHT' => $user->lang[$lang . '_HEIGHT'],
'L_ORDER' => $user->lang[$lang . '_ORDER'],
'L_NO_ICONS' => $user->lang['NO_' . $lang . '_' . strtoupper($action)],
'COLSPAN' => $colspan,
'ID' => $icon_id,
'U_BACK' => $this->u_action,
'U_ACTION' => $this->u_action . '&amp;action=' . (($action == 'add') ? 'create' : 'modify'),
));
foreach ($data as $img => $img_row)
{
$template->assign_block_vars('items', array(
'IMG' => $img,
'A_IMG' => addslashes($img),
'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $img,
'CODE' => ($mode == 'smilies' && isset($img_row['code'])) ? $img_row['code'] : '',
'EMOTION' => ($mode == 'smilies' && isset($img_row['emotion'])) ? $img_row['emotion'] : '',
'S_ID' => (isset($img_row[$fields . '_id'])) ? true : false,
'ID' => (isset($img_row[$fields . '_id'])) ? $img_row[$fields . '_id'] : 0,
'WIDTH' => (!empty($img_row[$fields .'_width'])) ? $img_row[$fields .'_width'] : $img_row['width'],
'HEIGHT' => (!empty($img_row[$fields .'_height'])) ? $img_row[$fields .'_height'] : $img_row['height'],
'TEXT_ALT' => ($mode == 'icons' && !empty($img_row['icons_alt'])) ? $img_row['icons_alt'] : $img,
'ALT' => ($mode == 'icons' && !empty($img_row['icons_alt'])) ? $img_row['icons_alt'] : '',
'POSTING_CHECKED' => (!empty($img_row['display_on_posting']) || $action == 'add') ? ' checked="checked"' : '',
));
}
// Ok, another row for adding an addition code for a pre-existing image...
if ($action == 'add' && $mode == 'smilies' && count($smilies))
{
$template->assign_vars(array(
'S_ADD_CODE' => true,
'S_IMG_OPTIONS' => $smiley_options,
'S_ADD_ORDER_LIST_DISPLAY' => $add_order_list . $add_order_lists[1],
'S_ADD_ORDER_LIST_UNDISPLAY' => $add_order_list . $add_order_lists[0],
'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $default_row['smiley_url'],
'IMG_PATH' => $img_path,
'CODE' => $default_row['code'],
'EMOTION' => $default_row['emotion'],
'WIDTH' => $default_row['smiley_width'],
'HEIGHT' => $default_row['smiley_height'],
));
}
return;
break;
case 'create':
case 'modify':
if (!check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Get items to create/modify
$images = (isset($_POST['image'])) ? array_keys($request->variable('image', array('' => 0))) : array();
// Now really get the items
$image_id = (isset($_POST['id'])) ? $request->variable('id', array('' => 0)) : array();
$image_order = (isset($_POST['order'])) ? $request->variable('order', array('' => 0)) : array();
$image_width = (isset($_POST['width'])) ? $request->variable('width', array('' => 0)) : array();
$image_height = (isset($_POST['height'])) ? $request->variable('height', array('' => 0)) : array();
$image_add = (isset($_POST['add_img'])) ? $request->variable('add_img', array('' => 0)) : array();
$image_emotion = $request->variable('emotion', array('' => ''), true);
$image_code = $request->variable('code', array('' => ''), true);
$image_alt = ($request->is_set_post('alt')) ? $request->variable('alt', array('' => ''), true) : array();
$image_display_on_posting = (isset($_POST['display_on_posting'])) ? $request->variable('display_on_posting', array('' => 0)) : array();
// Ok, add the relevant bits if we are adding new codes to existing emoticons...
if ($request->variable('add_additional_code', false, false, \phpbb\request\request_interface::POST))
{
$add_image = $request->variable('add_image', '');
$add_code = $request->variable('add_code', '', true);
$add_emotion = $request->variable('add_emotion', '', true);
if ($add_image && $add_emotion && $add_code)
{
$images[] = $add_image;
$image_add[$add_image] = true;
$image_code[$add_image] = $add_code;
$image_emotion[$add_image] = $add_emotion;
$image_width[$add_image] = $request->variable('add_width', 0);
$image_height[$add_image] = $request->variable('add_height', 0);
if ($request->variable('add_display_on_posting', false, false, \phpbb\request\request_interface::POST))
{
$image_display_on_posting[$add_image] = 1;
}
$image_order[$add_image] = $request->variable('add_order', 0);
}
}
if ($mode == 'smilies' && $action == 'create')
{
$smiley_count = $this->item_count($table);
$addable_smileys_count = count($images);
foreach ($images as $image)
{
if (!isset($image_add[$image]))
{
--$addable_smileys_count;
}
}
if ($smiley_count + $addable_smileys_count > SMILEY_LIMIT)
{
trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING);
}
}
$icons_updated = 0;
$errors = array();
foreach ($images as $image)
{
if ($mode == 'smilies' && ($image_emotion[$image] == '' || $image_code[$image] == ''))
{
$errors[$image] = 'SMILIE_NO_' . (($image_emotion[$image] == '') ? 'EMOTION' : 'CODE');
}
else if ($action == 'create' && !isset($image_add[$image]))
{
// skip images where add wasn't checked
}
else if (!file_exists($phpbb_root_path . $img_path . '/' . $image))
{
$errors[$image] = 'SMILIE_NO_FILE';
}
else
{
if ($image_width[$image] == 0 || $image_height[$image] == 0)
{
$img_size = getimagesize($phpbb_root_path . $img_path . '/' . $image);
$image_width[$image] = $img_size[0];
$image_height[$image] = $img_size[1];
}
// Adjust image width/height for icons
if ($mode == 'icons')
{
if ($image_width[$image] > 127 && $image_width[$image] > $image_height[$image])
{
$image_height[$image] = (int) ($image_height[$image] * (127 / $image_width[$image]));
$image_width[$image] = 127;
}
else if ($image_height[$image] > 127)
{
$image_width[$image] = (int) ($image_width[$image] * (127 / $image_height[$image]));
$image_height[$image] = 127;
}
}
$img_sql = array(
$fields . '_url' => $image,
$fields . '_width' => $image_width[$image],
$fields . '_height' => $image_height[$image],
'display_on_posting' => (isset($image_display_on_posting[$image])) ? 1 : 0,
);
if ($mode == 'smilies')
{
$img_sql = array_merge($img_sql, array(
'emotion' => $image_emotion[$image],
'code' => $image_code[$image])
);
}
if ($mode == 'icons')
{
$img_sql = array_merge($img_sql, array(
'icons_alt' => $image_alt[$image])
);
}
// Image_order holds the 'new' order value
if (!empty($image_order[$image]))
{
$img_sql = array_merge($img_sql, array(
$fields . '_order' => $image_order[$image])
);
// Since we always add 'after' an item, we just need to increase all following + the current by one
$sql = "UPDATE $table
SET {$fields}_order = {$fields}_order + 1
WHERE {$fields}_order >= {$image_order[$image]}";
$db->sql_query($sql);
// If we adjust the order, we need to adjust all other orders too - they became inaccurate...
foreach ($image_order as $_image => $_order)
{
if ($_image == $image)
{
continue;
}
if ($_order >= $image_order[$image])
{
$image_order[$_image]++;
}
}
}
if ($action == 'modify' && !empty($image_id[$image]))
{
$sql = "UPDATE $table
SET " . $db->sql_build_array('UPDATE', $img_sql) . "
WHERE {$fields}_id = " . $image_id[$image];
$db->sql_query($sql);
$icons_updated++;
}
else if ($action !== 'modify')
{
$sql = "INSERT INTO $table " . $db->sql_build_array('INSERT', $img_sql);
$db->sql_query($sql);
$icons_updated++;
}
}
}
$cache->destroy('_icons');
$cache->destroy('sql', $table);
$phpbb_container->get('text_formatter.cache')->invalidate();
$level = ($icons_updated) ? E_USER_NOTICE : E_USER_WARNING;
$errormsgs = '';
foreach ($errors as $img => $error)
{
$errormsgs .= '<br />' . sprintf($user->lang[$error], $img);
}
if ($action == 'modify')
{
trigger_error($user->lang($lang . '_EDITED', $icons_updated) . $errormsgs . adm_back_link($this->u_action), $level);
}
else
{
trigger_error($user->lang($lang . '_ADDED', $icons_updated) . $errormsgs . adm_back_link($this->u_action), $level);
}
break;
case 'import':
$pak = $request->variable('pak', '');
$current = $request->variable('current', '');
if ($pak != '')
{
$order = 0;
if (!check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (!($pak_ary = @file($phpbb_root_path . $img_path . '/' . $pak)))
{
trigger_error($user->lang['PAK_FILE_NOT_READABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Make sure the pak_ary is valid
foreach ($pak_ary as $pak_entry)
{
if (preg_match_all("#'(.*?)', ?#", $pak_entry, $data))
{
if ((count($data[1]) != 4 && $mode == 'icons') ||
((count($data[1]) != 6 || (empty($data[1][4]) || empty($data[1][5]))) && $mode == 'smilies' ))
{
trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
else
{
trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
// The user has already selected a smilies_pak file
if ($current == 'delete')
{
switch ($db->get_sql_layer())
{
case 'sqlite3':
$db->sql_query('DELETE FROM ' . $table);
break;
default:
$db->sql_query('TRUNCATE TABLE ' . $table);
break;
}
switch ($mode)
{
case 'smilies':
break;
case 'icons':
// Reset all icon_ids
$db->sql_query('UPDATE ' . TOPICS_TABLE . ' SET icon_id = 0');
$db->sql_query('UPDATE ' . POSTS_TABLE . ' SET icon_id = 0');
break;
}
}
else
{
$cur_img = array();
$field_sql = ($mode == 'smilies') ? 'code' : 'icons_url';
$sql = "SELECT $field_sql
FROM $table";
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
++$order;
$cur_img[$row[$field_sql]] = 1;
}
$db->sql_freeresult($result);
}
if ($mode == 'smilies')
{
$smiley_count = $this->item_count($table);
if ($smiley_count + count($pak_ary) > SMILEY_LIMIT)
{
trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING);
}
}
foreach ($pak_ary as $pak_entry)
{
$data = array();
if (preg_match_all("#'(.*?)', ?#", $pak_entry, $data))
{
if ((count($data[1]) != 4 && $mode == 'icons') ||
(count($data[1]) != 6 && $mode == 'smilies'))
{
trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Stripslash here because it got addslashed before... (on export)
$img = stripslashes($data[1][0]);
$width = stripslashes($data[1][1]);
$height = stripslashes($data[1][2]);
$display_on_posting = stripslashes($data[1][3]);
if (isset($data[1][4]) && isset($data[1][5]))
{
$emotion = stripslashes($data[1][4]);
$code = stripslashes($data[1][5]);
}
if ($current == 'replace' &&
(($mode == 'smilies' && !empty($cur_img[$code])) ||
($mode == 'icons' && !empty($cur_img[$img]))))
{
$replace_sql = ($mode == 'smilies') ? $code : $img;
$sql = array(
$fields . '_url' => $img,
$fields . '_height' => (int) $height,
$fields . '_width' => (int) $width,
'display_on_posting' => (int) $display_on_posting,
);
if ($mode == 'smilies')
{
$sql = array_merge($sql, array(
'emotion' => $emotion,
));
}
$sql = "UPDATE $table SET " . $db->sql_build_array('UPDATE', $sql) . "
WHERE $field_sql = '" . $db->sql_escape($replace_sql) . "'";
$db->sql_query($sql);
}
else
{
++$order;
$sql = array(
$fields . '_url' => $img,
$fields . '_height' => (int) $height,
$fields . '_width' => (int) $width,
$fields . '_order' => (int) $order,
'display_on_posting'=> (int) $display_on_posting,
);
if ($mode == 'smilies')
{
$sql = array_merge($sql, array(
'code' => $code,
'emotion' => $emotion,
));
}
$db->sql_query("INSERT INTO $table " . $db->sql_build_array('INSERT', $sql));
}
}
}
$cache->destroy('_icons');
$cache->destroy('sql', $table);
$phpbb_container->get('text_formatter.cache')->invalidate();
trigger_error($user->lang[$lang . '_IMPORT_SUCCESS'] . adm_back_link($this->u_action));
}
else
{
$pak_options = '';
foreach ($_paks as $pak)
{
$pak_options .= '<option value="' . $pak . '">' . htmlspecialchars($pak) . '</option>';
}
$template->assign_vars(array(
'S_CHOOSE_PAK' => true,
'S_PAK_OPTIONS' => $pak_options,
'L_TITLE' => $user->lang['ACP_' . $lang],
'L_EXPLAIN' => $user->lang['ACP_' . $lang . '_EXPLAIN'],
'L_NO_PAK_OPTIONS' => $user->lang['NO_' . $lang . '_PAK'],
'L_CURRENT' => $user->lang['CURRENT_' . $lang],
'L_CURRENT_EXPLAIN' => $user->lang['CURRENT_' . $lang . '_EXPLAIN'],
'L_IMPORT_SUBMIT' => $user->lang['IMPORT_' . $lang],
'U_BACK' => $this->u_action,
'U_ACTION' => $this->u_action . '&amp;action=import',
)
);
}
break;
case 'export':
$this->page_title = 'EXPORT_' . $lang;
$this->tpl_name = 'message_body';
$template->assign_vars(array(
'MESSAGE_TITLE' => $user->lang['EXPORT_' . $lang],
'MESSAGE_TEXT' => sprintf($user->lang['EXPORT_' . $lang . '_EXPLAIN'], '<a href="' . $this->u_action . '&amp;action=send&amp;hash=' . generate_link_hash('acp_icons') . '">', '</a>'),
'S_USER_NOTICE' => true,
)
);
return;
break;
case 'send':
if (!check_link_hash($request->variable('hash', ''), 'acp_icons'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = "SELECT *
FROM $table
ORDER BY {$fields}_order";
$result = $db->sql_query($sql);
$pak = '';
while ($row = $db->sql_fetchrow($result))
{
$pak .= "'" . addslashes($row[$fields . '_url']) . "', ";
$pak .= "'" . addslashes($row[$fields . '_width']) . "', ";
$pak .= "'" . addslashes($row[$fields . '_height']) . "', ";
$pak .= "'" . addslashes($row['display_on_posting']) . "', ";
if ($mode == 'smilies')
{
$pak .= "'" . addslashes($row['emotion']) . "', ";
$pak .= "'" . addslashes($row['code']) . "', ";
}
$pak .= "\n";
}
$db->sql_freeresult($result);
if ($pak != '')
{
garbage_collection();
header('Cache-Control: public');
// Send out the Headers
header('Content-Type: text/x-delimtext; name="' . $mode . '.pak"');
header('Content-Disposition: inline; filename="' . $mode . '.pak"');
echo $pak;
flush();
exit;
}
else
{
trigger_error($user->lang['NO_' . strtoupper($fields) . '_EXPORT'] . adm_back_link($this->u_action), E_USER_WARNING);
}
break;
case 'delete':
if (confirm_box(true))
{
$sql = "DELETE FROM $table
WHERE {$fields}_id = $icon_id";
$db->sql_query($sql);
switch ($mode)
{
case 'smilies':
break;
case 'icons':
// Reset appropriate icon_ids
$db->sql_query('UPDATE ' . TOPICS_TABLE . "
SET icon_id = 0
WHERE icon_id = $icon_id");
$db->sql_query('UPDATE ' . POSTS_TABLE . "
SET icon_id = 0
WHERE icon_id = $icon_id");
break;
}
$notice = $user->lang[$lang . '_DELETED'];
$cache->destroy('_icons');
$cache->destroy('sql', $table);
$phpbb_container->get('text_formatter.cache')->invalidate();
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'MESSAGE_TITLE' => $user->lang['INFORMATION'],
'MESSAGE_TEXT' => $notice,
'REFRESH_DATA' => array(
'time' => 3
)
));
}
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'id' => $icon_id,
'action' => 'delete',
)));
}
break;
case 'move_up':
case 'move_down':
if (!check_link_hash($request->variable('hash', ''), 'acp_icons'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Get current order id...
$sql = "SELECT {$fields}_order as current_order
FROM $table
WHERE {$fields}_id = $icon_id";
$result = $db->sql_query($sql);
$current_order = (int) $db->sql_fetchfield('current_order');
$db->sql_freeresult($result);
if ($current_order == 0 && $action == 'move_up')
{
break;
}
// on move_down, switch position with next order_id...
// on move_up, switch position with previous order_id...
$switch_order_id = ($action == 'move_down') ? $current_order + 1 : $current_order - 1;
//
$sql = "UPDATE $table
SET {$fields}_order = $current_order
WHERE {$fields}_order = $switch_order_id
AND {$fields}_id <> $icon_id";
$db->sql_query($sql);
$move_executed = (bool) $db->sql_affectedrows();
// Only update the other entry too if the previous entry got updated
if ($move_executed)
{
$sql = "UPDATE $table
SET {$fields}_order = $switch_order_id
WHERE {$fields}_order = $current_order
AND {$fields}_id = $icon_id";
$db->sql_query($sql);
}
$cache->destroy('_icons');
$cache->destroy('sql', $table);
$phpbb_container->get('text_formatter.cache')->invalidate();
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'success' => $move_executed,
));
}
break;
}
// By default, check that image_order is valid and fix it if necessary
$sql = "SELECT {$fields}_id AS order_id, {$fields}_order AS fields_order
FROM $table
ORDER BY display_on_posting DESC, {$fields}_order";
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
$order = 0;
do
{
++$order;
if ($row['fields_order'] != $order)
{
$db->sql_query("UPDATE $table
SET {$fields}_order = $order
WHERE {$fields}_id = " . $row['order_id']);
}
}
while ($row = $db->sql_fetchrow($result));
}
$db->sql_freeresult($result);
$template->assign_vars(array(
'L_TITLE' => $user->lang['ACP_' . $lang],
'L_EXPLAIN' => $user->lang['ACP_' . $lang . '_EXPLAIN'],
'L_IMPORT' => $user->lang['IMPORT_' . $lang],
'L_EXPORT' => $user->lang['EXPORT_' . $lang],
'L_NOT_DISPLAYED' => $user->lang[$lang . '_NOT_DISPLAYED'],
'L_ICON_ADD' => $user->lang['ADD_' . $lang],
'L_ICON_EDIT' => $user->lang['EDIT_' . $lang],
'NOTICE' => $notice,
'COLSPAN' => ($mode == 'smilies') ? 5 : 3,
'S_SMILIES' => ($mode == 'smilies') ? true : false,
'U_ACTION' => $this->u_action,
'U_IMPORT' => $this->u_action . '&amp;action=import',
'U_EXPORT' => $this->u_action . '&amp;action=export',
)
);
/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$pagination_start = $request->variable('start', 0);
$spacer = false;
$item_count = $this->item_count($table);
$sql = "SELECT *
FROM $table
ORDER BY {$fields}_order ASC";
$result = $db->sql_query_limit($sql, $config['smilies_per_page'], $pagination_start);
while ($row = $db->sql_fetchrow($result))
{
$alt_text = ($mode == 'smilies') ? $row['code'] : (($mode == 'icons' && !empty($row['icons_alt'])) ? $row['icons_alt'] : $row['icons_url']);
$template->assign_block_vars('items', array(
'S_SPACER' => (!$spacer && !$row['display_on_posting']) ? true : false,
'ALT_TEXT' => $alt_text,
'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $row[$fields . '_url'],
'WIDTH' => $row[$fields . '_width'],
'HEIGHT' => $row[$fields . '_height'],
'CODE' => (isset($row['code'])) ? $row['code'] : '',
'EMOTION' => (isset($row['emotion'])) ? $row['emotion'] : '',
'U_EDIT' => $this->u_action . '&amp;action=edit&amp;id=' . $row[$fields . '_id'],
'U_DELETE' => $this->u_action . '&amp;action=delete&amp;id=' . $row[$fields . '_id'],
'U_MOVE_UP' => $this->u_action . '&amp;action=move_up&amp;id=' . $row[$fields . '_id'] . '&amp;start=' . $pagination_start . '&amp;hash=' . generate_link_hash('acp_icons'),
'U_MOVE_DOWN' => $this->u_action . '&amp;action=move_down&amp;id=' . $row[$fields . '_id'] . '&amp;start=' . $pagination_start . '&amp;hash=' . generate_link_hash('acp_icons'),
));
if (!$spacer && !$row['display_on_posting'])
{
$spacer = true;
}
}
$db->sql_freeresult($result);
$pagination->generate_template_pagination($this->u_action, 'pagination', 'start', $item_count, $config['smilies_per_page'], $pagination_start);
}
/**
* Returns the count of smilies or icons in the database
*
* @param string $table The table of items to count.
* @return int number of items
*/
/* private */ function item_count($table)
{
global $db;
$sql = "SELECT COUNT(*) AS item_count
FROM $table";
$result = $db->sql_query($sql);
$item_count = (int) $db->sql_fetchfield('item_count');
$db->sql_freeresult($result);
return $item_count;
}
}

View File

@@ -0,0 +1,322 @@
<?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;
}
class acp_inactive
{
var $u_action;
var $p_master;
function __construct($p_master)
{
$this->p_master = $p_master;
}
function main($id, $mode)
{
global $config, $db, $user, $auth, $template, $phpbb_container, $phpbb_log, $request;
global $phpbb_root_path, $phpbb_admin_path, $phpEx;
if (!function_exists('user_active_flip'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
$user->add_lang('memberlist');
$action = $request->variable('action', '');
$mark = (isset($_REQUEST['mark'])) ? $request->variable('mark', array(0)) : array();
$start = $request->variable('start', 0);
$submit = isset($_POST['submit']);
// Sort keys
$sort_days = $request->variable('st', 0);
$sort_key = $request->variable('sk', 'i');
$sort_dir = $request->variable('sd', 'd');
$form_key = 'acp_inactive';
add_form_key($form_key);
/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// We build the sort key and per page settings here, because they may be needed later
// Number of entries to display
$per_page = $request->variable('users_per_page', (int) $config['topics_per_page']);
// Sorting
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('i' => $user->lang['SORT_INACTIVE'], 'j' => $user->lang['SORT_REG_DATE'], 'l' => $user->lang['SORT_LAST_VISIT'], 'd' => $user->lang['SORT_LAST_REMINDER'], 'r' => $user->lang['SORT_REASON'], 'u' => $user->lang['SORT_USERNAME'], 'p' => $user->lang['SORT_POSTS'], 'e' => $user->lang['SORT_REMINDER']);
$sort_by_sql = array('i' => 'user_inactive_time', 'j' => 'user_regdate', 'l' => 'user_lastvisit', 'd' => 'user_reminded_time', 'r' => 'user_inactive_reason', 'u' => 'username_clean', 'p' => 'user_posts', 'e' => 'user_reminded');
$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
if ($submit && count($mark))
{
if ($action !== 'delete' && !check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
switch ($action)
{
case 'activate':
case 'delete':
$sql = 'SELECT user_id, username
FROM ' . USERS_TABLE . '
WHERE ' . $db->sql_in_set('user_id', $mark);
$result = $db->sql_query($sql);
$user_affected = array();
while ($row = $db->sql_fetchrow($result))
{
$user_affected[$row['user_id']] = $row['username'];
}
$db->sql_freeresult($result);
if ($action == 'activate')
{
// Get those 'being activated'...
$sql = 'SELECT user_id, username' . (($config['require_activation'] == USER_ACTIVATION_ADMIN) ? ', user_email, user_lang' : '') . '
FROM ' . USERS_TABLE . '
WHERE ' . $db->sql_in_set('user_id', $mark) . '
AND user_type = ' . USER_INACTIVE;
$result = $db->sql_query($sql);
$inactive_users = array();
while ($row = $db->sql_fetchrow($result))
{
$inactive_users[] = $row;
}
$db->sql_freeresult($result);
user_active_flip('activate', $mark);
if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !empty($inactive_users))
{
if (!class_exists('messenger'))
{
include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
}
$messenger = new messenger(false);
foreach ($inactive_users as $row)
{
$messenger->template('admin_welcome_activated', $row['user_lang']);
$messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($row['username']))
);
$messenger->send(NOTIFY_EMAIL);
}
$messenger->save_queue();
}
if (!empty($inactive_users))
{
foreach ($inactive_users as $row)
{
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_ACTIVE', false, array($row['username']));
$phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_ACTIVE_USER', false, array(
'reportee_id' => $row['user_id']
));
}
trigger_error(sprintf($user->lang['LOG_INACTIVE_ACTIVATE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action)));
}
// For activate we really need to redirect, else a refresh can result in users being deactivated again
$u_action = $this->u_action . "&amp;$u_sort_param&amp;start=$start";
$u_action .= ($per_page != $config['topics_per_page']) ? "&amp;users_per_page=$per_page" : '';
redirect($u_action);
}
else if ($action == 'delete')
{
if (confirm_box(true))
{
if (!$auth->acl_get('a_userdel'))
{
send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
user_delete('retain', $mark, true);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_INACTIVE_' . strtoupper($action), false, array(implode(', ', $user_affected)));
trigger_error(sprintf($user->lang['LOG_INACTIVE_DELETE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action)));
}
else
{
$s_hidden_fields = array(
'mode' => $mode,
'action' => $action,
'mark' => $mark,
'submit' => 1,
'start' => $start,
);
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields));
}
}
break;
case 'remind':
if (empty($config['email_enable']))
{
trigger_error($user->lang['EMAIL_DISABLED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type, user_regdate, user_actkey
FROM ' . USERS_TABLE . '
WHERE ' . $db->sql_in_set('user_id', $mark) . '
AND user_inactive_reason';
$sql .= ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? ' = ' . INACTIVE_REMIND : ' <> ' . INACTIVE_MANUAL;
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
// Send the messages
if (!class_exists('messenger'))
{
include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
}
$messenger = new messenger();
$usernames = $user_ids = array();
do
{
$messenger->template('user_remind_inactive', $row['user_lang']);
$messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($row['username']),
'REGISTER_DATE' => $user->format_date($row['user_regdate'], false, true),
'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u=" . $row['user_id'] . '&k=' . $row['user_actkey'])
);
$messenger->send($row['user_notify_type']);
$usernames[] = $row['username'];
$user_ids[] = (int) $row['user_id'];
}
while ($row = $db->sql_fetchrow($result));
$messenger->save_queue();
// Add the remind state to the database
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_reminded = user_reminded + 1,
user_reminded_time = ' . time() . '
WHERE ' . $db->sql_in_set('user_id', $user_ids);
$db->sql_query($sql);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_INACTIVE_REMIND', false, array(implode(', ', $usernames)));
trigger_error(sprintf($user->lang['LOG_INACTIVE_REMIND'], implode($user->lang['COMMA_SEPARATOR'], $usernames) . ' ' . adm_back_link($this->u_action)));
}
$db->sql_freeresult($result);
// For remind we really need to redirect, else a refresh can result in more than one reminder
$u_action = $this->u_action . "&amp;$u_sort_param&amp;start=$start";
$u_action .= ($per_page != $config['topics_per_page']) ? "&amp;users_per_page=$per_page" : '';
redirect($u_action);
break;
}
}
// Define where and sort sql for use in displaying logs
$sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0;
$sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
$inactive = array();
$inactive_count = 0;
$start = view_inactive_users($inactive, $inactive_count, $per_page, $start, $sql_where, $sql_sort);
foreach ($inactive as $row)
{
$template->assign_block_vars('inactive', array(
'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']),
'REMINDED_DATE' => $user->format_date($row['user_reminded_time']),
'JOINED' => $user->format_date($row['user_regdate']),
'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']),
'REASON' => $row['inactive_reason'],
'USER_ID' => $row['user_id'],
'POSTS' => ($row['user_posts']) ? $row['user_posts'] : 0,
'REMINDED' => $row['user_reminded'],
'REMINDED_EXPLAIN' => $user->lang('USER_LAST_REMINDED', (int) $row['user_reminded'], $user->format_date($row['user_reminded_time'])),
'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview&amp;redirect=acp_inactive')),
'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']),
'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']),
'USER_EMAIL' => $row['user_email'],
'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&amp;mode=overview&amp;u={$row['user_id']}"),
'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$row['user_id']}&amp;sr=posts") : '',
));
}
$option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE');
if ($config['email_enable'])
{
$option_ary += array('remind' => 'REMIND');
}
$base_url = $this->u_action . "&amp;$u_sort_param&amp;users_per_page=$per_page";
$pagination->generate_template_pagination($base_url, 'pagination', 'start', $inactive_count, $per_page, $start);
$template->assign_vars(array(
'S_INACTIVE_USERS' => true,
'S_INACTIVE_OPTIONS' => build_select($option_ary),
'S_LIMIT_DAYS' => $s_limit_days,
'S_SORT_KEY' => $s_sort_key,
'S_SORT_DIR' => $s_sort_dir,
'USERS_PER_PAGE' => $per_page,
'U_ACTION' => $this->u_action . "&amp;$u_sort_param&amp;users_per_page=$per_page&amp;start=$start",
));
$this->tpl_name = 'acp_inactive';
$this->page_title = 'ACP_INACTIVE_USERS';
}
}

144
includes/acp/acp_jabber.php Normal file
View File

@@ -0,0 +1,144 @@
<?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.
*
*/
/**
* @todo Check/enter/update transport info
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
class acp_jabber
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $phpbb_log, $request;
global $config, $phpbb_root_path, $phpEx;
$user->add_lang('acp/board');
if (!class_exists('jabber'))
{
include($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
}
$submit = (isset($_POST['submit'])) ? true : false;
if ($mode != 'settings')
{
return;
}
$this->tpl_name = 'acp_jabber';
$this->page_title = 'ACP_JABBER_SETTINGS';
$jab_enable = $request->variable('jab_enable', (bool) $config['jab_enable']);
$jab_host = $request->variable('jab_host', (string) $config['jab_host']);
$jab_port = $request->variable('jab_port', (int) $config['jab_port']);
$jab_username = $request->variable('jab_username', (string) $config['jab_username']);
$jab_password = $request->variable('jab_password', (string) $config['jab_password']);
$jab_package_size = $request->variable('jab_package_size', (int) $config['jab_package_size']);
$jab_use_ssl = $request->variable('jab_use_ssl', (bool) $config['jab_use_ssl']);
$jab_verify_peer = $request->variable('jab_verify_peer', (bool) $config['jab_verify_peer']);
$jab_verify_peer_name = $request->variable('jab_verify_peer_name', (bool) $config['jab_verify_peer_name']);
$jab_allow_self_signed = $request->variable('jab_allow_self_signed', (bool) $config['jab_allow_self_signed']);
$form_name = 'acp_jabber';
add_form_key($form_name);
if ($submit)
{
if (!check_form_key($form_name))
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
$message = $user->lang['JAB_SETTINGS_CHANGED'];
$log = 'JAB_SETTINGS_CHANGED';
// Is this feature enabled? Then try to establish a connection
if ($jab_enable)
{
$jabber = new jabber($jab_host, $jab_port, $jab_username, $jab_password, $jab_use_ssl, $jab_verify_peer, $jab_verify_peer_name, $jab_allow_self_signed);
if (!$jabber->connect())
{
trigger_error($user->lang['ERR_JAB_CONNECT'] . '<br /><br />' . $jabber->get_log() . adm_back_link($this->u_action), E_USER_WARNING);
}
// We'll try to authorise using this account
if (!$jabber->login())
{
trigger_error($user->lang['ERR_JAB_AUTH'] . '<br /><br />' . $jabber->get_log() . adm_back_link($this->u_action), E_USER_WARNING);
}
$jabber->disconnect();
}
else
{
// This feature is disabled.
// We update the user table to be sure all users that have IM as notify type are set to both as notify type
// We set this to both because users still have their jabber address entered and may want to receive jabber notifications again once it is re-enabled.
$sql_ary = array(
'user_notify_type' => NOTIFY_BOTH,
);
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE user_notify_type = ' . NOTIFY_IM;
$db->sql_query($sql);
}
$config->set('jab_enable', $jab_enable);
$config->set('jab_host', $jab_host);
$config->set('jab_port', $jab_port);
$config->set('jab_username', $jab_username);
if ($jab_password !== '********')
{
$config->set('jab_password', $jab_password);
}
$config->set('jab_package_size', $jab_package_size);
$config->set('jab_use_ssl', $jab_use_ssl);
$config->set('jab_verify_peer', $jab_verify_peer);
$config->set('jab_verify_peer_name', $jab_verify_peer_name);
$config->set('jab_allow_self_signed', $jab_allow_self_signed);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_' . $log);
trigger_error($message . adm_back_link($this->u_action));
}
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
'JAB_ENABLE' => $jab_enable,
'L_JAB_SERVER_EXPLAIN' => sprintf($user->lang['JAB_SERVER_EXPLAIN'], '<a href="http://www.jabber.org/">', '</a>'),
'JAB_HOST' => $jab_host,
'JAB_PORT' => ($jab_port) ? $jab_port : '',
'JAB_USERNAME' => $jab_username,
'JAB_PASSWORD' => $jab_password !== '' ? '********' : '',
'JAB_PACKAGE_SIZE' => $jab_package_size,
'JAB_USE_SSL' => $jab_use_ssl,
'JAB_VERIFY_PEER' => $jab_verify_peer,
'JAB_VERIFY_PEER_NAME' => $jab_verify_peer_name,
'JAB_ALLOW_SELF_SIGNED' => $jab_allow_self_signed,
'S_CAN_USE_SSL' => jabber::can_use_ssl(),
'S_GTALK_NOTE' => (!@function_exists('dns_get_record')) ? true : false,
));
}
}

View File

@@ -0,0 +1,461 @@
<?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;
}
class acp_language
{
var $u_action;
var $main_files;
var $language_header = '';
var $lang_header = '';
var $language_file = '';
var $language_directory = '';
function main($id, $mode)
{
global $config, $db, $user, $template, $phpbb_log, $phpbb_container;
global $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher;
if (!function_exists('validate_language_iso_name'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
// Check and set some common vars
$action = (isset($_POST['update_details'])) ? 'update_details' : '';
$action = (isset($_POST['remove_store'])) ? 'details' : $action;
$submit = (empty($action) && !isset($_POST['update']) && !isset($_POST['test_connection'])) ? false : true;
$action = (empty($action)) ? $request->variable('action', '') : $action;
$form_name = 'acp_lang';
add_form_key('acp_lang');
$lang_id = $request->variable('id', 0);
$selected_lang_file = $request->variable('language_file', '|common.' . $phpEx);
list($this->language_directory, $this->language_file) = explode('|', $selected_lang_file);
$this->language_directory = basename($this->language_directory);
$this->language_file = basename($this->language_file);
$user->add_lang('acp/language');
$this->tpl_name = 'acp_language';
$this->page_title = 'ACP_LANGUAGE_PACKS';
switch ($action)
{
case 'update_details':
if (!$submit || !check_form_key($form_name))
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
if (!$lang_id)
{
trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT *
FROM ' . LANG_TABLE . "
WHERE lang_id = $lang_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$sql_ary = array(
'lang_english_name' => $request->variable('lang_english_name', $row['lang_english_name']),
'lang_local_name' => $request->variable('lang_local_name', $row['lang_local_name'], true),
'lang_author' => $request->variable('lang_author', $row['lang_author'], true),
);
$db->sql_query('UPDATE ' . LANG_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE lang_id = ' . $lang_id);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_UPDATED', false, array($sql_ary['lang_english_name']));
trigger_error($user->lang['LANGUAGE_DETAILS_UPDATED'] . adm_back_link($this->u_action));
break;
case 'details':
if (!$lang_id)
{
trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$this->page_title = 'LANGUAGE_PACK_DETAILS';
$sql = 'SELECT *
FROM ' . LANG_TABLE . '
WHERE lang_id = ' . $lang_id;
$result = $db->sql_query($sql);
$lang_entries = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$lang_entries)
{
trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$lang_iso = $lang_entries['lang_iso'];
$template->assign_vars(array(
'S_DETAILS' => true,
'U_ACTION' => $this->u_action . "&amp;action=details&amp;id=$lang_id",
'U_BACK' => $this->u_action,
'LANG_LOCAL_NAME' => $lang_entries['lang_local_name'],
'LANG_ENGLISH_NAME' => $lang_entries['lang_english_name'],
'LANG_ISO' => $lang_iso,
'LANG_AUTHOR' => $lang_entries['lang_author'],
'L_MISSING_FILES' => $user->lang('THOSE_MISSING_LANG_FILES', $lang_entries['lang_local_name']),
'L_MISSING_VARS_EXPLAIN' => $user->lang('THOSE_MISSING_LANG_VARIABLES', $lang_entries['lang_local_name']),
));
// If current lang is different from the default lang, then highlight missing files and variables
if ($lang_iso != $config['default_lang'])
{
try
{
$iterator = new \RecursiveIteratorIterator(
new \phpbb\recursive_dot_prefix_filter_iterator(
new \RecursiveDirectoryIterator(
$phpbb_root_path . 'language/' . $config['default_lang'] . '/',
\FilesystemIterator::SKIP_DOTS
)
),
\RecursiveIteratorIterator::LEAVES_ONLY
);
}
catch (\Exception $e)
{
return array();
}
foreach ($iterator as $file_info)
{
/** @var \RecursiveDirectoryIterator $file_info */
$relative_path = $iterator->getInnerIterator()->getSubPathname();
$relative_path = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path);
if (file_exists($phpbb_root_path . 'language/' . $lang_iso . '/' . $relative_path))
{
if (substr($relative_path, 0 - strlen($phpEx)) === $phpEx)
{
$missing_vars = $this->compare_language_files($config['default_lang'], $lang_iso, $relative_path);
if (!empty($missing_vars))
{
$template->assign_block_vars('missing_varfile', array(
'FILE_NAME' => $relative_path,
));
foreach ($missing_vars as $var)
{
$template->assign_block_vars('missing_varfile.variable', array(
'VAR_NAME' => $var,
));
}
}
}
}
else
{
$template->assign_block_vars('missing_files', array(
'FILE_NAME' => $relative_path,
));
}
}
}
return;
break;
case 'delete':
if (!$lang_id)
{
trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT *
FROM ' . LANG_TABLE . '
WHERE lang_id = ' . $lang_id;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($row['lang_iso'] == $config['default_lang'])
{
trigger_error($user->lang['NO_REMOVE_DEFAULT_LANG'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (confirm_box(true))
{
$db->sql_query('DELETE FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id);
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_lang = '" . $db->sql_escape($config['default_lang']) . "'
WHERE user_lang = '" . $db->sql_escape($row['lang_iso']) . "'";
$db->sql_query($sql);
// We also need to remove the translated entries for custom profile fields - we want clean tables, don't we?
$sql = 'DELETE FROM ' . PROFILE_LANG_TABLE . ' WHERE lang_id = ' . $lang_id;
$db->sql_query($sql);
$sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id;
$db->sql_query($sql);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_DELETED', false, array($row['lang_english_name']));
$delete_message = sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']);
$lang_iso = $row['lang_iso'];
/**
* Run code after language deleted
*
* @event core.acp_language_after_delete
* @var string lang_iso Language ISO code
* @var string delete_message Delete message appear to user
* @since 3.2.2-RC1
*/
$vars = array('lang_iso', 'delete_message');
extract($phpbb_dispatcher->trigger_event('core.acp_language_after_delete', compact($vars)));
trigger_error($delete_message . adm_back_link($this->u_action));
}
else
{
$s_hidden_fields = array(
'i' => $id,
'mode' => $mode,
'action' => $action,
'id' => $lang_id,
);
confirm_box(false, $user->lang('DELETE_LANGUAGE_CONFIRM', $row['lang_english_name']), build_hidden_fields($s_hidden_fields));
}
break;
case 'install':
if (!check_link_hash($request->variable('hash', ''), 'acp_language'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$lang_iso = $request->variable('iso', '');
$lang_iso = basename($lang_iso);
if (!$lang_iso || !file_exists("{$phpbb_root_path}language/$lang_iso/iso.txt"))
{
trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$file = file("{$phpbb_root_path}language/$lang_iso/iso.txt");
$lang_pack = array(
'iso' => $lang_iso,
'name' => trim(htmlspecialchars($file[0])),
'local_name'=> trim(htmlspecialchars($file[1], ENT_COMPAT, 'UTF-8')),
'author' => trim(htmlspecialchars($file[2], ENT_COMPAT, 'UTF-8'))
);
unset($file);
$sql = 'SELECT lang_iso
FROM ' . LANG_TABLE . "
WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($row)
{
trigger_error($user->lang['LANGUAGE_PACK_ALREADY_INSTALLED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (!$lang_pack['name'] || !$lang_pack['local_name'])
{
trigger_error($user->lang['INVALID_LANGUAGE_PACK'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Add language pack
$sql_ary = array(
'lang_iso' => $lang_pack['iso'],
'lang_dir' => $lang_pack['iso'],
'lang_english_name' => $lang_pack['name'],
'lang_local_name' => $lang_pack['local_name'],
'lang_author' => $lang_pack['author']
);
$db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$lang_id = $db->sql_nextid();
// Now let's copy the default language entries for custom profile fields for this new language - makes admin's life easier.
$sql = 'SELECT lang_id
FROM ' . LANG_TABLE . "
WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
$result = $db->sql_query($sql);
$default_lang_id = (int) $db->sql_fetchfield('lang_id');
$db->sql_freeresult($result);
// We want to notify the admin that custom profile fields need to be updated for the new language.
$notify_cpf_update = 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"
$sql = 'SELECT field_id, lang_name, lang_explain, lang_default_value
FROM ' . PROFILE_LANG_TABLE . '
WHERE lang_id = ' . $default_lang_id;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$row['lang_id'] = $lang_id;
$db->sql_query('INSERT INTO ' . PROFILE_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $row));
$notify_cpf_update = true;
}
$db->sql_freeresult($result);
$sql = 'SELECT field_id, option_id, field_type, lang_value
FROM ' . PROFILE_FIELDS_LANG_TABLE . '
WHERE lang_id = ' . $default_lang_id;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$row['lang_id'] = $lang_id;
$db->sql_query('INSERT INTO ' . PROFILE_FIELDS_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $row));
$notify_cpf_update = true;
}
$db->sql_freeresult($result);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_INSTALLED', false, array($lang_pack['name']));
$message = sprintf($user->lang['LANGUAGE_PACK_INSTALLED'], $lang_pack['name']);
$message .= ($notify_cpf_update) ? '<br /><br />' . $user->lang['LANGUAGE_PACK_CPF_UPDATE'] : '';
trigger_error($message . adm_back_link($this->u_action));
break;
}
$sql = 'SELECT user_lang, COUNT(user_lang) AS lang_count
FROM ' . USERS_TABLE . '
GROUP BY user_lang';
$result = $db->sql_query($sql);
$lang_count = array();
while ($row = $db->sql_fetchrow($result))
{
$lang_count[$row['user_lang']] = $row['lang_count'];
}
$db->sql_freeresult($result);
$sql = 'SELECT *
FROM ' . LANG_TABLE . '
ORDER BY lang_english_name';
$result = $db->sql_query($sql);
$installed = array();
while ($row = $db->sql_fetchrow($result))
{
$installed[] = $row['lang_iso'];
$tagstyle = ($row['lang_iso'] == $config['default_lang']) ? '*' : '';
$template->assign_block_vars('lang', array(
'U_DETAILS' => $this->u_action . "&amp;action=details&amp;id={$row['lang_id']}",
'U_DOWNLOAD' => $this->u_action . "&amp;action=download&amp;id={$row['lang_id']}",
'U_DELETE' => $this->u_action . "&amp;action=delete&amp;id={$row['lang_id']}",
'ENGLISH_NAME' => $row['lang_english_name'],
'TAG' => $tagstyle,
'LOCAL_NAME' => $row['lang_local_name'],
'ISO' => $row['lang_iso'],
'USED_BY' => (isset($lang_count[$row['lang_iso']])) ? $lang_count[$row['lang_iso']] : 0,
));
}
$db->sql_freeresult($result);
$new_ary = $iso = array();
/** @var \phpbb\language\language_file_helper $language_helper */
$language_helper = $phpbb_container->get('language.helper.language_file');
$iso = $language_helper->get_available_languages();
foreach ($iso as $lang_array)
{
$lang_iso = $lang_array['iso'];
if (!in_array($lang_iso, $installed))
{
$new_ary[$lang_iso] = $lang_array;
}
}
unset($installed);
if (count($new_ary))
{
foreach ($new_ary as $iso => $lang_ary)
{
$template->assign_block_vars('notinst', array(
'ISO' => htmlspecialchars($lang_ary['iso']),
'LOCAL_NAME' => htmlspecialchars($lang_ary['local_name'], ENT_COMPAT, 'UTF-8'),
'NAME' => htmlspecialchars($lang_ary['name'], ENT_COMPAT, 'UTF-8'),
'U_INSTALL' => $this->u_action . '&amp;action=install&amp;iso=' . urlencode($lang_ary['iso']) . '&amp;hash=' . generate_link_hash('acp_language'))
);
}
}
unset($new_ary);
}
/**
* Compare two language files
*/
function compare_language_files($source_lang, $dest_lang, $file)
{
global $phpbb_root_path;
$source_file = $phpbb_root_path . 'language/' . $source_lang . '/' . $file;
$dest_file = $phpbb_root_path . 'language/' . $dest_lang . '/' . $file;
if (!file_exists($dest_file))
{
return array();
}
$lang = array();
include($source_file);
$lang_entry_src = $lang;
$lang = array();
include($dest_file);
$lang_entry_dst = $lang;
unset($lang);
return array_diff(array_keys($lang_entry_src), array_keys($lang_entry_dst));
}
}

176
includes/acp/acp_logs.php Normal file
View File

@@ -0,0 +1,176 @@
<?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;
}
class acp_logs
{
var $u_action;
function main($id, $mode)
{
global $user, $auth, $template, $phpbb_container;
global $config;
global $request;
$user->add_lang('mcp');
// Set up general vars
$action = $request->variable('action', '');
$forum_id = $request->variable('f', 0);
$start = $request->variable('start', 0);
$deletemark = $request->variable('delmarked', false, false, \phpbb\request\request_interface::POST);
$deleteall = $request->variable('delall', false, false, \phpbb\request\request_interface::POST);
$marked = $request->variable('mark', array(0));
// Sort keys
$sort_days = $request->variable('st', 0);
$sort_key = $request->variable('sk', 't');
$sort_dir = $request->variable('sd', 'd');
$this->tpl_name = 'acp_logs';
$this->log_type = constant('LOG_' . strtoupper($mode));
/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// Delete entries if requested and able
if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs'))
{
if (confirm_box(true))
{
$conditions = array();
if ($deletemark && count($marked))
{
$conditions['log_id'] = array('IN' => $marked);
}
if ($deleteall)
{
if ($sort_days)
{
$conditions['log_time'] = array('>=', time() - ($sort_days * 86400));
}
$keywords = $request->variable('keywords', '', true);
$conditions['keywords'] = $keywords;
}
/* @var $phpbb_log \phpbb\log\log_interface */
$phpbb_log = $phpbb_container->get('log');
$phpbb_log->delete($mode, $conditions);
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'f' => $forum_id,
'start' => $start,
'delmarked' => $deletemark,
'delall' => $deleteall,
'mark' => $marked,
'st' => $sort_days,
'sk' => $sort_key,
'sd' => $sort_dir,
'i' => $id,
'mode' => $mode,
'action' => $action))
);
}
}
// Sorting
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('u' => $user->lang['SORT_USERNAME'], 't' => $user->lang['SORT_DATE'], 'i' => $user->lang['SORT_IP'], 'o' => $user->lang['SORT_ACTION']);
$sort_by_sql = array('u' => 'u.username_clean', 't' => 'l.log_time', 'i' => 'l.log_ip', 'o' => 'l.log_operation');
$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
// Define where and sort sql for use in displaying logs
$sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0;
$sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
$keywords = $request->variable('keywords', '', true);
$keywords_param = !empty($keywords) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
$l_title = $user->lang['ACP_' . strtoupper($mode) . '_LOGS'];
$l_title_explain = $user->lang['ACP_' . strtoupper($mode) . '_LOGS_EXPLAIN'];
$this->page_title = $l_title;
// Define forum list if we're looking @ mod logs
if ($mode == 'mod')
{
$forum_box = '<option value="0">' . $user->lang['ALL_FORUMS'] . '</option>' . make_forum_select($forum_id);
$template->assign_vars(array(
'S_SHOW_FORUMS' => true,
'S_FORUM_BOX' => $forum_box)
);
}
// Grab log data
$log_data = array();
$log_count = 0;
$start = view_log($mode, $log_data, $log_count, $config['topics_per_page'], $start, $forum_id, 0, 0, $sql_where, $sql_sort, $keywords);
$base_url = $this->u_action . "&amp;$u_sort_param$keywords_param";
$pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start);
$template->assign_vars(array(
'L_TITLE' => $l_title,
'L_EXPLAIN' => $l_title_explain,
'U_ACTION' => $this->u_action . "&amp;$u_sort_param$keywords_param&amp;start=$start",
'S_LIMIT_DAYS' => $s_limit_days,
'S_SORT_KEY' => $s_sort_key,
'S_SORT_DIR' => $s_sort_dir,
'S_CLEARLOGS' => $auth->acl_get('a_clearlogs'),
'S_KEYWORDS' => $keywords,
)
);
foreach ($log_data as $row)
{
$data = array();
$checks = array('viewpost', 'viewtopic', 'viewlogs', 'viewforum');
foreach ($checks as $check)
{
if (isset($row[$check]) && $row[$check])
{
$data[] = '<a href="' . $row[$check] . '">' . $user->lang['LOGVIEW_' . strtoupper($check)] . '</a>';
}
}
$template->assign_block_vars('log', array(
'USERNAME' => $row['username_full'],
'REPORTEE_USERNAME' => ($row['reportee_username'] && $row['user_id'] != $row['reportee_id']) ? $row['reportee_username_full'] : '',
'IP' => $row['ip'],
'DATE' => $user->format_date($row['time']),
'ACTION' => $row['action'],
'DATA' => (count($data)) ? implode(' | ', $data) : '',
'ID' => $row['id'],
)
);
}
}
}

707
includes/acp/acp_main.php Normal file
View File

@@ -0,0 +1,707 @@
<?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;
}
class acp_main
{
var $u_action;
function main($id, $mode)
{
global $config, $db, $cache, $user, $auth, $template, $request, $phpbb_log;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container, $phpbb_dispatcher, $phpbb_filesystem;
// Show restore permissions notice
if ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm'))
{
$this->tpl_name = 'acp_main';
$this->page_title = 'ACP_MAIN';
$sql = 'SELECT user_id, username, user_colour
FROM ' . USERS_TABLE . '
WHERE user_id = ' . $user->data['user_perm_from'];
$result = $db->sql_query($sql);
$user_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$perm_from = get_username_string('full', $user_row['user_id'], $user_row['username'], $user_row['user_colour']);
$template->assign_vars(array(
'S_RESTORE_PERMISSIONS' => true,
'U_RESTORE_PERMISSIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm'),
'PERM_FROM' => $perm_from,
'L_PERMISSIONS_TRANSFERRED_EXPLAIN' => sprintf($user->lang['PERMISSIONS_TRANSFERRED_EXPLAIN'], $perm_from, append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm')),
));
return;
}
$action = $request->variable('action', '');
if ($action)
{
if ($action === 'admlogout')
{
$user->unset_admin();
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
if (!confirm_box(true))
{
switch ($action)
{
case 'online':
$confirm = true;
$confirm_lang = 'RESET_ONLINE_CONFIRM';
break;
case 'stats':
$confirm = true;
$confirm_lang = 'RESYNC_STATS_CONFIRM';
break;
case 'user':
$confirm = true;
$confirm_lang = 'RESYNC_POSTCOUNTS_CONFIRM';
break;
case 'date':
$confirm = true;
$confirm_lang = 'RESET_DATE_CONFIRM';
break;
case 'db_track':
$confirm = true;
$confirm_lang = 'RESYNC_POST_MARKING_CONFIRM';
break;
case 'purge_cache':
$confirm = true;
$confirm_lang = 'PURGE_CACHE_CONFIRM';
break;
case 'purge_sessions':
$confirm = true;
$confirm_lang = 'PURGE_SESSIONS_CONFIRM';
break;
default:
$confirm = true;
$confirm_lang = 'CONFIRM_OPERATION';
}
if ($confirm)
{
confirm_box(false, $user->lang[$confirm_lang], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'action' => $action,
)));
}
}
else
{
switch ($action)
{
case 'online':
if (!$auth->acl_get('a_board'))
{
send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$config->set('record_online_users', 1, false);
$config->set('record_online_date', time(), false);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESET_ONLINE');
if ($request->is_ajax())
{
trigger_error('RESET_ONLINE_SUCCESS');
}
break;
case 'stats':
if (!$auth->acl_get('a_board'))
{
send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT COUNT(post_id) AS stat
FROM ' . POSTS_TABLE . '
WHERE post_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$config->set('num_posts', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
WHERE topic_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$config->set('num_topics', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(user_id) AS stat
FROM ' . USERS_TABLE . '
WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')';
$result = $db->sql_query($sql);
$config->set('num_users', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(attach_id) as stat
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 0';
$result = $db->sql_query($sql);
$config->set('num_files', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT SUM(filesize) as stat
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 0';
$result = $db->sql_query($sql);
$config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
if (!function_exists('update_last_username'))
{
include($phpbb_root_path . "includes/functions_user.$phpEx");
}
update_last_username();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_STATS');
if ($request->is_ajax())
{
trigger_error('RESYNC_STATS_SUCCESS');
}
break;
case 'user':
if (!$auth->acl_get('a_board'))
{
send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Resync post counts
$start = $max_post_id = 0;
// Find the maximum post ID, we can only stop the cycle when we've reached it
$sql = 'SELECT MAX(forum_last_post_id) as max_post_id
FROM ' . FORUMS_TABLE;
$result = $db->sql_query($sql);
$max_post_id = (int) $db->sql_fetchfield('max_post_id');
$db->sql_freeresult($result);
// No maximum post id? :o
if (!$max_post_id)
{
$sql = 'SELECT MAX(post_id) as max_post_id
FROM ' . POSTS_TABLE;
$result = $db->sql_query($sql);
$max_post_id = (int) $db->sql_fetchfield('max_post_id');
$db->sql_freeresult($result);
}
// Still no maximum post id? Then we are finished
if (!$max_post_id)
{
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS');
break;
}
$step = ($config['num_posts']) ? (max((int) ($config['num_posts'] / 5), 20000)) : 20000;
$db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_posts = 0');
while ($start < $max_post_id)
{
$sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
FROM ' . POSTS_TABLE . '
WHERE post_id BETWEEN ' . ($start + 1) . ' AND ' . ($start + $step) . '
AND post_postcount = 1 AND post_visibility = ' . ITEM_APPROVED . '
GROUP BY poster_id';
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
do
{
$sql = 'UPDATE ' . USERS_TABLE . " SET user_posts = user_posts + {$row['num_posts']} WHERE user_id = {$row['poster_id']}";
$db->sql_query($sql);
}
while ($row = $db->sql_fetchrow($result));
}
$db->sql_freeresult($result);
$start += $step;
}
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS');
if ($request->is_ajax())
{
trigger_error('RESYNC_POSTCOUNTS_SUCCESS');
}
break;
case 'date':
if (!$auth->acl_get('a_board'))
{
send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$config->set('board_startdate', time() - 1);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESET_DATE');
if ($request->is_ajax())
{
trigger_error('RESET_DATE_SUCCESS');
}
break;
case 'db_track':
switch ($db->get_sql_layer())
{
case 'sqlite3':
$db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE);
break;
default:
$db->sql_query('TRUNCATE TABLE ' . TOPICS_POSTED_TABLE);
break;
}
// This can get really nasty... therefore we only do the last six months
$get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60);
// Select forum ids, do not include categories
$sql = 'SELECT forum_id
FROM ' . FORUMS_TABLE . '
WHERE forum_type <> ' . FORUM_CAT;
$result = $db->sql_query($sql);
$forum_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$forum_ids[] = $row['forum_id'];
}
$db->sql_freeresult($result);
// Any global announcements? ;)
$forum_ids[] = 0;
// Now go through the forums and get us some topics...
foreach ($forum_ids as $forum_id)
{
$sql = 'SELECT p.poster_id, p.topic_id
FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
WHERE t.forum_id = ' . $forum_id . '
AND t.topic_moved_id = 0
AND t.topic_last_post_time > ' . $get_from_time . '
AND t.topic_id = p.topic_id
AND p.poster_id <> ' . ANONYMOUS . '
GROUP BY p.poster_id, p.topic_id';
$result = $db->sql_query($sql);
$posted = array();
while ($row = $db->sql_fetchrow($result))
{
$posted[$row['poster_id']][] = $row['topic_id'];
}
$db->sql_freeresult($result);
$sql_ary = array();
foreach ($posted as $user_id => $topic_row)
{
foreach ($topic_row as $topic_id)
{
$sql_ary[] = array(
'user_id' => (int) $user_id,
'topic_id' => (int) $topic_id,
'topic_posted' => 1,
);
}
}
unset($posted);
if (count($sql_ary))
{
$db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
}
}
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POST_MARKING');
if ($request->is_ajax())
{
trigger_error('RESYNC_POST_MARKING_SUCCESS');
}
break;
case 'purge_cache':
$config->increment('assets_version', 1);
$cache->purge();
// Remove old renderers from the text_formatter service. Since this
// operation is performed after the cache is purged, there is not "current"
// renderer and in effect all renderers will be purged
$phpbb_container->get('text_formatter.cache')->tidy();
// Clear permissions
$auth->acl_clear_prefetch();
phpbb_cache_moderators($db, $cache, $auth);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_CACHE');
if ($request->is_ajax())
{
trigger_error('PURGE_CACHE_SUCCESS');
}
break;
case 'purge_sessions':
if ((int) $user->data['user_type'] !== USER_FOUNDER)
{
send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$tables = array(CONFIRM_TABLE, SESSIONS_TABLE);
foreach ($tables as $table)
{
switch ($db->get_sql_layer())
{
case 'sqlite3':
$db->sql_query("DELETE FROM $table");
break;
default:
$db->sql_query("TRUNCATE TABLE $table");
break;
}
}
// let's restore the admin session
$reinsert_ary = array(
'session_id' => (string) $user->session_id,
'session_page' => (string) substr($user->page['page'], 0, 199),
'session_forum_id' => $user->page['forum'],
'session_user_id' => (int) $user->data['user_id'],
'session_start' => (int) $user->data['session_start'],
'session_last_visit' => (int) $user->data['session_last_visit'],
'session_time' => (int) $user->time_now,
'session_browser' => (string) trim(substr($user->browser, 0, 149)),
'session_forwarded_for' => (string) $user->forwarded_for,
'session_ip' => (string) $user->ip,
'session_autologin' => (int) $user->data['session_autologin'],
'session_admin' => 1,
'session_viewonline' => (int) $user->data['session_viewonline'],
);
$sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $reinsert_ary);
$db->sql_query($sql);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_SESSIONS');
if ($request->is_ajax())
{
trigger_error('PURGE_SESSIONS_SUCCESS');
}
break;
}
}
}
// Version check
$user->add_lang('install');
if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.4.0', '<'))
{
$template->assign_vars(array(
'S_PHP_VERSION_OLD' => true,
'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], PHP_VERSION, '5.4.0', '<a href="https://www.phpbb.com/support/docs/en/3.2/ug/quickstart/requirements">', '</a>'),
));
}
if ($auth->acl_get('a_board'))
{
$version_helper = $phpbb_container->get('version_helper');
try
{
$recheck = $request->variable('versioncheck_force', false);
$updates_available = $version_helper->get_update_on_branch($recheck);
$upgrades_available = $version_helper->get_suggested_updates();
if (!empty($upgrades_available))
{
$upgrades_available = array_pop($upgrades_available);
}
$template->assign_vars(array(
'S_VERSION_UP_TO_DATE' => empty($updates_available),
'S_VERSION_UPGRADEABLE' => !empty($upgrades_available),
'UPGRADE_INSTRUCTIONS' => !empty($upgrades_available) ? $user->lang('UPGRADE_INSTRUCTIONS', $upgrades_available['current'], $upgrades_available['announcement']) : false,
));
}
catch (\RuntimeException $e)
{
$message = call_user_func_array(array($user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$template->assign_vars(array(
'S_VERSIONCHECK_FAIL' => true,
'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '',
));
}
}
else
{
// We set this template var to true, to not display an outdated version notice.
$template->assign_var('S_VERSION_UP_TO_DATE', true);
}
// Incomplete update?
if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<'))
{
$template->assign_var('S_UPDATE_INCOMPLETE', true);
}
/**
* Notice admin
*
* @event core.acp_main_notice
* @since 3.1.0-RC3
*/
$phpbb_dispatcher->dispatch('core.acp_main_notice');
// Get forum statistics
$total_posts = $config['num_posts'];
$total_topics = $config['num_topics'];
$total_users = $config['num_users'];
$total_files = $config['num_files'];
$start_date = $user->format_date($config['board_startdate']);
$boarddays = (time() - $config['board_startdate']) / 86400;
$posts_per_day = sprintf('%.2f', $total_posts / $boarddays);
$topics_per_day = sprintf('%.2f', $total_topics / $boarddays);
$users_per_day = sprintf('%.2f', $total_users / $boarddays);
$files_per_day = sprintf('%.2f', $total_files / $boarddays);
$upload_dir_size = get_formatted_filesize($config['upload_dir_size']);
$avatar_dir_size = 0;
if ($avatar_dir = @opendir($phpbb_root_path . $config['avatar_path']))
{
while (($file = readdir($avatar_dir)) !== false)
{
if ($file[0] != '.' && $file != 'CVS' && strpos($file, 'index.') === false)
{
$avatar_dir_size += filesize($phpbb_root_path . $config['avatar_path'] . '/' . $file);
}
}
closedir($avatar_dir);
$avatar_dir_size = get_formatted_filesize($avatar_dir_size);
}
else
{
// Couldn't open Avatar dir.
$avatar_dir_size = $user->lang['NOT_AVAILABLE'];
}
if ($posts_per_day > $total_posts)
{
$posts_per_day = $total_posts;
}
if ($topics_per_day > $total_topics)
{
$topics_per_day = $total_topics;
}
if ($users_per_day > $total_users)
{
$users_per_day = $total_users;
}
if ($files_per_day > $total_files)
{
$files_per_day = $total_files;
}
if ($config['allow_attachments'] || $config['allow_pm_attach'])
{
$sql = 'SELECT COUNT(attach_id) AS total_orphan
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 1
AND filetime < ' . (time() - 3*60*60);
$result = $db->sql_query($sql);
$total_orphan = (int) $db->sql_fetchfield('total_orphan');
$db->sql_freeresult($result);
}
else
{
$total_orphan = false;
}
$dbsize = get_database_size();
$template->assign_vars(array(
'TOTAL_POSTS' => $total_posts,
'POSTS_PER_DAY' => $posts_per_day,
'TOTAL_TOPICS' => $total_topics,
'TOPICS_PER_DAY' => $topics_per_day,
'TOTAL_USERS' => $total_users,
'USERS_PER_DAY' => $users_per_day,
'TOTAL_FILES' => $total_files,
'FILES_PER_DAY' => $files_per_day,
'START_DATE' => $start_date,
'AVATAR_DIR_SIZE' => $avatar_dir_size,
'DBSIZE' => $dbsize,
'UPLOAD_DIR_SIZE' => $upload_dir_size,
'TOTAL_ORPHAN' => $total_orphan,
'S_TOTAL_ORPHAN' => ($total_orphan === false) ? false : true,
'GZIP_COMPRESSION' => ($config['gzip_compress'] && @extension_loaded('zlib')) ? $user->lang['ON'] : $user->lang['OFF'],
'DATABASE_INFO' => $db->sql_server_info(),
'PHP_VERSION_INFO' => PHP_VERSION,
'BOARD_VERSION' => $config['version'],
'U_ACTION' => $this->u_action,
'U_ADMIN_LOG' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&amp;mode=admin'),
'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&amp;mode=list'),
'U_VERSIONCHECK' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=update&amp;mode=version_check'),
'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", 'versioncheck_force=1'),
'U_ATTACH_ORPHAN' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=acp_attachments&mode=orphan'),
'S_VERSIONCHECK' => ($auth->acl_get('a_board')) ? true : false,
'S_ACTION_OPTIONS' => ($auth->acl_get('a_board')) ? true : false,
'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false,
)
);
$log_data = array();
$log_count = false;
if ($auth->acl_get('a_viewlogs'))
{
view_log('admin', $log_data, $log_count, 5);
foreach ($log_data as $row)
{
$template->assign_block_vars('log', array(
'USERNAME' => $row['username_full'],
'IP' => $row['ip'],
'DATE' => $user->format_date($row['time']),
'ACTION' => $row['action'])
);
}
}
if ($auth->acl_get('a_user'))
{
$user->add_lang('memberlist');
$inactive = array();
$inactive_count = 0;
view_inactive_users($inactive, $inactive_count, 10);
foreach ($inactive as $row)
{
$template->assign_block_vars('inactive', array(
'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']),
'REMINDED_DATE' => $user->format_date($row['user_reminded_time']),
'JOINED' => $user->format_date($row['user_regdate']),
'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']),
'REASON' => $row['inactive_reason'],
'USER_ID' => $row['user_id'],
'POSTS' => ($row['user_posts']) ? $row['user_posts'] : 0,
'REMINDED' => $row['user_reminded'],
'REMINDED_EXPLAIN' => $user->lang('USER_LAST_REMINDED', (int) $row['user_reminded'], $user->format_date($row['user_reminded_time'])),
'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview')),
'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']),
'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']),
'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&amp;mode=overview&amp;u={$row['user_id']}"),
'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$row['user_id']}&amp;sr=posts") : '',
));
}
$option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE');
if ($config['email_enable'])
{
$option_ary += array('remind' => 'REMIND');
}
$template->assign_vars(array(
'S_INACTIVE_USERS' => true,
'S_INACTIVE_OPTIONS' => build_select($option_ary))
);
}
// Warn if install is still present
if (file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install'))
{
$template->assign_var('S_REMOVE_INSTALL', true);
}
// Warn if no search index is created
if ($config['num_posts'] && class_exists($config['search_type']))
{
$error = false;
$search_type = $config['search_type'];
$search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
if (!$search->index_created())
{
$template->assign_vars(array(
'S_SEARCH_INDEX_MISSING' => true,
'L_NO_SEARCH_INDEX' => $user->lang('NO_SEARCH_INDEX', $search->get_name(), '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=acp_search&amp;mode=index') . '">', '</a>'),
));
}
}
if (!defined('PHPBB_DISABLE_CONFIG_CHECK') && file_exists($phpbb_root_path . 'config.' . $phpEx) && $phpbb_filesystem->is_writable($phpbb_root_path . 'config.' . $phpEx))
{
// World-Writable? (000x)
$template->assign_var('S_WRITABLE_CONFIG', (bool) (@fileperms($phpbb_root_path . 'config.' . $phpEx) & 0x0002));
}
if (extension_loaded('mbstring'))
{
$template->assign_vars(array(
'S_MBSTRING_LOADED' => true,
'S_MBSTRING_FUNC_OVERLOAD_FAIL' => (intval(@ini_get('mbstring.func_overload')) & (MB_OVERLOAD_MAIL | MB_OVERLOAD_STRING)),
'S_MBSTRING_ENCODING_TRANSLATION_FAIL' => (@ini_get('mbstring.encoding_translation') != 0),
'S_MBSTRING_HTTP_INPUT_FAIL' => !in_array(@ini_get('mbstring.http_input'), array('pass', '')),
'S_MBSTRING_HTTP_OUTPUT_FAIL' => !in_array(@ini_get('mbstring.http_output'), array('pass', '')),
));
}
// Fill dbms version if not yet filled
if (empty($config['dbms_version']))
{
$config->set('dbms_version', $db->sql_server_info(true));
}
$this->tpl_name = 'acp_main';
$this->page_title = 'ACP_MAIN';
}
}

View File

@@ -0,0 +1,666 @@
<?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;
}
use phpbb\module\exception\module_exception;
/**
* - Able to check for new module versions (modes changed/adjusted/added/removed)
* Icons for:
* - module enabled and displayed (common)
* - module enabled and not displayed
* - module deactivated
* - category (enabled)
* - category disabled
*/
class acp_modules
{
var $module_class = '';
var $parent_id;
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $module, $request, $phpbb_log, $phpbb_container;
/** @var \phpbb\module\module_manager $module_manager */
$module_manager = $phpbb_container->get('module.manager');
// Set a global define for modules we might include (the author is able to prevent execution of code by checking this constant)
define('MODULE_INCLUDE', true);
$user->add_lang('acp/modules');
$this->tpl_name = 'acp_modules';
$form_key = 'acp_modules';
add_form_key($form_key);
// module class
$this->module_class = $mode;
if ($this->module_class == 'ucp')
{
$user->add_lang('ucp');
}
else if ($this->module_class == 'mcp')
{
$user->add_lang('mcp');
}
if ($module->p_class != $this->module_class)
{
$module->add_mod_info($this->module_class);
}
$this->page_title = strtoupper($this->module_class);
$this->parent_id = $request->variable('parent_id', 0);
$module_id = $request->variable('m', 0);
$action = $request->variable('action', '');
$errors = array();
switch ($action)
{
case 'delete':
if (!$module_id)
{
trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
if (confirm_box(true))
{
// Make sure we are not directly within a module
if ($module_id == $this->parent_id)
{
$sql = 'SELECT parent_id
FROM ' . MODULES_TABLE . '
WHERE module_id = ' . $module_id;
$result = $db->sql_query($sql);
$this->parent_id = (int) $db->sql_fetchfield('parent_id');
$db->sql_freeresult($result);
}
try
{
$row = $module_manager->get_module_row($module_id, $this->module_class);
$module_manager->delete_module($module_id, $this->module_class);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_REMOVED', false, array($user->lang($row['module_langname'])));
}
catch (module_exception $e)
{
$msg = $user->lang($e->getMessage());
trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
$module_manager->remove_cache_file($this->module_class);
trigger_error($user->lang['MODULE_DELETED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
}
else
{
confirm_box(false, 'DELETE_MODULE', build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'parent_id' => $this->parent_id,
'module_id' => $module_id,
'action' => $action,
)));
}
break;
case 'enable':
case 'disable':
if (!$module_id)
{
trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
if (!check_link_hash($request->variable('hash', ''), 'acp_modules'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
$sql = 'SELECT *
FROM ' . MODULES_TABLE . "
WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
AND module_id = $module_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$row)
{
trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
$sql = 'UPDATE ' . MODULES_TABLE . '
SET module_enabled = ' . (($action == 'enable') ? 1 : 0) . "
WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
AND module_id = $module_id";
$db->sql_query($sql);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_' . strtoupper($action), false, array($user->lang($row['module_langname'])));
$module_manager->remove_cache_file($this->module_class);
break;
case 'move_up':
case 'move_down':
if (!$module_id)
{
trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
if (!check_link_hash($request->variable('hash', ''), 'acp_modules'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
$sql = 'SELECT *
FROM ' . MODULES_TABLE . "
WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
AND module_id = $module_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$row)
{
trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
try
{
$move_module_name = $module_manager->move_module_by($row, $this->module_class, $action, 1);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_' . strtoupper($action), false, array($user->lang($row['module_langname']), $move_module_name));
$module_manager->remove_cache_file($this->module_class);
}
catch (module_exception $e)
{
// Do nothing
}
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'success' => ($move_module_name !== false),
));
}
break;
case 'quickadd':
$quick_install = $request->variable('quick_install', '');
if (confirm_box(true))
{
if (!$quick_install || strpos($quick_install, '::') === false)
{
break;
}
list($module_basename, $module_mode) = explode('::', $quick_install);
// Check if module name and mode exist...
$fileinfo = $module_manager->get_module_infos($this->module_class, $module_basename);
$fileinfo = $fileinfo[$module_basename];
if (isset($fileinfo['modes'][$module_mode]))
{
$module_data = array(
'module_basename' => $module_basename,
'module_enabled' => 0,
'module_display' => (isset($fileinfo['modes'][$module_mode]['display'])) ? $fileinfo['modes'][$module_mode]['display'] : 1,
'parent_id' => $this->parent_id,
'module_class' => $this->module_class,
'module_langname' => $fileinfo['modes'][$module_mode]['title'],
'module_mode' => $module_mode,
'module_auth' => $fileinfo['modes'][$module_mode]['auth'],
);
try
{
$module_manager->update_module_data($module_data);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_ADD', false, array($user->lang($module_data['module_langname'])));
}
catch (\phpbb\module\exception\module_exception $e)
{
$msg = $user->lang($e->getMessage());
trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
if (!count($errors))
{
$module_manager->remove_cache_file($this->module_class);
trigger_error($user->lang['MODULE_ADDED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
}
}
}
else
{
confirm_box(false, 'ADD_MODULE', build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'parent_id' => $this->parent_id,
'action' => 'quickadd',
'quick_install' => $quick_install,
)));
}
break;
case 'edit':
if (!$module_id)
{
trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
try
{
$module_row = $module_manager->get_module_row($module_id, $this->module_class);
}
catch (\phpbb\module\exception\module_not_found_exception $e)
{
$msg = $user->lang($e->getMessage());
trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
// no break
case 'add':
if ($action == 'add')
{
$module_row = array(
'module_basename' => '',
'module_enabled' => 0,
'module_display' => 1,
'parent_id' => 0,
'module_langname' => $request->variable('module_langname', '', true),
'module_mode' => '',
'module_auth' => '',
);
}
$module_data = array();
$module_data['module_basename'] = $request->variable('module_basename', (string) $module_row['module_basename']);
$module_data['module_enabled'] = $request->variable('module_enabled', (int) $module_row['module_enabled']);
$module_data['module_display'] = $request->variable('module_display', (int) $module_row['module_display']);
$module_data['parent_id'] = $request->variable('module_parent_id', (int) $module_row['parent_id']);
$module_data['module_class'] = $this->module_class;
$module_data['module_langname'] = $request->variable('module_langname', (string) $module_row['module_langname'], true);
$module_data['module_mode'] = $request->variable('module_mode', (string) $module_row['module_mode']);
$submit = (isset($_POST['submit'])) ? true : false;
if ($submit)
{
if (!check_form_key($form_key))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
if (!$module_data['module_langname'])
{
trigger_error($user->lang['NO_MODULE_LANGNAME'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
$module_type = $request->variable('module_type', 'category');
if ($module_type == 'category')
{
$module_data['module_basename'] = $module_data['module_mode'] = $module_data['module_auth'] = '';
$module_data['module_display'] = 1;
}
if ($action == 'edit')
{
$module_data['module_id'] = $module_id;
}
// Adjust auth row
if ($module_data['module_basename'] && $module_data['module_mode'])
{
$fileinfo = $module_manager->get_module_infos($this->module_class, $module_data['module_basename']);
$module_data['module_auth'] = $fileinfo[$module_data['module_basename']]['modes'][$module_data['module_mode']]['auth'];
}
try
{
$module_manager->update_module_data($module_data);
$phpbb_log->add('admin',
$user->data['user_id'],
$user->ip,
($action === 'edit') ? 'LOG_MODULE_EDIT' : 'LOG_MODULE_ADD',
false,
array($user->lang($module_data['module_langname']))
); }
catch (\phpbb\module\exception\module_exception $e)
{
$msg = $user->lang($e->getMessage());
trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
if (!count($errors))
{
$module_manager->remove_cache_file($this->module_class);
trigger_error((($action == 'add') ? $user->lang['MODULE_ADDED'] : $user->lang['MODULE_EDITED']) . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
}
}
// Category/not category?
$is_cat = (!$module_data['module_basename']) ? true : false;
// Get module information
$module_infos = $module_manager->get_module_infos($this->module_class);
// Build name options
$s_name_options = $s_mode_options = '';
foreach ($module_infos as $option => $values)
{
if (!$module_data['module_basename'])
{
$module_data['module_basename'] = $option;
}
// Name options
$s_name_options .= '<option value="' . $option . '"' . (($option == $module_data['module_basename']) ? ' selected="selected"' : '') . '>' . $user->lang($values['title']) . ' [' . $option . ']</option>';
$template->assign_block_vars('m_names', array('NAME' => $option, 'A_NAME' => addslashes($option)));
// Build module modes
foreach ($values['modes'] as $m_mode => $m_values)
{
if ($option == $module_data['module_basename'])
{
$s_mode_options .= '<option value="' . $m_mode . '"' . (($m_mode == $module_data['module_mode']) ? ' selected="selected"' : '') . '>' . $user->lang($m_values['title']) . '</option>';
}
$template->assign_block_vars('m_names.modes', array(
'OPTION' => $m_mode,
'VALUE' => $user->lang($m_values['title']),
'A_OPTION' => addslashes($m_mode),
'A_VALUE' => addslashes($user->lang($m_values['title'])))
);
}
}
$s_cat_option = '<option value="0"' . (($module_data['parent_id'] == 0) ? ' selected="selected"' : '') . '>' . $user->lang['NO_PARENT'] . '</option>';
$template->assign_vars(array_merge(array(
'S_EDIT_MODULE' => true,
'S_IS_CAT' => $is_cat,
'S_CAT_OPTIONS' => $s_cat_option . $this->make_module_select($module_data['parent_id'], ($action == 'edit') ? $module_row['module_id'] : false, false, false, false, true),
'S_MODULE_NAMES' => $s_name_options,
'S_MODULE_MODES' => $s_mode_options,
'U_BACK' => $this->u_action . '&amp;parent_id=' . $this->parent_id,
'U_EDIT_ACTION' => $this->u_action . '&amp;parent_id=' . $this->parent_id,
'L_TITLE' => $user->lang[strtoupper($action) . '_MODULE'],
'MODULENAME' => $user->lang($module_data['module_langname']),
'ACTION' => $action,
'MODULE_ID' => $module_id,
),
array_change_key_case($module_data, CASE_UPPER))
);
if (count($errors))
{
$template->assign_vars(array(
'S_ERROR' => true,
'ERROR_MSG' => implode('<br />', $errors))
);
}
return;
break;
}
// Default management page
if (count($errors))
{
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'MESSAGE_TITLE' => $user->lang('ERROR'),
'MESSAGE_TEXT' => implode('<br />', $errors),
'SUCCESS' => false,
));
}
$template->assign_vars(array(
'S_ERROR' => true,
'ERROR_MSG' => implode('<br />', $errors))
);
}
if (!$this->parent_id)
{
$navigation = strtoupper($this->module_class);
}
else
{
$navigation = '<a href="' . $this->u_action . '">' . strtoupper($this->module_class) . '</a>';
$modules_nav = $module_manager->get_module_branch($this->parent_id, $this->module_class, 'parents');
foreach ($modules_nav as $row)
{
$langname = $user->lang($row['module_langname']);
if ($row['module_id'] == $this->parent_id)
{
$navigation .= ' -&gt; ' . $langname;
}
else
{
$navigation .= ' -&gt; <a href="' . $this->u_action . '&amp;parent_id=' . $row['module_id'] . '">' . $langname . '</a>';
}
}
}
// Jumpbox
$module_box = $this->make_module_select($this->parent_id, false, false, false, false);
$sql = 'SELECT *
FROM ' . MODULES_TABLE . "
WHERE parent_id = {$this->parent_id}
AND module_class = '" . $db->sql_escape($this->module_class) . "'
ORDER BY left_id";
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
do
{
$langname = $user->lang($row['module_langname']);
if (!$row['module_enabled'])
{
$module_image = '<img src="images/icon_folder_lock.gif" alt="' . $user->lang['DEACTIVATED_MODULE'] .'" />';
}
else
{
$module_image = (!$row['module_basename'] || $row['left_id'] + 1 != $row['right_id']) ? '<img src="images/icon_subfolder.gif" alt="' . $user->lang['CATEGORY'] . '" />' : '<img src="images/icon_folder.gif" alt="' . $user->lang['MODULE'] . '" />';
}
$url = $this->u_action . '&amp;parent_id=' . $this->parent_id . '&amp;m=' . $row['module_id'];
$template->assign_block_vars('modules', array(
'MODULE_IMAGE' => $module_image,
'MODULE_TITLE' => $langname,
'MODULE_ENABLED' => ($row['module_enabled']) ? true : false,
'MODULE_DISPLAYED' => ($row['module_display']) ? true : false,
'S_ACP_CAT_SYSTEM' => ($this->module_class == 'acp' && $row['module_langname'] == 'ACP_CAT_SYSTEM') ? true : false,
'S_ACP_MODULE_MANAGEMENT' => ($this->module_class == 'acp' && ($row['module_basename'] == 'modules' || $row['module_langname'] == 'ACP_MODULE_MANAGEMENT')) ? true : false,
'U_MODULE' => $this->u_action . '&amp;parent_id=' . $row['module_id'],
'U_MOVE_UP' => $url . '&amp;action=move_up&amp;hash=' . generate_link_hash('acp_modules'),
'U_MOVE_DOWN' => $url . '&amp;action=move_down&amp;hash=' . generate_link_hash('acp_modules'),
'U_EDIT' => $url . '&amp;action=edit',
'U_DELETE' => $url . '&amp;action=delete',
'U_ENABLE' => $url . '&amp;action=enable&amp;hash=' . generate_link_hash('acp_modules'),
'U_DISABLE' => $url . '&amp;action=disable&amp;hash=' . generate_link_hash('acp_modules'))
);
}
while ($row = $db->sql_fetchrow($result));
}
else if ($this->parent_id)
{
try
{
$row = $module_manager->get_module_row($this->parent_id, $this->module_class);
}
catch (\phpbb\module\exception\module_not_found_exception $e)
{
$msg = $user->lang($e->getMessage());
trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
$url = $this->u_action . '&amp;parent_id=' . $this->parent_id . '&amp;m=' . $row['module_id'];
$template->assign_vars(array(
'S_NO_MODULES' => true,
'MODULE_TITLE' => $langname,
'MODULE_ENABLED' => ($row['module_enabled']) ? true : false,
'MODULE_DISPLAYED' => ($row['module_display']) ? true : false,
'U_EDIT' => $url . '&amp;action=edit',
'U_DELETE' => $url . '&amp;action=delete',
'U_ENABLE' => $url . '&amp;action=enable&amp;hash=' . generate_link_hash('acp_modules'),
'U_DISABLE' => $url . '&amp;action=disable&amp;hash=' . generate_link_hash('acp_modules'))
);
}
$db->sql_freeresult($result);
// Quick adding module
$module_infos = $module_manager->get_module_infos($this->module_class);
// Build quick options
$s_install_options = '';
foreach ($module_infos as $option => $values)
{
// Name options
$s_install_options .= '<optgroup label="' . $user->lang($values['title']) . ' [' . $option . ']">';
// Build module modes
foreach ($values['modes'] as $m_mode => $m_values)
{
$s_install_options .= '<option value="' . $option . '::' . $m_mode . '">&nbsp; &nbsp;' . $user->lang($m_values['title']) . '</option>';
}
$s_install_options .= '</optgroup>';
}
$template->assign_vars(array(
'U_SEL_ACTION' => $this->u_action,
'U_ACTION' => $this->u_action . '&amp;parent_id=' . $this->parent_id,
'NAVIGATION' => $navigation,
'MODULE_BOX' => $module_box,
'PARENT_ID' => $this->parent_id,
'S_INSTALL_OPTIONS' => $s_install_options,
)
);
}
/**
* Simple version of jumpbox, just lists modules
*/
function make_module_select($select_id = false, $ignore_id = false, $ignore_acl = false, $ignore_nonpost = false, $ignore_emptycat = true, $ignore_noncat = false)
{
global $db, $user;
$sql = 'SELECT module_id, module_enabled, module_basename, parent_id, module_langname, left_id, right_id, module_auth
FROM ' . MODULES_TABLE . "
WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
ORDER BY left_id ASC";
$result = $db->sql_query($sql);
$right = $iteration = 0;
$padding_store = array('0' => '');
$module_list = $padding = '';
while ($row = $db->sql_fetchrow($result))
{
if ($row['left_id'] < $right)
{
$padding .= '&nbsp; &nbsp;';
$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'];
if (!$ignore_acl && $row['module_auth'])
{
// We use zero as the forum id to check - global setting.
if (!p_master::module_auth($row['module_auth'], 0))
{
continue;
}
}
// ignore this module?
if ((is_array($ignore_id) && in_array($row['module_id'], $ignore_id)) || $row['module_id'] == $ignore_id)
{
continue;
}
// empty category
if (!$row['module_basename'] && ($row['left_id'] + 1 == $row['right_id']) && $ignore_emptycat)
{
continue;
}
// ignore non-category?
if ($row['module_basename'] && $ignore_noncat)
{
continue;
}
$selected = (is_array($select_id)) ? ((in_array($row['module_id'], $select_id)) ? ' selected="selected"' : '') : (($row['module_id'] == $select_id) ? ' selected="selected"' : '');
$langname = $user->lang($row['module_langname']);
$module_list .= '<option value="' . $row['module_id'] . '"' . $selected . ((!$row['module_enabled']) ? ' class="disabled"' : '') . '>' . $padding . $langname . '</option>';
$iteration++;
}
$db->sql_freeresult($result);
unset($padding_store);
return $module_list;
}
}

View File

@@ -0,0 +1,596 @@
<?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;
}
class acp_permission_roles
{
var $u_action;
protected $auth_admin;
function main($id, $mode)
{
global $db, $user, $template, $phpbb_container;
global $phpbb_root_path, $phpEx;
global $request, $phpbb_log;
if (!function_exists('user_get_id_name'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
if (!class_exists('auth_admin'))
{
include($phpbb_root_path . 'includes/acp/auth.' . $phpEx);
}
$this->auth_admin = new auth_admin();
$user->add_lang('acp/permissions');
add_permission_language();
$this->tpl_name = 'acp_permission_roles';
$submit = (isset($_POST['submit'])) ? true : false;
$role_id = $request->variable('role_id', 0);
$action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : $action;
$form_name = 'acp_permissions';
add_form_key($form_name);
if (!$role_id && in_array($action, array('remove', 'edit', 'move_up', 'move_down')))
{
trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
switch ($mode)
{
case 'admin_roles':
$permission_type = 'a_';
$this->page_title = 'ACP_ADMIN_ROLES';
break;
case 'user_roles':
$permission_type = 'u_';
$this->page_title = 'ACP_USER_ROLES';
break;
case 'mod_roles':
$permission_type = 'm_';
$this->page_title = 'ACP_MOD_ROLES';
break;
case 'forum_roles':
$permission_type = 'f_';
$this->page_title = 'ACP_FORUM_ROLES';
break;
default:
trigger_error('NO_MODE', E_USER_ERROR);
break;
}
$template->assign_vars(array(
'L_TITLE' => $user->lang[$this->page_title],
'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'])
);
// Take action... admin submitted something
if ($submit || $action == 'remove')
{
switch ($action)
{
case 'remove':
$sql = 'SELECT *
FROM ' . ACL_ROLES_TABLE . '
WHERE role_id = ' . $role_id;
$result = $db->sql_query($sql);
$role_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$role_row)
{
trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (confirm_box(true))
{
$this->remove_role($role_id, $permission_type);
$role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_' . strtoupper($permission_type) . 'ROLE_REMOVED', false, array($role_name));
trigger_error($user->lang['ROLE_DELETED'] . adm_back_link($this->u_action));
}
else
{
confirm_box(false, 'DELETE_ROLE', build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'role_id' => $role_id,
'action' => $action,
)));
}
break;
case 'edit':
// Get role we edit
$sql = 'SELECT *
FROM ' . ACL_ROLES_TABLE . '
WHERE role_id = ' . $role_id;
$result = $db->sql_query($sql);
$role_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$role_row)
{
trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// no break;
case 'add':
if (!check_form_key($form_name))
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
$role_name = $request->variable('role_name', '', true);
$role_description = $request->variable('role_description', '', true);
$auth_settings = $request->variable('setting', array('' => 0));
if (!$role_name)
{
trigger_error($user->lang['NO_ROLE_NAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (utf8_strlen($role_description) > 4000)
{
trigger_error($user->lang['ROLE_DESCRIPTION_LONG'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// if we add/edit a role we check the name to be unique among the settings...
$sql = 'SELECT role_id
FROM ' . ACL_ROLES_TABLE . "
WHERE role_type = '" . $db->sql_escape($permission_type) . "'
AND role_name = '" . $db->sql_escape($role_name) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
// Make sure we only print out the error if we add the role or change it's name
if ($row && ($mode == 'add' || ($mode == 'edit' && $role_row['role_name'] != $role_name)))
{
trigger_error(sprintf($user->lang['ROLE_NAME_ALREADY_EXIST'], $role_name) . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql_ary = array(
'role_name' => (string) $role_name,
'role_description' => (string) $role_description,
'role_type' => (string) $permission_type,
);
if ($action == 'edit')
{
$sql = 'UPDATE ' . ACL_ROLES_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE role_id = ' . $role_id;
$db->sql_query($sql);
}
else
{
// Get maximum role order for inserting a new role...
$sql = 'SELECT MAX(role_order) as max_order
FROM ' . ACL_ROLES_TABLE . "
WHERE role_type = '" . $db->sql_escape($permission_type) . "'";
$result = $db->sql_query($sql);
$max_order = (int) $db->sql_fetchfield('max_order');
$db->sql_freeresult($result);
$sql_ary['role_order'] = $max_order + 1;
$sql = 'INSERT INTO ' . ACL_ROLES_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
$db->sql_query($sql);
$role_id = $db->sql_nextid();
}
// Now add the auth settings
$this->auth_admin->acl_set_role($role_id, $auth_settings);
$role_name = (!empty($user->lang[$role_name])) ? $user->lang[$role_name] : $role_name;
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_' . strtoupper($permission_type) . 'ROLE_' . strtoupper($action), false, array($role_name));
trigger_error($user->lang['ROLE_' . strtoupper($action) . '_SUCCESS'] . adm_back_link($this->u_action));
break;
}
}
// Display screens
switch ($action)
{
case 'add':
$options_from = $request->variable('options_from', 0);
$role_row = array(
'role_name' => $request->variable('role_name', '', true),
'role_description' => $request->variable('role_description', '', true),
'role_type' => $permission_type,
);
if ($options_from)
{
$sql = 'SELECT p.auth_option_id, p.auth_setting, o.auth_option
FROM ' . ACL_ROLES_DATA_TABLE . ' p, ' . ACL_OPTIONS_TABLE . ' o
WHERE o.auth_option_id = p.auth_option_id
AND p.role_id = ' . $options_from . '
ORDER BY p.auth_option_id';
$result = $db->sql_query($sql);
$auth_options = array();
while ($row = $db->sql_fetchrow($result))
{
$auth_options[$row['auth_option']] = $row['auth_setting'];
}
$db->sql_freeresult($result);
}
else
{
$sql = 'SELECT auth_option_id, auth_option
FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()) . "
AND auth_option <> '{$permission_type}'
ORDER BY auth_option_id";
$result = $db->sql_query($sql);
$auth_options = array();
while ($row = $db->sql_fetchrow($result))
{
$auth_options[$row['auth_option']] = ACL_NO;
}
$db->sql_freeresult($result);
}
// no break;
case 'edit':
if ($action == 'edit')
{
$sql = 'SELECT *
FROM ' . ACL_ROLES_TABLE . '
WHERE role_id = ' . $role_id;
$result = $db->sql_query($sql);
$role_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$sql = 'SELECT p.auth_option_id, p.auth_setting, o.auth_option
FROM ' . ACL_ROLES_DATA_TABLE . ' p, ' . ACL_OPTIONS_TABLE . ' o
WHERE o.auth_option_id = p.auth_option_id
AND p.role_id = ' . $role_id . '
ORDER BY p.auth_option_id';
$result = $db->sql_query($sql);
$auth_options = array();
while ($row = $db->sql_fetchrow($result))
{
$auth_options[$row['auth_option']] = $row['auth_setting'];
}
$db->sql_freeresult($result);
}
if (!$role_row)
{
trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
/* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
$template->assign_vars(array(
'S_EDIT' => true,
'U_ACTION' => $this->u_action . "&amp;action={$action}&amp;role_id={$role_id}",
'U_BACK' => $this->u_action,
'ROLE_NAME' => $role_row['role_name'],
'ROLE_DESCRIPTION' => $role_row['role_description'],
'L_ACL_TYPE' => $phpbb_permissions->get_type_lang($permission_type),
));
// We need to fill the auth options array with ACL_NO options ;)
$sql = 'SELECT auth_option_id, auth_option
FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()) . "
AND auth_option <> '{$permission_type}'
ORDER BY auth_option_id";
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
if (!isset($auth_options[$row['auth_option']]))
{
$auth_options[$row['auth_option']] = ACL_NO;
}
}
$db->sql_freeresult($result);
// Unset global permission option
unset($auth_options[$permission_type]);
// Display auth options
$this->display_auth_options($auth_options);
// Get users/groups/forums using this preset...
if ($action == 'edit')
{
$hold_ary = $this->auth_admin->get_role_mask($role_id);
if (count($hold_ary))
{
$role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
$template->assign_vars(array(
'S_DISPLAY_ROLE_MASK' => true,
'L_ROLE_ASSIGNED_TO' => sprintf($user->lang['ROLE_ASSIGNED_TO'], $role_name))
);
$this->auth_admin->display_role_mask($hold_ary);
}
}
return;
break;
case 'move_up':
case 'move_down':
if (!check_link_hash($request->variable('hash', ''), 'acp_permission_roles'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT role_order
FROM ' . ACL_ROLES_TABLE . "
WHERE role_id = $role_id";
$result = $db->sql_query($sql);
$order = $db->sql_fetchfield('role_order');
$db->sql_freeresult($result);
if ($order === false || ($order == 0 && $action == 'move_up'))
{
break;
}
$order = (int) $order;
$order_total = $order * 2 + (($action == 'move_up') ? -1 : 1);
$sql = 'UPDATE ' . ACL_ROLES_TABLE . '
SET role_order = ' . $order_total . " - role_order
WHERE role_type = '" . $db->sql_escape($permission_type) . "'
AND role_order IN ($order, " . (($action == 'move_up') ? $order - 1 : $order + 1) . ')';
$db->sql_query($sql);
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'success' => (bool) $db->sql_affectedrows(),
));
}
break;
}
// By default, check that role_order is valid and fix it if necessary
$sql = 'SELECT role_id, role_order
FROM ' . ACL_ROLES_TABLE . "
WHERE role_type = '" . $db->sql_escape($permission_type) . "'
ORDER BY role_order ASC";
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
$order = 0;
do
{
$order++;
if ($row['role_order'] != $order)
{
$db->sql_query('UPDATE ' . ACL_ROLES_TABLE . " SET role_order = $order WHERE role_id = {$row['role_id']}");
}
}
while ($row = $db->sql_fetchrow($result));
}
$db->sql_freeresult($result);
// Display assigned items?
$display_item = $request->variable('display_item', 0);
// Select existing roles
$sql = 'SELECT *
FROM ' . ACL_ROLES_TABLE . "
WHERE role_type = '" . $db->sql_escape($permission_type) . "'
ORDER BY role_order ASC";
$result = $db->sql_query($sql);
$s_role_options = '';
while ($row = $db->sql_fetchrow($result))
{
$role_name = (!empty($user->lang[$row['role_name']])) ? $user->lang[$row['role_name']] : $row['role_name'];
$template->assign_block_vars('roles', array(
'ROLE_NAME' => $role_name,
'ROLE_DESCRIPTION' => (!empty($user->lang[$row['role_description']])) ? $user->lang[$row['role_description']] : nl2br($row['role_description']),
'U_EDIT' => $this->u_action . '&amp;action=edit&amp;role_id=' . $row['role_id'],
'U_REMOVE' => $this->u_action . '&amp;action=remove&amp;role_id=' . $row['role_id'],
'U_MOVE_UP' => $this->u_action . '&amp;action=move_up&amp;role_id=' . $row['role_id'] . '&amp;hash=' . generate_link_hash('acp_permission_roles'),
'U_MOVE_DOWN' => $this->u_action . '&amp;action=move_down&amp;role_id=' . $row['role_id'] . '&amp;hash=' . generate_link_hash('acp_permission_roles'),
'U_DISPLAY_ITEMS' => ($row['role_id'] == $display_item) ? '' : $this->u_action . '&amp;display_item=' . $row['role_id'] . '#assigned_to')
);
$s_role_options .= '<option value="' . $row['role_id'] . '">' . $role_name . '</option>';
if ($display_item == $row['role_id'])
{
$template->assign_vars(array(
'L_ROLE_ASSIGNED_TO' => sprintf($user->lang['ROLE_ASSIGNED_TO'], $role_name))
);
}
}
$db->sql_freeresult($result);
$template->assign_vars(array(
'S_ROLE_OPTIONS' => $s_role_options)
);
if ($display_item)
{
$template->assign_vars(array(
'S_DISPLAY_ROLE_MASK' => true)
);
$hold_ary = $this->auth_admin->get_role_mask($display_item);
$this->auth_admin->display_role_mask($hold_ary);
}
}
/**
* Display permission settings able to be set
*/
function display_auth_options($auth_options)
{
global $template, $phpbb_container;
/* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
$content_array = $categories = array();
$key_sort_array = array(0);
$auth_options = array(0 => $auth_options);
// Making use of auth_admin method here (we do not really want to change two similar code fragments)
$this->auth_admin->build_permission_array($auth_options, $content_array, $categories, $key_sort_array);
$content_array = $content_array[0];
$template->assign_var('S_NUM_PERM_COLS', count($categories));
// Assign to template
foreach ($content_array as $cat => $cat_array)
{
$template->assign_block_vars('auth', array(
'CAT_NAME' => $phpbb_permissions->get_category_lang($cat),
'S_YES' => ($cat_array['S_YES'] && !$cat_array['S_NEVER'] && !$cat_array['S_NO']) ? true : false,
'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false,
'S_NO' => ($cat_array['S_NO'] && !$cat_array['S_NEVER'] && !$cat_array['S_YES']) ? true : false)
);
foreach ($cat_array['permissions'] as $permission => $allowed)
{
$template->assign_block_vars('auth.mask', array(
'S_YES' => ($allowed == ACL_YES) ? true : false,
'S_NEVER' => ($allowed == ACL_NEVER) ? true : false,
'S_NO' => ($allowed == ACL_NO) ? true : false,
'FIELD_NAME' => $permission,
'PERMISSION' => $phpbb_permissions->get_permission_lang($permission),
));
}
}
}
/**
* Remove role
*/
function remove_role($role_id, $permission_type)
{
global $db;
// Get complete auth array
$sql = 'SELECT auth_option, auth_option_id
FROM ' . ACL_OPTIONS_TABLE . "
WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char());
$result = $db->sql_query($sql);
$auth_settings = array();
while ($row = $db->sql_fetchrow($result))
{
$auth_settings[$row['auth_option']] = ACL_NO;
}
$db->sql_freeresult($result);
// Get the role auth settings we need to re-set...
$sql = 'SELECT o.auth_option, r.auth_setting
FROM ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' o
WHERE o.auth_option_id = r.auth_option_id
AND r.role_id = ' . $role_id;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$auth_settings[$row['auth_option']] = $row['auth_setting'];
}
$db->sql_freeresult($result);
// Get role assignments
$hold_ary = $this->auth_admin->get_role_mask($role_id);
// Re-assign permissions
foreach ($hold_ary as $forum_id => $forum_ary)
{
if (isset($forum_ary['users']))
{
$this->auth_admin->acl_set('user', $forum_id, $forum_ary['users'], $auth_settings, 0, false);
}
if (isset($forum_ary['groups']))
{
$this->auth_admin->acl_set('group', $forum_id, $forum_ary['groups'], $auth_settings, 0, false);
}
}
// Remove role from users and groups just to be sure (happens through acl_set)
$sql = 'DELETE FROM ' . ACL_USERS_TABLE . '
WHERE auth_role_id = ' . $role_id;
$db->sql_query($sql);
$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
WHERE auth_role_id = ' . $role_id;
$db->sql_query($sql);
// Remove role data and role
$sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
WHERE role_id = ' . $role_id;
$db->sql_query($sql);
$sql = 'DELETE FROM ' . ACL_ROLES_TABLE . '
WHERE role_id = ' . $role_id;
$db->sql_query($sql);
$this->auth_admin->acl_clear_prefetch();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
<?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;
}
class acp_php_info
{
var $u_action;
function main($id, $mode)
{
global $template;
if ($mode != 'info')
{
trigger_error('NO_MODE', E_USER_ERROR);
}
$this->tpl_name = 'acp_php_info';
$this->page_title = 'ACP_PHP_INFO';
ob_start();
phpinfo(INFO_GENERAL | INFO_CONFIGURATION | INFO_MODULES | INFO_VARIABLES);
$phpinfo = ob_get_clean();
$phpinfo = trim($phpinfo);
// Here we play around a little with the PHP Info HTML to try and stylise
// it along phpBB's lines ... hopefully without breaking anything. The idea
// for this was nabbed from the PHP annotated manual
preg_match_all('#<body[^>]*>(.*)</body>#si', $phpinfo, $output);
if (empty($phpinfo) || empty($output[1][0]))
{
trigger_error('NO_PHPINFO_AVAILABLE', E_USER_WARNING);
}
$output = $output[1][0];
// expose_php can make the image not exist
if (preg_match('#<a[^>]*><img[^>]*></a>#', $output))
{
$output = preg_replace('#<tr class="v"><td>(.*?<a[^>]*><img[^>]*></a>)(.*?)</td></tr>#s', '<tr class="row1"><td><table class="type2"><tr><td>\2</td><td>\1</td></tr></table></td></tr>', $output);
}
else
{
$output = preg_replace('#<tr class="v"><td>(.*?)</td></tr>#s', '<tr class="row1"><td><table class="type2"><tr><td>\1</td></tr></table></td></tr>', $output);
}
$output = preg_replace('#<table[^>]+>#i', '<table>', $output);
$output = preg_replace('#<img border="0"#i', '<img', $output);
$output = str_replace(array('class="e"', 'class="v"', 'class="h"', '<hr />', '<font', '</font>'), array('class="row1"', 'class="row2"', '', '', '<span', '</span>'), $output);
// Fix invalid anchor names (eg "module_Zend Optimizer")
$output = preg_replace_callback('#<a name="([^"]+)">#', array($this, 'remove_spaces'), $output);
if (empty($output))
{
trigger_error('NO_PHPINFO_AVAILABLE', E_USER_WARNING);
}
$orig_output = $output;
preg_match_all('#<div class="center">(.*)</div>#siU', $output, $output);
$output = (!empty($output[1][0])) ? $output[1][0] : $orig_output;
$template->assign_var('PHPINFO', $output);
}
function remove_spaces($matches)
{
return '<a name="' . str_replace(' ', '_', $matches[1]) . '">';
}
}

1292
includes/acp/acp_profile.php Normal file

File diff suppressed because it is too large Load Diff

587
includes/acp/acp_prune.php Normal file
View File

@@ -0,0 +1,587 @@
<?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;
}
class acp_prune
{
var $u_action;
function main($id, $mode)
{
global $user, $phpEx, $phpbb_root_path;
$user->add_lang('acp/prune');
if (!function_exists('user_active_flip'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
switch ($mode)
{
case 'forums':
$this->tpl_name = 'acp_prune_forums';
$this->page_title = 'ACP_PRUNE_FORUMS';
$this->prune_forums($id, $mode);
break;
case 'users':
$this->tpl_name = 'acp_prune_users';
$this->page_title = 'ACP_PRUNE_USERS';
$this->prune_users($id, $mode);
break;
}
}
/**
* Prune forums
*/
function prune_forums($id, $mode)
{
global $db, $user, $auth, $template, $phpbb_log, $request, $phpbb_dispatcher;
$all_forums = $request->variable('all_forums', 0);
$forum_id = $request->variable('f', array(0));
$submit = (isset($_POST['submit'])) ? true : false;
if ($all_forums)
{
$sql = 'SELECT forum_id
FROM ' . FORUMS_TABLE . '
ORDER BY left_id';
$result = $db->sql_query($sql);
$forum_id = array();
while ($row = $db->sql_fetchrow($result))
{
$forum_id[] = $row['forum_id'];
}
$db->sql_freeresult($result);
}
if ($submit)
{
if (confirm_box(true))
{
$prune_posted = $request->variable('prune_days', 0);
$prune_viewed = $request->variable('prune_vieweddays', 0);
$prune_all = (!$prune_posted && !$prune_viewed) ? true : false;
$prune_flags = 0;
$prune_flags += ($request->variable('prune_old_polls', 0)) ? 2 : 0;
$prune_flags += ($request->variable('prune_announce', 0)) ? 4 : 0;
$prune_flags += ($request->variable('prune_sticky', 0)) ? 8 : 0;
// Convert days to seconds for timestamp functions...
$prunedate_posted = time() - ($prune_posted * 86400);
$prunedate_viewed = time() - ($prune_viewed * 86400);
$template->assign_vars(array(
'S_PRUNED' => true)
);
$sql_forum = (count($forum_id)) ? ' AND ' . $db->sql_in_set('forum_id', $forum_id) : '';
// Get a list of forum's or the data for the forum that we are pruning.
$sql = 'SELECT forum_id, forum_name
FROM ' . FORUMS_TABLE . '
WHERE forum_type = ' . FORUM_POST . "
$sql_forum
ORDER BY left_id ASC";
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
$prune_ids = array();
$p_result['topics'] = 0;
$p_result['posts'] = 0;
$log_data = '';
do
{
if (!$auth->acl_get('f_list', $row['forum_id']))
{
continue;
}
if ($prune_all)
{
$p_result = prune($row['forum_id'], 'posted', time(), $prune_flags, false);
}
else
{
if ($prune_posted)
{
$return = prune($row['forum_id'], 'posted', $prunedate_posted, $prune_flags, false);
$p_result['topics'] += $return['topics'];
$p_result['posts'] += $return['posts'];
}
if ($prune_viewed)
{
$return = prune($row['forum_id'], 'viewed', $prunedate_viewed, $prune_flags, false);
$p_result['topics'] += $return['topics'];
$p_result['posts'] += $return['posts'];
}
}
$prune_ids[] = $row['forum_id'];
$template->assign_block_vars('pruned', array(
'FORUM_NAME' => $row['forum_name'],
'NUM_TOPICS' => $p_result['topics'],
'NUM_POSTS' => $p_result['posts'])
);
$log_data .= (($log_data != '') ? ', ' : '') . $row['forum_name'];
}
while ($row = $db->sql_fetchrow($result));
// Sync all pruned forums at once
sync('forum', 'forum_id', $prune_ids, true, true);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PRUNE', false, array($log_data));
}
$db->sql_freeresult($result);
return;
}
else
{
$hidden_fields = array(
'i' => $id,
'mode' => $mode,
'submit' => 1,
'all_forums' => $all_forums,
'f' => $forum_id,
'prune_days' => $request->variable('prune_days', 0),
'prune_vieweddays' => $request->variable('prune_vieweddays', 0),
'prune_old_polls' => $request->variable('prune_old_polls', 0),
'prune_announce' => $request->variable('prune_announce', 0),
'prune_sticky' => $request->variable('prune_sticky', 0),
);
/**
* Use this event to pass data from the prune form to the confirmation screen
*
* @event core.prune_forums_settings_confirm
* @var array hidden_fields Hidden fields that are passed through the confirm screen
* @since 3.2.2-RC1
*/
$vars = array('hidden_fields');
extract($phpbb_dispatcher->trigger_event('core.prune_forums_settings_confirm', compact($vars)));
confirm_box(false, $user->lang['PRUNE_FORUM_CONFIRM'], build_hidden_fields($hidden_fields));
}
}
// If they haven't selected a forum for pruning yet then
// display a select box to use for pruning.
if (!count($forum_id))
{
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
'S_SELECT_FORUM' => true,
'S_FORUM_OPTIONS' => make_forum_select(false, false, false))
);
}
else
{
$sql = 'SELECT forum_id, forum_name
FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_id);
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
if (!$row)
{
$db->sql_freeresult($result);
trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$forum_list = $s_hidden_fields = '';
do
{
$forum_list .= (($forum_list != '') ? ', ' : '') . '<b>' . $row['forum_name'] . '</b>';
$s_hidden_fields .= '<input type="hidden" name="f[]" value="' . $row['forum_id'] . '" />';
}
while ($row = $db->sql_fetchrow($result));
$db->sql_freeresult($result);
$l_selected_forums = (count($forum_id) == 1) ? 'SELECTED_FORUM' : 'SELECTED_FORUMS';
$template_data = array(
'L_SELECTED_FORUMS' => $user->lang[$l_selected_forums],
'U_ACTION' => $this->u_action,
'U_BACK' => $this->u_action,
'FORUM_LIST' => $forum_list,
'S_HIDDEN_FIELDS' => $s_hidden_fields,
);
/**
* Event to add/modify prune forums settings template data
*
* @event core.prune_forums_settings_template_data
* @var array template_data Array with form template data
* @since 3.2.2-RC1
*/
$vars = array('template_data');
extract($phpbb_dispatcher->trigger_event('core.prune_forums_settings_template_data', compact($vars)));
$template->assign_vars($template_data);
}
}
/**
* Prune users
*/
function prune_users($id, $mode)
{
global $db, $user, $auth, $template, $phpbb_log, $request;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container;
/** @var \phpbb\group\helper $group_helper */
$group_helper = $phpbb_container->get('group_helper');
$user->add_lang('memberlist');
$prune = (isset($_POST['prune'])) ? true : false;
if ($prune)
{
$action = $request->variable('action', 'deactivate');
$deleteposts = $request->variable('deleteposts', 0);
if (confirm_box(true))
{
$user_ids = $usernames = array();
$this->get_prune_users($user_ids, $usernames);
if (count($user_ids))
{
if ($action == 'deactivate')
{
user_active_flip('deactivate', $user_ids);
$l_log = 'LOG_PRUNE_USER_DEAC';
}
else if ($action == 'delete')
{
if ($deleteposts)
{
user_delete('remove', $user_ids);
$l_log = 'LOG_PRUNE_USER_DEL_DEL';
}
else
{
user_delete('retain', $user_ids, true);
$l_log = 'LOG_PRUNE_USER_DEL_ANON';
}
}
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, $l_log, false, array(implode(', ', $usernames)));
$msg = $user->lang['USER_' . strtoupper($action) . '_SUCCESS'];
}
else
{
$msg = $user->lang['USER_PRUNE_FAILURE'];
}
trigger_error($msg . adm_back_link($this->u_action));
}
else
{
// We list the users which will be pruned...
$user_ids = $usernames = array();
$this->get_prune_users($user_ids, $usernames);
if (!count($user_ids))
{
trigger_error($user->lang['USER_PRUNE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Assign to template
foreach ($user_ids as $user_id)
{
$template->assign_block_vars('users', array(
'USERNAME' => $usernames[$user_id],
'USER_ID' => $user_id,
'U_PROFILE' => get_username_string('profile', $user_id, $usernames[$user_id]),
'U_USER_ADMIN' => ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview&amp;u=' . $user_id, true, $user->session_id) : '',
));
}
$template->assign_vars(array(
'S_DEACTIVATE' => ($action == 'deactivate') ? true : false,
'S_DELETE' => ($action == 'delete') ? true : false,
));
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'prune' => 1,
'deleteposts' => $request->variable('deleteposts', 0),
'action' => $request->variable('action', ''),
)), 'confirm_body_prune.html');
}
}
$find_count = array('lt' => $user->lang['LESS_THAN'], 'eq' => $user->lang['EQUAL_TO'], 'gt' => $user->lang['MORE_THAN']);
$s_find_count = '';
foreach ($find_count as $key => $value)
{
$selected = ($key == 'eq') ? ' selected="selected"' : '';
$s_find_count .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
}
$find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']);
$s_find_active_time = '';
foreach ($find_time as $key => $value)
{
$s_find_active_time .= '<option value="' . $key . '">' . $value . '</option>';
}
$sql = 'SELECT group_id, group_name
FROM ' . GROUPS_TABLE . '
WHERE group_type <> ' . GROUP_SPECIAL . '
ORDER BY group_name ASC';
$result = $db->sql_query($sql);
$s_group_list = '';
while ($row = $db->sql_fetchrow($result))
{
$s_group_list .= '<option value="' . $row['group_id'] . '">' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
if ($s_group_list)
{
// Only prepend the "All groups" option if there are groups,
// otherwise we don't want to display this option at all.
$s_group_list = '<option value="0">' . $user->lang['PRUNE_USERS_GROUP_NONE'] . '</option>' . $s_group_list;
}
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
'S_ACTIVE_OPTIONS' => $s_find_active_time,
'S_GROUP_LIST' => $s_group_list,
'S_COUNT_OPTIONS' => $s_find_count,
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=acp_prune&amp;field=users'),
));
}
/**
* Get user_ids/usernames from those being pruned
*/
function get_prune_users(&$user_ids, &$usernames)
{
global $user, $db, $request;
$users_by_name = $request->variable('users', '', true);
$users_by_id = $request->variable('user_ids', array(0));
$group_id = $request->variable('group_id', 0);
$posts_on_queue = (trim($request->variable('posts_on_queue', '')) === '') ? false : $request->variable('posts_on_queue', 0);
if ($users_by_name)
{
$users = explode("\n", $users_by_name);
$where_sql = ' AND ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', $users));
}
else if (!empty($users_by_id))
{
$user_ids = $users_by_id;
user_get_id_name($user_ids, $usernames);
$where_sql = ' AND ' . $db->sql_in_set('user_id', $user_ids);
}
else
{
$username = $request->variable('username', '', true);
$email = $request->variable('email', '');
$active_select = $request->variable('active_select', 'lt');
$count_select = $request->variable('count_select', 'eq');
$queue_select = $request->variable('queue_select', 'gt');
$joined_before = $request->variable('joined_before', '');
$joined_after = $request->variable('joined_after', '');
$active = $request->variable('active', '');
$count = ($request->variable('count', '') === '') ? false : $request->variable('count', 0);
$active = ($active) ? explode('-', $active) : array();
$joined_before = ($joined_before) ? explode('-', $joined_before) : array();
$joined_after = ($joined_after) ? explode('-', $joined_after) : array();
// calculate the conditions required by the join time criteria
$joined_sql = '';
if (!empty($joined_before) && !empty($joined_after))
{
// if the two entered dates are equal, we need to adjust
// so that our time range is a full day instead of 1 second
if ($joined_after == $joined_before)
{
$joined_after[2] += 1;
}
$joined_sql = ' AND user_regdate BETWEEN ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]) .
' AND ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]);
}
else if (empty($joined_before) && !empty($joined_after))
{
$joined_sql = ' AND user_regdate > ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]);
}
else if (empty($joined_after) && !empty($joined_before))
{
$joined_sql = ' AND user_regdate < ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]);
}
// implicit else when both arrays are empty do nothing
if ((count($active) && count($active) != 3) || (count($joined_before) && count($joined_before) != 3) || (count($joined_after) && count($joined_after) != 3))
{
trigger_error($user->lang['WRONG_ACTIVE_JOINED_DATE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$key_match = array('lt' => '<', 'gt' => '>', 'eq' => '=');
$where_sql = '';
$where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : '';
$where_sql .= ($email) ? ' AND user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : '';
$where_sql .= $joined_sql;
$where_sql .= ($count !== false) ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : '';
// First handle pruning of users who never logged in, last active date is 0000-00-00
if (count($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0)
{
$where_sql .= ' AND user_lastvisit = 0';
}
else if (count($active) && $active_select != 'lt')
{
$where_sql .= ' AND user_lastvisit ' . $key_match[$active_select] . ' ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]);
}
else if (count($active))
{
$where_sql .= ' AND (user_lastvisit > 0 AND user_lastvisit < ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]) . ')';
}
}
// If no search criteria were provided, go no further.
if (!$where_sql && !$group_id && $posts_on_queue === false)
{
return;
}
// Get bot ids
$sql = 'SELECT user_id
FROM ' . BOTS_TABLE;
$result = $db->sql_query($sql);
$bot_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$bot_ids[] = $row['user_id'];
}
$db->sql_freeresult($result);
// Protect the admin, do not prune if no options are given...
if ($where_sql)
{
// Do not prune founder members
$sql = 'SELECT user_id, username
FROM ' . USERS_TABLE . '
WHERE user_id <> ' . ANONYMOUS . '
AND user_type <> ' . USER_FOUNDER . "
$where_sql";
$result = $db->sql_query($sql);
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
// Do not prune bots and the user currently pruning.
if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids))
{
$user_ids[] = $row['user_id'];
$usernames[$row['user_id']] = $row['username'];
}
}
$db->sql_freeresult($result);
}
if ($group_id)
{
$sql = 'SELECT u.user_id, u.username
FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u
WHERE ug.group_id = ' . (int) $group_id . '
AND ug.user_id <> ' . ANONYMOUS . '
AND u.user_type <> ' . USER_FOUNDER . '
AND ug.user_pending = 0
AND u.user_id = ug.user_id
' . (!empty($user_ids) ? ' AND ' . $db->sql_in_set('ug.user_id', $user_ids) : '');
$result = $db->sql_query($sql);
// we're performing an intersection operation, so all the relevant users
// come from this most recent query (which was limited to the results of the
// previous query)
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
// Do not prune bots and the user currently pruning.
if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids))
{
$user_ids[] = $row['user_id'];
$usernames[$row['user_id']] = $row['username'];
}
}
$db->sql_freeresult($result);
}
if ($posts_on_queue !== false)
{
$sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
WHERE u.user_id <> ' . ANONYMOUS . '
AND u.user_type <> ' . USER_FOUNDER . '
AND ' . $db->sql_in_set('p.post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)) . '
AND u.user_id = p.poster_id
' . (!empty($user_ids) ? ' AND ' . $db->sql_in_set('p.poster_id', $user_ids) : '') . '
GROUP BY p.poster_id
HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue;
$result = $db->sql_query($sql);
// same intersection logic as the above group ID portion
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
// Do not prune bots and the user currently pruning.
if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids))
{
$user_ids[] = $row['user_id'];
$usernames[$row['user_id']] = $row['username'];
}
}
$db->sql_freeresult($result);
}
}
}

285
includes/acp/acp_ranks.php Normal file
View File

@@ -0,0 +1,285 @@
<?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;
}
class acp_ranks
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $cache, $request, $phpbb_dispatcher;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpbb_log;
$user->add_lang('acp/posting');
// Set up general vars
$action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : $action;
$action = (isset($_POST['save'])) ? 'save' : $action;
$rank_id = $request->variable('id', 0);
$this->tpl_name = 'acp_ranks';
$this->page_title = 'ACP_MANAGE_RANKS';
$form_name = 'acp_ranks';
add_form_key($form_name);
switch ($action)
{
case 'save':
if (!check_form_key($form_name))
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
$rank_title = $request->variable('title', '', true);
$special_rank = $request->variable('special_rank', 0);
$min_posts = ($special_rank) ? 0 : max(0, $request->variable('min_posts', 0));
$rank_image = $request->variable('rank_image', '');
// The rank image has to be a jpg, gif or png
if ($rank_image != '' && !preg_match('#(\.gif|\.png|\.jpg|\.jpeg)$#i', $rank_image))
{
$rank_image = '';
}
if (!$rank_title)
{
trigger_error($user->lang['NO_RANK_TITLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql_ary = array(
'rank_title' => $rank_title,
'rank_special' => $special_rank,
'rank_min' => $min_posts,
'rank_image' => htmlspecialchars_decode($rank_image)
);
/**
* Modify the SQL array when saving a rank
*
* @event core.acp_ranks_save_modify_sql_ary
* @var int rank_id The ID of the rank (if available)
* @var array sql_ary Array with the rank's data
* @since 3.1.0-RC3
*/
$vars = array('rank_id', 'sql_ary');
extract($phpbb_dispatcher->trigger_event('core.acp_ranks_save_modify_sql_ary', compact($vars)));
if ($rank_id)
{
$sql = 'UPDATE ' . RANKS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " WHERE rank_id = $rank_id";
$message = $user->lang['RANK_UPDATED'];
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RANK_UPDATED', false, array($rank_title));
}
else
{
$sql = 'INSERT INTO ' . RANKS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
$message = $user->lang['RANK_ADDED'];
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RANK_ADDED', false, array($rank_title));
}
$db->sql_query($sql);
$cache->destroy('_ranks');
trigger_error($message . adm_back_link($this->u_action));
break;
case 'delete':
if (!$rank_id)
{
trigger_error($user->lang['MUST_SELECT_RANK'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (confirm_box(true))
{
$sql = 'SELECT rank_title
FROM ' . RANKS_TABLE . '
WHERE rank_id = ' . $rank_id;
$result = $db->sql_query($sql);
$rank_title = (string) $db->sql_fetchfield('rank_title');
$db->sql_freeresult($result);
$sql = 'DELETE FROM ' . RANKS_TABLE . "
WHERE rank_id = $rank_id";
$db->sql_query($sql);
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_rank = 0
WHERE user_rank = $rank_id";
$db->sql_query($sql);
$cache->destroy('_ranks');
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RANK_REMOVED', false, array($rank_title));
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'MESSAGE_TITLE' => $user->lang['INFORMATION'],
'MESSAGE_TEXT' => $user->lang['RANK_REMOVED'],
'REFRESH_DATA' => array(
'time' => 3
)
));
}
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'rank_id' => $rank_id,
'action' => 'delete',
)));
}
break;
case 'edit':
case 'add':
$ranks = $existing_imgs = array();
$sql = 'SELECT *
FROM ' . RANKS_TABLE . '
ORDER BY rank_min ASC, rank_special ASC';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$existing_imgs[] = $row['rank_image'];
if ($action == 'edit' && $rank_id == $row['rank_id'])
{
$ranks = $row;
}
}
$db->sql_freeresult($result);
$imglist = filelist($phpbb_root_path . $config['ranks_path'], '');
$edit_img = $filename_list = '';
foreach ($imglist as $path => $img_ary)
{
sort($img_ary);
foreach ($img_ary as $img)
{
$img = $path . $img;
if ($ranks && $img == $ranks['rank_image'])
{
$selected = ' selected="selected"';
$edit_img = $img;
}
else
{
$selected = '';
}
if (strlen($img) > 255)
{
continue;
}
$filename_list .= '<option value="' . htmlspecialchars($img) . '"' . $selected . '>' . $img . ((in_array($img, $existing_imgs)) ? ' ' . $user->lang['RANK_IMAGE_IN_USE'] : '') . '</option>';
}
}
$filename_list = '<option value=""' . (($edit_img == '') ? ' selected="selected"' : '') . '>----------</option>' . $filename_list;
unset($existing_imgs, $imglist);
$tpl_ary = array(
'S_EDIT' => true,
'U_BACK' => $this->u_action,
'RANKS_PATH' => $phpbb_root_path . $config['ranks_path'],
'U_ACTION' => $this->u_action . '&amp;id=' . $rank_id,
'RANK_TITLE' => (isset($ranks['rank_title'])) ? $ranks['rank_title'] : '',
'S_FILENAME_LIST' => $filename_list,
'RANK_IMAGE' => ($edit_img) ? $phpbb_root_path . $config['ranks_path'] . '/' . $edit_img : htmlspecialchars($phpbb_admin_path) . 'images/spacer.gif',
'S_SPECIAL_RANK' => (isset($ranks['rank_special']) && $ranks['rank_special']) ? true : false,
'MIN_POSTS' => (isset($ranks['rank_min']) && !$ranks['rank_special']) ? $ranks['rank_min'] : 0,
);
/**
* Modify the template output array for editing/adding ranks
*
* @event core.acp_ranks_edit_modify_tpl_ary
* @var array ranks Array with the rank's data
* @var array tpl_ary Array with the rank's template data
* @since 3.1.0-RC3
*/
$vars = array('ranks', 'tpl_ary');
extract($phpbb_dispatcher->trigger_event('core.acp_ranks_edit_modify_tpl_ary', compact($vars)));
$template->assign_vars($tpl_ary);
return;
break;
}
$template->assign_vars(array(
'U_ACTION' => $this->u_action)
);
$sql = 'SELECT *
FROM ' . RANKS_TABLE . '
ORDER BY rank_special DESC, rank_min ASC, rank_title ASC';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$rank_row = array(
'S_RANK_IMAGE' => ($row['rank_image']) ? true : false,
'S_SPECIAL_RANK' => ($row['rank_special']) ? true : false,
'RANK_IMAGE' => $phpbb_root_path . $config['ranks_path'] . '/' . $row['rank_image'],
'RANK_TITLE' => $row['rank_title'],
'MIN_POSTS' => $row['rank_min'],
'U_EDIT' => $this->u_action . '&amp;action=edit&amp;id=' . $row['rank_id'],
'U_DELETE' => $this->u_action . '&amp;action=delete&amp;id=' . $row['rank_id'],
);
/**
* Modify the template output array for each listed rank
*
* @event core.acp_ranks_list_modify_rank_row
* @var array row Array with the rank's data
* @var array rank_row Array with the rank's template data
* @since 3.1.0-RC3
*/
$vars = array('row', 'rank_row');
extract($phpbb_dispatcher->trigger_event('core.acp_ranks_list_modify_rank_row', compact($vars)));
$template->assign_block_vars('ranks', $rank_row);
}
$db->sql_freeresult($result);
}
}

View File

@@ -0,0 +1,394 @@
<?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;
}
class acp_reasons
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template;
global $request, $phpbb_log;
$user->add_lang(array('mcp', 'acp/posting'));
// Set up general vars
$action = $request->variable('action', '');
$submit = (isset($_POST['submit'])) ? true : false;
$reason_id = $request->variable('id', 0);
$this->tpl_name = 'acp_reasons';
$this->page_title = 'ACP_REASONS';
$form_name = 'acp_reason';
add_form_key('acp_reason');
$error = array();
switch ($action)
{
case 'add':
case 'edit':
$reason_row = array(
'reason_title' => $request->variable('reason_title', '', true),
'reason_description' => $request->variable('reason_description', '', true),
);
if ($submit)
{
if (!check_form_key($form_name))
{
$error[] = $user->lang['FORM_INVALID'];
}
// Reason specified?
if (!$reason_row['reason_title'] || !$reason_row['reason_description'])
{
$error[] = $user->lang['NO_REASON_INFO'];
}
$check_double = ($action == 'add') ? true : false;
if ($action == 'edit')
{
$sql = 'SELECT reason_title
FROM ' . REPORTS_REASONS_TABLE . "
WHERE reason_id = $reason_id";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (strtolower($row['reason_title']) == 'other' || strtolower($reason_row['reason_title']) == 'other')
{
$reason_row['reason_title'] = 'other';
}
if ($row['reason_title'] != $reason_row['reason_title'])
{
$check_double = true;
}
}
// Check for same reason if adding it...
if ($check_double)
{
$sql = 'SELECT reason_id
FROM ' . REPORTS_REASONS_TABLE . "
WHERE reason_title = '" . $db->sql_escape($reason_row['reason_title']) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if ($row || ($action == 'add' && strtolower($reason_row['reason_title']) == 'other'))
{
$error[] = $user->lang['REASON_ALREADY_EXIST'];
}
}
if (!count($error))
{
// New reason?
if ($action == 'add')
{
// Get new order...
$sql = 'SELECT MAX(reason_order) as max_reason_order
FROM ' . REPORTS_REASONS_TABLE;
$result = $db->sql_query($sql);
$max_order = (int) $db->sql_fetchfield('max_reason_order');
$db->sql_freeresult($result);
$sql_ary = array(
'reason_title' => (string) $reason_row['reason_title'],
'reason_description' => (string) $reason_row['reason_description'],
'reason_order' => $max_order + 1
);
$db->sql_query('INSERT INTO ' . REPORTS_REASONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$log = 'ADDED';
}
else if ($reason_id)
{
$sql_ary = array(
'reason_title' => (string) $reason_row['reason_title'],
'reason_description' => (string) $reason_row['reason_description'],
);
$db->sql_query('UPDATE ' . REPORTS_REASONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE reason_id = ' . $reason_id);
$log = 'UPDATED';
}
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_REASON_' . $log, false, array($reason_row['reason_title']));
trigger_error($user->lang['REASON_' . $log] . adm_back_link($this->u_action));
}
}
else if ($reason_id)
{
$sql = 'SELECT *
FROM ' . REPORTS_REASONS_TABLE . '
WHERE reason_id = ' . $reason_id;
$result = $db->sql_query($sql);
$reason_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$reason_row)
{
trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
$l_title = ($action == 'edit') ? 'EDIT' : 'ADD';
$translated = false;
// If the reason is defined within the language file, we will use the localized version, else just use the database entry...
if (isset($user->lang['report_reasons']['TITLE'][strtoupper($reason_row['reason_title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])]))
{
$translated = true;
}
$template->assign_vars(array(
'L_TITLE' => $user->lang['REASON_' . $l_title],
'U_ACTION' => $this->u_action . "&amp;id=$reason_id&amp;action=$action",
'U_BACK' => $this->u_action,
'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
'REASON_TITLE' => $reason_row['reason_title'],
'REASON_DESCRIPTION' => $reason_row['reason_description'],
'TRANSLATED_TITLE' => ($translated) ? $user->lang['report_reasons']['TITLE'][strtoupper($reason_row['reason_title'])] : '',
'TRANSLATED_DESCRIPTION'=> ($translated) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])] : '',
'S_AVAILABLE_TITLES' => implode($user->lang['COMMA_SEPARATOR'], array_map('htmlspecialchars', array_keys($user->lang['report_reasons']['TITLE']))),
'S_EDIT_REASON' => true,
'S_TRANSLATED' => $translated,
'S_ERROR' => (count($error)) ? true : false,
)
);
return;
break;
case 'delete':
$sql = 'SELECT *
FROM ' . REPORTS_REASONS_TABLE . '
WHERE reason_id = ' . $reason_id;
$result = $db->sql_query($sql);
$reason_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
if (!$reason_row)
{
trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (strtolower($reason_row['reason_title']) == 'other')
{
trigger_error($user->lang['NO_REMOVE_DEFAULT_REASON'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Let the deletion be confirmed...
if (confirm_box(true))
{
$sql = 'SELECT reason_id
FROM ' . REPORTS_REASONS_TABLE . "
WHERE LOWER(reason_title) = 'other'";
$result = $db->sql_query($sql);
$other_reason_id = (int) $db->sql_fetchfield('reason_id');
$db->sql_freeresult($result);
switch ($db->get_sql_layer())
{
// The ugly one!
case 'mysqli':
case 'mysql4':
case 'mysql':
// Change the reports using this reason to 'other'
$sql = 'UPDATE ' . REPORTS_TABLE . '
SET reason_id = ' . $other_reason_id . ", report_text = CONCAT('" . $db->sql_escape($reason_row['reason_description']) . "\n\n', report_text)
WHERE reason_id = $reason_id";
break;
// Standard? What's that?
case 'mssql_odbc':
case 'mssqlnative':
// Change the reports using this reason to 'other'
$sql = "DECLARE @ptrval binary(16)
SELECT @ptrval = TEXTPTR(report_text)
FROM " . REPORTS_TABLE . "
WHERE reason_id = " . $reason_id . "
UPDATETEXT " . REPORTS_TABLE . ".report_text @ptrval 0 0 '" . $db->sql_escape($reason_row['reason_description']) . "\n\n'
UPDATE " . REPORTS_TABLE . '
SET reason_id = ' . $other_reason_id . "
WHERE reason_id = $reason_id";
break;
// Teh standard
case 'postgres':
case 'oracle':
case 'sqlite3':
// Change the reports using this reason to 'other'
$sql = 'UPDATE ' . REPORTS_TABLE . '
SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' || report_text
WHERE reason_id = $reason_id";
break;
}
$db->sql_query($sql);
$db->sql_query('DELETE FROM ' . REPORTS_REASONS_TABLE . ' WHERE reason_id = ' . $reason_id);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_REASON_REMOVED', false, array($reason_row['reason_title']));
trigger_error($user->lang['REASON_REMOVED'] . adm_back_link($this->u_action));
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'action' => $action,
'id' => $reason_id))
);
}
break;
case 'move_up':
case 'move_down':
if (!check_link_hash($request->variable('hash', ''), 'acp_reasons'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT reason_order
FROM ' . REPORTS_REASONS_TABLE . "
WHERE reason_id = $reason_id";
$result = $db->sql_query($sql);
$order = $db->sql_fetchfield('reason_order');
$db->sql_freeresult($result);
if ($order === false || ($order == 0 && $action == 'move_up'))
{
break;
}
$order = (int) $order;
$order_total = $order * 2 + (($action == 'move_up') ? -1 : 1);
$sql = 'UPDATE ' . REPORTS_REASONS_TABLE . '
SET reason_order = ' . $order_total . ' - reason_order
WHERE reason_order IN (' . $order . ', ' . (($action == 'move_up') ? $order - 1 : $order + 1) . ')';
$db->sql_query($sql);
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send(array(
'success' => (bool) $db->sql_affectedrows(),
));
}
break;
}
// By default, check that order is valid and fix it if necessary
$sql = 'SELECT reason_id, reason_order
FROM ' . REPORTS_REASONS_TABLE . '
ORDER BY reason_order';
$result = $db->sql_query($sql);
if ($row = $db->sql_fetchrow($result))
{
$order = 0;
do
{
++$order;
if ($row['reason_order'] != $order)
{
$sql = 'UPDATE ' . REPORTS_REASONS_TABLE . "
SET reason_order = $order
WHERE reason_id = {$row['reason_id']}";
$db->sql_query($sql);
}
}
while ($row = $db->sql_fetchrow($result));
}
$db->sql_freeresult($result);
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
)
);
// Reason count
$sql = 'SELECT reason_id, COUNT(reason_id) AS reason_count
FROM ' . REPORTS_TABLE . '
GROUP BY reason_id';
$result = $db->sql_query($sql);
$reason_count = array();
while ($row = $db->sql_fetchrow($result))
{
$reason_count[$row['reason_id']] = $row['reason_count'];
}
$db->sql_freeresult($result);
$sql = 'SELECT *
FROM ' . REPORTS_REASONS_TABLE . '
ORDER BY reason_order ASC';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$translated = false;
$other_reason = ($row['reason_title'] == 'other') ? true : false;
// If the reason is defined within the language file, we will use the localized version, else just use the database entry...
if (isset($user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]))
{
$row['reason_description'] = $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])];
$row['reason_title'] = $user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])];
$translated = true;
}
$template->assign_block_vars('reasons', array(
'REASON_TITLE' => $row['reason_title'],
'REASON_DESCRIPTION' => $row['reason_description'],
'REASON_COUNT' => (isset($reason_count[$row['reason_id']])) ? $reason_count[$row['reason_id']] : 0,
'S_TRANSLATED' => $translated,
'S_OTHER_REASON' => $other_reason,
'U_EDIT' => $this->u_action . '&amp;action=edit&amp;id=' . $row['reason_id'],
'U_DELETE' => (!$other_reason) ? $this->u_action . '&amp;action=delete&amp;id=' . $row['reason_id'] : '',
'U_MOVE_UP' => $this->u_action . '&amp;action=move_up&amp;id=' . $row['reason_id'] . '&amp;hash=' . generate_link_hash('acp_reasons'),
'U_MOVE_DOWN' => $this->u_action . '&amp;action=move_down&amp;id=' . $row['reason_id'] . '&amp;hash=' . generate_link_hash('acp_reasons'))
);
}
$db->sql_freeresult($result);
}
}

623
includes/acp/acp_search.php Normal file
View File

@@ -0,0 +1,623 @@
<?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;
}
class acp_search
{
var $u_action;
var $state;
var $search;
var $max_post_id;
var $batch_size = 100;
function main($id, $mode)
{
global $user;
$user->add_lang('acp/search');
// For some this may be of help...
@ini_set('memory_limit', '128M');
switch ($mode)
{
case 'settings':
$this->settings($id, $mode);
break;
case 'index':
$this->index($id, $mode);
break;
}
}
function settings($id, $mode)
{
global $user, $template, $phpbb_log, $request;
global $config, $phpbb_admin_path, $phpEx;
$submit = (isset($_POST['submit'])) ? true : false;
if ($submit && !check_link_hash($request->variable('hash', ''), 'acp_search'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$search_types = $this->get_search_types();
$settings = array(
'search_interval' => 'float',
'search_anonymous_interval' => 'float',
'load_search' => 'bool',
'limit_search_load' => 'float',
'min_search_author_chars' => 'integer',
'max_num_search_keywords' => 'integer',
'search_store_results' => 'integer',
);
$search = null;
$error = false;
$search_options = '';
foreach ($search_types as $type)
{
if ($this->init_search($type, $search, $error))
{
continue;
}
$name = $search->get_name();
$selected = ($config['search_type'] == $type) ? ' selected="selected"' : '';
$identifier = substr($type, strrpos($type, '\\') + 1);
$search_options .= "<option value=\"$type\"$selected data-toggle-setting=\"#search_{$identifier}_settings\">$name</option>";
if (method_exists($search, 'acp'))
{
$vars = $search->acp();
if (!$submit)
{
$template->assign_block_vars('backend', array(
'NAME' => $name,
'SETTINGS' => $vars['tpl'],
'IDENTIFIER' => $identifier,
));
}
else if (is_array($vars['config']))
{
$settings = array_merge($settings, $vars['config']);
}
}
}
unset($search);
unset($error);
$cfg_array = (isset($_REQUEST['config'])) ? $request->variable('config', array('' => ''), true) : array();
$updated = $request->variable('updated', false);
foreach ($settings as $config_name => $var_type)
{
if (!isset($cfg_array[$config_name]))
{
continue;
}
// e.g. integer:4:12 (min 4, max 12)
$var_type = explode(':', $var_type);
$config_value = $cfg_array[$config_name];
settype($config_value, $var_type[0]);
if (isset($var_type[1]))
{
$config_value = max($var_type[1], $config_value);
}
if (isset($var_type[2]))
{
$config_value = min($var_type[2], $config_value);
}
// only change config if anything was actually changed
if ($submit && ($config[$config_name] != $config_value))
{
$config->set($config_name, $config_value);
$updated = true;
}
}
if ($submit)
{
$extra_message = '';
if ($updated)
{
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_SEARCH');
}
if (isset($cfg_array['search_type']) && in_array($cfg_array['search_type'], $search_types, true) && ($cfg_array['search_type'] != $config['search_type']))
{
$search = null;
$error = false;
if (!$this->init_search($cfg_array['search_type'], $search, $error))
{
if (confirm_box(true))
{
if (!method_exists($search, 'init') || !($error = $search->init()))
{
$config->set('search_type', $cfg_array['search_type']);
if (!$updated)
{
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_SEARCH');
}
$extra_message = '<br />' . $user->lang['SWITCHED_SEARCH_BACKEND'] . '<br /><a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=search&amp;mode=index') . '">&raquo; ' . $user->lang['GO_TO_SEARCH_INDEX'] . '</a>';
}
else
{
trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
}
else
{
confirm_box(false, $user->lang['CONFIRM_SEARCH_BACKEND'], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'submit' => true,
'updated' => $updated,
'config' => array('search_type' => $cfg_array['search_type']),
)));
}
}
else
{
trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
}
$search = null;
$error = false;
if (!$this->init_search($config['search_type'], $search, $error))
{
if ($updated)
{
if (method_exists($search, 'config_updated'))
{
if ($search->config_updated())
{
trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
}
}
}
else
{
trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
trigger_error($user->lang['CONFIG_UPDATED'] . $extra_message . adm_back_link($this->u_action));
}
unset($cfg_array);
$this->tpl_name = 'acp_search';
$this->page_title = 'ACP_SEARCH_SETTINGS';
$template->assign_vars(array(
'LIMIT_SEARCH_LOAD' => (float) $config['limit_search_load'],
'MIN_SEARCH_AUTHOR_CHARS' => (int) $config['min_search_author_chars'],
'SEARCH_INTERVAL' => (float) $config['search_interval'],
'SEARCH_GUEST_INTERVAL' => (float) $config['search_anonymous_interval'],
'SEARCH_STORE_RESULTS' => (int) $config['search_store_results'],
'MAX_NUM_SEARCH_KEYWORDS' => (int) $config['max_num_search_keywords'],
'S_SEARCH_TYPES' => $search_options,
'S_YES_SEARCH' => (bool) $config['load_search'],
'S_SETTINGS' => true,
'U_ACTION' => $this->u_action . '&amp;hash=' . generate_link_hash('acp_search'))
);
}
function index($id, $mode)
{
global $db, $user, $template, $phpbb_log, $request;
global $config, $phpbb_admin_path, $phpEx;
$action = $request->variable('action', '');
$this->state = explode(',', $config['search_indexing_state']);
if (isset($_POST['cancel']))
{
$action = '';
$this->state = array();
$this->save_state();
}
$submit = $request->is_set_post('submit', false);
if (!check_link_hash($request->variable('hash', ''), 'acp_search') && in_array($action, array('create', 'delete')))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($action)
{
switch ($action)
{
case 'progress_bar':
$type = $request->variable('type', '');
$this->display_progress_bar($type);
break;
case 'delete':
$this->state[1] = 'delete';
break;
case 'create':
$this->state[1] = 'create';
break;
default:
trigger_error('NO_ACTION', E_USER_ERROR);
break;
}
if (empty($this->state[0]))
{
$this->state[0] = $request->variable('search_type', '');
}
$this->search = null;
$error = false;
if ($this->init_search($this->state[0], $this->search, $error))
{
trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
$name = $this->search->get_name();
$action = &$this->state[1];
$this->max_post_id = $this->get_max_post_id();
$post_counter = (isset($this->state[2])) ? $this->state[2] : 0;
$this->state[2] = &$post_counter;
$this->save_state();
switch ($action)
{
case 'delete':
if (method_exists($this->search, 'delete_index'))
{
// pass a reference to myself so the $search object can make use of save_state() and attributes
if ($error = $this->search->delete_index($this, append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=$mode&action=delete&hash=" . generate_link_hash('acp_search'), false)))
{
$this->state = array('');
$this->save_state();
trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING);
}
}
else
{
$starttime = microtime(true);
$row_count = 0;
while (still_on_time() && $post_counter <= $this->max_post_id)
{
$sql = 'SELECT post_id, poster_id, forum_id
FROM ' . POSTS_TABLE . '
WHERE post_id >= ' . (int) ($post_counter + 1) . '
AND post_id <= ' . (int) ($post_counter + $this->batch_size);
$result = $db->sql_query($sql);
$ids = $posters = $forum_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$ids[] = $row['post_id'];
$posters[] = $row['poster_id'];
$forum_ids[] = $row['forum_id'];
}
$db->sql_freeresult($result);
$row_count += count($ids);
if (count($ids))
{
$this->search->index_remove($ids, $posters, $forum_ids);
}
$post_counter += $this->batch_size;
}
// save the current state
$this->save_state();
if ($post_counter <= $this->max_post_id)
{
$totaltime = microtime(true) - $starttime;
$rows_per_second = $row_count / $totaltime;
meta_refresh(1, append_sid($this->u_action . '&amp;action=delete&amp;skip_rows=' . $post_counter . '&amp;hash=' . generate_link_hash('acp_search')));
trigger_error($user->lang('SEARCH_INDEX_DELETE_REDIRECT', (int) $row_count, $post_counter) . $user->lang('SEARCH_INDEX_DELETE_REDIRECT_RATE', $rows_per_second));
}
}
$this->search->tidy();
$this->state = array('');
$this->save_state();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_SEARCH_INDEX_REMOVED', false, array($name));
trigger_error($user->lang['SEARCH_INDEX_REMOVED'] . adm_back_link($this->u_action) . $this->close_popup_js());
break;
case 'create':
if (method_exists($this->search, 'create_index'))
{
// pass a reference to acp_search so the $search object can make use of save_state() and attributes
if ($error = $this->search->create_index($this, append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=$mode&action=create", false)))
{
$this->state = array('');
$this->save_state();
trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING);
}
}
else
{
$sql = 'SELECT forum_id, enable_indexing
FROM ' . FORUMS_TABLE;
$result = $db->sql_query($sql, 3600);
while ($row = $db->sql_fetchrow($result))
{
$forums[$row['forum_id']] = (bool) $row['enable_indexing'];
}
$db->sql_freeresult($result);
$starttime = microtime(true);
$row_count = 0;
while (still_on_time() && $post_counter <= $this->max_post_id)
{
$sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id
FROM ' . POSTS_TABLE . '
WHERE post_id >= ' . (int) ($post_counter + 1) . '
AND post_id <= ' . (int) ($post_counter + $this->batch_size);
$result = $db->sql_query($sql);
$buffer = $db->sql_buffer_nested_transactions();
if ($buffer)
{
$rows = $db->sql_fetchrowset($result);
$rows[] = false; // indicate end of array for while loop below
$db->sql_freeresult($result);
}
$i = 0;
while ($row = ($buffer ? $rows[$i++] : $db->sql_fetchrow($result)))
{
// Indexing enabled for this forum
if (isset($forums[$row['forum_id']]) && $forums[$row['forum_id']])
{
$this->search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']);
}
$row_count++;
}
if (!$buffer)
{
$db->sql_freeresult($result);
}
$post_counter += $this->batch_size;
}
// save the current state
$this->save_state();
// pretend the number of posts was as big as the number of ids we indexed so far
// just an estimation as it includes deleted posts
$num_posts = $config['num_posts'];
$config['num_posts'] = min($config['num_posts'], $post_counter);
$this->search->tidy();
$config['num_posts'] = $num_posts;
if ($post_counter <= $this->max_post_id)
{
$totaltime = microtime(true) - $starttime;
$rows_per_second = $row_count / $totaltime;
meta_refresh(1, append_sid($this->u_action . '&amp;action=create&amp;skip_rows=' . $post_counter . '&amp;hash=' . generate_link_hash('acp_search')));
trigger_error($user->lang('SEARCH_INDEX_CREATE_REDIRECT', (int) $row_count, $post_counter) . $user->lang('SEARCH_INDEX_CREATE_REDIRECT_RATE', $rows_per_second));
}
}
$this->search->tidy();
$this->state = array('');
$this->save_state();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_SEARCH_INDEX_CREATED', false, array($name));
trigger_error($user->lang['SEARCH_INDEX_CREATED'] . adm_back_link($this->u_action) . $this->close_popup_js());
break;
}
}
$search_types = $this->get_search_types();
$search = null;
$error = false;
foreach ($search_types as $type)
{
if ($this->init_search($type, $search, $error) || !method_exists($search, 'index_created'))
{
continue;
}
$name = $search->get_name();
$data = array();
if (method_exists($search, 'index_stats'))
{
$data = $search->index_stats();
}
$statistics = array();
foreach ($data as $statistic => $value)
{
$n = count($statistics);
if ($n && count($statistics[$n - 1]) < 3)
{
$statistics[$n - 1] += array('statistic_2' => $statistic, 'value_2' => $value);
}
else
{
$statistics[] = array('statistic_1' => $statistic, 'value_1' => $value);
}
}
$template->assign_block_vars('backend', array(
'L_NAME' => $name,
'NAME' => $type,
'S_ACTIVE' => ($type == $config['search_type']) ? true : false,
'S_HIDDEN_FIELDS' => build_hidden_fields(array('search_type' => $type)),
'S_INDEXED' => (bool) $search->index_created(),
'S_STATS' => (bool) count($statistics))
);
foreach ($statistics as $statistic)
{
$template->assign_block_vars('backend.data', array(
'STATISTIC_1' => $statistic['statistic_1'],
'VALUE_1' => $statistic['value_1'],
'STATISTIC_2' => (isset($statistic['statistic_2'])) ? $statistic['statistic_2'] : '',
'VALUE_2' => (isset($statistic['value_2'])) ? $statistic['value_2'] : '')
);
}
}
unset($search);
unset($error);
unset($statistics);
unset($data);
$this->tpl_name = 'acp_search';
$this->page_title = 'ACP_SEARCH_INDEX';
$template->assign_vars(array(
'S_INDEX' => true,
'U_ACTION' => $this->u_action . '&amp;hash=' . generate_link_hash('acp_search'),
'U_PROGRESS_BAR' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&amp;mode=$mode&amp;action=progress_bar"),
'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&amp;mode=$mode&amp;action=progress_bar")),
));
if (isset($this->state[1]))
{
$template->assign_vars(array(
'S_CONTINUE_INDEXING' => $this->state[1],
'U_CONTINUE_INDEXING' => $this->u_action . '&amp;action=' . $this->state[1] . '&amp;hash=' . generate_link_hash('acp_search'),
'L_CONTINUE' => ($this->state[1] == 'create') ? $user->lang['CONTINUE_INDEXING'] : $user->lang['CONTINUE_DELETING_INDEX'],
'L_CONTINUE_EXPLAIN' => ($this->state[1] == 'create') ? $user->lang['CONTINUE_INDEXING_EXPLAIN'] : $user->lang['CONTINUE_DELETING_INDEX_EXPLAIN'])
);
}
}
function display_progress_bar($type)
{
global $template, $user;
$l_type = ($type == 'create') ? 'INDEXING_IN_PROGRESS' : 'DELETING_INDEX_IN_PROGRESS';
adm_page_header($user->lang[$l_type]);
$template->set_filenames(array(
'body' => 'progress_bar.html')
);
$template->assign_vars(array(
'L_PROGRESS' => $user->lang[$l_type],
'L_PROGRESS_EXPLAIN' => $user->lang[$l_type . '_EXPLAIN'])
);
adm_page_footer();
}
function close_popup_js()
{
return "<script type=\"text/javascript\">\n" .
"// <![CDATA[\n" .
" close_waitscreen = 1;\n" .
"// ]]>\n" .
"</script>\n";
}
function get_search_types()
{
global $phpbb_extension_manager;
$finder = $phpbb_extension_manager->get_finder();
return $finder
->extension_suffix('_backend')
->extension_directory('/search')
->core_path('phpbb/search/')
->get_classes();
}
function get_max_post_id()
{
global $db;
$sql = 'SELECT MAX(post_id) as max_post_id
FROM '. POSTS_TABLE;
$result = $db->sql_query($sql);
$max_post_id = (int) $db->sql_fetchfield('max_post_id');
$db->sql_freeresult($result);
return $max_post_id;
}
function save_state($state = false)
{
global $config;
if ($state)
{
$this->state = $state;
}
ksort($this->state);
$config->set('search_indexing_state', implode(',', $this->state), true);
}
/**
* Initialises a search backend object
*
* @return false if no error occurred else an error message
*/
function init_search($type, &$search, &$error)
{
global $phpbb_root_path, $phpEx, $user, $auth, $config, $db, $phpbb_dispatcher;
if (!class_exists($type) || !method_exists($type, 'keyword_search'))
{
$error = $user->lang['NO_SUCH_SEARCH_MODULE'];
return $error;
}
$error = false;
$search = new $type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
return $error;
}
}

1373
includes/acp/acp_styles.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
<?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;
}
class acp_update
{
var $u_action;
function main($id, $mode)
{
global $config, $user, $template, $request;
global $phpbb_root_path, $phpEx, $phpbb_container;
$user->add_lang('install');
$this->tpl_name = 'acp_update';
$this->page_title = 'ACP_VERSION_CHECK';
/* @var $version_helper \phpbb\version_helper */
$version_helper = $phpbb_container->get('version_helper');
try
{
$recheck = $request->variable('versioncheck_force', false);
$updates_available = $version_helper->get_update_on_branch($recheck);
$upgrades_available = $version_helper->get_suggested_updates();
if (!empty($upgrades_available))
{
$upgrades_available = array_pop($upgrades_available);
}
}
catch (\RuntimeException $e)
{
$template->assign_var('S_VERSIONCHECK_FAIL', true);
$updates_available = array();
}
if (!empty($updates_available))
{
$template->assign_block_vars('updates_available', $updates_available);
}
$update_link = $phpbb_root_path . 'install/app.' . $phpEx;
$template->assign_vars(array(
'S_UP_TO_DATE' => empty($updates_available),
'U_ACTION' => $this->u_action,
'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&amp;versioncheck_force=1'),
'CURRENT_VERSION' => $config['version'],
'UPDATE_INSTRUCTIONS' => sprintf($user->lang['UPDATE_INSTRUCTIONS'], $update_link),
'S_VERSION_UPGRADEABLE' => !empty($upgrades_available),
'UPGRADE_INSTRUCTIONS' => !empty($upgrades_available) ? $user->lang('UPGRADE_INSTRUCTIONS', $upgrades_available['current'], $upgrades_available['announcement']) : false,
));
// Incomplete update?
if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<'))
{
$database_update_link = $phpbb_root_path . 'install/app.php/update';
$template->assign_vars(array(
'S_UPDATE_INCOMPLETE' => true,
'FILES_VERSION' => PHPBB_VERSION,
'INCOMPLETE_INSTRUCTIONS' => $user->lang('UPDATE_INCOMPLETE_EXPLAIN', $database_update_link),
));
}
}
}

2692
includes/acp/acp_users.php Normal file

File diff suppressed because it is too large Load Diff

191
includes/acp/acp_words.php Normal file
View File

@@ -0,0 +1,191 @@
<?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;
}
/**
* @todo [words] check regular expressions for special char replacements (stored specialchared in db)
*/
class acp_words
{
var $u_action;
function main($id, $mode)
{
global $db, $user, $template, $cache, $phpbb_log, $request, $phpbb_container;
$user->add_lang('acp/posting');
// Set up general vars
$action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : ((isset($_POST['save'])) ? 'save' : $action);
$s_hidden_fields = '';
$word_info = array();
$this->tpl_name = 'acp_words';
$this->page_title = 'ACP_WORDS';
$form_name = 'acp_words';
add_form_key($form_name);
switch ($action)
{
case 'edit':
$word_id = $request->variable('id', 0);
if (!$word_id)
{
trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT *
FROM ' . WORDS_TABLE . "
WHERE word_id = $word_id";
$result = $db->sql_query($sql);
$word_info = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$s_hidden_fields .= '<input type="hidden" name="id" value="' . $word_id . '" />';
case 'add':
$template->assign_vars(array(
'S_EDIT_WORD' => true,
'U_ACTION' => $this->u_action,
'U_BACK' => $this->u_action,
'WORD' => (isset($word_info['word'])) ? $word_info['word'] : '',
'REPLACEMENT' => (isset($word_info['replacement'])) ? $word_info['replacement'] : '',
'S_HIDDEN_FIELDS' => $s_hidden_fields)
);
return;
break;
case 'save':
if (!check_form_key($form_name))
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
$word_id = $request->variable('id', 0);
$word = $request->variable('word', '', true);
$replacement = $request->variable('replacement', '', true);
if ($word === '' || $replacement === '')
{
trigger_error($user->lang['ENTER_WORD'] . adm_back_link($this->u_action), E_USER_WARNING);
}
// Replace multiple consecutive asterisks with single one as those are not needed
$word = preg_replace('#\*{2,}#', '*', $word);
$sql_ary = array(
'word' => $word,
'replacement' => $replacement
);
if ($word_id)
{
$db->sql_query('UPDATE ' . WORDS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE word_id = ' . $word_id);
}
else
{
$db->sql_query('INSERT INTO ' . WORDS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
}
$cache->destroy('_word_censors');
$phpbb_container->get('text_formatter.cache')->invalidate();
$log_action = ($word_id) ? 'LOG_WORD_EDIT' : 'LOG_WORD_ADD';
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_action, false, array($word));
$message = ($word_id) ? $user->lang['WORD_UPDATED'] : $user->lang['WORD_ADDED'];
trigger_error($message . adm_back_link($this->u_action));
break;
case 'delete':
$word_id = $request->variable('id', 0);
if (!$word_id)
{
trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (confirm_box(true))
{
$sql = 'SELECT word
FROM ' . WORDS_TABLE . "
WHERE word_id = $word_id";
$result = $db->sql_query($sql);
$deleted_word = $db->sql_fetchfield('word');
$db->sql_freeresult($result);
$sql = 'DELETE FROM ' . WORDS_TABLE . "
WHERE word_id = $word_id";
$db->sql_query($sql);
$cache->destroy('_word_censors');
$phpbb_container->get('text_formatter.cache')->invalidate();
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WORD_DELETE', false, array($deleted_word));
trigger_error($user->lang['WORD_REMOVED'] . adm_back_link($this->u_action));
}
else
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
'i' => $id,
'mode' => $mode,
'id' => $word_id,
'action' => 'delete',
)));
}
break;
}
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
'S_HIDDEN_FIELDS' => $s_hidden_fields)
);
$sql = 'SELECT *
FROM ' . WORDS_TABLE . '
ORDER BY word';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$template->assign_block_vars('words', array(
'WORD' => $row['word'],
'REPLACEMENT' => $row['replacement'],
'U_EDIT' => $this->u_action . '&amp;action=edit&amp;id=' . $row['word_id'],
'U_DELETE' => $this->u_action . '&amp;action=delete&amp;id=' . $row['word_id'])
);
}
$db->sql_freeresult($result);
}
}

1323
includes/acp/auth.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
<?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.
*
*/
class acp_attachments_info
{
function module()
{
return array(
'filename' => 'acp_attachments',
'title' => 'ACP_ATTACHMENTS',
'modes' => array(
'attach' => array('title' => 'ACP_ATTACHMENT_SETTINGS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_ATTACHMENTS')),
'extensions' => array('title' => 'ACP_MANAGE_EXTENSIONS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
'ext_groups' => array('title' => 'ACP_EXTENSION_GROUPS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
'orphan' => array('title' => 'ACP_ORPHAN_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
'manage' => array('title' => 'ACP_MANAGE_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,36 @@
<?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.
*
*/
class acp_ban_info
{
function module()
{
return array(
'filename' => 'acp_ban',
'title' => 'ACP_BAN',
'modes' => array(
'email' => array('title' => 'ACP_BAN_EMAILS', 'auth' => 'acl_a_ban', 'cat' => array('ACP_USER_SECURITY')),
'ip' => array('title' => 'ACP_BAN_IPS', 'auth' => 'acl_a_ban', 'cat' => array('ACP_USER_SECURITY')),
'user' => array('title' => 'ACP_BAN_USERNAMES', 'auth' => 'acl_a_ban', 'cat' => array('ACP_USER_SECURITY')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_bbcodes_info
{
function module()
{
return array(
'filename' => 'acp_bbcodes',
'title' => 'ACP_BBCODES',
'modes' => array(
'bbcodes' => array('title' => 'ACP_BBCODES', 'auth' => 'acl_a_bbcode', 'cat' => array('ACP_MESSAGES')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,49 @@
<?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.
*
*/
class acp_board_info
{
function module()
{
return array(
'filename' => 'acp_board',
'title' => 'ACP_BOARD_MANAGEMENT',
'modes' => array(
'settings' => array('title' => 'ACP_BOARD_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'features' => array('title' => 'ACP_BOARD_FEATURES', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'avatar' => array('title' => 'ACP_AVATAR_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'message' => array('title' => 'ACP_MESSAGE_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_MESSAGES')),
'post' => array('title' => 'ACP_POST_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_MESSAGES')),
'signature' => array('title' => 'ACP_SIGNATURE_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'feed' => array('title' => 'ACP_FEED_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'registration' => array('title' => 'ACP_REGISTER_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'auth' => array('title' => 'ACP_AUTH_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_CLIENT_COMMUNICATION')),
'email' => array('title' => 'ACP_EMAIL_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_CLIENT_COMMUNICATION')),
'cookie' => array('title' => 'ACP_COOKIE_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
'server' => array('title' => 'ACP_SERVER_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
'security' => array('title' => 'ACP_SECURITY_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
'load' => array('title' => 'ACP_LOAD_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_bots_info
{
function module()
{
return array(
'filename' => 'acp_bots',
'title' => 'ACP_BOTS',
'modes' => array(
'bots' => array('title' => 'ACP_BOTS', 'auth' => 'acl_a_bots', 'cat' => array('ACP_GENERAL_TASKS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_captcha_info
{
function module()
{
return array(
'filename' => 'acp_captcha',
'title' => 'ACP_CAPTCHA',
'modes' => array(
'visual' => array('title' => 'ACP_VC_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'img' => array('title' => 'ACP_VC_CAPTCHA_DISPLAY', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION'), 'display' => false)
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,30 @@
<?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.
*
*/
/**
* @package module_install
*/
class acp_contact_info
{
public function module()
{
return array(
'filename' => 'acp_contact',
'title' => 'ACP_CONTACT',
'version' => '1.0.0',
'modes' => array(
'contact' => array('title' => 'ACP_CONTACT_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
),
);
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_database_info
{
function module()
{
return array(
'filename' => 'acp_database',
'title' => 'ACP_DATABASE',
'modes' => array(
'backup' => array('title' => 'ACP_BACKUP', 'auth' => 'acl_a_backup', 'cat' => array('ACP_CAT_DATABASE')),
'restore' => array('title' => 'ACP_RESTORE', 'auth' => 'acl_a_backup', 'cat' => array('ACP_CAT_DATABASE')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_disallow_info
{
function module()
{
return array(
'filename' => 'acp_disallow',
'title' => 'ACP_DISALLOW',
'modes' => array(
'usernames' => array('title' => 'ACP_DISALLOW_USERNAMES', 'auth' => 'acl_a_names', 'cat' => array('ACP_USER_SECURITY')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_email_info
{
function module()
{
return array(
'filename' => 'acp_email',
'title' => 'ACP_MASS_EMAIL',
'modes' => array(
'email' => array('title' => 'ACP_MASS_EMAIL', 'auth' => 'acl_a_email && cfg_email_enable', 'cat' => array('ACP_GENERAL_TASKS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_extensions_info
{
function module()
{
return array(
'filename' => 'acp_extensions',
'title' => 'ACP_EXTENSION_MANAGEMENT',
'modes' => array(
'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_EXTENSION_MANAGEMENT')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_forums_info
{
function module()
{
return array(
'filename' => 'acp_forums',
'title' => 'ACP_FORUM_MANAGEMENT',
'modes' => array(
'manage' => array('title' => 'ACP_MANAGE_FORUMS', 'auth' => 'acl_a_forum', 'cat' => array('ACP_MANAGE_FORUMS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_groups_info
{
function module()
{
return array(
'filename' => 'acp_groups',
'title' => 'ACP_GROUPS_MANAGEMENT',
'modes' => array(
'manage' => array('title' => 'ACP_GROUPS_MANAGE', 'auth' => 'acl_a_group', 'cat' => array('ACP_GROUPS')),
'position' => array('title' => 'ACP_GROUPS_POSITION', 'auth' => 'acl_a_group', 'cat' => array('ACP_GROUPS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_help_phpbb_info
{
function module()
{
return array(
'filename' => 'acp_help_phpbb',
'title' => 'ACP_HELP_PHPBB',
'modes' => array(
'help_phpbb' => array('title' => 'ACP_HELP_PHPBB', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_icons_info
{
function module()
{
return array(
'filename' => 'acp_icons',
'title' => 'ACP_ICONS_SMILIES',
'modes' => array(
'icons' => array('title' => 'ACP_ICONS', 'auth' => 'acl_a_icons', 'cat' => array('ACP_MESSAGES')),
'smilies' => array('title' => 'ACP_SMILIES', 'auth' => 'acl_a_icons', 'cat' => array('ACP_MESSAGES')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_inactive_info
{
function module()
{
return array(
'filename' => 'acp_inactive',
'title' => 'ACP_INACTIVE_USERS',
'modes' => array(
'list' => array('title' => 'ACP_INACTIVE_USERS', 'auth' => 'acl_a_user', 'cat' => array('ACP_CAT_USERS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_jabber_info
{
function module()
{
return array(
'filename' => 'acp_jabber',
'title' => 'ACP_JABBER_SETTINGS',
'modes' => array(
'settings' => array('title' => 'ACP_JABBER_SETTINGS', 'auth' => 'acl_a_jabber', 'cat' => array('ACP_CLIENT_COMMUNICATION')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_language_info
{
function module()
{
return array(
'filename' => 'acp_language',
'title' => 'ACP_LANGUAGE',
'modes' => array(
'lang_packs' => array('title' => 'ACP_LANGUAGE_PACKS', 'auth' => 'acl_a_language', 'cat' => array('ACP_LANGUAGE')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,52 @@
<?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.
*
*/
class acp_logs_info
{
function module()
{
global $phpbb_dispatcher;
$modes = array(
'admin' => array('title' => 'ACP_ADMIN_LOGS', 'auth' => 'acl_a_viewlogs', 'cat' => array('ACP_FORUM_LOGS')),
'mod' => array('title' => 'ACP_MOD_LOGS', 'auth' => 'acl_a_viewlogs', 'cat' => array('ACP_FORUM_LOGS')),
'users' => array('title' => 'ACP_USERS_LOGS', 'auth' => 'acl_a_viewlogs', 'cat' => array('ACP_FORUM_LOGS')),
'critical' => array('title' => 'ACP_CRITICAL_LOGS', 'auth' => 'acl_a_viewlogs', 'cat' => array('ACP_FORUM_LOGS')),
);
/**
* Event to add or modify ACP log modulemodes
*
* @event core.acp_logs_info_modify_modes
* @var array modes Array with modes info
* @since 3.1.11-RC1
* @since 3.2.1-RC1
*/
$vars = array('modes');
extract($phpbb_dispatcher->trigger_event('core.acp_logs_info_modify_modes', compact($vars)));
return array(
'filename' => 'acp_logs',
'title' => 'ACP_LOGGING',
'modes' => $modes,
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_main_info
{
function module()
{
return array(
'filename' => 'acp_main',
'title' => 'ACP_INDEX',
'modes' => array(
'main' => array('title' => 'ACP_INDEX', 'auth' => '', 'cat' => array('ACP_CAT_GENERAL')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,36 @@
<?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.
*
*/
class acp_modules_info
{
function module()
{
return array(
'filename' => 'acp_modules',
'title' => 'ACP_MODULE_MANAGEMENT',
'modes' => array(
'acp' => array('title' => 'ACP', 'auth' => 'acl_a_modules', 'cat' => array('ACP_MODULE_MANAGEMENT')),
'ucp' => array('title' => 'UCP', 'auth' => 'acl_a_modules', 'cat' => array('ACP_MODULE_MANAGEMENT')),
'mcp' => array('title' => 'MCP', 'auth' => 'acl_a_modules', 'cat' => array('ACP_MODULE_MANAGEMENT')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,37 @@
<?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.
*
*/
class acp_permission_roles_info
{
function module()
{
return array(
'filename' => 'acp_permission_roles',
'title' => 'ACP_PERMISSION_ROLES',
'modes' => array(
'admin_roles' => array('title' => 'ACP_ADMIN_ROLES', 'auth' => 'acl_a_roles && acl_a_aauth', 'cat' => array('ACP_PERMISSION_ROLES')),
'user_roles' => array('title' => 'ACP_USER_ROLES', 'auth' => 'acl_a_roles && acl_a_uauth', 'cat' => array('ACP_PERMISSION_ROLES')),
'mod_roles' => array('title' => 'ACP_MOD_ROLES', 'auth' => 'acl_a_roles && acl_a_mauth', 'cat' => array('ACP_PERMISSION_ROLES')),
'forum_roles' => array('title' => 'ACP_FORUM_ROLES', 'auth' => 'acl_a_roles && acl_a_fauth', 'cat' => array('ACP_PERMISSION_ROLES')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,51 @@
<?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.
*
*/
class acp_permissions_info
{
function module()
{
return array(
'filename' => 'acp_permissions',
'title' => 'ACP_PERMISSIONS',
'modes' => array(
'intro' => array('title' => 'ACP_PERMISSIONS', 'auth' => 'acl_a_authusers || acl_a_authgroups || acl_a_viewauth', 'cat' => array('ACP_CAT_PERMISSIONS')),
'trace' => array('title' => 'ACP_PERMISSION_TRACE', 'auth' => 'acl_a_viewauth', 'display' => false, 'cat' => array('ACP_PERMISSION_MASKS')),
'setting_forum_local' => array('title' => 'ACP_FORUM_PERMISSIONS', 'auth' => 'acl_a_fauth && (acl_a_authusers || acl_a_authgroups)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS')),
'setting_forum_copy' => array('title' => 'ACP_FORUM_PERMISSIONS_COPY', 'auth' => 'acl_a_fauth && acl_a_authusers && acl_a_authgroups && acl_a_mauth', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS')),
'setting_mod_local' => array('title' => 'ACP_FORUM_MODERATORS', 'auth' => 'acl_a_mauth && (acl_a_authusers || acl_a_authgroups)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS')),
'setting_user_global' => array('title' => 'ACP_USERS_PERMISSIONS', 'auth' => 'acl_a_authusers && (acl_a_aauth || acl_a_mauth || acl_a_uauth)', 'cat' => array('ACP_GLOBAL_PERMISSIONS', 'ACP_CAT_USERS')),
'setting_user_local' => array('title' => 'ACP_USERS_FORUM_PERMISSIONS', 'auth' => 'acl_a_authusers && (acl_a_mauth || acl_a_fauth)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS', 'ACP_CAT_USERS')),
'setting_group_global' => array('title' => 'ACP_GROUPS_PERMISSIONS', 'auth' => 'acl_a_authgroups && (acl_a_aauth || acl_a_mauth || acl_a_uauth)', 'cat' => array('ACP_GLOBAL_PERMISSIONS', 'ACP_GROUPS')),
'setting_group_local' => array('title' => 'ACP_GROUPS_FORUM_PERMISSIONS', 'auth' => 'acl_a_authgroups && (acl_a_mauth || acl_a_fauth)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS', 'ACP_GROUPS')),
'setting_admin_global' => array('title' => 'ACP_ADMINISTRATORS', 'auth' => 'acl_a_aauth && (acl_a_authusers || acl_a_authgroups)', 'cat' => array('ACP_GLOBAL_PERMISSIONS')),
'setting_mod_global' => array('title' => 'ACP_GLOBAL_MODERATORS', 'auth' => 'acl_a_mauth && (acl_a_authusers || acl_a_authgroups)', 'cat' => array('ACP_GLOBAL_PERMISSIONS')),
'view_admin_global' => array('title' => 'ACP_VIEW_ADMIN_PERMISSIONS', 'auth' => 'acl_a_viewauth', 'cat' => array('ACP_PERMISSION_MASKS')),
'view_user_global' => array('title' => 'ACP_VIEW_USER_PERMISSIONS', 'auth' => 'acl_a_viewauth', 'cat' => array('ACP_PERMISSION_MASKS')),
'view_mod_global' => array('title' => 'ACP_VIEW_GLOBAL_MOD_PERMISSIONS', 'auth' => 'acl_a_viewauth', 'cat' => array('ACP_PERMISSION_MASKS')),
'view_mod_local' => array('title' => 'ACP_VIEW_FORUM_MOD_PERMISSIONS', 'auth' => 'acl_a_viewauth', 'cat' => array('ACP_PERMISSION_MASKS')),
'view_forum_local' => array('title' => 'ACP_VIEW_FORUM_PERMISSIONS', 'auth' => 'acl_a_viewauth', 'cat' => array('ACP_PERMISSION_MASKS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_php_info_info
{
function module()
{
return array(
'filename' => 'acp_php_info',
'title' => 'ACP_PHP_INFO',
'modes' => array(
'info' => array('title' => 'ACP_PHP_INFO', 'auth' => 'acl_a_phpinfo', 'cat' => array('ACP_GENERAL_TASKS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_profile_info
{
function module()
{
return array(
'filename' => 'acp_profile',
'title' => 'ACP_CUSTOM_PROFILE_FIELDS',
'modes' => array(
'profile' => array('title' => 'ACP_CUSTOM_PROFILE_FIELDS', 'auth' => 'acl_a_profile', 'cat' => array('ACP_CAT_USERS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_prune_info
{
function module()
{
return array(
'filename' => 'acp_prune',
'title' => 'ACP_PRUNING',
'modes' => array(
'forums' => array('title' => 'ACP_PRUNE_FORUMS', 'auth' => 'acl_a_prune', 'cat' => array('ACP_MANAGE_FORUMS')),
'users' => array('title' => 'ACP_PRUNE_USERS', 'auth' => 'acl_a_userdel', 'cat' => array('ACP_CAT_USERS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_ranks_info
{
function module()
{
return array(
'filename' => 'acp_ranks',
'title' => 'ACP_RANKS',
'modes' => array(
'ranks' => array('title' => 'ACP_MANAGE_RANKS', 'auth' => 'acl_a_ranks', 'cat' => array('ACP_CAT_USERS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_reasons_info
{
function module()
{
return array(
'filename' => 'acp_reasons',
'title' => 'ACP_REASONS',
'modes' => array(
'main' => array('title' => 'ACP_MANAGE_REASONS', 'auth' => 'acl_a_reasons', 'cat' => array('ACP_GENERAL_TASKS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_search_info
{
function module()
{
return array(
'filename' => 'acp_search',
'title' => 'ACP_SEARCH',
'modes' => array(
'settings' => array('title' => 'ACP_SEARCH_SETTINGS', 'auth' => 'acl_a_search', 'cat' => array('ACP_SERVER_CONFIGURATION')),
'index' => array('title' => 'ACP_SEARCH_INDEX', 'auth' => 'acl_a_search', 'cat' => array('ACP_CAT_DATABASE')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class acp_styles_info
{
function module()
{
return array(
'filename' => 'acp_styles',
'title' => 'ACP_CAT_STYLES',
'modes' => array(
'style' => array('title' => 'ACP_STYLES', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_MANAGEMENT')),
'install' => array('title' => 'ACP_STYLES_INSTALL', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_MANAGEMENT')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_update_info
{
function module()
{
return array(
'filename' => 'acp_update',
'title' => 'ACP_UPDATE',
'modes' => array(
'version_check' => array('title' => 'ACP_VERSION_CHECK', 'auth' => 'acl_a_board', 'cat' => array('ACP_AUTOMATION')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,44 @@
<?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.
*
*/
class acp_users_info
{
function module()
{
return array(
'filename' => 'acp_users',
'title' => 'ACP_USER_MANAGEMENT',
'modes' => array(
'overview' => array('title' => 'ACP_MANAGE_USERS', 'auth' => 'acl_a_user', 'cat' => array('ACP_CAT_USERS')),
'feedback' => array('title' => 'ACP_USER_FEEDBACK', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'warnings' => array('title' => 'ACP_USER_WARNINGS', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'profile' => array('title' => 'ACP_USER_PROFILE', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'prefs' => array('title' => 'ACP_USER_PREFS', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'avatar' => array('title' => 'ACP_USER_AVATAR', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'rank' => array('title' => 'ACP_USER_RANK', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'sig' => array('title' => 'ACP_USER_SIG', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'groups' => array('title' => 'ACP_USER_GROUPS', 'auth' => 'acl_a_user && acl_a_group', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'perm' => array('title' => 'ACP_USER_PERM', 'auth' => 'acl_a_user && acl_a_viewauth', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
'attach' => array('title' => 'ACP_USER_ATTACH', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,34 @@
<?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.
*
*/
class acp_words_info
{
function module()
{
return array(
'filename' => 'acp_words',
'title' => 'ACP_WORDS',
'modes' => array(
'words' => array('title' => 'ACP_WORDS', 'auth' => 'acl_a_words', 'cat' => array('ACP_MESSAGES')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

707
includes/bbcode.php Normal file
View File

@@ -0,0 +1,707 @@
<?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;
}
/**
* BBCode class
*/
class bbcode
{
var $bbcode_uid = '';
var $bbcode_bitfield = '';
var $bbcode_cache = array();
var $bbcode_template = array();
var $bbcodes = array();
var $template_bitfield;
/**
* Constructor
*/
function __construct($bitfield = '')
{
$this->bbcode_set_bitfield($bitfield);
}
/**
* Init bbcode cache entries if bitfield is specified
*
* @param string $bbcode_bitfield The bbcode bitfield
*/
function bbcode_set_bitfield($bitfield = '')
{
if ($bitfield)
{
$this->bbcode_bitfield = $bitfield;
$this->bbcode_cache_init();
}
}
/**
* Second pass bbcodes
*/
function bbcode_second_pass(&$message, $bbcode_uid = '', $bbcode_bitfield = false)
{
if ($bbcode_uid)
{
$this->bbcode_uid = $bbcode_uid;
}
if ($bbcode_bitfield !== false)
{
$this->bbcode_bitfield = $bbcode_bitfield;
// Init those added with a new bbcode_bitfield (already stored codes will not get parsed again)
$this->bbcode_cache_init();
}
if (!$this->bbcode_bitfield)
{
// Remove the uid from tags that have not been transformed into HTML
if ($this->bbcode_uid)
{
$message = str_replace(':' . $this->bbcode_uid, '', $message);
}
return;
}
$str = array('search' => array(), 'replace' => array());
$preg = array('search' => array(), 'replace' => array());
$bitfield = new bitfield($this->bbcode_bitfield);
$bbcodes_set = $bitfield->get_all_set();
$undid_bbcode_specialchars = false;
foreach ($bbcodes_set as $bbcode_id)
{
if (!empty($this->bbcode_cache[$bbcode_id]))
{
foreach ($this->bbcode_cache[$bbcode_id] as $type => $array)
{
foreach ($array as $search => $replace)
{
${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search);
${$type}['replace'][] = $replace;
}
if (count($str['search']))
{
$message = str_replace($str['search'], $str['replace'], $message);
$str = array('search' => array(), 'replace' => array());
}
if (count($preg['search']))
{
// we need to turn the entities back into their original form to allow the
// search patterns to work properly
if (!$undid_bbcode_specialchars)
{
$message = str_replace(array('&#58;', '&#46;'), array(':', '.'), $message);
$undid_bbcode_specialchars = true;
}
foreach ($preg['search'] as $key => $search)
{
if (is_callable($preg['replace'][$key]))
{
$message = preg_replace_callback($search, $preg['replace'][$key], $message);
}
else
{
$message = preg_replace($search, $preg['replace'][$key], $message);
}
}
$preg = array('search' => array(), 'replace' => array());
}
}
}
}
// Remove the uid from tags that have not been transformed into HTML
$message = str_replace(':' . $this->bbcode_uid, '', $message);
}
/**
* Init bbcode cache
*
* requires: $this->bbcode_bitfield
* sets: $this->bbcode_cache with bbcode templates needed for bbcode_bitfield
*/
function bbcode_cache_init()
{
global $user, $phpbb_dispatcher, $phpbb_extension_manager, $phpbb_container, $phpbb_filesystem;
if (empty($this->template_filename))
{
$this->template_bitfield = new bitfield($user->style['bbcode_bitfield']);
$template = new \phpbb\template\twig\twig(
$phpbb_container->get('path_helper'),
$phpbb_container->get('config'),
new \phpbb\template\context(),
new \phpbb\template\twig\environment(
$phpbb_container->get('config'),
$phpbb_container->get('filesystem'),
$phpbb_container->get('path_helper'),
$phpbb_container->getParameter('core.cache_dir'),
$phpbb_container->get('ext.manager'),
new \phpbb\template\twig\loader(
$phpbb_filesystem
)
),
$phpbb_container->getParameter('core.cache_dir'),
$phpbb_container->get('user'),
$phpbb_container->get('template.twig.extensions.collection'),
$phpbb_extension_manager
);
$template->set_style();
$template->set_filenames(array('bbcode.html' => 'bbcode.html'));
$this->template_filename = $template->get_source_file_for_handle('bbcode.html');
}
$bbcode_ids = $rowset = $sql = array();
$bitfield = new bitfield($this->bbcode_bitfield);
$bbcodes_set = $bitfield->get_all_set();
foreach ($bbcodes_set as $bbcode_id)
{
if (isset($this->bbcode_cache[$bbcode_id]))
{
// do not try to re-cache it if it's already in
continue;
}
$bbcode_ids[] = $bbcode_id;
if ($bbcode_id > NUM_CORE_BBCODES)
{
$sql[] = $bbcode_id;
}
}
if (count($sql))
{
global $db;
$sql = 'SELECT *
FROM ' . BBCODES_TABLE . '
WHERE ' . $db->sql_in_set('bbcode_id', $sql);
$result = $db->sql_query($sql, 3600);
while ($row = $db->sql_fetchrow($result))
{
// To circumvent replacing newlines with <br /> for the generated html,
// we use carriage returns here. They are later changed back to newlines
$row['bbcode_tpl'] = str_replace("\n", "\r", $row['bbcode_tpl']);
$row['second_pass_replace'] = str_replace("\n", "\r", $row['second_pass_replace']);
$rowset[$row['bbcode_id']] = $row;
}
$db->sql_freeresult($result);
}
// To perform custom second pass in extension, use $this->bbcode_second_pass_by_extension()
// method which accepts variable number of parameters
foreach ($bbcode_ids as $bbcode_id)
{
switch ($bbcode_id)
{
case BBCODE_ID_QUOTE:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[/quote:$uid]' => $this->bbcode_tpl('quote_close', $bbcode_id)
),
'preg' => array(
'#\[quote(?:=&quot;(.*?)&quot;)?:$uid\]((?!\[quote(?:=&quot;.*?&quot;)?:$uid\]).)?#is' => function ($match) {
if (!isset($match[2]))
{
$match[2] = '';
}
return $this->bbcode_second_pass_quote($match[1], $match[2]);
},
)
);
break;
case BBCODE_ID_B:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[b:$uid]' => $this->bbcode_tpl('b_open', $bbcode_id),
'[/b:$uid]' => $this->bbcode_tpl('b_close', $bbcode_id),
)
);
break;
case BBCODE_ID_I:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[i:$uid]' => $this->bbcode_tpl('i_open', $bbcode_id),
'[/i:$uid]' => $this->bbcode_tpl('i_close', $bbcode_id),
)
);
break;
case BBCODE_ID_URL:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[url:$uid\]((.*?))\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id),
'#\[url=([^\[]+?):$uid\](.*?)\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id),
)
);
break;
case BBCODE_ID_IMG:
if ($user->optionget('viewimg'))
{
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[img:$uid\](.*?)\[/img:$uid\]#s' => $this->bbcode_tpl('img', $bbcode_id),
)
);
}
else
{
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[img:$uid\](.*?)\[/img:$uid\]#s' => str_replace('$2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id, true)),
)
);
}
break;
case BBCODE_ID_SIZE:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[size=([\-\+]?\d+):$uid\](.*?)\[/size:$uid\]#s' => $this->bbcode_tpl('size', $bbcode_id),
)
);
break;
case BBCODE_ID_COLOR:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+):$uid\](.*?)\[/color:$uid\]!is' => $this->bbcode_tpl('color', $bbcode_id),
)
);
break;
case BBCODE_ID_U:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[u:$uid]' => $this->bbcode_tpl('u_open', $bbcode_id),
'[/u:$uid]' => $this->bbcode_tpl('u_close', $bbcode_id),
)
);
break;
case BBCODE_ID_CODE:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#is' => function ($match) {
return $this->bbcode_second_pass_code($match[1], $match[2]);
},
)
);
break;
case BBCODE_ID_LIST:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#(\[\/?(list|\*):[mou]?:?$uid\])[\n]{1}#' => "\$1",
'#(\[list=([^\[]+):$uid\])[\n]{1}#' => "\$1",
'#\[list=([^\[]+):$uid\]#' => function ($match) {
return $this->bbcode_list($match[1]);
},
),
'str' => array(
'[list:$uid]' => $this->bbcode_tpl('ulist_open_default', $bbcode_id),
'[/list:u:$uid]' => $this->bbcode_tpl('ulist_close', $bbcode_id),
'[/list:o:$uid]' => $this->bbcode_tpl('olist_close', $bbcode_id),
'[*:$uid]' => $this->bbcode_tpl('listitem', $bbcode_id),
'[/*:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id),
'[/*:m:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id)
),
);
break;
case BBCODE_ID_EMAIL:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[email:$uid\]((.*?))\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id),
'#\[email=([^\[]+):$uid\](.*?)\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id)
)
);
break;
case BBCODE_ID_FLASH:
if ($user->optionget('viewflash'))
{
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => $this->bbcode_tpl('flash', $bbcode_id),
)
);
}
else
{
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => str_replace('$1', '$3', str_replace('$2', '[ flash ]', $this->bbcode_tpl('url', $bbcode_id, true)))
)
);
}
break;
case BBCODE_ID_ATTACH:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[/attachment:$uid]' => $this->bbcode_tpl('inline_attachment_close', $bbcode_id)
),
'preg' => array(
'#\[attachment=([0-9]+):$uid\]#' => $this->bbcode_tpl('inline_attachment_open', $bbcode_id)
)
);
break;
default:
if (isset($rowset[$bbcode_id]))
{
if ($this->template_bitfield->get($bbcode_id))
{
// The bbcode requires a custom template to be loaded
if (!$bbcode_tpl = $this->bbcode_tpl($rowset[$bbcode_id]['bbcode_tag'], $bbcode_id))
{
// For some reason, the required template seems not to be available, use the default template
$bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl'];
}
else
{
// In order to use templates with custom bbcodes we need
// to replace all {VARS} to corresponding backreferences
// Note that backreferences are numbered from bbcode_match
if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|INTTEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m))
{
foreach ($m[0] as $i => $tok)
{
$bbcode_tpl = str_replace($tok, '$' . ($i + 1), $bbcode_tpl);
}
}
}
}
else
{
// Default template
$bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl'];
}
// Replace {L_*} lang strings
$bbcode_tpl = preg_replace_callback('/{L_([A-Z0-9_]+)}/', function ($match) use ($user) {
return (!empty($user->lang[$match[1]])) ? $user->lang($match[1]) : ucwords(strtolower(str_replace('_', ' ', $match[1])));
}, $bbcode_tpl);
if (!empty($rowset[$bbcode_id]['second_pass_replace']))
{
// The custom BBCode requires second-pass pattern replacements
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl)
);
}
else
{
$this->bbcode_cache[$bbcode_id] = array(
'str' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl)
);
}
}
else
{
$this->bbcode_cache[$bbcode_id] = false;
}
break;
}
}
$bbcode_cache = $this->bbcode_cache;
$bbcode_bitfield = $this->bbcode_bitfield;
$bbcode_uid = $this->bbcode_uid;
/**
* Use this event to modify the bbcode_cache
*
* @event core.bbcode_cache_init_end
* @var array bbcode_cache The array of cached search and replace patterns of bbcodes
* @var string bbcode_bitfield The bbcode bitfield
* @var string bbcode_uid The bbcode uid
* @since 3.1.3-RC1
*/
$vars = array('bbcode_cache', 'bbcode_bitfield', 'bbcode_uid');
extract($phpbb_dispatcher->trigger_event('core.bbcode_cache_init_end', compact($vars)));
$this->bbcode_cache = $bbcode_cache;
$this->bbcode_bitfield = $bbcode_bitfield;
$this->bbcode_uid = $bbcode_uid;
}
/**
* Return bbcode template
*/
function bbcode_tpl($tpl_name, $bbcode_id = -1, $skip_bitfield_check = false)
{
static $bbcode_hardtpl = array();
if (empty($bbcode_hardtpl))
{
global $user;
$bbcode_hardtpl = array(
'b_open' => '<span style="font-weight: bold">',
'b_close' => '</span>',
'i_open' => '<span style="font-style: italic">',
'i_close' => '</span>',
'u_open' => '<span style="text-decoration: underline">',
'u_close' => '</span>',
'img' => '<img src="$1" class="postimage" alt="' . $user->lang['IMAGE'] . '" />',
'size' => '<span style="font-size: $1%; line-height: normal">$2</span>',
'color' => '<span style="color: $1">$2</span>',
'email' => '<a href="mailto:$1">$2</a>'
);
}
if ($bbcode_id != -1 && !$skip_bitfield_check && !$this->template_bitfield->get($bbcode_id))
{
return (isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false;
}
if (empty($this->bbcode_template))
{
if (($tpl = file_get_contents($this->template_filename)) === false)
{
trigger_error('Could not load bbcode template', E_USER_ERROR);
}
// replace \ with \\ and then ' with \'.
$tpl = str_replace('\\', '\\\\', $tpl);
$tpl = str_replace("'", "\'", $tpl);
// strip newlines and indent
$tpl = preg_replace("/\n[\n\r\s\t]*/", '', $tpl);
// Turn template blocks into PHP assignment statements for the values of $bbcode_tpl..
$this->bbcode_template = array();
// Capture the BBCode template matches
// Allow phpBB template or the Twig syntax
$matches = (preg_match_all('#<!-- BEGIN (.*?) -->(.*?)<!-- END (?:.*?) -->#', $tpl, $match)) ?:
preg_match_all('#{% for (.*?) in .*? %}(.*?){% endfor %}#s', $tpl, $match);
for ($i = 0; $i < $matches; $i++)
{
if (empty($match[1][$i]))
{
continue;
}
$this->bbcode_template[$match[1][$i]] = $this->bbcode_tpl_replace($match[1][$i], $match[2][$i]);
}
}
return (isset($this->bbcode_template[$tpl_name])) ? $this->bbcode_template[$tpl_name] : ((isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false);
}
/**
* Return bbcode template replacement
*/
function bbcode_tpl_replace($tpl_name, $tpl)
{
global $user;
static $replacements = array(
'quote_username_open' => array('{USERNAME}' => '$1'),
'color' => array('{COLOR}' => '$1', '{TEXT}' => '$2'),
'size' => array('{SIZE}' => '$1', '{TEXT}' => '$2'),
'img' => array('{URL}' => '$1'),
'flash' => array('{WIDTH}' => '$1', '{HEIGHT}' => '$2', '{URL}' => '$3'),
'url' => array('{URL}' => '$1', '{DESCRIPTION}' => '$2'),
'email' => array('{EMAIL}' => '$1', '{DESCRIPTION}' => '$2')
);
$tpl = preg_replace_callback('/{L_([A-Z0-9_]+)}/', function ($match) use ($user) {
return (!empty($user->lang[$match[1]])) ? $user->lang($match[1]) : ucwords(strtolower(str_replace('_', ' ', $match[1])));
}, $tpl);
if (!empty($replacements[$tpl_name]))
{
$tpl = strtr($tpl, $replacements[$tpl_name]);
}
return trim($tpl);
}
/**
* Second parse list bbcode
*/
function bbcode_list($type)
{
if ($type == '')
{
$tpl = 'ulist_open_default';
$type = 'default';
}
else if ($type == 'i')
{
$tpl = 'olist_open';
$type = 'lower-roman';
}
else if ($type == 'I')
{
$tpl = 'olist_open';
$type = 'upper-roman';
}
else if (preg_match('#^(disc|circle|square)$#i', $type))
{
$tpl = 'ulist_open';
$type = strtolower($type);
}
else if (preg_match('#^[a-z]$#', $type))
{
$tpl = 'olist_open';
$type = 'lower-alpha';
}
else if (preg_match('#[A-Z]#', $type))
{
$tpl = 'olist_open';
$type = 'upper-alpha';
}
else if (is_numeric($type))
{
$tpl = 'olist_open';
$type = 'decimal';
}
else
{
$tpl = 'olist_open';
$type = 'decimal';
}
return str_replace('{LIST_TYPE}', $type, $this->bbcode_tpl($tpl));
}
/**
* Second parse quote tag
*/
function bbcode_second_pass_quote($username, $quote)
{
// when using the /e modifier, preg_replace slashes double-quotes but does not
// seem to slash anything else
$quote = str_replace('\"', '"', $quote);
$username = str_replace('\"', '"', $username);
// remove newline at the beginning
if ($quote == "\n")
{
$quote = '';
}
$quote = (($username) ? str_replace('$1', $username, $this->bbcode_tpl('quote_username_open')) : $this->bbcode_tpl('quote_open')) . $quote;
return $quote;
}
/**
* Second parse code tag
*/
function bbcode_second_pass_code($type, $code)
{
// when using the /e modifier, preg_replace slashes double-quotes but does not
// seem to slash anything else
$code = str_replace('\"', '"', $code);
switch ($type)
{
case 'php':
// Not the english way, but valid because of hardcoded syntax highlighting
if (strpos($code, '<span class="syntaxdefault"><br /></span>') === 0)
{
$code = substr($code, 41);
}
// no break;
default:
$code = str_replace("\t", '&nbsp; &nbsp;', $code);
$code = str_replace(' ', '&nbsp; ', $code);
$code = str_replace(' ', ' &nbsp;', $code);
$code = str_replace("\n ", "\n&nbsp;", $code);
// keep space at the beginning
if (!empty($code) && $code[0] == ' ')
{
$code = '&nbsp;' . substr($code, 1);
}
// remove newline at the beginning
if (!empty($code) && $code[0] == "\n")
{
$code = substr($code, 1);
}
break;
}
$code = $this->bbcode_tpl('code_open') . $code . $this->bbcode_tpl('code_close');
return $code;
}
/**
* Function to perform custom bbcode second pass by extensions
* can be used to assign bbcode pattern replacement
* Example: '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_second_pass_by_extension('\$1')"
*
* Accepts variable number of parameters
*
* @return mixed Second pass result
*/
function bbcode_second_pass_by_extension()
{
global $phpbb_dispatcher;
$return = false;
$params_array = func_get_args();
/**
* Event to perform bbcode second pass with
* the custom validating methods provided by extensions
*
* @event core.bbcode_second_pass_by_extension
* @var array params_array Array with the function parameters
* @var mixed return Second pass result to return
*
* @since 3.1.5-RC1
*/
$vars = array('params_array', 'return');
extract($phpbb_dispatcher->trigger_event('core.bbcode_second_pass_by_extension', compact($vars)));
return $return;
}
}

View File

@@ -0,0 +1,84 @@
<?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.
*
*/
/**
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* Sets compatibility globals in the global scope
*
* This function registers compatibility variables to the global
* variable scope. This is required to make it possible to include this file
* in a service.
*/
function register_compatibility_globals()
{
global $phpbb_container;
global $cache, $phpbb_dispatcher, $request, $user, $auth, $db, $config, $language, $phpbb_log;
global $symfony_request, $phpbb_filesystem, $phpbb_path_helper, $phpbb_extension_manager, $template;
// set up caching
/* @var $cache \phpbb\cache\service */
$cache = $phpbb_container->get('cache');
// Instantiate some basic classes
/* @var $phpbb_dispatcher \phpbb\event\dispatcher */
$phpbb_dispatcher = $phpbb_container->get('dispatcher');
/* @var $request \phpbb\request\request_interface */
$request = $phpbb_container->get('request');
// Inject request instance, so only this instance is used with request_var
request_var('', 0, false, false, $request);
/* @var $user \phpbb\user */
$user = $phpbb_container->get('user');
/* @var \phpbb\language\language $language */
$language = $phpbb_container->get('language');
/* @var $auth \phpbb\auth\auth */
$auth = $phpbb_container->get('auth');
/* @var $db \phpbb\db\driver\driver_interface */
$db = $phpbb_container->get('dbal.conn');
// Grab global variables, re-cache if necessary
/* @var $config phpbb\config\db */
$config = $phpbb_container->get('config');
set_config('', '', false, $config);
set_config_count('', 0, false, $config);
/* @var $phpbb_log \phpbb\log\log_interface */
$phpbb_log = $phpbb_container->get('log');
/* @var $symfony_request \phpbb\symfony_request */
$symfony_request = $phpbb_container->get('symfony_request');
/* @var $phpbb_filesystem \phpbb\filesystem\filesystem_interface */
$phpbb_filesystem = $phpbb_container->get('filesystem');
/* @var $phpbb_path_helper \phpbb\path_helper */
$phpbb_path_helper = $phpbb_container->get('path_helper');
// load extensions
/* @var $phpbb_extension_manager \phpbb\extension\manager */
$phpbb_extension_manager = $phpbb_container->get('ext.manager');
/* @var $template \phpbb\template\template */
$template = $phpbb_container->get('template');
}

316
includes/constants.php Normal file
View File

@@ -0,0 +1,316 @@
<?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;
}
/**
* valid external constants:
* PHPBB_MSG_HANDLER
* PHPBB_DB_NEW_LINK
* PHPBB_ROOT_PATH
* PHPBB_ADMIN_PATH
*/
// phpBB Version
@define('PHPBB_VERSION', '3.2.7');
// QA-related
// define('PHPBB_QA', 1);
// User related
define('ANONYMOUS', 1);
define('USER_ACTIVATION_NONE', 0);
define('USER_ACTIVATION_SELF', 1);
define('USER_ACTIVATION_ADMIN', 2);
define('USER_ACTIVATION_DISABLE', 3);
define('AVATAR_UPLOAD', 1);
define('AVATAR_REMOTE', 2);
define('AVATAR_GALLERY', 3);
define('USER_NORMAL', 0);
define('USER_INACTIVE', 1);
define('USER_IGNORE', 2);
define('USER_FOUNDER', 3);
define('INACTIVE_REGISTER', 1); // Newly registered account
define('INACTIVE_PROFILE', 2); // Profile details changed
define('INACTIVE_MANUAL', 3); // Account deactivated by administrator
define('INACTIVE_REMIND', 4); // Forced user account reactivation
// ACL
define('ACL_NEVER', 0);
define('ACL_YES', 1);
define('ACL_NO', -1);
// Login error codes
define('LOGIN_CONTINUE', 1);
define('LOGIN_BREAK', 2);
define('LOGIN_SUCCESS', 3);
define('LOGIN_SUCCESS_CREATE_PROFILE', 20);
define('LOGIN_SUCCESS_LINK_PROFILE', 21);
define('LOGIN_ERROR_USERNAME', 10);
define('LOGIN_ERROR_PASSWORD', 11);
define('LOGIN_ERROR_ACTIVE', 12);
define('LOGIN_ERROR_ATTEMPTS', 13);
define('LOGIN_ERROR_EXTERNAL_AUTH', 14);
define('LOGIN_ERROR_PASSWORD_CONVERT', 15);
// Maximum login attempts
// The value is arbitrary, but it has to fit into the user_login_attempts field.
define('LOGIN_ATTEMPTS_MAX', 100);
// Group settings
define('GROUP_OPEN', 0);
define('GROUP_CLOSED', 1);
define('GROUP_HIDDEN', 2);
define('GROUP_SPECIAL', 3);
define('GROUP_FREE', 4);
// Forum/Topic states
define('FORUM_CAT', 0);
define('FORUM_POST', 1);
define('FORUM_LINK', 2);
define('ITEM_UNLOCKED', 0);
define('ITEM_LOCKED', 1);
define('ITEM_MOVED', 2);
define('ITEM_UNAPPROVED', 0); // => has not yet been approved
define('ITEM_APPROVED', 1); // => has been approved, and has not been soft deleted
define('ITEM_DELETED', 2); // => has been soft deleted
define('ITEM_REAPPROVE', 3); // => has been edited and needs to be re-approved
// Forum Flags
define('FORUM_FLAG_LINK_TRACK', 1);
define('FORUM_FLAG_PRUNE_POLL', 2);
define('FORUM_FLAG_PRUNE_ANNOUNCE', 4);
define('FORUM_FLAG_PRUNE_STICKY', 8);
define('FORUM_FLAG_ACTIVE_TOPICS', 16);
define('FORUM_FLAG_POST_REVIEW', 32);
define('FORUM_FLAG_QUICK_REPLY', 64);
// Forum Options... sequential order. Modifications should begin at number 10 (number 29 is maximum)
define('FORUM_OPTION_FEED_NEWS', 1);
define('FORUM_OPTION_FEED_EXCLUDE', 2);
// Optional text flags
define('OPTION_FLAG_BBCODE', 1);
define('OPTION_FLAG_SMILIES', 2);
define('OPTION_FLAG_LINKS', 4);
// Topic types
define('POST_NORMAL', 0);
define('POST_STICKY', 1);
define('POST_ANNOUNCE', 2);
define('POST_GLOBAL', 3);
// Lastread types
define('TRACK_NORMAL', 0);
define('TRACK_POSTED', 1);
// Notify methods
define('NOTIFY_EMAIL', 0);
define('NOTIFY_IM', 1);
define('NOTIFY_BOTH', 2);
// Notify status
define('NOTIFY_YES', 0);
define('NOTIFY_NO', 1);
// Email Priority Settings
define('MAIL_LOW_PRIORITY', 4);
define('MAIL_NORMAL_PRIORITY', 3);
define('MAIL_HIGH_PRIORITY', 2);
// Log types
define('LOG_ADMIN', 0);
define('LOG_MOD', 1);
define('LOG_CRITICAL', 2);
define('LOG_USERS', 3);
// Private messaging - Do NOT change these values
define('PRIVMSGS_HOLD_BOX', -4);
define('PRIVMSGS_NO_BOX', -3);
define('PRIVMSGS_OUTBOX', -2);
define('PRIVMSGS_SENTBOX', -1);
define('PRIVMSGS_INBOX', 0);
// Full Folder Actions
define('FULL_FOLDER_NONE', -3);
define('FULL_FOLDER_DELETE', -2);
define('FULL_FOLDER_HOLD', -1);
// Download Modes - Attachments
define('INLINE_LINK', 1);
// This mode is only used internally to allow modders extending the attachment functionality
define('PHYSICAL_LINK', 2);
// Confirm types
define('CONFIRM_REG', 1);
define('CONFIRM_LOGIN', 2);
define('CONFIRM_POST', 3);
define('CONFIRM_REPORT', 4);
// Categories - Attachments
define('ATTACHMENT_CATEGORY_NONE', 0);
define('ATTACHMENT_CATEGORY_IMAGE', 1); // Inline Images
define('ATTACHMENT_CATEGORY_WM', 2); // Windows Media Files - Streaming - @deprecated 3.2
define('ATTACHMENT_CATEGORY_RM', 3); // Real Media Files - Streaming - @deprecated 3.2
define('ATTACHMENT_CATEGORY_THUMB', 4); // Not used within the database, only while displaying posts
define('ATTACHMENT_CATEGORY_FLASH', 5); // Flash/SWF files
define('ATTACHMENT_CATEGORY_QUICKTIME', 6); // Quicktime/Mov files - @deprecated 3.2
// BBCode UID length
define('BBCODE_UID_LEN', 8);
// Number of core BBCodes
define('NUM_CORE_BBCODES', 12);
define('NUM_PREDEFINED_BBCODES', 22);
// BBCode IDs
define('BBCODE_ID_QUOTE', 0);
define('BBCODE_ID_B', 1);
define('BBCODE_ID_I', 2);
define('BBCODE_ID_URL', 3);
define('BBCODE_ID_IMG', 4);
define('BBCODE_ID_SIZE', 5);
define('BBCODE_ID_COLOR', 6);
define('BBCODE_ID_U', 7);
define('BBCODE_ID_CODE', 8);
define('BBCODE_ID_LIST', 9);
define('BBCODE_ID_EMAIL', 10);
define('BBCODE_ID_FLASH', 11);
define('BBCODE_ID_ATTACH', 12);
// BBCode hard limit
define('BBCODE_LIMIT', 1511);
// Smiley hard limit
define('SMILEY_LIMIT', 1000);
// Magic url types
define('MAGIC_URL_EMAIL', 1);
define('MAGIC_URL_FULL', 2);
define('MAGIC_URL_LOCAL', 3);
define('MAGIC_URL_WWW', 4);
// Profile Field Types
define('FIELD_INT', 1);
define('FIELD_STRING', 2);
define('FIELD_TEXT', 3);
define('FIELD_BOOL', 4);
define('FIELD_DROPDOWN', 5);
define('FIELD_DATE', 6);
// referer validation
define('REFERER_VALIDATE_NONE', 0);
define('REFERER_VALIDATE_HOST', 1);
define('REFERER_VALIDATE_PATH', 2);
// phpbb_chmod() permissions
@define('CHMOD_ALL', 7);
@define('CHMOD_READ', 4);
@define('CHMOD_WRITE', 2);
@define('CHMOD_EXECUTE', 1);
// Captcha code length
define('CAPTCHA_MIN_CHARS', 4);
define('CAPTCHA_MAX_CHARS', 7);
// Additional constants
define('VOTE_CONVERTED', 127);
// BC global FTW
global $table_prefix;
// Table names
define('ACL_GROUPS_TABLE', $table_prefix . 'acl_groups');
define('ACL_OPTIONS_TABLE', $table_prefix . 'acl_options');
define('ACL_ROLES_DATA_TABLE', $table_prefix . 'acl_roles_data');
define('ACL_ROLES_TABLE', $table_prefix . 'acl_roles');
define('ACL_USERS_TABLE', $table_prefix . 'acl_users');
define('ATTACHMENTS_TABLE', $table_prefix . 'attachments');
define('BANLIST_TABLE', $table_prefix . 'banlist');
define('BBCODES_TABLE', $table_prefix . 'bbcodes');
define('BOOKMARKS_TABLE', $table_prefix . 'bookmarks');
define('BOTS_TABLE', $table_prefix . 'bots');
@define('CONFIG_TABLE', $table_prefix . 'config');
define('CONFIG_TEXT_TABLE', $table_prefix . 'config_text');
define('CONFIRM_TABLE', $table_prefix . 'confirm');
define('DISALLOW_TABLE', $table_prefix . 'disallow');
define('DRAFTS_TABLE', $table_prefix . 'drafts');
define('EXT_TABLE', $table_prefix . 'ext');
define('EXTENSIONS_TABLE', $table_prefix . 'extensions');
define('EXTENSION_GROUPS_TABLE', $table_prefix . 'extension_groups');
define('FORUMS_TABLE', $table_prefix . 'forums');
define('FORUMS_ACCESS_TABLE', $table_prefix . 'forums_access');
define('FORUMS_TRACK_TABLE', $table_prefix . 'forums_track');
define('FORUMS_WATCH_TABLE', $table_prefix . 'forums_watch');
define('GROUPS_TABLE', $table_prefix . 'groups');
define('ICONS_TABLE', $table_prefix . 'icons');
define('LANG_TABLE', $table_prefix . 'lang');
define('LOG_TABLE', $table_prefix . 'log');
define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');
define('MIGRATIONS_TABLE', $table_prefix . 'migrations');
define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache');
define('MODULES_TABLE', $table_prefix . 'modules');
define('NOTIFICATION_TYPES_TABLE', $table_prefix . 'notification_types');
define('NOTIFICATIONS_TABLE', $table_prefix . 'notifications');
define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options');
define('POLL_VOTES_TABLE', $table_prefix . 'poll_votes');
define('POSTS_TABLE', $table_prefix . 'posts');
define('PRIVMSGS_TABLE', $table_prefix . 'privmsgs');
define('PRIVMSGS_FOLDER_TABLE', $table_prefix . 'privmsgs_folder');
define('PRIVMSGS_RULES_TABLE', $table_prefix . 'privmsgs_rules');
define('PRIVMSGS_TO_TABLE', $table_prefix . 'privmsgs_to');
define('PROFILE_FIELDS_TABLE', $table_prefix . 'profile_fields');
define('PROFILE_FIELDS_DATA_TABLE', $table_prefix . 'profile_fields_data');
define('PROFILE_FIELDS_LANG_TABLE', $table_prefix . 'profile_fields_lang');
define('PROFILE_LANG_TABLE', $table_prefix . 'profile_lang');
define('RANKS_TABLE', $table_prefix . 'ranks');
define('REPORTS_TABLE', $table_prefix . 'reports');
define('REPORTS_REASONS_TABLE', $table_prefix . 'reports_reasons');
define('SEARCH_RESULTS_TABLE', $table_prefix . 'search_results');
define('SEARCH_WORDLIST_TABLE', $table_prefix . 'search_wordlist');
define('SEARCH_WORDMATCH_TABLE', $table_prefix . 'search_wordmatch');
define('SESSIONS_TABLE', $table_prefix . 'sessions');
define('SESSIONS_KEYS_TABLE', $table_prefix . 'sessions_keys');
define('SITELIST_TABLE', $table_prefix . 'sitelist');
define('SMILIES_TABLE', $table_prefix . 'smilies');
define('SPHINX_TABLE', $table_prefix . 'sphinx');
define('STYLES_TABLE', $table_prefix . 'styles');
define('STYLES_TEMPLATE_TABLE', $table_prefix . 'styles_template');
define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data');
define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme');
define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset');
define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data');
define('TEAMPAGE_TABLE', $table_prefix . 'teampage');
define('TOPICS_TABLE', $table_prefix . 'topics');
define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted');
define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track');
define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch');
define('USER_GROUP_TABLE', $table_prefix . 'user_group');
define('USER_NOTIFICATIONS_TABLE', $table_prefix . 'user_notifications');
define('USERS_TABLE', $table_prefix . 'users');
define('WARNINGS_TABLE', $table_prefix . 'warnings');
define('WORDS_TABLE', $table_prefix . 'words');
define('ZEBRA_TABLE', $table_prefix . 'zebra');
// Additional tables

1152
includes/diff/diff.php Normal file

File diff suppressed because it is too large Load Diff

555
includes/diff/engine.php Normal file
View File

@@ -0,0 +1,555 @@
<?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;
}
/**
* Code from pear.php.net, Text_Diff-1.1.0 package
* http://pear.php.net/package/Text_Diff/ (native engine)
*
* Modified by phpBB Limited to meet our coding standards
* and being able to integrate into phpBB
*
* Class used internally by Text_Diff to actually compute the diffs. This
* class is implemented using native PHP code.
*
* The algorithm used here is mostly lifted from the perl module
* Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
*
* More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html
*
* Some ideas (and a bit of code) are taken from analyze.c, of GNU
* diffutils-2.7, which can be found at:
* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
*
* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
* Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
* code was written by him, and is used/adapted with his permission.
*
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
*
* @author Geoffrey T. Dairiki <dairiki@dairiki.org>
* @package diff
*
* @access private
*/
class diff_engine
{
/**
* If set to true we trim all lines before we compare them. This ensures that sole space/tab changes do not trigger diffs.
*/
var $skip_whitespace_changes = true;
function diff(&$from_lines, &$to_lines, $preserve_cr = true)
{
// Remove empty lines...
// If preserve_cr is true, we basically only change \r\n and bare \r to \n to get the same carriage returns for both files
// If it is false, we try to only use \n once per line and ommit all empty lines to be able to get a proper data diff
if (is_array($from_lines))
{
$from_lines = implode("\n", $from_lines);
}
if (is_array($to_lines))
{
$to_lines = implode("\n", $to_lines);
}
if ($preserve_cr)
{
$from_lines = explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $from_lines)));
$to_lines = explode("\n", str_replace("\r", "\n", str_replace("\r\n", "\n", $to_lines)));
}
else
{
$from_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $from_lines));
$to_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $to_lines));
}
$n_from = count($from_lines);
$n_to = count($to_lines);
$this->xchanged = $this->ychanged = $this->xv = $this->yv = $this->xind = $this->yind = array();
unset($this->seq, $this->in_seq, $this->lcs);
// Skip leading common lines.
for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++)
{
if (trim($from_lines[$skip]) !== trim($to_lines[$skip]))
{
break;
}
$this->xchanged[$skip] = $this->ychanged[$skip] = false;
}
// Skip trailing common lines.
$xi = $n_from;
$yi = $n_to;
for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++)
{
if (trim($from_lines[$xi]) !== trim($to_lines[$yi]))
{
break;
}
$this->xchanged[$xi] = $this->ychanged[$yi] = false;
}
// Ignore lines which do not exist in both files.
for ($xi = $skip; $xi < $n_from - $endskip; $xi++)
{
if ($this->skip_whitespace_changes) $xhash[trim($from_lines[$xi])] = 1; else $xhash[$from_lines[$xi]] = 1;
}
for ($yi = $skip; $yi < $n_to - $endskip; $yi++)
{
$line = ($this->skip_whitespace_changes) ? trim($to_lines[$yi]) : $to_lines[$yi];
if (($this->ychanged[$yi] = empty($xhash[$line])))
{
continue;
}
$yhash[$line] = 1;
$this->yv[] = $line;
$this->yind[] = $yi;
}
for ($xi = $skip; $xi < $n_from - $endskip; $xi++)
{
$line = ($this->skip_whitespace_changes) ? trim($from_lines[$xi]) : $from_lines[$xi];
if (($this->xchanged[$xi] = empty($yhash[$line])))
{
continue;
}
$this->xv[] = $line;
$this->xind[] = $xi;
}
// Find the LCS.
$this->_compareseq(0, count($this->xv), 0, count($this->yv));
// Merge edits when possible.
if ($this->skip_whitespace_changes)
{
$from_lines_clean = array_map('trim', $from_lines);
$to_lines_clean = array_map('trim', $to_lines);
$this->_shift_boundaries($from_lines_clean, $this->xchanged, $this->ychanged);
$this->_shift_boundaries($to_lines_clean, $this->ychanged, $this->xchanged);
unset($from_lines_clean, $to_lines_clean);
}
else
{
$this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
$this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
}
// Compute the edit operations.
$edits = array();
$xi = $yi = 0;
while ($xi < $n_from || $yi < $n_to)
{
// Skip matching "snake".
$copy = array();
while ($xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi])
{
$copy[] = $from_lines[$xi++];
$yi++;
}
if ($copy)
{
$edits[] = new diff_op_copy($copy);
}
// Find deletes & adds.
$delete = array();
while ($xi < $n_from && $this->xchanged[$xi])
{
$delete[] = $from_lines[$xi++];
}
$add = array();
while ($yi < $n_to && $this->ychanged[$yi])
{
$add[] = $to_lines[$yi++];
}
if ($delete && $add)
{
$edits[] = new diff_op_change($delete, $add);
}
else if ($delete)
{
$edits[] = new diff_op_delete($delete);
}
else if ($add)
{
$edits[] = new diff_op_add($add);
}
}
return $edits;
}
/**
* Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
* XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized segments.
*
* Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
* NCHUNKS+1 (X, Y) indexes giving the diving points between sub
* sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
* the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
* (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
*
* This function assumes that the first lines of the specified portions of
* the two files do not match, and likewise that the last lines do not
* match. The caller must trim matching lines from the beginning and end
* of the portions it is going to specify.
*/
function _diag($xoff, $xlim, $yoff, $ylim, $nchunks)
{
$flip = false;
if ($xlim - $xoff > $ylim - $yoff)
{
// Things seems faster (I'm not sure I understand why) when the shortest sequence is in X.
$flip = true;
list($xoff, $xlim, $yoff, $ylim) = array($yoff, $ylim, $xoff, $xlim);
}
if ($flip)
{
for ($i = $ylim - 1; $i >= $yoff; $i--)
{
$ymatches[$this->xv[$i]][] = $i;
}
}
else
{
for ($i = $ylim - 1; $i >= $yoff; $i--)
{
$ymatches[$this->yv[$i]][] = $i;
}
}
$this->lcs = 0;
$this->seq[0]= $yoff - 1;
$this->in_seq = array();
$ymids[0] = array();
$numer = $xlim - $xoff + $nchunks - 1;
$x = $xoff;
for ($chunk = 0; $chunk < $nchunks; $chunk++)
{
if ($chunk > 0)
{
for ($i = 0; $i <= $this->lcs; $i++)
{
$ymids[$i][$chunk - 1] = $this->seq[$i];
}
}
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
for (; $x < $x1; $x++)
{
$line = $flip ? $this->yv[$x] : $this->xv[$x];
if (empty($ymatches[$line]))
{
continue;
}
$matches = $ymatches[$line];
reset($matches);
while (list(, $y) = each($matches))
{
if (empty($this->in_seq[$y]))
{
$k = $this->_lcs_pos($y);
$ymids[$k] = $ymids[$k - 1];
break;
}
}
// no reset() here
while (list(, $y) = each($matches))
{
if ($y > $this->seq[$k - 1])
{
// Optimization: this is a common case: next match is just replacing previous match.
$this->in_seq[$this->seq[$k]] = false;
$this->seq[$k] = $y;
$this->in_seq[$y] = 1;
}
else if (empty($this->in_seq[$y]))
{
$k = $this->_lcs_pos($y);
$ymids[$k] = $ymids[$k - 1];
}
}
}
}
$seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
$ymid = $ymids[$this->lcs];
for ($n = 0; $n < $nchunks - 1; $n++)
{
$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
$y1 = $ymid[$n] + 1;
$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
}
$seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
return array($this->lcs, $seps);
}
function _lcs_pos($ypos)
{
$end = $this->lcs;
if ($end == 0 || $ypos > $this->seq[$end])
{
$this->seq[++$this->lcs] = $ypos;
$this->in_seq[$ypos] = 1;
return $this->lcs;
}
$beg = 1;
while ($beg < $end)
{
$mid = (int)(($beg + $end) / 2);
if ($ypos > $this->seq[$mid])
{
$beg = $mid + 1;
}
else
{
$end = $mid;
}
}
$this->in_seq[$this->seq[$end]] = false;
$this->seq[$end] = $ypos;
$this->in_seq[$ypos] = 1;
return $end;
}
/**
* Finds LCS of two sequences.
*
* The results are recorded in the vectors $this->{x,y}changed[], by
* storing a 1 in the element for each line that is an insertion or
* deletion (ie. is not in the LCS).
*
* The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
*
* Note that XLIM, YLIM are exclusive bounds. All line numbers are
* origin-0 and discarded lines are not counted.
*/
function _compareseq($xoff, $xlim, $yoff, $ylim)
{
// Slide down the bottom initial diagonal.
while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff])
{
++$xoff;
++$yoff;
}
// Slide up the top initial diagonal.
while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1])
{
--$xlim;
--$ylim;
}
if ($xoff == $xlim || $yoff == $ylim)
{
$lcs = 0;
}
else
{
// This is ad hoc but seems to work well.
// $nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
// $nchunks = max(2,min(8,(int)$nchunks));
$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
list($lcs, $seps) = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
}
if ($lcs == 0)
{
// X and Y sequences have no common subsequence: mark all changed.
while ($yoff < $ylim)
{
$this->ychanged[$this->yind[$yoff++]] = 1;
}
while ($xoff < $xlim)
{
$this->xchanged[$this->xind[$xoff++]] = 1;
}
}
else
{
// Use the partitions to split this problem into subproblems.
reset($seps);
$pt1 = $seps[0];
while ($pt2 = next($seps))
{
$this->_compareseq($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
$pt1 = $pt2;
}
}
}
/**
* Adjusts inserts/deletes of identical lines to join changes as much as possible.
*
* We do something when a run of changed lines include a line at one end
* and has an excluded, identical line at the other. We are free to
* choose which identical line is included. 'compareseq' usually chooses
* the one at the beginning, but usually it is cleaner to consider the
* following identical line to be the "change".
*
* This is extracted verbatim from analyze.c (GNU diffutils-2.7).
*/
function _shift_boundaries($lines, &$changed, $other_changed)
{
$i = 0;
$j = 0;
$len = count($lines);
$other_len = count($other_changed);
while (1)
{
// Scan forward to find the beginning of another run of
// changes. Also keep track of the corresponding point in the other file.
//
// Throughout this code, $i and $j are adjusted together so that
// the first $i elements of $changed and the first $j elements of
// $other_changed both contain the same number of zeros (unchanged lines).
//
// Furthermore, $j is always kept so that $j == $other_len or $other_changed[$j] == false.
while ($j < $other_len && $other_changed[$j])
{
$j++;
}
while ($i < $len && ! $changed[$i])
{
$i++;
$j++;
while ($j < $other_len && $other_changed[$j])
{
$j++;
}
}
if ($i == $len)
{
break;
}
$start = $i;
// Find the end of this run of changes.
while (++$i < $len && $changed[$i])
{
continue;
}
do
{
// Record the length of this run of changes, so that we can later determine whether the run has grown.
$runlength = $i - $start;
// Move the changed region back, so long as the previous unchanged line matches the last changed one.
// This merges with previous changed regions.
while ($start > 0 && $lines[$start - 1] == $lines[$i - 1])
{
$changed[--$start] = 1;
$changed[--$i] = false;
while ($start > 0 && $changed[$start - 1])
{
$start--;
}
while ($other_changed[--$j])
{
continue;
}
}
// Set CORRESPONDING to the end of the changed run, at the last point where it corresponds to a changed run in the
// other file. CORRESPONDING == LEN means no such point has been found.
$corresponding = $j < $other_len ? $i : $len;
// Move the changed region forward, so long as the first changed line matches the following unchanged one.
// This merges with following changed regions.
// Do this second, so that if there are no merges, the changed region is moved forward as far as possible.
while ($i < $len && $lines[$start] == $lines[$i])
{
$changed[$start++] = false;
$changed[$i++] = 1;
while ($i < $len && $changed[$i])
{
$i++;
}
$j++;
if ($j < $other_len && $other_changed[$j])
{
$corresponding = $i;
while ($j < $other_len && $other_changed[$j])
{
$j++;
}
}
}
}
while ($runlength != $i - $start);
// If possible, move the fully-merged run of changes back to a corresponding run in the other file.
while ($corresponding < $i)
{
$changed[--$start] = 1;
$changed[--$i] = 0;
while ($other_changed[--$j])
{
continue;
}
}
}
}
}

861
includes/diff/renderer.php Normal file
View File

@@ -0,0 +1,861 @@
<?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;
}
/**
* Code from pear.php.net, Text_Diff-1.1.0 package
* http://pear.php.net/package/Text_Diff/
*
* Modified by phpBB Limited to meet our coding standards
* and being able to integrate into phpBB
*
* A class to render Diffs in different formats.
*
* This class renders the diff in classic diff format. It is intended that
* this class be customized via inheritance, to obtain fancier outputs.
*
* Copyright 2004-2008 The Horde Project (http://www.horde.org/)
*
* @package diff
*/
class diff_renderer
{
/**
* Number of leading context "lines" to preserve.
*
* This should be left at zero for this class, but subclasses may want to
* set this to other values.
*/
var $_leading_context_lines = 0;
/**
* Number of trailing context "lines" to preserve.
*
* This should be left at zero for this class, but subclasses may want to
* set this to other values.
*/
var $_trailing_context_lines = 0;
/**
* Constructor.
*/
function __construct($params = array())
{
foreach ($params as $param => $value)
{
$v = '_' . $param;
if (isset($this->$v))
{
$this->$v = $value;
}
}
}
/**
* Get any renderer parameters.
*
* @return array All parameters of this renderer object.
*/
function get_params()
{
$params = array();
foreach (get_object_vars($this) as $k => $v)
{
if ($k[0] == '_')
{
$params[substr($k, 1)] = $v;
}
}
return $params;
}
/**
* Renders a diff.
*
* @param diff &$diff A diff object.
*
* @return string The formatted output.
*/
function render(&$diff)
{
$xi = $yi = 1;
$block = false;
$context = array();
// Create a new diff object if it is a 3-way diff
if (is_a($diff, 'diff3'))
{
$diff3 = &$diff;
$diff_1 = $diff3->get_original();
$diff_2 = $diff3->merged_output();
unset($diff3);
$diff = new diff($diff_1, $diff_2);
}
$nlead = $this->_leading_context_lines;
$ntrail = $this->_trailing_context_lines;
$output = $this->_start_diff();
$diffs = $diff->get_diff();
foreach ($diffs as $i => $edit)
{
// If these are unchanged (copied) lines, and we want to keep leading or trailing context lines, extract them from the copy block.
if (is_a($edit, 'diff_op_copy'))
{
// Do we have any diff blocks yet?
if (is_array($block))
{
// How many lines to keep as context from the copy block.
$keep = ($i == count($diffs) - 1) ? $ntrail : $nlead + $ntrail;
if (count($edit->orig) <= $keep)
{
// We have less lines in the block than we want for context => keep the whole block.
$block[] = $edit;
}
else
{
if ($ntrail)
{
// Create a new block with as many lines as we need for the trailing context.
$context = array_slice($edit->orig, 0, $ntrail);
$block[] = new diff_op_copy($context);
}
$output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
$block = false;
}
}
// Keep the copy block as the context for the next block.
$context = $edit->orig;
}
else
{
// Don't we have any diff blocks yet?
if (!is_array($block))
{
// Extract context lines from the preceding copy block.
$context = array_slice($context, count($context) - $nlead);
$x0 = $xi - count($context);
$y0 = $yi - count($context);
$block = array();
if ($context)
{
$block[] = new diff_op_copy($context);
}
}
$block[] = $edit;
}
$xi += ($edit->orig) ? count($edit->orig) : 0;
$yi += ($edit->final) ? count($edit->final) : 0;
}
if (is_array($block))
{
$output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
}
return $output . $this->_end_diff();
}
function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
{
$output = $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
foreach ($edits as $edit)
{
switch (get_class($edit))
{
case 'diff_op_copy':
$output .= $this->_context($edit->orig);
break;
case 'diff_op_add':
$output .= $this->_added($edit->final);
break;
case 'diff_op_delete':
$output .= $this->_deleted($edit->orig);
break;
case 'diff_op_change':
$output .= $this->_changed($edit->orig, $edit->final);
break;
}
}
return $output . $this->_end_block();
}
function _start_diff()
{
return '';
}
function _end_diff()
{
return '';
}
function _block_header($xbeg, $xlen, $ybeg, $ylen)
{
if ($xlen > 1)
{
$xbeg .= ',' . ($xbeg + $xlen - 1);
}
if ($ylen > 1)
{
$ybeg .= ',' . ($ybeg + $ylen - 1);
}
// this matches the GNU Diff behaviour
if ($xlen && !$ylen)
{
$ybeg--;
}
else if (!$xlen)
{
$xbeg--;
}
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
}
function _start_block($header)
{
return $header . "\n";
}
function _end_block()
{
return '';
}
function _lines($lines, $prefix = ' ')
{
return $prefix . implode("\n$prefix", $lines) . "\n";
}
function _context($lines)
{
return $this->_lines($lines, ' ');
}
function _added($lines)
{
return $this->_lines($lines, '> ');
}
function _deleted($lines)
{
return $this->_lines($lines, '< ');
}
function _changed($orig, $final)
{
return $this->_deleted($orig) . "---\n" . $this->_added($final);
}
/**
* Our function to get the diff
*/
function get_diff_content($diff)
{
return $this->render($diff);
}
}
/**
* Renders a unified diff
* @package diff
*/
class diff_renderer_unified extends diff_renderer
{
var $_leading_context_lines = 4;
var $_trailing_context_lines = 4;
/**
* Our function to get the diff
*/
function get_diff_content($diff)
{
return nl2br($this->render($diff));
}
function _block_header($xbeg, $xlen, $ybeg, $ylen)
{
if ($xlen != 1)
{
$xbeg .= ',' . $xlen;
}
if ($ylen != 1)
{
$ybeg .= ',' . $ylen;
}
return '<div class="diff"><big class="info">@@ -' . $xbeg . ' +' . $ybeg . ' @@</big></div>';
}
function _context($lines)
{
return '<pre class="diff context">' . htmlspecialchars($this->_lines($lines, ' ')) . '<br /></pre>';
}
function _added($lines)
{
return '<pre class="diff added">' . htmlspecialchars($this->_lines($lines, '+')) . '<br /></pre>';
}
function _deleted($lines)
{
return '<pre class="diff removed">' . htmlspecialchars($this->_lines($lines, '-')) . '<br /></pre>';
}
function _changed($orig, $final)
{
return $this->_deleted($orig) . $this->_added($final);
}
function _start_diff()
{
$start = '<div class="file">';
return $start;
}
function _end_diff()
{
return '</div>';
}
function _end_block()
{
return '';
}
}
/**
* "Inline" diff renderer.
*
* This class renders diffs in the Wiki-style "inline" format.
*
* @author Ciprian Popovici
* @package diff
*/
class diff_renderer_inline extends diff_renderer
{
var $_leading_context_lines = 10000;
var $_trailing_context_lines = 10000;
// Prefix and suffix for inserted text
var $_ins_prefix = '<span class="ins">';
var $_ins_suffix = '</span>';
// Prefix and suffix for deleted text
var $_del_prefix = '<span class="del">';
var $_del_suffix = '</span>';
var $_block_head = '';
// What are we currently splitting on? Used to recurse to show word-level
var $_split_level = 'lines';
/**
* Our function to get the diff
*/
function get_diff_content($diff)
{
return '<pre>' . nl2br($this->render($diff)) . '<br /></pre>';
}
function _start_diff()
{
return '';
}
function _end_diff()
{
return '';
}
function _block_header($xbeg, $xlen, $ybeg, $ylen)
{
return $this->_block_head;
}
function _start_block($header)
{
return $header;
}
function _lines($lines, $prefix = ' ', $encode = true)
{
if ($encode)
{
array_walk($lines, array(&$this, '_encode'));
}
if ($this->_split_level == 'words')
{
return implode('', $lines);
}
else
{
return implode("\n", $lines) . "\n";
}
}
function _added($lines)
{
array_walk($lines, array(&$this, '_encode'));
$lines[0] = $this->_ins_prefix . $lines[0];
$lines[count($lines) - 1] .= $this->_ins_suffix;
return $this->_lines($lines, ' ', false);
}
function _deleted($lines, $words = false)
{
array_walk($lines, array(&$this, '_encode'));
$lines[0] = $this->_del_prefix . $lines[0];
$lines[count($lines) - 1] .= $this->_del_suffix;
return $this->_lines($lines, ' ', false);
}
function _changed($orig, $final)
{
// If we've already split on words, don't try to do so again - just display.
if ($this->_split_level == 'words')
{
$prefix = '';
while ($orig[0] !== false && $final[0] !== false && substr($orig[0], 0, 1) == ' ' && substr($final[0], 0, 1) == ' ')
{
$prefix .= substr($orig[0], 0, 1);
$orig[0] = substr($orig[0], 1);
$final[0] = substr($final[0], 1);
}
return $prefix . $this->_deleted($orig) . $this->_added($final);
}
$text1 = implode("\n", $orig);
$text2 = implode("\n", $final);
// Non-printing newline marker.
$nl = "\0";
// We want to split on word boundaries, but we need to preserve whitespace as well.
// Therefore we split on words, but include all blocks of whitespace in the wordlist.
$splitted_text_1 = $this->_split_on_words($text1, $nl);
$splitted_text_2 = $this->_split_on_words($text2, $nl);
$diff = new diff($splitted_text_1, $splitted_text_2);
unset($splitted_text_1, $splitted_text_2);
// Get the diff in inline format.
$renderer = new diff_renderer_inline(array_merge($this->get_params(), array('split_level' => 'words')));
// Run the diff and get the output.
return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
}
function _split_on_words($string, $newline_escape = "\n")
{
// Ignore \0; otherwise the while loop will never finish.
$string = str_replace("\0", '', $string);
$words = array();
$length = strlen($string);
$pos = 0;
$tab_there = true;
while ($pos < $length)
{
// Check for tabs... do not include them
if ($tab_there && substr($string, $pos, 1) === "\t")
{
$words[] = "\t";
$pos++;
continue;
}
else
{
$tab_there = false;
}
// Eat a word with any preceding whitespace.
$spaces = strspn(substr($string, $pos), " \n");
$nextpos = strcspn(substr($string, $pos + $spaces), " \n");
$words[] = str_replace("\n", $newline_escape, substr($string, $pos, $spaces + $nextpos));
$pos += $spaces + $nextpos;
}
return $words;
}
function _encode(&$string)
{
$string = htmlspecialchars($string);
}
}
/**
* "raw" diff renderer.
* This class could be used to output a raw unified patch file
*
* @package diff
*/
class diff_renderer_raw extends diff_renderer
{
var $_leading_context_lines = 4;
var $_trailing_context_lines = 4;
/**
* Our function to get the diff
*/
function get_diff_content($diff)
{
return '<textarea style="height: 290px;" rows="15" cols="76" class="full">' . htmlspecialchars($this->render($diff)) . '</textarea>';
}
function _block_header($xbeg, $xlen, $ybeg, $ylen)
{
if ($xlen != 1)
{
$xbeg .= ',' . $xlen;
}
if ($ylen != 1)
{
$ybeg .= ',' . $ylen;
}
return '@@ -' . $xbeg . ' +' . $ybeg . ' @@';
}
function _context($lines)
{
return $this->_lines($lines, ' ');
}
function _added($lines)
{
return $this->_lines($lines, '+');
}
function _deleted($lines)
{
return $this->_lines($lines, '-');
}
function _changed($orig, $final)
{
return $this->_deleted($orig) . $this->_added($final);
}
}
/**
* "chora (Horde)" diff renderer - similar style.
* This renderer class is a modified human_readable function from the Horde Framework.
*
* @package diff
*/
class diff_renderer_side_by_side extends diff_renderer
{
var $_leading_context_lines = 3;
var $_trailing_context_lines = 3;
var $lines = array();
// Hold the left and right columns of lines for change blocks.
var $cols;
var $state;
var $data = false;
/**
* Our function to get the diff
*/
function get_diff_content($diff)
{
global $user;
$output = '';
$output .= '<table cellspacing="0" class="hrdiff">
<caption>
<span class="unmodified">&nbsp;</span> ' . $user->lang['LINE_UNMODIFIED'] . '
<span class="added">&nbsp;</span> ' . $user->lang['LINE_ADDED'] . '
<span class="modified">&nbsp;</span> ' . $user->lang['LINE_MODIFIED'] . '
<span class="removed">&nbsp;</span> ' . $user->lang['LINE_REMOVED'] . '
</caption>
<tbody>
';
$this->render($diff);
// Is the diff empty?
if (!count($this->lines))
{
$output .= '<tr><th colspan="2">' . $user->lang['NO_VISIBLE_CHANGES'] . '</th></tr>';
}
else
{
// Iterate through every header block of changes
foreach ($this->lines as $header)
{
$output .= '<tr><th>' . $user->lang['LINE'] . ' ' . $header['oldline'] . '</th><th>' . $user->lang['LINE'] . ' ' . $header['newline'] . '</th></tr>';
// Each header block consists of a number of changes (add, remove, change).
$current_context = '';
foreach ($header['contents'] as $change)
{
if (!empty($current_context) && $change['type'] != 'empty')
{
$line = $current_context;
$current_context = '';
$output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<br /></pre></td>
<td><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<br /></pre></td></tr>';
}
switch ($change['type'])
{
case 'add':
$line = '';
foreach ($change['lines'] as $_line)
{
$line .= htmlspecialchars($_line) . '<br />';
}
$output .= '<tr><td class="added_empty">&nbsp;</td><td class="added"><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<br /></pre></td></tr>';
break;
case 'remove':
$line = '';
foreach ($change['lines'] as $_line)
{
$line .= htmlspecialchars($_line) . '<br />';
}
$output .= '<tr><td class="removed"><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<br /></pre></td><td class="removed_empty">&nbsp;</td></tr>';
break;
case 'empty':
$current_context .= htmlspecialchars($change['line']) . '<br />';
break;
case 'change':
// Pop the old/new stacks one by one, until both are empty.
$oldsize = count($change['old']);
$newsize = count($change['new']);
$left = $right = '';
for ($row = 0, $row_max = max($oldsize, $newsize); $row < $row_max; ++$row)
{
$left .= isset($change['old'][$row]) ? htmlspecialchars($change['old'][$row]) : '';
$left .= '<br />';
$right .= isset($change['new'][$row]) ? htmlspecialchars($change['new'][$row]) : '';
$right .= '<br />';
}
$output .= '<tr>';
if (!empty($left))
{
$output .= '<td class="modified"><pre>' . $left . '<br /></pre></td>';
}
else if ($row < $oldsize)
{
$output .= '<td class="modified">&nbsp;</td>';
}
else
{
$output .= '<td class="unmodified">&nbsp;</td>';
}
if (!empty($right))
{
$output .= '<td class="modified"><pre>' . $right . '<br /></pre></td>';
}
else if ($row < $newsize)
{
$output .= '<td class="modified">&nbsp;</td>';
}
else
{
$output .= '<td class="unmodified">&nbsp;</td>';
}
$output .= '</tr>';
break;
}
}
if (!empty($current_context))
{
$line = $current_context;
$current_context = '';
$output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<br /></pre></td>';
$output .= '<td><pre>' . ((strlen($line)) ? $line : '&nbsp;') . '<br /></pre></td></tr>';
}
}
}
$output .= '</tbody></table>';
return $output;
}
function _start_diff()
{
$this->lines = array();
$this->data = false;
$this->cols = array(array(), array());
$this->state = 'empty';
return '';
}
function _end_diff()
{
// Just flush any remaining entries in the columns stack.
switch ($this->state)
{
case 'add':
$this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]);
break;
case 'remove':
// We have some removal lines pending in our stack, so flush them.
$this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]);
break;
case 'change':
// We have both remove and addition lines, so this is a change block.
$this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]);
break;
}
if ($this->data !== false)
{
$this->lines[] = $this->data;
}
return '';
}
function _block_header($xbeg, $xlen, $ybeg, $ylen)
{
// Push any previous header information to the return stack.
if ($this->data !== false)
{
$this->lines[] = $this->data;
}
$this->data = array('type' => 'header', 'oldline' => $xbeg, 'newline' => $ybeg, 'contents' => array());
$this->state = 'dump';
}
function _added($lines)
{
array_walk($lines, array(&$this, '_perform_add'));
}
function _perform_add($line)
{
if ($this->state == 'empty')
{
return '';
}
// This is just an addition line.
if ($this->state == 'dump' || $this->state == 'add')
{
// Start adding to the addition stack.
$this->cols[0][] = $line;
$this->state = 'add';
}
else
{
// This is inside a change block, so start accumulating lines.
$this->state = 'change';
$this->cols[1][] = $line;
}
}
function _deleted($lines)
{
array_walk($lines, array(&$this, '_perform_delete'));
}
function _perform_delete($line)
{
// This is a removal line.
$this->state = 'remove';
$this->cols[0][] = $line;
}
function _context($lines)
{
array_walk($lines, array(&$this, '_perform_context'));
}
function _perform_context($line)
{
// An empty block with no action.
switch ($this->state)
{
case 'add':
$this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]);
break;
case 'remove':
// We have some removal lines pending in our stack, so flush them.
$this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]);
break;
case 'change':
// We have both remove and addition lines, so this is a change block.
$this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]);
break;
}
$this->cols = array(array(), array());
$this->data['contents'][] = array('type' => 'empty', 'line' => $line);
$this->state = 'dump';
}
function _changed($orig, $final)
{
return $this->_deleted($orig) . $this->_added($final);
}
}

4947
includes/functions.php Normal file

File diff suppressed because it is too large Load Diff

726
includes/functions_acp.php Normal file
View File

@@ -0,0 +1,726 @@
<?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;
}
/**
* Header for acp pages
*/
function adm_page_header($page_title)
{
global $config, $user, $template;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $SID, $_SID;
global $phpbb_dispatcher, $phpbb_container;
if (defined('HEADER_INC'))
{
return;
}
define('HEADER_INC', true);
// A listener can set this variable to `true` when it overrides this function
$adm_page_header_override = false;
/**
* Execute code and/or overwrite adm_page_header()
*
* @event core.adm_page_header
* @var string page_title Page title
* @var bool adm_page_header_override Shall we return instead of
* running the rest of adm_page_header()
* @since 3.1.0-a1
*/
$vars = array('page_title', 'adm_page_header_override');
extract($phpbb_dispatcher->trigger_event('core.adm_page_header', compact($vars)));
if ($adm_page_header_override)
{
return;
}
$user->update_session_infos();
// gzip_compression
if ($config['gzip_compress'])
{
if (@extension_loaded('zlib') && !headers_sent())
{
ob_start('ob_gzhandler');
}
}
$template->assign_vars(array(
'PAGE_TITLE' => $page_title,
'USERNAME' => $user->data['username'],
'SID' => $SID,
'_SID' => $_SID,
'SESSION_ID' => $user->session_id,
'ROOT_PATH' => $phpbb_root_path,
'ADMIN_ROOT_PATH' => $phpbb_admin_path,
'U_LOGOUT' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout'),
'U_ADM_LOGOUT' => append_sid("{$phpbb_admin_path}index.$phpEx", 'action=admlogout'),
'U_ADM_INDEX' => append_sid("{$phpbb_admin_path}index.$phpEx"),
'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"),
'T_IMAGES_PATH' => "{$phpbb_root_path}images/",
'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/",
'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/",
'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/",
'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/",
'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/",
'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/",
'T_FONT_AWESOME_LINK' => !empty($config['allow_cdn']) && !empty($config['load_font_awesome_url']) ? $config['load_font_awesome_url'] : "{$phpbb_root_path}assets/css/font-awesome.min.css?assets_version=" . $config['assets_version'],
'T_ASSETS_VERSION' => $config['assets_version'],
'ICON_MOVE_UP' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_up.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />',
'ICON_MOVE_UP_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_up_disabled.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />',
'ICON_MOVE_DOWN' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_down.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />',
'ICON_MOVE_DOWN_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_down_disabled.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />',
'ICON_EDIT' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_edit.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />',
'ICON_EDIT_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_edit_disabled.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />',
'ICON_DELETE' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_delete.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />',
'ICON_DELETE_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_delete_disabled.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />',
'ICON_SYNC' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_sync.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />',
'ICON_SYNC_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_sync_disabled.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />',
'S_USER_LANG' => $user->lang['USER_LANG'],
'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'],
'S_CONTENT_ENCODING' => 'UTF-8',
'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
'CONTAINER_EXCEPTION' => $phpbb_container->hasParameter('container_exception') ? $phpbb_container->getParameter('container_exception') : false,
));
// An array of http headers that phpbb will set. The following event may override these.
$http_headers = array(
// application/xhtml+xml not used because of IE
'Content-type' => 'text/html; charset=UTF-8',
'Cache-Control' => 'private, no-cache="set-cookie"',
'Expires' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
);
/**
* Execute code and/or overwrite _common_ template variables after they have been assigned.
*
* @event core.adm_page_header_after
* @var string page_title Page title
* @var array http_headers HTTP headers that should be set by phpbb
*
* @since 3.1.0-RC3
*/
$vars = array('page_title', 'http_headers');
extract($phpbb_dispatcher->trigger_event('core.adm_page_header_after', compact($vars)));
foreach ($http_headers as $hname => $hval)
{
header((string) $hname . ': ' . (string) $hval);
}
return;
}
/**
* Page footer for acp pages
*/
function adm_page_footer($copyright_html = true)
{
global $db, $config, $template, $user, $auth;
global $phpbb_root_path;
global $request, $phpbb_dispatcher;
// A listener can set this variable to `true` when it overrides this function
$adm_page_footer_override = false;
/**
* Execute code and/or overwrite adm_page_footer()
*
* @event core.adm_page_footer
* @var bool copyright_html Shall we display the copyright?
* @var bool adm_page_footer_override Shall we return instead of
* running the rest of adm_page_footer()
* @since 3.1.0-a1
*/
$vars = array('copyright_html', 'adm_page_footer_override');
extract($phpbb_dispatcher->trigger_event('core.adm_page_footer', compact($vars)));
if ($adm_page_footer_override)
{
return;
}
phpbb_check_and_display_sql_report($request, $auth, $db);
$template->assign_vars(array(
'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher),
'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '',
'S_COPYRIGHT_HTML' => $copyright_html,
'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited'),
'T_JQUERY_LINK' => !empty($config['allow_cdn']) && !empty($config['load_jquery_url']) ? $config['load_jquery_url'] : "{$phpbb_root_path}assets/javascript/jquery.min.js",
'S_ALLOW_CDN' => !empty($config['allow_cdn']),
'VERSION' => $config['version'])
);
$template->display('body');
garbage_collection();
exit_handler();
}
/**
* Generate back link for acp pages
*/
function adm_back_link($u_action)
{
global $user;
return '<br /><br /><a href="' . $u_action . '">&laquo; ' . $user->lang['BACK_TO_PREV'] . '</a>';
}
/**
* Build select field options in acp pages
*/
function build_select($option_ary, $option_default = false)
{
global $user;
$html = '';
foreach ($option_ary as $value => $title)
{
$selected = ($option_default !== false && $value == $option_default) ? ' selected="selected"' : '';
$html .= '<option value="' . $value . '"' . $selected . '>' . $user->lang[$title] . '</option>';
}
return $html;
}
/**
* Build radio fields in acp pages
*/
function h_radio($name, $input_ary, $input_default = false, $id = false, $key = false, $separator = '')
{
global $user;
$html = '';
$id_assigned = false;
foreach ($input_ary as $value => $title)
{
$selected = ($input_default !== false && $value == $input_default) ? ' checked="checked"' : '';
$html .= '<label><input type="radio" name="' . $name . '"' . (($id && !$id_assigned) ? ' id="' . $id . '"' : '') . ' value="' . $value . '"' . $selected . (($key) ? ' accesskey="' . $key . '"' : '') . ' class="radio" /> ' . $user->lang[$title] . '</label>' . $separator;
$id_assigned = true;
}
return $html;
}
/**
* Build configuration template for acp configuration pages
*/
function build_cfg_template($tpl_type, $key, &$new_ary, $config_key, $vars)
{
global $user, $module, $phpbb_dispatcher;
$tpl = '';
$name = 'config[' . $config_key . ']';
// Make sure there is no notice printed out for non-existent config options (we simply set them)
if (!isset($new_ary[$config_key]))
{
$new_ary[$config_key] = '';
}
switch ($tpl_type[0])
{
case 'password':
if ($new_ary[$config_key] !== '')
{
// replace passwords with asterixes
$new_ary[$config_key] = '********';
}
case 'text':
case 'url':
case 'email':
case 'tel':
case 'search':
// maxlength and size are only valid for these types and will be
// ignored for other input types.
$size = (int) $tpl_type[1];
$maxlength = (int) $tpl_type[2];
$tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new_ary[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />';
break;
case 'color':
case 'datetime':
case 'datetime-local':
case 'month':
case 'week':
$tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '" name="' . $name . '" value="' . $new_ary[$config_key] . '" />';
break;
case 'date':
case 'time':
case 'number':
case 'range':
$max = '';
$min = ( isset($tpl_type[1]) ) ? (int) $tpl_type[1] : false;
if ( isset($tpl_type[2]) )
{
$max = (int) $tpl_type[2];
}
$tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (( $min != '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="' . $name . '" value="' . $new_ary[$config_key] . '" />';
break;
case 'dimension':
$max = '';
$min = (int) $tpl_type[1];
if ( isset($tpl_type[2]) )
{
$max = (int) $tpl_type[2];
}
$tpl = '<input id="' . $key . '" type="number"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_width]" value="' . $new_ary[$config_key . '_width'] . '" /> x <input type="number"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_height]" value="' . $new_ary[$config_key . '_height'] . '" />';
break;
case 'textarea':
$rows = (int) $tpl_type[1];
$cols = (int) $tpl_type[2];
$tpl = '<textarea id="' . $key . '" name="' . $name . '" rows="' . $rows . '" cols="' . $cols . '">' . $new_ary[$config_key] . '</textarea>';
break;
case 'radio':
$key_yes = ($new_ary[$config_key]) ? ' checked="checked"' : '';
$key_no = (!$new_ary[$config_key]) ? ' checked="checked"' : '';
$tpl_type_cond = explode('_', $tpl_type[1]);
$type_no = ($tpl_type_cond[0] == 'disabled' || $tpl_type_cond[0] == 'enabled') ? false : true;
$tpl_no = '<label><input type="radio" name="' . $name . '" value="0"' . $key_no . ' class="radio" /> ' . (($type_no) ? $user->lang['NO'] : $user->lang['DISABLED']) . '</label>';
$tpl_yes = '<label><input type="radio" id="' . $key . '" name="' . $name . '" value="1"' . $key_yes . ' class="radio" /> ' . (($type_no) ? $user->lang['YES'] : $user->lang['ENABLED']) . '</label>';
$tpl = ($tpl_type_cond[0] == 'yes' || $tpl_type_cond[0] == 'enabled') ? $tpl_yes . $tpl_no : $tpl_no . $tpl_yes;
break;
case 'select':
case 'custom':
if (isset($vars['method']))
{
$call = array($module->module, $vars['method']);
}
else if (isset($vars['function']))
{
$call = $vars['function'];
}
else
{
break;
}
if (isset($vars['params']))
{
$args = array();
foreach ($vars['params'] as $value)
{
switch ($value)
{
case '{CONFIG_VALUE}':
$value = $new_ary[$config_key];
break;
case '{KEY}':
$value = $key;
break;
}
$args[] = $value;
}
}
else
{
$args = array($new_ary[$config_key], $key);
}
$return = call_user_func_array($call, $args);
if ($tpl_type[0] == 'select')
{
$size = (isset($tpl_type[1])) ? (int) $tpl_type[1] : 1;
$data_toggle = (!empty($tpl_type[2])) ? ' data-togglable-settings="true"' : '';
$tpl = '<select id="' . $key . '" name="' . $name . '"' . (($size > 1) ? ' size="' . $size . '"' : '') . $data_toggle . '>' . $return . '</select>';
}
else
{
$tpl = $return;
}
break;
default:
break;
}
if (isset($vars['append']))
{
$tpl .= $vars['append'];
}
$new = $new_ary;
/**
* Overwrite the html code we display for the config value
*
* @event core.build_config_template
* @var array tpl_type Config type array:
* 0 => data type
* 1 [optional] => string: size, int: minimum
* 2 [optional] => string: max. length, int: maximum
* @var string key Should be used for the id attribute in html
* @var array new Array with the config values we display
* @var string name Should be used for the name attribute
* @var array vars Array with the options for the config
* @var string tpl The resulting html code we display
* @since 3.1.0-a1
*/
$vars = array('tpl_type', 'key', 'new', 'name', 'vars', 'tpl');
extract($phpbb_dispatcher->trigger_event('core.build_config_template', compact($vars)));
$new_ary = $new;
unset($new);
return $tpl;
}
/**
* Going through a config array and validate values, writing errors to $error. The validation method accepts parameters separated by ':' for string and int.
* The first parameter defines the type to be used, the second the lower bound and the third the upper bound. Only the type is required.
*/
function validate_config_vars($config_vars, &$cfg_array, &$error)
{
global $phpbb_root_path, $user, $phpbb_dispatcher, $phpbb_filesystem, $language;
$type = 0;
$min = 1;
$max = 2;
foreach ($config_vars as $config_name => $config_definition)
{
if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false)
{
continue;
}
if (!isset($config_definition['validate']))
{
continue;
}
$validator = explode(':', $config_definition['validate']);
// Validate a bit. ;) (0 = type, 1 = min, 2= max)
switch ($validator[$type])
{
case 'url':
$cfg_array[$config_name] = trim($cfg_array[$config_name]);
if (!empty($cfg_array[$config_name]) && !preg_match('#^' . get_preg_expression('url') . '$#iu', $cfg_array[$config_name]))
{
$error[] = $language->lang('URL_INVALID', $language->lang($config_definition['lang']));
}
// no break here
case 'string':
$length = utf8_strlen($cfg_array[$config_name]);
// the column is a VARCHAR
$validator[$max] = (isset($validator[$max])) ? min(255, $validator[$max]) : 255;
if (isset($validator[$min]) && $length < $validator[$min])
{
$error[] = sprintf($user->lang['SETTING_TOO_SHORT'], $user->lang[$config_definition['lang']], $validator[$min]);
}
else if (isset($validator[$max]) && $length > $validator[2])
{
$error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$config_definition['lang']], $validator[$max]);
}
break;
case 'bool':
$cfg_array[$config_name] = ($cfg_array[$config_name]) ? 1 : 0;
break;
case 'int':
$cfg_array[$config_name] = (int) $cfg_array[$config_name];
if (isset($validator[$min]) && $cfg_array[$config_name] < $validator[$min])
{
$error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], $validator[$min]);
}
else if (isset($validator[$max]) && $cfg_array[$config_name] > $validator[$max])
{
$error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$config_definition['lang']], $validator[$max]);
}
if (strpos($config_name, '_max') !== false)
{
// Min/max pairs of settings should ensure that min <= max
// Replace _max with _min to find the name of the minimum
// corresponding configuration variable
$min_name = str_replace('_max', '_min', $config_name);
if (isset($cfg_array[$min_name]) && is_numeric($cfg_array[$min_name]) && $cfg_array[$config_name] < $cfg_array[$min_name])
{
// A minimum value exists and the maximum value is less than it
$error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], (int) $cfg_array[$min_name]);
}
}
break;
case 'email':
if (!preg_match('/^' . get_preg_expression('email') . '$/i', $cfg_array[$config_name]))
{
$error[] = $user->lang['EMAIL_INVALID_EMAIL'];
}
break;
// Absolute path
case 'script_path':
if (!$cfg_array[$config_name])
{
break;
}
$destination = str_replace('\\', '/', $cfg_array[$config_name]);
if ($destination !== '/')
{
// Adjust destination path (no trailing slash)
if (substr($destination, -1, 1) == '/')
{
$destination = substr($destination, 0, -1);
}
$destination = str_replace(array('../', './'), '', $destination);
if ($destination[0] != '/')
{
$destination = '/' . $destination;
}
}
$cfg_array[$config_name] = trim($destination);
break;
// Absolute path
case 'lang':
if (!$cfg_array[$config_name])
{
break;
}
$cfg_array[$config_name] = basename($cfg_array[$config_name]);
if (!file_exists($phpbb_root_path . 'language/' . $cfg_array[$config_name] . '/'))
{
$error[] = $user->lang['WRONG_DATA_LANG'];
}
break;
// Relative path (appended $phpbb_root_path)
case 'rpath':
case 'rwpath':
if (!$cfg_array[$config_name])
{
break;
}
$destination = $cfg_array[$config_name];
// Adjust destination path (no trailing slash)
if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
{
$destination = substr($destination, 0, -1);
}
$destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
{
$destination = '';
}
$cfg_array[$config_name] = trim($destination);
// Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir...
case 'path':
case 'wpath':
if (!$cfg_array[$config_name])
{
break;
}
$cfg_array[$config_name] = trim($cfg_array[$config_name]);
// Make sure no NUL byte is present...
if (strpos($cfg_array[$config_name], "\0") !== false || strpos($cfg_array[$config_name], '%00') !== false)
{
$cfg_array[$config_name] = '';
break;
}
$path = $phpbb_root_path . $cfg_array[$config_name];
if (!file_exists($path))
{
$error[] = sprintf($user->lang['DIRECTORY_DOES_NOT_EXIST'], $cfg_array[$config_name]);
}
if (file_exists($path) && !is_dir($path))
{
$error[] = sprintf($user->lang['DIRECTORY_NOT_DIR'], $cfg_array[$config_name]);
}
// Check if the path is writable
if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath')
{
if (file_exists($path) && !$phpbb_filesystem->is_writable($path))
{
$error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]);
}
}
break;
default:
/**
* Validate a config value
*
* @event core.validate_config_variable
* @var array cfg_array Array with config values
* @var string config_name Name of the config we validate
* @var array config_definition Array with the options for
* this config
* @var array error Array of errors, the errors should
* be strings only, language keys are
* not replaced afterwards
* @since 3.1.0-a1
*/
$vars = array('cfg_array', 'config_name', 'config_definition', 'error');
extract($phpbb_dispatcher->trigger_event('core.validate_config_variable', compact($vars)));
break;
}
}
return;
}
/**
* Checks whatever or not a variable is OK for use in the Database
* param mixed $value_ary An array of the form array(array('lang' => ..., 'value' => ..., 'column_type' =>))'
* param mixed $error The error array
*/
function validate_range($value_ary, &$error)
{
global $user;
$column_types = array(
'BOOL' => array('php_type' => 'int', 'min' => 0, 'max' => 1),
'USINT' => array('php_type' => 'int', 'min' => 0, 'max' => 65535),
'UINT' => array('php_type' => 'int', 'min' => 0, 'max' => (int) 0x7fffffff),
// Do not use (int) 0x80000000 - it evaluates to different
// values on 32-bit and 64-bit systems.
// Apparently -2147483648 is a float on 32-bit systems,
// despite fitting in an int, thus explicit cast is needed.
'INT' => array('php_type' => 'int', 'min' => (int) -2147483648, 'max' => (int) 0x7fffffff),
'TINT' => array('php_type' => 'int', 'min' => -128, 'max' => 127),
'VCHAR' => array('php_type' => 'string', 'min' => 0, 'max' => 255),
);
foreach ($value_ary as $value)
{
$column = explode(':', $value['column_type']);
if (!isset($column_types[$column[0]]))
{
continue;
}
else
{
$type = $column_types[$column[0]];
}
switch ($type['php_type'])
{
case 'string' :
$max = (isset($column[1])) ? min($column[1],$type['max']) : $type['max'];
if (utf8_strlen($value['value']) > $max)
{
$error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$value['lang']], $max);
}
break;
case 'int':
$min = (isset($column[1])) ? max($column[1],$type['min']) : $type['min'];
$max = (isset($column[2])) ? min($column[2],$type['max']) : $type['max'];
if ($value['value'] < $min)
{
$error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$value['lang']], $min);
}
else if ($value['value'] > $max)
{
$error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$value['lang']], $max);
}
break;
}
}
}
/**
* Inserts new config display_vars into an exisiting display_vars array
* at the given position.
*
* @param array $display_vars An array of existing config display vars
* @param array $add_config_vars An array of new config display vars
* @param array $where Where to place the new config vars,
* before or after an exisiting config, as an array
* of the form: array('after' => 'config_name') or
* array('before' => 'config_name').
* @return array The array of config display vars
*/
function phpbb_insert_config_array($display_vars, $add_config_vars, $where)
{
if (is_array($where) && array_key_exists(current($where), $display_vars))
{
$position = array_search(current($where), array_keys($display_vars)) + ((key($where) == 'before') ? 0 : 1);
$display_vars = array_merge(
array_slice($display_vars, 0, $position),
$add_config_vars,
array_slice($display_vars, $position)
);
}
return $display_vars;
}

3109
includes/functions_admin.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,513 @@
<?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;
}
/**
* Get user avatar
*
* @deprecated 3.1.0-a1 (To be removed: 3.3.0)
*
* @param string $avatar Users assigned avatar name
* @param int $avatar_type Type of avatar
* @param string $avatar_width Width of users avatar
* @param string $avatar_height Height of users avatar
* @param string $alt Optional language string for alt tag within image, can be a language key or text
* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
* @param bool $lazy If true, will be lazy loaded (requires JS)
*
* @return string Avatar image
*/
function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false, $lazy = false)
{
// map arguments to new function phpbb_get_avatar()
$row = array(
'avatar' => $avatar,
'avatar_type' => $avatar_type,
'avatar_width' => $avatar_width,
'avatar_height' => $avatar_height,
);
return phpbb_get_avatar($row, $alt, $ignore_config, $lazy);
}
/**
* Hash the password
*
* @deprecated 3.1.0-a2 (To be removed: 3.3.0)
*
* @param string $password Password to be hashed
*
* @return string|bool Password hash or false if something went wrong during hashing
*/
function phpbb_hash($password)
{
global $phpbb_container;
/* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
return $passwords_manager->hash($password);
}
/**
* Check for correct password
*
* @deprecated 3.1.0-a2 (To be removed: 3.3.0)
*
* @param string $password The password in plain text
* @param string $hash The stored password hash
*
* @return bool Returns true if the password is correct, false if not.
*/
function phpbb_check_hash($password, $hash)
{
global $phpbb_container;
/* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
return $passwords_manager->check($password, $hash);
}
/**
* Eliminates useless . and .. components from specified path.
*
* Deprecated, use filesystem class instead
*
* @param string $path Path to clean
* @return string Cleaned path
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function phpbb_clean_path($path)
{
global $phpbb_path_helper, $phpbb_container;
if (!$phpbb_path_helper && $phpbb_container)
{
/* @var $phpbb_path_helper \phpbb\path_helper */
$phpbb_path_helper = $phpbb_container->get('path_helper');
}
else if (!$phpbb_path_helper)
{
global $phpbb_root_path, $phpEx;
// The container is not yet loaded, use a new instance
if (!class_exists('\phpbb\path_helper'))
{
require($phpbb_root_path . 'phpbb/path_helper.' . $phpEx);
}
$request = new phpbb\request\request();
$phpbb_path_helper = new phpbb\path_helper(
new phpbb\symfony_request(
$request
),
new phpbb\filesystem\filesystem(),
$request,
$phpbb_root_path,
$phpEx
);
}
return $phpbb_path_helper->clean_path($path);
}
/**
* Pick a timezone
*
* @param string $default A timezone to select
* @param boolean $truncate Shall we truncate the options text
*
* @return string Returns the options for timezone selector only
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function tz_select($default = '', $truncate = false)
{
global $template, $user;
return phpbb_timezone_select($template, $user, $default, $truncate);
}
/**
* Cache moderators. Called whenever permissions are changed
* via admin_permissions. Changes of usernames and group names
* must be carried through for the moderators table.
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
* @return null
*/
function cache_moderators()
{
global $db, $cache, $auth;
return phpbb_cache_moderators($db, $cache, $auth);
}
/**
* Removes moderators and administrators from foe lists.
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore
* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore
* @return null
*/
function update_foes($group_id = false, $user_id = false)
{
global $db, $auth;
return phpbb_update_foes($db, $auth, $group_id, $user_id);
}
/**
* Get user rank title and image
*
* @param int $user_rank the current stored users rank id
* @param int $user_posts the users number of posts
* @param string &$rank_title the rank title will be stored here after execution
* @param string &$rank_img the rank image as full img tag is stored here after execution
* @param string &$rank_img_src the rank image source is stored here after execution
*
* @deprecated 3.1.0-RC5 (To be removed: 3.3.0)
*
* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false
*/
function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src)
{
global $phpbb_root_path, $phpEx;
if (!function_exists('phpbb_get_user_rank'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
$rank_data = phpbb_get_user_rank(array('user_rank' => $user_rank), $user_posts);
$rank_title = $rank_data['title'];
$rank_img = $rank_data['img'];
$rank_img_src = $rank_data['img_src'];
}
/**
* Retrieve contents from remotely stored file
*
* @deprecated 3.1.2 Use file_downloader instead
*/
function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6)
{
global $phpbb_container;
// Get file downloader and assign $errstr and $errno
/* @var $file_downloader \phpbb\file_downloader */
$file_downloader = $phpbb_container->get('file_downloader');
$file_data = $file_downloader->get($host, $directory, $filename, $port, $timeout);
$errstr = $file_downloader->get_error_string();
$errno = $file_downloader->get_error_number();
return $file_data;
}
/**
* Add log entry
*
* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
* @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise
* @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise
* @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise
* @param string $log_operation Name of the operation
* @param array $additional_data More arguments can be added, depending on the log_type
*
* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function add_log()
{
global $phpbb_log, $user;
$args = func_get_args();
$mode = array_shift($args);
// This looks kind of dirty, but add_log has some additional data before the log_operation
$additional_data = array();
switch ($mode)
{
case 'admin':
case 'critical':
break;
case 'mod':
$additional_data['forum_id'] = array_shift($args);
$additional_data['topic_id'] = array_shift($args);
break;
case 'user':
$additional_data['reportee_id'] = array_shift($args);
break;
}
$log_operation = array_shift($args);
$additional_data = array_merge($additional_data, $args);
$user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id'];
$user_ip = (empty($user->ip)) ? '' : $user->ip;
return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
}
/**
* Sets a configuration option's value.
*
* Please note that this function does not update the is_dynamic value for
* an already existing config option.
*
* @param string $config_name The configuration option's name
* @param string $config_value New configuration value
* @param bool $is_dynamic Whether this variable should be cached (false) or
* if it changes too frequently (true) to be
* efficiently cached.
*
* @return null
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function set_config($config_name, $config_value, $is_dynamic = false, \phpbb\config\config $set_config = null)
{
static $config = null;
if ($set_config !== null)
{
$config = $set_config;
if (empty($config_name))
{
return;
}
}
$config->set($config_name, $config_value, !$is_dynamic);
}
/**
* Increments an integer config value directly in the database.
*
* @param string $config_name The configuration option's name
* @param int $increment Amount to increment by
* @param bool $is_dynamic Whether this variable should be cached (false) or
* if it changes too frequently (true) to be
* efficiently cached.
*
* @return null
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function set_config_count($config_name, $increment, $is_dynamic = false, \phpbb\config\config $set_config = null)
{
static $config = null;
if ($set_config !== null)
{
$config = $set_config;
if (empty($config_name))
{
return;
}
}
$config->increment($config_name, $increment, !$is_dynamic);
}
/**
* Wrapper function of \phpbb\request\request::variable which exists for backwards compatability.
* See {@link \phpbb\request\request_interface::variable \phpbb\request\request_interface::variable} for
* documentation of this function's use.
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
* @param mixed $var_name The form variable's name from which data shall be retrieved.
* If the value is an array this may be an array of indizes which will give
* direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
* then specifying array("var", 1) as the name will return "a".
* If you pass an instance of {@link \phpbb\request\request_interface phpbb_request_interface}
* as this parameter it will overwrite the current request class instance. If you do
* not do so, it will create its own instance (but leave superglobals enabled).
* @param mixed $default A default value that is returned if the variable was not set.
* This function will always return a value of the same type as the default.
* @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
* Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
* @param bool $cookie This param is mapped to \phpbb\request\request_interface::COOKIE as the last param for
* \phpbb\request\request_interface::variable for backwards compatability reasons.
* @param \phpbb\request\request_interface|null|false If an instance of \phpbb\request\request_interface is given the instance is stored in
* a static variable and used for all further calls where this parameters is null. Until
* the function is called with an instance it automatically creates a new \phpbb\request\request
* instance on every call. By passing false this per-call instantiation can be restored
* after having passed in a \phpbb\request\request_interface instance.
*
* @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
* the same as that of $default. If the variable is not set $default is returned.
*/
function request_var($var_name, $default, $multibyte = false, $cookie = false, $request = null)
{
// This is all just an ugly hack to add "Dependency Injection" to a function
// the only real code is the function call which maps this function to a method.
static $static_request = null;
if ($request instanceof \phpbb\request\request_interface)
{
$static_request = $request;
if (empty($var_name))
{
return;
}
}
else if ($request === false)
{
$static_request = null;
if (empty($var_name))
{
return;
}
}
$tmp_request = $static_request;
// no request class set, create a temporary one ourselves to keep backwards compatibility
if ($tmp_request === null)
{
// false param: enable super globals, so the created request class does not
// make super globals inaccessible everywhere outside this function.
$tmp_request = new \phpbb\request\request(new \phpbb\request\type_cast_helper(), false);
}
return $tmp_request->variable($var_name, $default, $multibyte, ($cookie) ? \phpbb\request\request_interface::COOKIE : \phpbb\request\request_interface::REQUEST);
}
/**
* Get tables of a database
*
* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function get_tables($db)
{
$db_tools_factory = new \phpbb\db\tools\factory();
$db_tools = $db_tools_factory->get($db);
return $db_tools->sql_list_tables();
}
/**
* Global function for chmodding directories and files for internal use
*
* This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
* The function determines owner and group from common.php file and sets the same to the provided file.
* The function uses bit fields to build the permissions.
* The function sets the appropiate execute bit on directories.
*
* Supported constants representing bit fields are:
*
* CHMOD_ALL - all permissions (7)
* CHMOD_READ - read permission (4)
* CHMOD_WRITE - write permission (2)
* CHMOD_EXECUTE - execute permission (1)
*
* NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
*
* @param string $filename The file/directory to be chmodded
* @param int $perms Permissions to set
*
* @return bool true on success, otherwise false
*
* @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::phpbb_chmod() instead
*/
function phpbb_chmod($filename, $perms = CHMOD_READ)
{
global $phpbb_filesystem;
try
{
$phpbb_filesystem->phpbb_chmod($filename, $perms);
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
return false;
}
return true;
}
/**
* Test if a file/directory is writable
*
* This function calls the native is_writable() when not running under
* Windows and it is not disabled.
*
* @param string $file Path to perform write test on
* @return bool True when the path is writable, otherwise false.
*
* @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::is_writable() instead
*/
function phpbb_is_writable($file)
{
global $phpbb_filesystem;
return $phpbb_filesystem->is_writable($file);
}
/**
* Checks if a path ($path) is absolute or relative
*
* @param string $path Path to check absoluteness of
* @return boolean
*
* @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::is_absolute_path() instead
*/
function phpbb_is_absolute($path)
{
global $phpbb_filesystem;
return $phpbb_filesystem->is_absolute_path($path);
}
/**
* A wrapper for realpath
*
* @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::realpath() instead
*/
function phpbb_realpath($path)
{
global $phpbb_filesystem;
return $phpbb_filesystem->realpath($path);
}
/**
* Determine which plural form we should use.
* For some languages this is not as simple as for English.
*
* @param $rule int ID of the plural rule we want to use, see https://area51.phpbb.com/docs/dev/32x/language/plurals.html
* @param $number int|float The number we want to get the plural case for. Float numbers are floored.
* @return int The plural-case we need to use for the number plural-rule combination
*
* @deprecated 3.2.0-dev (To be removed: 3.3.0)
*/
function phpbb_get_plural_form($rule, $number)
{
global $phpbb_container;
/** @var \phpbb\language\language $language */
$language = $phpbb_container->get('language');
return $language->get_plural_form($number, $rule);
}
/**
* @return bool Always true
* @deprecated 3.2.0-dev
*/
function phpbb_pcre_utf8_support()
{
return true;
}

View File

@@ -0,0 +1,830 @@
<?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;
}
/**
* Class for handling archives (compression/decompression)
*/
class compress
{
var $fp = 0;
/**
* @var array
*/
protected $filelist = array();
/**
* Add file to archive
*/
function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '')
{
global $phpbb_root_path;
$skip_files = explode(',', $skip_files);
// Remove rm prefix from src path
$src_path = ($src_rm_prefix) ? preg_replace('#^(' . preg_quote($src_rm_prefix, '#') . ')#', '', $src) : $src;
// Add src prefix
$src_path = ($src_add_prefix) ? ($src_add_prefix . ((substr($src_add_prefix, -1) != '/') ? '/' : '') . $src_path) : $src_path;
// Remove initial "/" if present
$src_path = (substr($src_path, 0, 1) == '/') ? substr($src_path, 1) : $src_path;
if (is_file($phpbb_root_path . $src))
{
$this->data($src_path, file_get_contents("$phpbb_root_path$src"), stat("$phpbb_root_path$src"), false);
}
else if (is_dir($phpbb_root_path . $src))
{
// Clean up path, add closing / if not present
$src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path;
$filelist = filelist("$phpbb_root_path$src", '', '*');
krsort($filelist);
/**
* Commented out, as adding the folders produces corrupted archives
if ($src_path)
{
$this->data($src_path, '', true, stat("$phpbb_root_path$src"));
}
*/
foreach ($filelist as $path => $file_ary)
{
/**
* Commented out, as adding the folders produces corrupted archives
if ($path)
{
// Same as for src_path
$path = (substr($path, 0, 1) == '/') ? substr($path, 1) : $path;
$path = ($path && substr($path, -1) != '/') ? $path . '/' : $path;
$this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path"));
}
*/
foreach ($file_ary as $file)
{
if (in_array($path . $file, $skip_files))
{
continue;
}
$this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), stat("$phpbb_root_path$src$path$file"), false);
}
}
}
else
{
// $src does not exist
return false;
}
return true;
}
/**
* Add custom file (the filepath will not be adjusted)
*/
function add_custom_file($src, $filename)
{
if (!file_exists($src))
{
return false;
}
$this->data($filename, file_get_contents($src), stat($src), false);
return true;
}
/**
* Add file data
*/
function add_data($src, $name)
{
$stat = array();
$stat[2] = 436; //384
$stat[4] = $stat[5] = 0;
$stat[7] = strlen($src);
$stat[9] = time();
$this->data($name, $src, $stat, false);
return true;
}
/**
* Checks if a file by that name as already been added and, if it has,
* returns a new, unique name.
*
* @param string $name The filename
* @return string A unique filename
*/
protected function unique_filename($name)
{
if (isset($this->filelist[$name]))
{
$start = $name;
$ext = '';
$this->filelist[$name]++;
// Separate the extension off the end of the filename to preserve it
$pos = strrpos($name, '.');
if ($pos !== false)
{
$start = substr($name, 0, $pos);
$ext = substr($name, $pos);
}
return $start . '_' . $this->filelist[$name] . $ext;
}
$this->filelist[$name] = 0;
return $name;
}
/**
* Return available methods
*
* @return array Array of strings of available compression methods (.tar, .tar.gz, .zip, etc.)
*/
static public function methods()
{
$methods = array('.tar');
$available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
foreach ($available_methods as $type => $module)
{
if (!@extension_loaded($module))
{
continue;
}
$methods[] = $type;
}
return $methods;
}
}
/**
* Zip creation class from phpMyAdmin 2.3.0 (c) Tobias Ratschiller, Olivier Müller, Loïc Chapeaux,
* Marc Delisle, http://www.phpmyadmin.net/
*
* Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com
*
* Modified extensively by psoTFX and DavidMJ, (c) phpBB Limited, 2003
*
* Based on work by Eric Mueller and Denis125
* Official ZIP file format: http://www.pkware.com/appnote.txt
*/
class compress_zip extends compress
{
var $datasec = array();
var $ctrl_dir = array();
var $eof_cdh = "\x50\x4b\x05\x06\x00\x00\x00\x00";
var $old_offset = 0;
var $datasec_len = 0;
/**
* @var \phpbb\filesystem\filesystem_interface
*/
protected $filesystem;
/**
* Constructor
*/
function __construct($mode, $file)
{
global $phpbb_filesystem;
$this->fp = @fopen($file, $mode . 'b');
$this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem();
if (!$this->fp)
{
trigger_error('Unable to open file ' . $file . ' [' . $mode . 'b]');
}
}
/**
* Convert unix to dos time
*/
function unix_to_dos_time($time)
{
$timearray = (!$time) ? getdate() : getdate($time);
if ($timearray['year'] < 1980)
{
$timearray['year'] = 1980;
$timearray['mon'] = $timearray['mday'] = 1;
$timearray['hours'] = $timearray['minutes'] = $timearray['seconds'] = 0;
}
return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
}
/**
* Extract archive
*/
function extract($dst)
{
// Loop the file, looking for files and folders
$dd_try = false;
rewind($this->fp);
while (!feof($this->fp))
{
// Check if the signature is valid...
$signature = fread($this->fp, 4);
switch ($signature)
{
// 'Local File Header'
case "\x50\x4b\x03\x04":
// Lets get everything we need.
// We don't store the version needed to extract, the general purpose bit flag or the date and time fields
$data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field", fread($this->fp, 26));
$file_name = fread($this->fp, $data['name_len']); // filename
if ($data['extra_field'])
{
fread($this->fp, $data['extra_field']); // extra field
}
$target_filename = "$dst$file_name";
if (!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/')
{
if (!is_dir($target_filename))
{
$str = '';
$folders = explode('/', $target_filename);
// Create and folders and subfolders if they do not exist
foreach ($folders as $folder)
{
$folder = trim($folder);
if (!$folder)
{
continue;
}
$str = (!empty($str)) ? $str . '/' . $folder : $folder;
if (!is_dir($str))
{
if (!@mkdir($str, 0777))
{
trigger_error("Could not create directory $folder");
}
try
{
$this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
// Do nothing
}
}
}
}
// This is a directory, we are not writting files
continue;
}
else
{
// Some archivers are punks, they don't include folders in their archives!
$str = '';
$folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME));
// Create and folders and subfolders if they do not exist
foreach ($folders as $folder)
{
$folder = trim($folder);
if (!$folder)
{
continue;
}
$str = (!empty($str)) ? $str . '/' . $folder : $folder;
if (!is_dir($str))
{
if (!@mkdir($str, 0777))
{
trigger_error("Could not create directory $folder");
}
try
{
$this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
// Do nothing
}
}
}
}
if (!$data['uc_size'])
{
$content = '';
}
else
{
$content = fread($this->fp, $data['c_size']);
}
$fp = fopen($target_filename, "w");
switch ($data['c_method'])
{
case 0:
// Not compressed
fwrite($fp, $content);
break;
case 8:
// Deflate
fwrite($fp, gzinflate($content, $data['uc_size']));
break;
case 12:
// Bzip2
fwrite($fp, bzdecompress($content));
break;
}
fclose($fp);
break;
// We hit the 'Central Directory Header', we can stop because nothing else in here requires our attention
// or we hit the end of the central directory record, we can safely end the loop as we are totally finished with looking for files and folders
case "\x50\x4b\x01\x02":
// This case should simply never happen.. but it does exist..
case "\x50\x4b\x05\x06":
break 2;
// 'Packed to Removable Disk', ignore it and look for the next signature...
case 'PK00':
continue 2;
// We have encountered a header that is weird. Lets look for better data...
default:
if (!$dd_try)
{
// Unexpected header. Trying to detect wrong placed 'Data Descriptor';
$dd_try = true;
fseek($this->fp, 8, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4)
continue 2;
}
trigger_error("Unexpected header, ending loop");
break 2;
}
$dd_try = false;
}
}
/**
* Close archive
*/
function close()
{
// Write out central file directory and footer ... if it exists
if (count($this->ctrl_dir))
{
fwrite($this->fp, $this->file());
}
fclose($this->fp);
}
/**
* Create the structures ... note we assume version made by is MSDOS
*/
function data($name, $data, $stat, $is_dir = false)
{
$name = str_replace('\\', '/', $name);
$name = $this->unique_filename($name);
$hexdtime = pack('V', $this->unix_to_dos_time($stat[9]));
if ($is_dir)
{
$unc_len = $c_len = $crc = 0;
$zdata = '';
$var_ext = 10;
}
else
{
$unc_len = strlen($data);
$crc = crc32($data);
$zdata = gzdeflate($data);
$c_len = strlen($zdata);
$var_ext = 20;
// Did we compress? No, then use data as is
if ($c_len >= $unc_len)
{
$zdata = $data;
$c_len = $unc_len;
$var_ext = 10;
}
}
unset($data);
// If we didn't compress set method to store, else deflate
$c_method = ($c_len == $unc_len) ? "\x00\x00" : "\x08\x00";
// Are we a file or a directory? Set archive for file
$attrib = ($is_dir) ? 16 : 32;
// File Record Header
$fr = "\x50\x4b\x03\x04"; // Local file header 4bytes
$fr .= pack('v', $var_ext); // ver needed to extract 2bytes
$fr .= "\x00\x00"; // gen purpose bit flag 2bytes
$fr .= $c_method; // compression method 2bytes
$fr .= $hexdtime; // last mod time and date 2+2bytes
$fr .= pack('V', $crc); // crc32 4bytes
$fr .= pack('V', $c_len); // compressed filesize 4bytes
$fr .= pack('V', $unc_len); // uncompressed filesize 4bytes
$fr .= pack('v', strlen($name));// length of filename 2bytes
$fr .= pack('v', 0); // extra field length 2bytes
$fr .= $name;
$fr .= $zdata;
unset($zdata);
$this->datasec_len += strlen($fr);
// Add data to file ... by writing data out incrementally we save some memory
fwrite($this->fp, $fr);
unset($fr);
// Central Directory Header
$cdrec = "\x50\x4b\x01\x02"; // header 4bytes
$cdrec .= "\x00\x00"; // version made by
$cdrec .= pack('v', $var_ext); // version needed to extract
$cdrec .= "\x00\x00"; // gen purpose bit flag
$cdrec .= $c_method; // compression method
$cdrec .= $hexdtime; // last mod time & date
$cdrec .= pack('V', $crc); // crc32
$cdrec .= pack('V', $c_len); // compressed filesize
$cdrec .= pack('V', $unc_len); // uncompressed filesize
$cdrec .= pack('v', strlen($name)); // length of filename
$cdrec .= pack('v', 0); // extra field length
$cdrec .= pack('v', 0); // file comment length
$cdrec .= pack('v', 0); // disk number start
$cdrec .= pack('v', 0); // internal file attributes
$cdrec .= pack('V', $attrib); // external file attributes
$cdrec .= pack('V', $this->old_offset); // relative offset of local header
$cdrec .= $name;
// Save to central directory
$this->ctrl_dir[] = $cdrec;
$this->old_offset = $this->datasec_len;
}
/**
* file
*/
function file()
{
$ctrldir = implode('', $this->ctrl_dir);
return $ctrldir . $this->eof_cdh .
pack('v', count($this->ctrl_dir)) . // total # of entries "on this disk"
pack('v', count($this->ctrl_dir)) . // total # of entries overall
pack('V', strlen($ctrldir)) . // size of central dir
pack('V', $this->datasec_len) . // offset to start of central dir
"\x00\x00"; // .zip file comment length
}
/**
* Download archive
*/
function download($filename, $download_name = false)
{
global $phpbb_root_path;
if ($download_name === false)
{
$download_name = $filename;
}
$mimetype = 'application/zip';
header('Cache-Control: private, no-cache');
header("Content-Type: $mimetype; name=\"$download_name.zip\"");
header("Content-disposition: attachment; filename=$download_name.zip");
$fp = @fopen("{$phpbb_root_path}store/$filename.zip", 'rb');
if ($fp)
{
while ($buffer = fread($fp, 1024))
{
echo $buffer;
}
fclose($fp);
}
}
}
/**
* Tar/tar.gz compression routine
* Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994
*/
class compress_tar extends compress
{
var $isgz = false;
var $isbz = false;
var $filename = '';
var $mode = '';
var $type = '';
var $wrote = false;
/**
* @var \phpbb\filesystem\filesystem_interface
*/
protected $filesystem;
/**
* Constructor
*/
function __construct($mode, $file, $type = '')
{
global $phpbb_filesystem;
$type = (!$type) ? $file : $type;
$this->isgz = preg_match('#(\.tar\.gz|\.tgz)$#', $type);
$this->isbz = preg_match('#\.tar\.bz2$#', $type);
$this->mode = &$mode;
$this->file = &$file;
$this->type = &$type;
$this->open();
$this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem();
}
/**
* Extract archive
*/
function extract($dst)
{
$fzread = ($this->isbz && function_exists('bzread')) ? 'bzread' : (($this->isgz && @extension_loaded('zlib')) ? 'gzread' : 'fread');
// Run through the file and grab directory entries
while ($buffer = $fzread($this->fp, 512))
{
$tmp = unpack('A6magic', substr($buffer, 257, 6));
if (trim($tmp['magic']) == 'ustar')
{
$tmp = unpack('A100name', $buffer);
$filename = trim($tmp['name']);
$tmp = unpack('Atype', substr($buffer, 156, 1));
$filetype = (int) trim($tmp['type']);
$tmp = unpack('A12size', substr($buffer, 124, 12));
$filesize = octdec((int) trim($tmp['size']));
$target_filename = "$dst$filename";
if ($filetype == 5)
{
if (!is_dir($target_filename))
{
$str = '';
$folders = explode('/', $target_filename);
// Create and folders and subfolders if they do not exist
foreach ($folders as $folder)
{
$folder = trim($folder);
if (!$folder)
{
continue;
}
$str = (!empty($str)) ? $str . '/' . $folder : $folder;
if (!is_dir($str))
{
if (!@mkdir($str, 0777))
{
trigger_error("Could not create directory $folder");
}
try
{
$this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
// Do nothing
}
}
}
}
}
else if ($filesize >= 0 && ($filetype == 0 || $filetype == "\0"))
{
// Some archivers are punks, they don't properly order the folders in their archives!
$str = '';
$folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME));
// Create and folders and subfolders if they do not exist
foreach ($folders as $folder)
{
$folder = trim($folder);
if (!$folder)
{
continue;
}
$str = (!empty($str)) ? $str . '/' . $folder : $folder;
if (!is_dir($str))
{
if (!@mkdir($str, 0777))
{
trigger_error("Could not create directory $folder");
}
try
{
$this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
// Do nothing
}
}
}
// Write out the files
if (!($fp = fopen($target_filename, 'wb')))
{
trigger_error("Couldn't create file $filename");
}
try
{
$this->filesystem->phpbb_chmod($target_filename, CHMOD_READ);
}
catch (\phpbb\filesystem\exception\filesystem_exception $e)
{
// Do nothing
}
// Grab the file contents
fwrite($fp, ($filesize) ? $fzread($this->fp, ($filesize + 511) &~ 511) : '', $filesize);
fclose($fp);
}
}
}
}
/**
* Close archive
*/
function close()
{
$fzclose = ($this->isbz && function_exists('bzclose')) ? 'bzclose' : (($this->isgz && @extension_loaded('zlib')) ? 'gzclose' : 'fclose');
if ($this->wrote)
{
$fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite');
// The end of a tar archive ends in two records of all NULLs (1024 bytes of \0)
$fzwrite($this->fp, str_repeat("\0", 1024));
}
$fzclose($this->fp);
}
/**
* Create the structures
*/
function data($name, $data, $stat, $is_dir = false)
{
$name = $this->unique_filename($name);
$this->wrote = true;
$fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite');
$typeflag = ($is_dir) ? '5' : '';
// This is the header data, it contains all the info we know about the file or folder that we are about to archive
$header = '';
$header .= pack('a100', $name); // file name
$header .= pack('a8', sprintf("%07o", $stat[2])); // file mode
$header .= pack('a8', sprintf("%07o", $stat[4])); // owner id
$header .= pack('a8', sprintf("%07o", $stat[5])); // group id
$header .= pack('a12', sprintf("%011o", $stat[7])); // file size
$header .= pack('a12', sprintf("%011o", $stat[9])); // last mod time
// Checksum
$checksum = 0;
for ($i = 0; $i < 148; $i++)
{
$checksum += ord($header[$i]);
}
// We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions
$checksum += 2415 + (($is_dir) ? 53 : 0);
$header .= pack('a8', sprintf("%07o", $checksum)); // checksum
$header .= pack('a1', $typeflag); // link indicator
$header .= pack('a100', ''); // name of linked file
$header .= pack('a6', 'ustar'); // ustar indicator
$header .= pack('a2', '00'); // ustar version
$header .= pack('a32', 'Unknown'); // owner name
$header .= pack('a32', 'Unknown'); // group name
$header .= pack('a8', ''); // device major number
$header .= pack('a8', ''); // device minor number
$header .= pack('a155', ''); // filename prefix
$header .= pack('a12', ''); // end
// This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512
$fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : ''));
unset($data);
}
/**
* Open archive
*/
function open()
{
$fzopen = ($this->isbz && function_exists('bzopen')) ? 'bzopen' : (($this->isgz && @extension_loaded('zlib')) ? 'gzopen' : 'fopen');
$this->fp = @$fzopen($this->file, $this->mode . (($fzopen == 'bzopen') ? '' : 'b') . (($fzopen == 'gzopen') ? '9' : ''));
if (!$this->fp)
{
trigger_error('Unable to open file ' . $this->file . ' [' . $fzopen . ' - ' . $this->mode . 'b]');
}
}
/**
* Download archive
*/
function download($filename, $download_name = false)
{
global $phpbb_root_path;
if ($download_name === false)
{
$download_name = $filename;
}
switch ($this->type)
{
case '.tar':
$mimetype = 'application/x-tar';
break;
case '.tar.gz':
$mimetype = 'application/x-gzip';
break;
case '.tar.bz2':
$mimetype = 'application/x-bzip2';
break;
default:
$mimetype = 'application/octet-stream';
break;
}
header('Cache-Control: private, no-cache');
header("Content-Type: $mimetype; name=\"$download_name$this->type\"");
header("Content-disposition: attachment; filename=$download_name$this->type");
$fp = @fopen("{$phpbb_root_path}store/$filename$this->type", 'rb');
if ($fp)
{
while ($buffer = fread($fp, 1024))
{
echo $buffer;
}
fclose($fp);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,210 @@
<?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;
}
/**
* Updates rows in given table from a set of values to a new value.
* If this results in rows violating uniqueness constraints, the duplicate
* rows are eliminated.
*
* The only supported table is bookmarks.
*
* @param \phpbb\db\driver\driver_interface $db Database object
* @param string $table Table on which to perform the update
* @param string $column Column whose values to change
* @param array $from_values An array of values that should be changed
* @param int $to_value The new value
* @return null
*/
function phpbb_update_rows_avoiding_duplicates(\phpbb\db\driver\driver_interface $db, $table, $column, $from_values, $to_value)
{
$sql = "SELECT $column, user_id
FROM $table
WHERE " . $db->sql_in_set($column, $from_values);
$result = $db->sql_query($sql);
$old_user_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$old_user_ids[$row[$column]][] = (int) $row['user_id'];
}
$db->sql_freeresult($result);
$sql = "SELECT $column, user_id
FROM $table
WHERE $column = " . (int) $to_value;
$result = $db->sql_query($sql);
$new_user_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$new_user_ids[$row[$column]][] = (int) $row['user_id'];
}
$db->sql_freeresult($result);
$queries = array();
foreach ($from_values as $from_value)
{
if (!isset($old_user_ids[$from_value]))
{
continue;
}
if (empty($new_user_ids))
{
$sql = "UPDATE $table
SET $column = " . (int) $to_value . "
WHERE $column = '" . $db->sql_escape($from_value) . "'";
$queries[] = $sql;
}
else
{
$different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]);
if (!empty($different_user_ids))
{
$sql = "UPDATE $table
SET $column = " . (int) $to_value . "
WHERE $column = '" . $db->sql_escape($from_value) . "'
AND " . $db->sql_in_set('user_id', $different_user_ids);
$queries[] = $sql;
}
}
}
if (!empty($queries))
{
$db->sql_transaction('begin');
foreach ($queries as $sql)
{
$db->sql_query($sql);
}
$sql = "DELETE FROM $table
WHERE " . $db->sql_in_set($column, $from_values);
$db->sql_query($sql);
$db->sql_transaction('commit');
}
}
/**
* Updates rows in given table from a set of values to a new value.
* If this results in rows violating uniqueness constraints, the duplicate
* rows are merged respecting notify_status (0 takes precedence over 1).
*
* The only supported table is topics_watch.
*
* @param \phpbb\db\driver\driver_interface $db Database object
* @param string $table Table on which to perform the update
* @param string $column Column whose values to change
* @param array $from_values An array of values that should be changed
* @param int $to_value The new value
* @return null
*/
function phpbb_update_rows_avoiding_duplicates_notify_status(\phpbb\db\driver\driver_interface $db, $table, $column, $from_values, $to_value)
{
$sql = "SELECT $column, user_id, notify_status
FROM $table
WHERE " . $db->sql_in_set($column, $from_values);
$result = $db->sql_query($sql);
$old_user_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$old_user_ids[(int) $row['notify_status']][$row[$column]][] = (int) $row['user_id'];
}
$db->sql_freeresult($result);
$sql = "SELECT $column, user_id
FROM $table
WHERE $column = " . (int) $to_value;
$result = $db->sql_query($sql);
$new_user_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$new_user_ids[$row[$column]][] = (int) $row['user_id'];
}
$db->sql_freeresult($result);
$queries = array();
$extra_updates = array(
0 => 'notify_status = 0',
1 => '',
);
foreach ($from_values as $from_value)
{
foreach ($extra_updates as $notify_status => $extra_update)
{
if (!isset($old_user_ids[$notify_status][$from_value]))
{
continue;
}
if (empty($new_user_ids))
{
$sql = "UPDATE $table
SET $column = " . (int) $to_value . "
WHERE $column = '" . $db->sql_escape($from_value) . "'";
$queries[] = $sql;
}
else
{
$different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]);
if (!empty($different_user_ids))
{
$sql = "UPDATE $table
SET $column = " . (int) $to_value . "
WHERE $column = '" . $db->sql_escape($from_value) . "'
AND " . $db->sql_in_set('user_id', $different_user_ids);
$queries[] = $sql;
}
if ($extra_update)
{
$same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids);
if (!empty($same_user_ids))
{
$sql = "UPDATE $table
SET $extra_update
WHERE $column = '" . (int) $to_value . "'
AND " . $db->sql_in_set('user_id', $same_user_ids);
$queries[] = $sql;
}
}
}
}
}
if (!empty($queries))
{
$db->sql_transaction('begin');
foreach ($queries as $sql)
{
$db->sql_query($sql);
}
$sql = "DELETE FROM $table
WHERE " . $db->sql_in_set($column, $from_values);
$db->sql_query($sql);
$db->sql_transaction('commit');
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,790 @@
<?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;
}
/**
* A simplified function to deliver avatars
* The argument needs to be checked before calling this function.
*/
function send_avatar_to_browser($file, $browser)
{
global $config, $phpbb_root_path;
$prefix = $config['avatar_salt'] . '_';
$image_dir = $config['avatar_path'];
// Adjust image_dir path (no trailing slash)
if (substr($image_dir, -1, 1) == '/' || substr($image_dir, -1, 1) == '\\')
{
$image_dir = substr($image_dir, 0, -1) . '/';
}
$image_dir = str_replace(array('../', '..\\', './', '.\\'), '', $image_dir);
if ($image_dir && ($image_dir[0] == '/' || $image_dir[0] == '\\'))
{
$image_dir = '';
}
$file_path = $phpbb_root_path . $image_dir . '/' . $prefix . $file;
if ((@file_exists($file_path) && @is_readable($file_path)) && !headers_sent())
{
header('Cache-Control: public');
$image_data = @getimagesize($file_path);
header('Content-Type: ' . image_type_to_mime_type($image_data[2]));
if ((strpos(strtolower($browser), 'msie') !== false) && !phpbb_is_greater_ie_version($browser, 7))
{
header('Content-Disposition: attachment; ' . header_filename($file));
if (strpos(strtolower($browser), 'msie 6.0') !== false)
{
header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
}
else
{
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
}
}
else
{
header('Content-Disposition: inline; ' . header_filename($file));
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
}
$size = @filesize($file_path);
if ($size)
{
header("Content-Length: $size");
}
if (@readfile($file_path) == false)
{
$fp = @fopen($file_path, 'rb');
if ($fp !== false)
{
while (!feof($fp))
{
echo fread($fp, 8192);
}
fclose($fp);
}
}
flush();
}
else
{
header('HTTP/1.0 404 Not Found');
}
}
/**
* Wraps an url into a simple html page. Used to display attachments in IE.
* this is a workaround for now; might be moved to template system later
* direct any complaints to 1 Microsoft Way, Redmond
*/
function wrap_img_in_html($src, $title)
{
echo '<!DOCTYPE html>';
echo '<html>';
echo '<head>';
echo '<meta charset="utf-8">';
echo '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
echo '<title>' . $title . '</title>';
echo '</head>';
echo '<body>';
echo '<div>';
echo '<img src="' . $src . '" alt="' . $title . '" />';
echo '</div>';
echo '</body>';
echo '</html>';
}
/**
* Send file to browser
*/
function send_file_to_browser($attachment, $upload_dir, $category)
{
global $user, $db, $phpbb_dispatcher, $phpbb_root_path, $request;
$filename = $phpbb_root_path . $upload_dir . '/' . $attachment['physical_filename'];
if (!@file_exists($filename))
{
send_status_line(404, 'Not Found');
trigger_error('ERROR_NO_ATTACHMENT');
}
// Correct the mime type - we force application/octetstream for all files, except images
// Please do not change this, it is a security precaution
if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0)
{
$attachment['mimetype'] = (strpos(strtolower($user->browser), 'msie') !== false || strpos(strtolower($user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream';
}
if (@ob_get_length())
{
@ob_end_clean();
}
// Now send the File Contents to the Browser
$size = @filesize($filename);
/**
* Event to alter attachment before it is sent to browser.
*
* @event core.send_file_to_browser_before
* @var array attachment Attachment data
* @var string upload_dir Relative path of upload directory
* @var int category Attachment category
* @var string filename Path to file, including filename
* @var int size File size
* @since 3.1.11-RC1
*/
$vars = array(
'attachment',
'upload_dir',
'category',
'filename',
'size',
);
extract($phpbb_dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars)));
// To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work)
// Check if headers already sent or not able to get the file contents.
if (headers_sent() || !@file_exists($filename) || !@is_readable($filename))
{
// PHP track_errors setting On?
if (!empty($php_errormsg))
{
send_status_line(500, 'Internal Server Error');
trigger_error($user->lang['UNABLE_TO_DELIVER_FILE'] . '<br />' . sprintf($user->lang['TRACKED_PHP_ERROR'], $php_errormsg));
}
send_status_line(500, 'Internal Server Error');
trigger_error('UNABLE_TO_DELIVER_FILE');
}
// Make sure the database record for the filesize is correct
if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false)
{
// Update database record
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
SET filesize = ' . (int) $size . '
WHERE attach_id = ' . (int) $attachment['attach_id'];
$db->sql_query($sql);
}
// Now the tricky part... let's dance
header('Cache-Control: public');
// Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer.
header('Content-Type: ' . $attachment['mimetype']);
if (phpbb_is_greater_ie_version($user->browser, 7))
{
header('X-Content-Type-Options: nosniff');
}
if ($category == ATTACHMENT_CATEGORY_FLASH && $request->variable('view', 0) === 1)
{
// We use content-disposition: inline for flash files and view=1 to let it correctly play with flash player 10 - any other disposition will fail to play inline
header('Content-Disposition: inline');
}
else
{
if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)))
{
header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false))
{
header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
}
}
else
{
header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0))
{
header('X-Download-Options: noopen');
}
}
}
// Close the db connection before sending the file etc.
file_gc(false);
if (!set_modified_headers($attachment['filetime'], $user->browser))
{
// We make sure those have to be enabled manually by defining a constant
// because of the potential disclosure of full attachment path
// in case support for features is absent in the webserver software.
if (defined('PHPBB_ENABLE_X_ACCEL_REDIRECT') && PHPBB_ENABLE_X_ACCEL_REDIRECT)
{
// X-Accel-Redirect - http://wiki.nginx.org/XSendfile
header('X-Accel-Redirect: ' . $user->page['root_script_path'] . $upload_dir . '/' . $attachment['physical_filename']);
exit;
}
else if (defined('PHPBB_ENABLE_X_SENDFILE') && PHPBB_ENABLE_X_SENDFILE && !phpbb_http_byte_range($size))
{
// X-Sendfile - http://blog.lighttpd.net/articles/2006/07/02/x-sendfile
// Lighttpd's X-Sendfile does not support range requests as of 1.4.26
// and always requires an absolute path.
header('X-Sendfile: ' . dirname(__FILE__) . "/../$upload_dir/{$attachment['physical_filename']}");
exit;
}
if ($size)
{
header("Content-Length: $size");
}
// Try to deliver in chunks
@set_time_limit(0);
$fp = @fopen($filename, 'rb');
if ($fp !== false)
{
// Deliver file partially if requested
if ($range = phpbb_http_byte_range($size))
{
fseek($fp, $range['byte_pos_start']);
send_status_line(206, 'Partial Content');
header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']);
header('Content-Length: ' . $range['bytes_requested']);
// First read chunks
while (!feof($fp) && ftell($fp) < $range['byte_pos_end'] - 8192)
{
echo fread($fp, 8192);
}
// Then, read the remainder
echo fread($fp, $range['bytes_requested'] % 8192);
}
else
{
while (!feof($fp))
{
echo fread($fp, 8192);
}
}
fclose($fp);
}
else
{
@readfile($filename);
}
flush();
}
exit;
}
/**
* Get a browser friendly UTF-8 encoded filename
*/
function header_filename($file)
{
global $request;
$user_agent = $request->header('User-Agent');
// There be dragons here.
// Not many follows the RFC...
if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false)
{
return "filename=" . rawurlencode($file);
}
// follow the RFC for extended filename for the rest
return "filename*=UTF-8''" . rawurlencode($file);
}
/**
* Check if downloading item is allowed
*/
function download_allowed()
{
global $config, $user, $db, $request;
if (!$config['secure_downloads'])
{
return true;
}
$url = htmlspecialchars_decode($request->header('Referer'));
if (!$url)
{
return ($config['secure_allow_empty_referer']) ? true : false;
}
// Split URL into domain and script part
$url = @parse_url($url);
if ($url === false)
{
return ($config['secure_allow_empty_referer']) ? true : false;
}
$hostname = $url['host'];
unset($url);
$allowed = ($config['secure_allow_deny']) ? false : true;
$iplist = array();
if (($ip_ary = @gethostbynamel($hostname)) !== false)
{
foreach ($ip_ary as $ip)
{
if ($ip)
{
$iplist[] = $ip;
}
}
}
// Check for own server...
$server_name = $user->host;
// Forcing server vars is the only way to specify/override the protocol
if ($config['force_server_vars'] || !$server_name)
{
$server_name = $config['server_name'];
}
if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname))
{
$allowed = true;
}
// Get IP's and Hostnames
if (!$allowed)
{
$sql = 'SELECT site_ip, site_hostname, ip_exclude
FROM ' . SITELIST_TABLE;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$site_ip = trim($row['site_ip']);
$site_hostname = trim($row['site_hostname']);
if ($site_ip)
{
foreach ($iplist as $ip)
{
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip))
{
if ($row['ip_exclude'])
{
$allowed = ($config['secure_allow_deny']) ? false : true;
break 2;
}
else
{
$allowed = ($config['secure_allow_deny']) ? true : false;
}
}
}
}
if ($site_hostname)
{
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname))
{
if ($row['ip_exclude'])
{
$allowed = ($config['secure_allow_deny']) ? false : true;
break;
}
else
{
$allowed = ($config['secure_allow_deny']) ? true : false;
}
}
}
}
$db->sql_freeresult($result);
}
return $allowed;
}
/**
* Check if the browser has the file already and set the appropriate headers-
* @returns false if a resend is in order.
*/
function set_modified_headers($stamp, $browser)
{
global $request;
// let's see if we have to send the file at all
$last_load = $request->header('If-Modified-Since') ? strtotime(trim($request->header('If-Modified-Since'))) : false;
if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7))
{
if ($last_load !== false && $last_load >= $stamp)
{
send_status_line(304, 'Not Modified');
// seems that we need those too ... browsers
header('Cache-Control: public');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
return true;
}
else
{
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT');
}
}
return false;
}
/**
* Garbage Collection
*
* @param bool $exit Whether to die or not.
*
* @return null
*/
function file_gc($exit = true)
{
global $cache, $db;
if (!empty($cache))
{
$cache->unload();
}
$db->sql_close();
if ($exit)
{
exit;
}
}
/**
* HTTP range support (RFC 2616 Section 14.35)
*
* Allows browsers to request partial file content
* in case a download has been interrupted.
*
* @param int $filesize the size of the file in bytes we are about to deliver
*
* @return mixed false if the whole file has to be delivered
* associative array on success
*/
function phpbb_http_byte_range($filesize)
{
// Only call find_range_request() once.
static $request_array;
if (!$filesize)
{
return false;
}
if (!isset($request_array))
{
$request_array = phpbb_find_range_request();
}
return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize);
}
/**
* Searches for HTTP range request in request headers.
*
* @return mixed false if no request found
* array of strings containing the requested ranges otherwise
* e.g. array(0 => '0-0', 1 => '123-125')
*/
function phpbb_find_range_request()
{
global $request;
$value = $request->header('Range');
// Make sure range request starts with "bytes="
if (strpos($value, 'bytes=') === 0)
{
// Strip leading 'bytes='
// Multiple ranges can be separated by a comma
return explode(',', substr($value, 6));
}
return false;
}
/**
* Analyses a range request array.
*
* A range request can contain multiple ranges,
* we however only handle the first request and
* only support requests from a given byte to the end of the file.
*
* @param array $request_array array of strings containing the requested ranges
* @param int $filesize the full size of the file in bytes that has been requested
*
* @return mixed false if the whole file has to be delivered
* associative array on success
* byte_pos_start the first byte position, can be passed to fseek()
* byte_pos_end the last byte position
* bytes_requested the number of bytes requested
* bytes_total the full size of the file
*/
function phpbb_parse_range_request($request_array, $filesize)
{
$first_byte_pos = -1;
$last_byte_pos = -1;
// Go through all ranges
foreach ($request_array as $range_string)
{
$range = explode('-', trim($range_string));
// "-" is invalid, "0-0" however is valid and means the very first byte.
if (count($range) != 2 || $range[0] === '' && $range[1] === '')
{
continue;
}
// Substitute defaults
if ($range[0] === '')
{
$range[0] = 0;
}
if ($range[1] === '')
{
$range[1] = $filesize - 1;
}
if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0])
{
// We only support contiguous ranges, no multipart stuff :(
return false;
}
if ($range[1] && $range[1] < $range[0])
{
// The requested range contains 0 bytes.
continue;
}
// Return bytes from $range[0] to $range[1]
if ($first_byte_pos < 0)
{
$first_byte_pos = (int) $range[0];
}
$last_byte_pos = (int) $range[1];
if ($first_byte_pos >= $filesize)
{
// Requested range not satisfiable
return false;
}
// Adjust last-byte-pos if it is absent or greater than the content.
if ($range[1] === '' || $last_byte_pos >= $filesize)
{
$last_byte_pos = $filesize - 1;
}
}
if ($first_byte_pos < 0 || $last_byte_pos < 0)
{
return false;
}
return array(
'byte_pos_start' => $first_byte_pos,
'byte_pos_end' => $last_byte_pos,
'bytes_requested' => $last_byte_pos - $first_byte_pos + 1,
'bytes_total' => $filesize,
);
}
/**
* Increments the download count of all provided attachments
*
* @param \phpbb\db\driver\driver_interface $db The database object
* @param array|int $ids The attach_id of each attachment
*
* @return null
*/
function phpbb_increment_downloads($db, $ids)
{
if (!is_array($ids))
{
$ids = array($ids);
}
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
SET download_count = download_count + 1
WHERE ' . $db->sql_in_set('attach_id', $ids);
$db->sql_query($sql);
}
/**
* Handles authentication when downloading attachments from a post or topic
*
* @param \phpbb\db\driver\driver_interface $db The database object
* @param \phpbb\auth\auth $auth The authentication object
* @param int $topic_id The id of the topic that we are downloading from
*
* @return null
*/
function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
{
global $phpbb_container;
$sql_array = array(
'SELECT' => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id',
'FROM' => array(
TOPICS_TABLE => 't',
FORUMS_TABLE => 'f',
),
'WHERE' => 't.topic_id = ' . (int) $topic_id . '
AND t.forum_id = f.forum_id',
);
$sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
if ($row && !$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row))
{
send_status_line(404, 'Not Found');
trigger_error('ERROR_NO_ATTACHMENT');
}
else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']))
{
if ($row['forum_password'])
{
// Do something else ... ?
login_forum_box($row);
}
}
else
{
send_status_line(403, 'Forbidden');
trigger_error('SORRY_AUTH_VIEW_ATTACH');
}
}
/**
* Handles authentication when downloading attachments from PMs
*
* @param \phpbb\db\driver\driver_interface $db The database object
* @param \phpbb\auth\auth $auth The authentication object
* @param int $user_id The user id
* @param int $msg_id The id of the PM that we are downloading from
*
* @return null
*/
function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id)
{
global $phpbb_dispatcher;
if (!$auth->acl_get('u_pm_download'))
{
send_status_line(403, 'Forbidden');
trigger_error('SORRY_AUTH_VIEW_ATTACH');
}
$allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id);
/**
* Event to modify PM attachments download auth
*
* @event core.modify_pm_attach_download_auth
* @var bool allowed Whether the user is allowed to download from that PM or not
* @var int msg_id The id of the PM to download from
* @var int user_id The user id for auth check
* @since 3.1.11-RC1
*/
$vars = array('allowed', 'msg_id', 'user_id');
extract($phpbb_dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars)));
if (!$allowed)
{
send_status_line(403, 'Forbidden');
trigger_error('ERROR_NO_ATTACHMENT');
}
}
/**
* Checks whether a user can download from a particular PM
*
* @param \phpbb\db\driver\driver_interface $db The database object
* @param int $user_id The user id
* @param int $msg_id The id of the PM that we are downloading from
*
* @return bool Whether the user is allowed to download from that PM or not
*/
function phpbb_download_check_pm_auth($db, $user_id, $msg_id)
{
// Check if the attachment is within the users scope...
$sql = 'SELECT msg_id
FROM ' . PRIVMSGS_TO_TABLE . '
WHERE msg_id = ' . (int) $msg_id . '
AND (
user_id = ' . (int) $user_id . '
OR author_id = ' . (int) $user_id . '
)';
$result = $db->sql_query_limit($sql, 1);
$allowed = (bool) $db->sql_fetchfield('msg_id');
$db->sql_freeresult($result);
return $allowed;
}
/**
* Check if the browser is internet explorer version 7+
*
* @param string $user_agent User agent HTTP header
* @param int $version IE version to check against
*
* @return bool true if internet explorer version is greater than $version
*/
function phpbb_is_greater_ie_version($user_agent, $version)
{
if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches))
{
$ie_version = (int) $matches[1];
return ($ie_version > $version);
}
else
{
return false;
}
}

View File

@@ -0,0 +1,904 @@
<?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;
}
/**
*
* Jabber class from Flyspray project
*
* @version class.jabber2.php 1595 2008-09-19 (0.9.9)
* @copyright 2006 Flyspray.org
* @author Florian Schmitz (floele)
*
* Only slightly modified by Acyd Burn
*/
class jabber
{
var $connection = null;
var $session = array();
var $timeout = 10;
var $server;
var $connect_server;
var $port;
var $username;
var $password;
var $use_ssl;
var $verify_peer;
var $verify_peer_name;
var $allow_self_signed;
var $resource = 'functions_jabber.phpbb.php';
var $enable_logging;
var $log_array;
var $features = array();
/**
* Constructor
*
* @param string $server Jabber server
* @param int $port Jabber server port
* @param string $username Jabber username or JID
* @param string $password Jabber password
* @param boold $use_ssl Use ssl
* @param bool $verify_peer Verify SSL certificate
* @param bool $verify_peer_name Verify Jabber peer name
* @param bool $allow_self_signed Allow self signed certificates
*/
function __construct($server, $port, $username, $password, $use_ssl = false, $verify_peer = true, $verify_peer_name = true, $allow_self_signed = false)
{
$this->connect_server = ($server) ? $server : 'localhost';
$this->port = ($port) ? $port : 5222;
// Get the server and the username
if (strpos($username, '@') === false)
{
$this->server = $this->connect_server;
$this->username = $username;
}
else
{
$jid = explode('@', $username, 2);
$this->username = $jid[0];
$this->server = $jid[1];
}
$this->password = $password;
$this->use_ssl = ($use_ssl && self::can_use_ssl()) ? true : false;
$this->verify_peer = $verify_peer;
$this->verify_peer_name = $verify_peer_name;
$this->allow_self_signed = $allow_self_signed;
// Change port if we use SSL
if ($this->port == 5222 && $this->use_ssl)
{
$this->port = 5223;
}
$this->enable_logging = true;
$this->log_array = array();
}
/**
* Able to use the SSL functionality?
*/
static public function can_use_ssl()
{
return @extension_loaded('openssl');
}
/**
* Able to use TLS?
*/
static public function can_use_tls()
{
if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('stream_set_blocking') || !function_exists('stream_get_wrappers'))
{
return false;
}
/**
* Make sure the encryption stream is supported
* Also seem to work without the crypto stream if correctly compiled
$streams = stream_get_wrappers();
if (!in_array('streams.crypto', $streams))
{
return false;
}
*/
return true;
}
/**
* Sets the resource which is used. No validation is done here, only escaping.
* @param string $name
* @access public
*/
function set_resource($name)
{
$this->resource = $name;
}
/**
* Connect
*/
function connect()
{
/* if (!$this->check_jid($this->username . '@' . $this->server))
{
$this->add_to_log('Error: Jabber ID is not valid: ' . $this->username . '@' . $this->server);
return false;
}*/
$this->session['ssl'] = $this->use_ssl;
if ($this->open_socket($this->connect_server, $this->port, $this->use_ssl, $this->verify_peer, $this->verify_peer_name, $this->allow_self_signed))
{
$this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n");
$this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n");
}
else
{
$this->add_to_log('Error: connect() #2');
return false;
}
// Now we listen what the server has to say...and give appropriate responses
$this->response($this->listen());
return true;
}
/**
* Disconnect
*/
function disconnect()
{
if ($this->connected())
{
// disconnect gracefully
if (isset($this->session['sent_presence']))
{
$this->send_presence('offline', '', true);
}
$this->send('</stream:stream>');
$this->session = array();
return fclose($this->connection);
}
return false;
}
/**
* Connected?
*/
function connected()
{
return (is_resource($this->connection) && !feof($this->connection)) ? true : false;
}
/**
* Initiates login (using data from contructor, after calling connect())
* @access public
* @return bool
*/
function login()
{
if (!count($this->features))
{
$this->add_to_log('Error: No feature information from server available.');
return false;
}
return $this->response($this->features);
}
/**
* Send data to the Jabber server
* @param string $xml
* @access public
* @return bool
*/
function send($xml)
{
if ($this->connected())
{
$xml = trim($xml);
$this->add_to_log('SEND: '. $xml);
return fwrite($this->connection, $xml);
}
else
{
$this->add_to_log('Error: Could not send, connection lost (flood?).');
return false;
}
}
/**
* OpenSocket
* @param string $server host to connect to
* @param int $port port number
* @param bool $use_ssl use ssl or not
* @param bool $verify_peer verify ssl certificate
* @param bool $verify_peer_name verify peer name
* @param bool $allow_self_signed allow self-signed ssl certificates
* @access public
* @return bool
*/
function open_socket($server, $port, $use_ssl, $verify_peer, $verify_peer_name, $allow_self_signed)
{
if (@function_exists('dns_get_record'))
{
$record = @dns_get_record("_xmpp-client._tcp.$server", DNS_SRV);
if (!empty($record) && !empty($record[0]['target']))
{
$server = $record[0]['target'];
}
}
$options = array();
if ($use_ssl)
{
$remote_socket = 'ssl://' . $server . ':' . $port;
// Set ssl context options, see http://php.net/manual/en/context.ssl.php
$options['ssl'] = array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed);
}
else
{
$remote_socket = $server . ':' . $port;
}
$socket_context = stream_context_create($options);
if ($this->connection = @stream_socket_client($remote_socket, $errorno, $errorstr, $this->timeout, STREAM_CLIENT_CONNECT, $socket_context))
{
stream_set_blocking($this->connection, 0);
stream_set_timeout($this->connection, 60);
return true;
}
// Apparently an error occurred...
$this->add_to_log('Error: open_socket() - ' . $errorstr);
return false;
}
/**
* Return log
*/
function get_log()
{
if ($this->enable_logging && count($this->log_array))
{
return implode("<br /><br />", $this->log_array);
}
return '';
}
/**
* Add information to log
*/
function add_to_log($string)
{
if ($this->enable_logging)
{
$this->log_array[] = utf8_htmlspecialchars($string);
}
}
/**
* Listens to the connection until it gets data or the timeout is reached.
* Thus, it should only be called if data is expected to be received.
* @access public
* @return mixed either false for timeout or an array with the received data
*/
function listen($timeout = 10, $wait = false)
{
if (!$this->connected())
{
return false;
}
// Wait for a response until timeout is reached
$start = time();
$data = '';
do
{
$read = trim(fread($this->connection, 4096));
$data .= $read;
}
while (time() <= $start + $timeout && !feof($this->connection) && ($wait || $data == '' || $read != '' || (substr(rtrim($data), -1) != '>')));
if ($data != '')
{
$this->add_to_log('RECV: '. $data);
return $this->xmlize($data);
}
else
{
$this->add_to_log('Timeout, no response from server.');
return false;
}
}
/**
* Initiates account registration (based on data used for contructor)
* @access public
* @return bool
*/
function register()
{
if (!isset($this->session['id']) || isset($this->session['jid']))
{
$this->add_to_log('Error: Cannot initiate registration.');
return false;
}
$this->send("<iq type='get' id='reg_1'><query xmlns='jabber:iq:register'/></iq>");
return $this->response($this->listen());
}
/**
* Sets account presence. No additional info required (default is "online" status)
* @param $message online, offline...
* @param $type dnd, away, chat, xa or nothing
* @param $unavailable set this to true if you want to become unavailable
* @access public
* @return bool
*/
function send_presence($message = '', $type = '', $unavailable = false)
{
if (!isset($this->session['jid']))
{
$this->add_to_log('ERROR: send_presence() - Cannot set presence at this point, no jid given.');
return false;
}
$type = strtolower($type);
$type = (in_array($type, array('dnd', 'away', 'chat', 'xa'))) ? '<show>'. $type .'</show>' : '';
$unavailable = ($unavailable) ? " type='unavailable'" : '';
$message = ($message) ? '<status>' . utf8_htmlspecialchars($message) .'</status>' : '';
$this->session['sent_presence'] = !$unavailable;
return $this->send("<presence$unavailable>" . $type . $message . '</presence>');
}
/**
* This handles all the different XML elements
* @param array $xml
* @access public
* @return bool
*/
function response($xml)
{
if (!is_array($xml) || !count($xml))
{
return false;
}
// did we get multiple elements? do one after another
// array('message' => ..., 'presence' => ...)
if (count($xml) > 1)
{
foreach ($xml as $key => $value)
{
$this->response(array($key => $value));
}
return;
}
else
{
// or even multiple elements of the same type?
// array('message' => array(0 => ..., 1 => ...))
if (count(reset($xml)) > 1)
{
foreach (reset($xml) as $value)
{
$this->response(array(key($xml) => array(0 => $value)));
}
return;
}
}
switch (key($xml))
{
case 'stream:stream':
// Connection initialised (or after authentication). Not much to do here...
if (isset($xml['stream:stream'][0]['#']['stream:features']))
{
// we already got all info we need
$this->features = $xml['stream:stream'][0]['#'];
}
else
{
$this->features = $this->listen();
}
$second_time = isset($this->session['id']);
$this->session['id'] = $xml['stream:stream'][0]['@']['id'];
if ($second_time)
{
// If we are here for the second time after TLS, we need to continue logging in
return $this->login();
}
// go on with authentication?
if (isset($this->features['stream:features'][0]['#']['bind']) || !empty($this->session['tls']))
{
return $this->response($this->features);
}
break;
case 'stream:features':
// Resource binding after successful authentication
if (isset($this->session['authenticated']))
{
// session required?
$this->session['sess_required'] = isset($xml['stream:features'][0]['#']['session']);
$this->send("<iq type='set' id='bind_1'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<resource>" . utf8_htmlspecialchars($this->resource) . '</resource>
</bind>
</iq>');
return $this->response($this->listen());
}
// Let's use TLS if SSL is not enabled and we can actually use it
if (!$this->session['ssl'] && self::can_use_tls() && self::can_use_ssl() && isset($xml['stream:features'][0]['#']['starttls']))
{
$this->add_to_log('Switching to TLS.');
$this->send("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n");
return $this->response($this->listen());
}
// Does the server support SASL authentication?
// I hope so, because we do (and no other method).
if (isset($xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns']) && $xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-sasl')
{
// Now decide on method
$methods = array();
foreach ($xml['stream:features'][0]['#']['mechanisms'][0]['#']['mechanism'] as $value)
{
$methods[] = $value['#'];
}
// we prefer DIGEST-MD5
// we don't want to use plain authentication (neither does the server usually) if no encryption is in place
// http://www.xmpp.org/extensions/attic/jep-0078-1.7.html
// The plaintext mechanism SHOULD NOT be used unless the underlying stream is encrypted (using SSL or TLS)
// and the client has verified that the server certificate is signed by a trusted certificate authority.
if (in_array('DIGEST-MD5', $methods))
{
$this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>");
}
else if (in_array('PLAIN', $methods) && ($this->session['ssl'] || !empty($this->session['tls'])))
{
// http://www.ietf.org/rfc/rfc4616.txt (PLAIN SASL Mechanism)
$this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>"
. base64_encode($this->username . '@' . $this->server . chr(0) . $this->username . chr(0) . $this->password) .
'</auth>');
}
else if (in_array('ANONYMOUS', $methods))
{
$this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>");
}
else
{
// not good...
$this->add_to_log('Error: No authentication method supported.');
$this->disconnect();
return false;
}
return $this->response($this->listen());
}
else
{
// ok, this is it. bye.
$this->add_to_log('Error: Server does not offer SASL authentication.');
$this->disconnect();
return false;
}
break;
case 'challenge':
// continue with authentication...a challenge literally -_-
$decoded = base64_decode($xml['challenge'][0]['#']);
$decoded = $this->parse_data($decoded);
if (!isset($decoded['digest-uri']))
{
$decoded['digest-uri'] = 'xmpp/'. $this->server;
}
// better generate a cnonce, maybe it's needed
$decoded['cnonce'] = base64_encode(md5(uniqid(mt_rand(), true)));
// second challenge?
if (isset($decoded['rspauth']))
{
$this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
}
else
{
// Make sure we only use 'auth' for qop (relevant for $this->encrypt_password())
// If the <response> is choking up on the changed parameter we may need to adjust encrypt_password() directly
if (isset($decoded['qop']) && $decoded['qop'] != 'auth' && strpos($decoded['qop'], 'auth') !== false)
{
$decoded['qop'] = 'auth';
}
$response = array(
'username' => $this->username,
'response' => $this->encrypt_password(array_merge($decoded, array('nc' => '00000001'))),
'charset' => 'utf-8',
'nc' => '00000001',
'qop' => 'auth', // only auth being supported
);
foreach (array('nonce', 'digest-uri', 'realm', 'cnonce') as $key)
{
if (isset($decoded[$key]))
{
$response[$key] = $decoded[$key];
}
}
$this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" . base64_encode($this->implode_data($response)) . '</response>');
}
return $this->response($this->listen());
break;
case 'failure':
$this->add_to_log('Error: Server sent "failure".');
$this->disconnect();
return false;
break;
case 'proceed':
// continue switching to TLS
$meta = stream_get_meta_data($this->connection);
stream_set_blocking($this->connection, 1);
if (!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT))
{
$this->add_to_log('Error: TLS mode change failed.');
return false;
}
stream_set_blocking($this->connection, $meta['blocked']);
$this->session['tls'] = true;
// new stream
$this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n");
$this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n");
return $this->response($this->listen());
break;
case 'success':
// Yay, authentication successful.
$this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n");
$this->session['authenticated'] = true;
// we have to wait for another response
return $this->response($this->listen());
break;
case 'iq':
// we are not interested in IQs we did not expect
if (!isset($xml['iq'][0]['@']['id']))
{
return false;
}
// multiple possibilities here
switch ($xml['iq'][0]['@']['id'])
{
case 'bind_1':
$this->session['jid'] = $xml['iq'][0]['#']['bind'][0]['#']['jid'][0]['#'];
// and (maybe) yet another request to be able to send messages *finally*
if ($this->session['sess_required'])
{
$this->send("<iq to='{$this->server}' type='set' id='sess_1'>
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
</iq>");
return $this->response($this->listen());
}
return true;
break;
case 'sess_1':
return true;
break;
case 'reg_1':
$this->send("<iq type='set' id='reg_2'>
<query xmlns='jabber:iq:register'>
<username>" . utf8_htmlspecialchars($this->username) . "</username>
<password>" . utf8_htmlspecialchars($this->password) . "</password>
</query>
</iq>");
return $this->response($this->listen());
break;
case 'reg_2':
// registration end
if (isset($xml['iq'][0]['#']['error']))
{
$this->add_to_log('Warning: Registration failed.');
return false;
}
return true;
break;
case 'unreg_1':
return true;
break;
default:
$this->add_to_log('Notice: Received unexpected IQ.');
return false;
break;
}
break;
case 'message':
// we are only interested in content...
if (!isset($xml['message'][0]['#']['body']))
{
return false;
}
$message['body'] = $xml['message'][0]['#']['body'][0]['#'];
$message['from'] = $xml['message'][0]['@']['from'];
if (isset($xml['message'][0]['#']['subject']))
{
$message['subject'] = $xml['message'][0]['#']['subject'][0]['#'];
}
$this->session['messages'][] = $message;
break;
default:
// hm...don't know this response
$this->add_to_log('Notice: Unknown server response (' . key($xml) . ')');
return false;
break;
}
}
function send_message($to, $text, $subject = '', $type = 'normal')
{
if (!isset($this->session['jid']))
{
return false;
}
if (!in_array($type, array('chat', 'normal', 'error', 'groupchat', 'headline')))
{
$type = 'normal';
}
return $this->send("<message from='" . utf8_htmlspecialchars($this->session['jid']) . "' to='" . utf8_htmlspecialchars($to) . "' type='$type' id='" . uniqid('msg') . "'>
<subject>" . utf8_htmlspecialchars($subject) . "</subject>
<body>" . utf8_htmlspecialchars($text) . "</body>
</message>"
);
}
/**
* Encrypts a password as in RFC 2831
* @param array $data Needs data from the client-server connection
* @access public
* @return string
*/
function encrypt_password($data)
{
// let's me think about <challenge> again...
foreach (array('realm', 'cnonce', 'digest-uri') as $key)
{
if (!isset($data[$key]))
{
$data[$key] = '';
}
}
$pack = md5($this->username . ':' . $data['realm'] . ':' . $this->password);
if (isset($data['authzid']))
{
$a1 = pack('H32', $pack) . sprintf(':%s:%s:%s', $data['nonce'], $data['cnonce'], $data['authzid']);
}
else
{
$a1 = pack('H32', $pack) . sprintf(':%s:%s', $data['nonce'], $data['cnonce']);
}
// should be: qop = auth
$a2 = 'AUTHENTICATE:'. $data['digest-uri'];
return md5(sprintf('%s:%s:%s:%s:%s:%s', md5($a1), $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'], md5($a2)));
}
/**
* parse_data like a="b",c="d",... or like a="a, b", c, d="e", f=g,...
* @param string $data
* @access public
* @return array a => b ...
*/
function parse_data($data)
{
$data = explode(',', $data);
$pairs = array();
$key = false;
foreach ($data as $pair)
{
$dd = strpos($pair, '=');
if ($dd)
{
$key = trim(substr($pair, 0, $dd));
$pairs[$key] = trim(trim(substr($pair, $dd + 1)), '"');
}
else if (strpos(strrev(trim($pair)), '"') === 0 && $key)
{
// We are actually having something left from "a, b" values, add it to the last one we handled.
$pairs[$key] .= ',' . trim(trim($pair), '"');
continue;
}
}
return $pairs;
}
/**
* opposite of jabber::parse_data()
* @param array $data
* @access public
* @return string
*/
function implode_data($data)
{
$return = array();
foreach ($data as $key => $value)
{
$return[] = $key . '="' . $value . '"';
}
return implode(',', $return);
}
/**
* xmlize()
* @author Hans Anderson
* @copyright Hans Anderson / http://www.hansanderson.com/php/xml/
*/
function xmlize($data, $skip_white = 1, $encoding = 'UTF-8')
{
$data = trim($data);
if (substr($data, 0, 5) != '<?xml')
{
// mod
$data = '<root>'. $data . '</root>';
}
$vals = $index = $array = array();
$parser = xml_parser_create($encoding);
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, $skip_white);
xml_parse_into_struct($parser, $data, $vals, $index);
xml_parser_free($parser);
$i = 0;
$tagname = $vals[$i]['tag'];
$array[$tagname][0]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array();
$array[$tagname][0]['#'] = $this->_xml_depth($vals, $i);
if (substr($data, 0, 5) != '<?xml')
{
$array = $array['root'][0]['#'];
}
return $array;
}
/**
* _xml_depth()
* @author Hans Anderson
* @copyright Hans Anderson / http://www.hansanderson.com/php/xml/
*/
function _xml_depth($vals, &$i)
{
$children = array();
if (isset($vals[$i]['value']))
{
array_push($children, $vals[$i]['value']);
}
while (++$i < count($vals))
{
switch ($vals[$i]['type'])
{
case 'open':
$tagname = (isset($vals[$i]['tag'])) ? $vals[$i]['tag'] : '';
$size = (isset($children[$tagname])) ? count($children[$tagname]) : 0;
if (isset($vals[$i]['attributes']))
{
$children[$tagname][$size]['@'] = $vals[$i]['attributes'];
}
$children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i);
break;
case 'cdata':
array_push($children, $vals[$i]['value']);
break;
case 'complete':
$tagname = $vals[$i]['tag'];
$size = (isset($children[$tagname])) ? count($children[$tagname]) : 0;
$children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? $vals[$i]['value'] : array();
if (isset($vals[$i]['attributes']))
{
$children[$tagname][$size]['@'] = $vals[$i]['attributes'];
}
break;
case 'close':
return $children;
break;
}
}
return $children;
}
}

743
includes/functions_mcp.php Normal file
View File

@@ -0,0 +1,743 @@
<?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;
}
/**
* Functions used to generate additional URL paramters
*/
function phpbb_module__url($mode, $module_row)
{
return phpbb_extra_url();
}
function phpbb_module_notes_url($mode, $module_row)
{
if ($mode == 'front')
{
return '';
}
global $user_id;
return ($user_id) ? "&amp;u=$user_id" : '';
}
function phpbb_module_warn_url($mode, $module_row)
{
if ($mode == 'front' || $mode == 'list')
{
global $forum_id;
return ($forum_id) ? "&amp;f=$forum_id" : '';
}
if ($mode == 'warn_post')
{
global $forum_id, $post_id;
$url_extra = ($forum_id) ? "&amp;f=$forum_id" : '';
$url_extra .= ($post_id) ? "&amp;p=$post_id" : '';
return $url_extra;
}
else
{
global $user_id;
return ($user_id) ? "&amp;u=$user_id" : '';
}
}
function phpbb_module_main_url($mode, $module_row)
{
return phpbb_extra_url();
}
function phpbb_module_logs_url($mode, $module_row)
{
return phpbb_extra_url();
}
function phpbb_module_ban_url($mode, $module_row)
{
return phpbb_extra_url();
}
function phpbb_module_queue_url($mode, $module_row)
{
return phpbb_extra_url();
}
function phpbb_module_reports_url($mode, $module_row)
{
return phpbb_extra_url();
}
function phpbb_extra_url()
{
global $forum_id, $topic_id, $post_id, $report_id, $user_id;
$url_extra = '';
$url_extra .= ($forum_id) ? "&amp;f=$forum_id" : '';
$url_extra .= ($topic_id) ? "&amp;t=$topic_id" : '';
$url_extra .= ($post_id) ? "&amp;p=$post_id" : '';
$url_extra .= ($user_id) ? "&amp;u=$user_id" : '';
$url_extra .= ($report_id) ? "&amp;r=$report_id" : '';
return $url_extra;
}
/**
* Get simple topic data
*/
function phpbb_get_topic_data($topic_ids, $acl_list = false, $read_tracking = false)
{
global $auth, $db, $config, $user;
static $rowset = array();
$topics = array();
if (!count($topic_ids))
{
return array();
}
// cache might not contain read tracking info, so we can't use it if read
// tracking information is requested
if (!$read_tracking)
{
$cache_topic_ids = array_intersect($topic_ids, array_keys($rowset));
$topic_ids = array_diff($topic_ids, array_keys($rowset));
}
else
{
$cache_topic_ids = array();
}
if (count($topic_ids))
{
$sql_array = array(
'SELECT' => 't.*, f.*',
'FROM' => array(
TOPICS_TABLE => 't',
),
'LEFT_JOIN' => array(
array(
'FROM' => array(FORUMS_TABLE => 'f'),
'ON' => 'f.forum_id = t.forum_id'
)
),
'WHERE' => $db->sql_in_set('t.topic_id', $topic_ids)
);
if ($read_tracking && $config['load_db_lastread'])
{
$sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time';
$sql_array['LEFT_JOIN'][] = array(
'FROM' => array(TOPICS_TRACK_TABLE => 'tt'),
'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id'
);
$sql_array['LEFT_JOIN'][] = array(
'FROM' => array(FORUMS_TRACK_TABLE => 'ft'),
'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id'
);
}
$sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$rowset[$row['topic_id']] = $row;
if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
{
continue;
}
$topics[$row['topic_id']] = $row;
}
$db->sql_freeresult($result);
}
foreach ($cache_topic_ids as $id)
{
if (!$acl_list || $auth->acl_gets($acl_list, $rowset[$id]['forum_id']))
{
$topics[$id] = $rowset[$id];
}
}
return $topics;
}
/**
* Get simple post data
*/
function phpbb_get_post_data($post_ids, $acl_list = false, $read_tracking = false)
{
global $db, $auth, $config, $user, $phpbb_container;
$rowset = array();
if (!count($post_ids))
{
return array();
}
$sql_array = array(
'SELECT' => 'p.*, u.*, t.*, f.*',
'FROM' => array(
USERS_TABLE => 'u',
POSTS_TABLE => 'p',
TOPICS_TABLE => 't',
),
'LEFT_JOIN' => array(
array(
'FROM' => array(FORUMS_TABLE => 'f'),
'ON' => 'f.forum_id = t.forum_id'
)
),
'WHERE' => $db->sql_in_set('p.post_id', $post_ids) . '
AND u.user_id = p.poster_id
AND t.topic_id = p.topic_id',
);
if ($read_tracking && $config['load_db_lastread'])
{
$sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time';
$sql_array['LEFT_JOIN'][] = array(
'FROM' => array(TOPICS_TRACK_TABLE => 'tt'),
'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id'
);
$sql_array['LEFT_JOIN'][] = array(
'FROM' => array(FORUMS_TRACK_TABLE => 'ft'),
'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id'
);
}
$sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
unset($sql_array);
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
while ($row = $db->sql_fetchrow($result))
{
if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
{
continue;
}
if (!$phpbb_content_visibility->is_visible('post', $row['forum_id'], $row))
{
// Moderators without the permission to approve post should at least not see them. ;)
continue;
}
$rowset[$row['post_id']] = $row;
}
$db->sql_freeresult($result);
return $rowset;
}
/**
* Get simple forum data
*/
function phpbb_get_forum_data($forum_id, $acl_list = 'f_list', $read_tracking = false)
{
global $auth, $db, $user, $config, $phpbb_container;
$rowset = array();
if (!is_array($forum_id))
{
$forum_id = array($forum_id);
}
if (!count($forum_id))
{
return array();
}
if ($read_tracking && $config['load_db_lastread'])
{
$read_tracking_join = ' LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . '
AND ft.forum_id = f.forum_id)';
$read_tracking_select = ', ft.mark_time';
}
else
{
$read_tracking_join = $read_tracking_select = '';
}
$sql = "SELECT f.* $read_tracking_select
FROM " . FORUMS_TABLE . " f$read_tracking_join
WHERE " . $db->sql_in_set('f.forum_id', $forum_id);
$result = $db->sql_query($sql);
/* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
while ($row = $db->sql_fetchrow($result))
{
if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
{
continue;
}
$row['forum_topics_approved'] = $phpbb_content_visibility->get_count('forum_topics', $row, $row['forum_id']);
$rowset[$row['forum_id']] = $row;
}
$db->sql_freeresult($result);
return $rowset;
}
/**
* Get simple pm data
*/
function phpbb_get_pm_data($pm_ids)
{
global $db;
$rowset = array();
if (!count($pm_ids))
{
return array();
}
$sql_array = array(
'SELECT' => 'p.*, u.*',
'FROM' => array(
USERS_TABLE => 'u',
PRIVMSGS_TABLE => 'p',
),
'WHERE' => $db->sql_in_set('p.msg_id', $pm_ids) . '
AND u.user_id = p.author_id',
);
$sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
unset($sql_array);
while ($row = $db->sql_fetchrow($result))
{
$rowset[$row['msg_id']] = $row;
}
$db->sql_freeresult($result);
return $rowset;
}
/**
* sorting in mcp
*
* @param string $where_sql should either be WHERE (default if ommited) or end with AND or OR
*
* $mode reports and reports_closed: the $where parameters uses aliases p for posts table and r for report table
* $mode unapproved_posts: the $where parameters uses aliases p for posts table and t for topic table
*/
function phpbb_mcp_sorting($mode, &$sort_days_val, &$sort_key_val, &$sort_dir_val, &$sort_by_sql_ary, &$sort_order_sql, &$total_val, $forum_id = 0, $topic_id = 0, $where_sql = 'WHERE')
{
global $db, $user, $auth, $template, $request, $phpbb_dispatcher;
$sort_days_val = $request->variable('st', 0);
$min_time = ($sort_days_val) ? time() - ($sort_days_val * 86400) : 0;
switch ($mode)
{
case 'viewforum':
$type = 'topics';
$default_key = 't';
$default_dir = 'd';
$sql = 'SELECT COUNT(topic_id) AS total
FROM ' . TOPICS_TABLE . "
$where_sql forum_id = $forum_id
AND topic_type NOT IN (" . POST_ANNOUNCE . ', ' . POST_GLOBAL . ")
AND topic_last_post_time >= $min_time";
if (!$auth->acl_get('m_approve', $forum_id))
{
$sql .= ' AND topic_visibility = ' . ITEM_APPROVED;
}
break;
case 'viewtopic':
$type = 'posts';
$default_key = 't';
$default_dir = 'a';
$sql = 'SELECT COUNT(post_id) AS total
FROM ' . POSTS_TABLE . "
$where_sql topic_id = $topic_id
AND post_time >= $min_time";
if (!$auth->acl_get('m_approve', $forum_id))
{
$sql .= ' AND post_visibility = ' . ITEM_APPROVED;
}
break;
case 'unapproved_posts':
case 'deleted_posts':
$visibility_const = ($mode == 'unapproved_posts') ? array(ITEM_UNAPPROVED, ITEM_REAPPROVE) : ITEM_DELETED;
$type = 'posts';
$default_key = 't';
$default_dir = 'd';
$where_sql .= ($topic_id) ? ' p.topic_id = ' . $topic_id . ' AND' : '';
$sql = 'SELECT COUNT(p.post_id) AS total
FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t
$where_sql " . $db->sql_in_set('p.forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_approve'))) . '
AND ' . $db->sql_in_set('p.post_visibility', $visibility_const) .'
AND t.topic_id = p.topic_id
AND t.topic_visibility <> p.post_visibility';
if ($min_time)
{
$sql .= ' AND post_time >= ' . $min_time;
}
break;
case 'unapproved_topics':
case 'deleted_topics':
$visibility_const = ($mode == 'unapproved_topics') ? array(ITEM_UNAPPROVED, ITEM_REAPPROVE) : ITEM_DELETED;
$type = 'topics';
$default_key = 't';
$default_dir = 'd';
$sql = 'SELECT COUNT(topic_id) AS total
FROM ' . TOPICS_TABLE . "
$where_sql " . $db->sql_in_set('forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_approve'))) . '
AND ' . $db->sql_in_set('topic_visibility', $visibility_const);
if ($min_time)
{
$sql .= ' AND topic_time >= ' . $min_time;
}
break;
case 'pm_reports':
case 'pm_reports_closed':
case 'reports':
case 'reports_closed':
$pm = (strpos($mode, 'pm_') === 0) ? true : false;
$type = ($pm) ? 'pm_reports' : 'reports';
$default_key = 't';
$default_dir = 'd';
$limit_time_sql = ($min_time) ? "AND r.report_time >= $min_time" : '';
if ($topic_id)
{
$where_sql .= ' p.topic_id = ' . $topic_id . ' AND ';
}
else if ($forum_id)
{
$where_sql .= ' p.forum_id = ' . $forum_id . ' AND ';
}
else if (!$pm)
{
$where_sql .= ' ' . $db->sql_in_set('p.forum_id', get_forum_list(array('!f_read', '!m_report')), true, true) . ' AND ';
}
if ($mode == 'reports' || $mode == 'pm_reports')
{
$where_sql .= ' r.report_closed = 0 AND ';
}
else
{
$where_sql .= ' r.report_closed = 1 AND ';
}
if ($pm)
{
$sql = 'SELECT COUNT(r.report_id) AS total
FROM ' . REPORTS_TABLE . ' r, ' . PRIVMSGS_TABLE . " p
$where_sql r.post_id = 0
AND p.msg_id = r.pm_id
$limit_time_sql";
}
else
{
$sql = 'SELECT COUNT(r.report_id) AS total
FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . " p
$where_sql r.pm_id = 0
AND p.post_id = r.post_id
$limit_time_sql";
}
break;
case 'viewlogs':
$type = 'logs';
$default_key = 't';
$default_dir = 'd';
$sql = 'SELECT COUNT(log_id) AS total
FROM ' . LOG_TABLE . "
$where_sql " . $db->sql_in_set('forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_'))) . '
AND log_time >= ' . $min_time . '
AND log_type = ' . LOG_MOD;
break;
}
$sort_key_val = $request->variable('sk', $default_key);
$sort_dir_val = $request->variable('sd', $default_dir);
$sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']);
switch ($type)
{
case 'topics':
$limit_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'tt' => $user->lang['TOPIC_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']);
$sort_by_sql_ary = array('a' => 't.topic_first_poster_name', 't' => array('t.topic_last_post_time', 't.topic_last_post_id'), 'tt' => 't.topic_time', 'r' => (($auth->acl_get('m_approve', $forum_id)) ? 't.topic_posts_approved + t.topic_posts_unapproved + t.topic_posts_softdeleted' : 't.topic_posts_approved'), 's' => 't.topic_title', 'v' => 't.topic_views');
$limit_time_sql = ($min_time) ? "AND t.topic_last_post_time >= $min_time" : '';
break;
case 'posts':
$limit_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']);
$sort_by_sql_ary = array('a' => 'u.username_clean', 't' => array('p.post_time', 'p.post_id'), 's' => 'p.post_subject');
$limit_time_sql = ($min_time) ? "AND p.post_time >= $min_time" : '';
break;
case 'reports':
$limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']);
$sort_by_sql_ary = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => array('p.post_time', 'p.post_id'), 't' => 'r.report_time', 's' => 'p.post_subject');
break;
case 'pm_reports':
$limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']);
$sort_by_sql_ary = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => 'p.message_time', 't' => 'r.report_time', 's' => 'p.message_subject');
break;
case 'logs':
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('u' => $user->lang['SORT_USERNAME'], 't' => $user->lang['SORT_DATE'], 'i' => $user->lang['SORT_IP'], 'o' => $user->lang['SORT_ACTION']);
$sort_by_sql_ary = array('u' => 'u.username_clean', 't' => 'l.log_time', 'i' => 'l.log_ip', 'o' => 'l.log_operation');
$limit_time_sql = ($min_time) ? "AND l.log_time >= $min_time" : '';
break;
}
// Default total to -1 to allow editing by the event
$total_val = -1;
$sort_by_sql = $sort_by_sql_ary;
$sort_days = $sort_days_val;
$sort_dir = $sort_dir_val;
$sort_key = $sort_key_val;
$total = $total_val;
/**
* This event allows you to control the SQL query used to get the total number
* of reports the user can access.
*
* This total is used for the pagination and for displaying the total number
* of reports to the user
*
*
* @event core.mcp_sorting_query_before
* @var string sql The current SQL search string
* @var string mode An id related to the module(s) the user is viewing
* @var string type Which kind of information is this being used for displaying. Posts, topics, etc...
* @var int forum_id The forum id of the posts the user is trying to access, if not 0
* @var int topic_id The topic id of the posts the user is trying to access, if not 0
* @var int sort_days The max age of the oldest report to be shown, in days
* @var string sort_key The way the user has decided to sort the data.
* The valid values must be in the keys of the sort_by_* variables
* @var string sort_dir Either 'd' for "DESC" or 'a' for 'ASC' in the SQL query
* @var int limit_days The possible max ages of the oldest report for the user to choose, in days.
* @var array sort_by_sql SQL text (values) for the possible names of the ways of sorting data (keys).
* @var array sort_by_text Language text (values) for the possible names of the ways of sorting data (keys).
* @var int min_time Integer with the minimum post time that the user is searching for
* @var int limit_time_sql Time limiting options used in the SQL query.
* @var int total The total number of reports that exist. Only set if you want to override the result
* @var string where_sql Extra information included in the WHERE clause. It must end with "WHERE" or "AND" or "OR".
* Set to "WHERE" and set total above -1 to override the total value
* @since 3.1.4-RC1
*/
$vars = array(
'sql',
'mode',
'type',
'forum_id',
'topic_id',
'sort_days',
'sort_key',
'sort_dir',
'limit_days',
'sort_by_sql',
'sort_by_text',
'min_time',
'limit_time_sql',
'total',
'where_sql',
);
extract($phpbb_dispatcher->trigger_event('core.mcp_sorting_query_before', compact($vars)));
$sort_by_sql_ary = $sort_by_sql;
$sort_days_val = $sort_days;
$sort_key_val = $sort_key;
$sort_dir_val = $sort_dir;
$total_val = $total;
unset($sort_by_sql);
unset($sort_days);
unset($sort_key);
unset($sort_dir);
unset($total);
if (!isset($sort_by_sql_ary[$sort_key_val]))
{
$sort_key_val = $default_key;
}
$direction = ($sort_dir_val == 'd') ? 'DESC' : 'ASC';
if (is_array($sort_by_sql_ary[$sort_key_val]))
{
$sort_order_sql = implode(' ' . $direction . ', ', $sort_by_sql_ary[$sort_key_val]) . ' ' . $direction;
}
else
{
$sort_order_sql = $sort_by_sql_ary[$sort_key_val] . ' ' . $direction;
}
$s_limit_days = $s_sort_key = $s_sort_dir = $sort_url = '';
gen_sort_selects($limit_days, $sort_by_text, $sort_days_val, $sort_key_val, $sort_dir_val, $s_limit_days, $s_sort_key, $s_sort_dir, $sort_url);
$template->assign_vars(array(
'S_SELECT_SORT_DIR' => $s_sort_dir,
'S_SELECT_SORT_KEY' => $s_sort_key,
'S_SELECT_SORT_DAYS' => $s_limit_days)
);
if (($sort_days_val && $mode != 'viewlogs') || in_array($mode, array('reports', 'unapproved_topics', 'unapproved_posts', 'deleted_topics', 'deleted_posts')) || $where_sql != 'WHERE')
{
$result = $db->sql_query($sql);
$total_val = (int) $db->sql_fetchfield('total');
$db->sql_freeresult($result);
}
else if ($total_val < -1)
{
$total_val = -1;
}
}
/**
* Validate ids
*
* @param array &$ids The relevant ids to check
* @param string $table The table to find the ids in
* @param string $sql_id The ids relevant column name
* @param array $acl_list A list of permissions the user need to have
* @param mixed $singe_forum Limit to one forum id (int) or the first forum found (true)
*
* @return mixed False if no ids were able to be retrieved, true if at least one id left.
* Additionally, this value can be the forum_id assigned if $single_forum was set.
* Therefore checking the result for with !== false is the best method.
*/
function phpbb_check_ids(&$ids, $table, $sql_id, $acl_list = false, $single_forum = false)
{
global $db, $auth;
if (!is_array($ids) || empty($ids))
{
return false;
}
$sql = "SELECT $sql_id, forum_id FROM $table
WHERE " . $db->sql_in_set($sql_id, $ids);
$result = $db->sql_query($sql);
$ids = array();
$forum_id = false;
while ($row = $db->sql_fetchrow($result))
{
if ($acl_list && $row['forum_id'] && !$auth->acl_gets($acl_list, $row['forum_id']))
{
continue;
}
if ($acl_list && !$row['forum_id'] && !$auth->acl_getf_global($acl_list))
{
continue;
}
// Limit forum? If not, just assign the id.
if ($single_forum === false)
{
$ids[] = $row[$sql_id];
continue;
}
// Limit forum to a specific forum id?
// This can get really tricky, because we do not want to create a failure on global topics. :)
if ($row['forum_id'])
{
if ($single_forum !== true && $row['forum_id'] == (int) $single_forum)
{
$forum_id = (int) $single_forum;
}
else if ($forum_id === false)
{
$forum_id = $row['forum_id'];
}
if ($row['forum_id'] == $forum_id)
{
$ids[] = $row[$sql_id];
}
}
else
{
// Always add a global topic
$ids[] = $row[$sql_id];
}
}
$db->sql_freeresult($result);
if (!count($ids))
{
return false;
}
// If forum id is false and ids populated we may have only global announcements selected (returning 0 because of (int) $forum_id)
return ($single_forum === false) ? true : (int) $forum_id;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,899 @@
<?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;
}
/**
* Transfer class, wrapper for ftp/sftp/ssh
*/
class transfer
{
var $connection;
var $host;
var $port;
var $username;
var $password;
var $timeout;
var $root_path;
var $tmp_path;
var $file_perms;
var $dir_perms;
/**
* Constructor - init some basic values
*/
function __construct()
{
global $phpbb_root_path;
$this->file_perms = 0644;
$this->dir_perms = 0777;
// We use the store directory as temporary path to circumvent open basedir restrictions
$this->tmp_path = $phpbb_root_path . 'store/';
}
/**
* Write file to location
*/
function write_file($destination_file = '', $contents = '')
{
global $phpbb_root_path;
$destination_file = $this->root_path . str_replace($phpbb_root_path, '', $destination_file);
// need to create a temp file and then move that temp file.
// ftp functions can only move files around and can't create.
// This means that the users will need to have access to write
// temporary files or have write access on a folder within phpBB
// like the cache folder. If the user can't do either, then
// he/she needs to use the fsock ftp method
$temp_name = tempnam($this->tmp_path, 'transfer_');
@unlink($temp_name);
$fp = @fopen($temp_name, 'w');
if (!$fp)
{
trigger_error('Unable to create temporary file ' . $temp_name, E_USER_ERROR);
}
@fwrite($fp, $contents);
@fclose($fp);
$result = $this->overwrite_file($temp_name, $destination_file);
// remove temporary file now
@unlink($temp_name);
return $result;
}
/**
* Moving file into location. If the destination file already exists it gets overwritten
*/
function overwrite_file($source_file, $destination_file)
{
/**
* @todo generally think about overwriting files in another way, by creating a temporary file and then renaming it
* @todo check for the destination file existance too
*/
$this->_delete($destination_file);
$result = $this->_put($source_file, $destination_file);
$this->_chmod($destination_file, $this->file_perms);
return $result;
}
/**
* Create directory structure
*/
function make_dir($dir)
{
global $phpbb_root_path;
$dir = str_replace($phpbb_root_path, '', $dir);
$dir = explode('/', $dir);
$dirs = '';
for ($i = 0, $total = count($dir); $i < $total; $i++)
{
$result = true;
if (strpos($dir[$i], '.') === 0)
{
continue;
}
$cur_dir = $dir[$i] . '/';
if (!file_exists($phpbb_root_path . $dirs . $cur_dir))
{
// create the directory
$result = $this->_mkdir($dir[$i]);
$this->_chmod($dir[$i], $this->dir_perms);
}
$this->_chdir($this->root_path . $dirs . $dir[$i]);
$dirs .= $cur_dir;
}
$this->_chdir($this->root_path);
/**
* @todo stack result into array to make sure every path creation has been taken care of
*/
return $result;
}
/**
* Copy file from source location to destination location
*/
function copy_file($from_loc, $to_loc)
{
global $phpbb_root_path;
$from_loc = ((strpos($from_loc, $phpbb_root_path) !== 0) ? $phpbb_root_path : '') . $from_loc;
$to_loc = $this->root_path . str_replace($phpbb_root_path, '', $to_loc);
if (!file_exists($from_loc))
{
return false;
}
$result = $this->overwrite_file($from_loc, $to_loc);
return $result;
}
/**
* Remove file
*/
function delete_file($file)
{
global $phpbb_root_path;
$file = $this->root_path . str_replace($phpbb_root_path, '', $file);
return $this->_delete($file);
}
/**
* Remove directory
* @todo remove child directories?
*/
function remove_dir($dir)
{
global $phpbb_root_path;
$dir = $this->root_path . str_replace($phpbb_root_path, '', $dir);
return $this->_rmdir($dir);
}
/**
* Rename a file or folder
*/
function rename($old_handle, $new_handle)
{
global $phpbb_root_path;
$old_handle = $this->root_path . str_replace($phpbb_root_path, '', $old_handle);
return $this->_rename($old_handle, $new_handle);
}
/**
* Check if a specified file exist...
*/
function file_exists($directory, $filename)
{
global $phpbb_root_path;
$directory = $this->root_path . str_replace($phpbb_root_path, '', $directory);
$this->_chdir($directory);
$result = $this->_ls();
if ($result !== false && is_array($result))
{
return (in_array($filename, $result)) ? true : false;
}
return false;
}
/**
* Open session
*/
function open_session()
{
return $this->_init();
}
/**
* Close current session
*/
function close_session()
{
return $this->_close();
}
/**
* Determine methods able to be used
*/
static public function methods()
{
$methods = array();
$disabled_functions = explode(',', @ini_get('disable_functions'));
if (@extension_loaded('ftp'))
{
$methods[] = 'ftp';
}
if (!in_array('fsockopen', $disabled_functions))
{
$methods[] = 'ftp_fsock';
}
return $methods;
}
}
/**
* FTP transfer class
*/
class ftp extends transfer
{
/**
* Standard parameters for FTP session
*/
function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
{
$this->host = $host;
$this->port = $port;
$this->username = $username;
$this->password = $password;
$this->timeout = $timeout;
// Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
$this->root_path = str_replace('\\', '/', $this->root_path);
if (!empty($root_path))
{
$this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
}
// Init some needed values
$this->transfer();
return;
}
/**
* Requests data
*/
static public function data()
{
global $user;
return array(
'host' => 'localhost',
'username' => 'anonymous',
'password' => '',
'root_path' => $user->page['root_script_path'],
'port' => 21,
'timeout' => 10
);
}
/**
* Init FTP Session
* @access private
*/
function _init()
{
// connect to the server
$this->connection = @ftp_connect($this->host, $this->port, $this->timeout);
if (!$this->connection)
{
return 'ERR_CONNECTING_SERVER';
}
// login to the server
if (!@ftp_login($this->connection, $this->username, $this->password))
{
return 'ERR_UNABLE_TO_LOGIN';
}
// attempt to turn pasv mode on
@ftp_pasv($this->connection, true);
// change to the root directory
if (!$this->_chdir($this->root_path))
{
return 'ERR_CHANGING_DIRECTORY';
}
return true;
}
/**
* Create Directory (MKDIR)
* @access private
*/
function _mkdir($dir)
{
return @ftp_mkdir($this->connection, $dir);
}
/**
* Remove directory (RMDIR)
* @access private
*/
function _rmdir($dir)
{
return @ftp_rmdir($this->connection, $dir);
}
/**
* Rename file
* @access private
*/
function _rename($old_handle, $new_handle)
{
return @ftp_rename($this->connection, $old_handle, $new_handle);
}
/**
* Change current working directory (CHDIR)
* @access private
*/
function _chdir($dir = '')
{
if ($dir && $dir !== '/')
{
if (substr($dir, -1, 1) == '/')
{
$dir = substr($dir, 0, -1);
}
}
return @ftp_chdir($this->connection, $dir);
}
/**
* change file permissions (CHMOD)
* @access private
*/
function _chmod($file, $perms)
{
if (function_exists('ftp_chmod'))
{
$err = @ftp_chmod($this->connection, $perms, $file);
}
else
{
// Unfortunatly CHMOD is not expecting an octal value...
// We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
$chmod_cmd = 'CHMOD ' . base_convert($perms, 10, 8) . ' ' . $file;
$err = $this->_site($chmod_cmd);
}
return $err;
}
/**
* Upload file to location (PUT)
* @access private
*/
function _put($from_file, $to_file)
{
// We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
$mode = FTP_BINARY;
$to_dir = dirname($to_file);
$to_file = basename($to_file);
$this->_chdir($to_dir);
$result = @ftp_put($this->connection, $to_file, $from_file, $mode);
$this->_chdir($this->root_path);
return $result;
}
/**
* Delete file (DELETE)
* @access private
*/
function _delete($file)
{
return @ftp_delete($this->connection, $file);
}
/**
* Close ftp session (CLOSE)
* @access private
*/
function _close()
{
if (!$this->connection)
{
return false;
}
return @ftp_quit($this->connection);
}
/**
* Return current working directory (CWD)
* At the moment not used by parent class
* @access private
*/
function _cwd()
{
return @ftp_pwd($this->connection);
}
/**
* Return list of files in a given directory (LS)
* @access private
*/
function _ls($dir = './')
{
$list = @ftp_nlist($this->connection, $dir);
// See bug #46295 - Some FTP daemons don't like './'
if ($dir === './')
{
// Let's try some alternatives
$list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list;
$list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list;
}
// Return on error
if ($list === false)
{
return false;
}
// Remove path if prepended
foreach ($list as $key => $item)
{
// Use same separator for item and dir
$item = str_replace('\\', '/', $item);
$dir = str_replace('\\', '/', $dir);
if (!empty($dir) && strpos($item, $dir) === 0)
{
$item = substr($item, strlen($dir));
}
$list[$key] = $item;
}
return $list;
}
/**
* FTP SITE command (ftp-only function)
* @access private
*/
function _site($command)
{
return @ftp_site($this->connection, $command);
}
}
/**
* FTP fsock transfer class
*/
class ftp_fsock extends transfer
{
var $data_connection;
/**
* Standard parameters for FTP session
*/
function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
{
$this->host = $host;
$this->port = $port;
$this->username = $username;
$this->password = $password;
$this->timeout = $timeout;
// Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end)
$this->root_path = str_replace('\\', '/', $this->root_path);
if (!empty($root_path))
{
$this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/');
}
// Init some needed values
parent::__construct();
return;
}
/**
* Requests data
*/
static public function data()
{
global $user;
return array(
'host' => 'localhost',
'username' => 'anonymous',
'password' => '',
'root_path' => $user->page['root_script_path'],
'port' => 21,
'timeout' => 10
);
}
/**
* Init FTP Session
* @access private
*/
function _init()
{
$errno = 0;
$errstr = '';
// connect to the server
$this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
if (!$this->connection || !$this->_check_command())
{
return 'ERR_CONNECTING_SERVER';
}
@stream_set_timeout($this->connection, $this->timeout);
// login
if (!$this->_send_command('USER', $this->username))
{
return 'ERR_UNABLE_TO_LOGIN';
}
if (!$this->_send_command('PASS', $this->password))
{
return 'ERR_UNABLE_TO_LOGIN';
}
// change to the root directory
if (!$this->_chdir($this->root_path))
{
return 'ERR_CHANGING_DIRECTORY';
}
return true;
}
/**
* Create Directory (MKDIR)
* @access private
*/
function _mkdir($dir)
{
return $this->_send_command('MKD', $dir);
}
/**
* Remove directory (RMDIR)
* @access private
*/
function _rmdir($dir)
{
return $this->_send_command('RMD', $dir);
}
/**
* Rename File
* @access private
*/
function _rename($old_handle, $new_handle)
{
$this->_send_command('RNFR', $old_handle);
return $this->_send_command('RNTO', $new_handle);
}
/**
* Change current working directory (CHDIR)
* @access private
*/
function _chdir($dir = '')
{
if ($dir && $dir !== '/')
{
if (substr($dir, -1, 1) == '/')
{
$dir = substr($dir, 0, -1);
}
}
return $this->_send_command('CWD', $dir);
}
/**
* change file permissions (CHMOD)
* @access private
*/
function _chmod($file, $perms)
{
// Unfortunatly CHMOD is not expecting an octal value...
// We need to transform the integer (which was an octal) to an octal representation (to get the int) and then pass as is. ;)
return $this->_send_command('SITE CHMOD', base_convert($perms, 10, 8) . ' ' . $file);
}
/**
* Upload file to location (PUT)
* @access private
*/
function _put($from_file, $to_file)
{
// We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
// 'I' == BINARY
// 'A' == ASCII
if (!$this->_send_command('TYPE', 'I'))
{
return false;
}
// open the connection to send file over
if (!$this->_open_data_connection())
{
return false;
}
$this->_send_command('STOR', $to_file, false);
// send the file
$fp = @fopen($from_file, 'rb');
while (!@feof($fp))
{
@fwrite($this->data_connection, @fread($fp, 4096));
}
@fclose($fp);
// close connection
$this->_close_data_connection();
return $this->_check_command();
}
/**
* Delete file (DELETE)
* @access private
*/
function _delete($file)
{
return $this->_send_command('DELE', $file);
}
/**
* Close ftp session (CLOSE)
* @access private
*/
function _close()
{
if (!$this->connection)
{
return false;
}
return $this->_send_command('QUIT');
}
/**
* Return current working directory (CWD)
* At the moment not used by parent class
* @access private
*/
function _cwd()
{
$this->_send_command('PWD', '', false);
return preg_replace('#^[0-9]{3} "(.+)" .+\r\n#', '\\1', $this->_check_command(true));
}
/**
* Return list of files in a given directory (LS)
* @access private
*/
function _ls($dir = './')
{
if (!$this->_open_data_connection())
{
return false;
}
$this->_send_command('NLST', $dir);
$list = array();
while (!@feof($this->data_connection))
{
$filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512));
if ($filename !== '')
{
$list[] = $filename;
}
}
$this->_close_data_connection();
// Clear buffer
$this->_check_command();
// See bug #46295 - Some FTP daemons don't like './'
if ($dir === './' && empty($list))
{
// Let's try some alternatives
$list = $this->_ls('.');
if (empty($list))
{
$list = $this->_ls('');
}
return $list;
}
// Remove path if prepended
foreach ($list as $key => $item)
{
// Use same separator for item and dir
$item = str_replace('\\', '/', $item);
$dir = str_replace('\\', '/', $dir);
if (!empty($dir) && strpos($item, $dir) === 0)
{
$item = substr($item, strlen($dir));
}
$list[$key] = $item;
}
return $list;
}
/**
* Send a command to server (FTP fsock only function)
* @access private
*/
function _send_command($command, $args = '', $check = true)
{
if (!empty($args))
{
$command = "$command $args";
}
fwrite($this->connection, $command . "\r\n");
if ($check === true && !$this->_check_command())
{
return false;
}
return true;
}
/**
* Opens a connection to send data (FTP fosck only function)
* @access private
*/
function _open_data_connection()
{
// Try to find out whether we have a IPv4 or IPv6 (control) connection
if (function_exists('stream_socket_get_name'))
{
$socket_name = stream_socket_get_name($this->connection, true);
$server_ip = substr($socket_name, 0, strrpos($socket_name, ':'));
}
if (!isset($server_ip) || preg_match(get_preg_expression('ipv4'), $server_ip))
{
// Passive mode
$this->_send_command('PASV', '', false);
if (!$ip_port = $this->_check_command(true))
{
return false;
}
// open the connection to start sending the file
if (!preg_match('#[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+#', $ip_port, $temp))
{
// bad ip and port
return false;
}
$temp = explode(',', $temp[0]);
$server_ip = $temp[0] . '.' . $temp[1] . '.' . $temp[2] . '.' . $temp[3];
$server_port = $temp[4] * 256 + $temp[5];
}
else
{
// Extended Passive Mode - RFC2428
$this->_send_command('EPSV', '', false);
if (!$epsv_response = $this->_check_command(true))
{
return false;
}
// Response looks like "229 Entering Extended Passive Mode (|||12345|)"
// where 12345 is the tcp port for the data connection
if (!preg_match('#\(\|\|\|([0-9]+)\|\)#', $epsv_response, $match))
{
return false;
}
$server_port = (int) $match[1];
// fsockopen expects IPv6 address in square brackets
$server_ip = "[$server_ip]";
}
$errno = 0;
$errstr = '';
if (!$this->data_connection = @fsockopen($server_ip, $server_port, $errno, $errstr, $this->timeout))
{
return false;
}
@stream_set_timeout($this->data_connection, $this->timeout);
return true;
}
/**
* Closes a connection used to send data
* @access private
*/
function _close_data_connection()
{
return @fclose($this->data_connection);
}
/**
* Check to make sure command was successful (FTP fsock only function)
* @access private
*/
function _check_command($return = false)
{
$response = '';
do
{
$result = @fgets($this->connection, 512);
$response .= $result;
}
while (substr($result, 3, 1) !== ' ');
if (!preg_match('#^[123]#', $response))
{
return false;
}
return ($return) ? $response : true;
}
}

3759
includes/functions_user.php Normal file

File diff suppressed because it is too large Load Diff

250
includes/hooks/index.php Normal file
View File

@@ -0,0 +1,250 @@
<?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;
}
/**
* phpBB Hook Class
*/
class phpbb_hook
{
/**
* Registered hooks
*/
var $hooks = array();
/**
* Results returned by functions called
*/
var $hook_result = array();
/**
* internal pointer
*/
var $current_hook = NULL;
/**
* Initialize hook class.
*
* @param array $valid_hooks array containing the hookable functions/methods
*/
function __construct($valid_hooks)
{
foreach ($valid_hooks as $_null => $method)
{
$this->add_hook($method);
}
if (function_exists('phpbb_hook_register'))
{
phpbb_hook_register($this);
}
}
/**
* Register function/method to be called within hook
* This function is normally called by the modification/application to attach/register the functions.
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
* @param mixed $hook The replacement function/method to be called. Passing function name or array with object/class definition
* @param string $mode Specify the priority/chain mode. 'normal' -> hook gets appended to the chain. 'standalone' -> only the specified hook gets called - later hooks are not able to overwrite this (E_NOTICE is triggered then). 'first' -> hook is called as the first one within the chain. 'last' -> hook is called as the last one within the chain.
*/
function register($definition, $hook, $mode = 'normal')
{
$class = (!is_array($definition)) ? '__global' : $definition[0];
$function = (!is_array($definition)) ? $definition : $definition[1];
// Method able to be hooked?
if (isset($this->hooks[$class][$function]))
{
switch ($mode)
{
case 'standalone':
if (!isset($this->hooks[$class][$function]['standalone']))
{
$this->hooks[$class][$function] = array('standalone' => $hook);
}
else
{
trigger_error('Hook not able to be called standalone, previous hook already standalone.', E_NOTICE);
}
break;
case 'first':
case 'last':
$this->hooks[$class][$function][$mode][] = $hook;
break;
case 'normal':
default:
$this->hooks[$class][$function]['normal'][] = $hook;
break;
}
}
}
/**
* Calling all functions/methods attached to a specified hook.
* Called by the function allowing hooks...
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
* @return bool False if no hook got executed, true otherwise
*/
function call_hook($definition)
{
$class = (!is_array($definition)) ? '__global' : $definition[0];
$function = (!is_array($definition)) ? $definition : $definition[1];
if (!empty($this->hooks[$class][$function]))
{
// Developer tries to call a hooked function within the hooked function...
if ($this->current_hook !== NULL && $this->current_hook['class'] === $class && $this->current_hook['function'] === $function)
{
return false;
}
// Call the hook with the arguments attached and store result
$arguments = func_get_args();
$this->current_hook = array('class' => $class, 'function' => $function);
$arguments[0] = &$this;
// Call the hook chain...
if (isset($this->hooks[$class][$function]['standalone']))
{
$this->hook_result[$class][$function] = call_user_func_array($this->hooks[$class][$function]['standalone'], $arguments);
}
else
{
foreach (array('first', 'normal', 'last') as $mode)
{
if (!isset($this->hooks[$class][$function][$mode]))
{
continue;
}
foreach ($this->hooks[$class][$function][$mode] as $hook)
{
$this->hook_result[$class][$function] = call_user_func_array($hook, $arguments);
}
}
}
$this->current_hook = NULL;
return true;
}
$this->current_hook = NULL;
return false;
}
/**
* Get result from previously called functions/methods for the same hook
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
* @return mixed False if nothing returned if there is no result, else array('result' => ... )
*/
function previous_hook_result($definition)
{
$class = (!is_array($definition)) ? '__global' : $definition[0];
$function = (!is_array($definition)) ? $definition : $definition[1];
if (!empty($this->hooks[$class][$function]) && isset($this->hook_result[$class][$function]))
{
return array('result' => $this->hook_result[$class][$function]);
}
return false;
}
/**
* Check if the called functions/methods returned something.
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
* @return bool True if results are there, false if not
*/
function hook_return($definition)
{
$class = (!is_array($definition)) ? '__global' : $definition[0];
$function = (!is_array($definition)) ? $definition : $definition[1];
if (!empty($this->hooks[$class][$function]) && isset($this->hook_result[$class][$function]))
{
return true;
}
return false;
}
/**
* Give actual result from called functions/methods back.
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
* @return mixed The result
*/
function hook_return_result($definition)
{
$class = (!is_array($definition)) ? '__global' : $definition[0];
$function = (!is_array($definition)) ? $definition : $definition[1];
if (!empty($this->hooks[$class][$function]) && isset($this->hook_result[$class][$function]))
{
$result = $this->hook_result[$class][$function];
unset($this->hook_result[$class][$function]);
return $result;
}
return;
}
/**
* Add new function to the allowed hooks.
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
*/
function add_hook($definition)
{
if (!is_array($definition))
{
$definition = array('__global', $definition);
}
$this->hooks[$definition[0]][$definition[1]] = array();
}
/**
* Remove function from the allowed hooks.
*
* @param mixed $definition Declaring function (with __FUNCTION__) or class with array(__CLASS__, __FUNCTION__)
*/
function remove_hook($definition)
{
$class = (!is_array($definition)) ? '__global' : $definition[0];
$function = (!is_array($definition)) ? $definition : $definition[1];
if (isset($this->hooks[$class][$function]))
{
unset($this->hooks[$class][$function]);
if (isset($this->hook_result[$class][$function]))
{
unset($this->hook_result[$class][$function]);
}
}
}
}

10
includes/index.htm Normal file
View File

@@ -0,0 +1,10 @@
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#FFFFFF" text="#000000">
</body>
</html>

View File

@@ -0,0 +1,36 @@
<?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.
*
*/
class mcp_ban_info
{
function module()
{
return array(
'filename' => 'mcp_ban',
'title' => 'MCP_BAN',
'modes' => array(
'user' => array('title' => 'MCP_BAN_USERNAMES', 'auth' => 'acl_m_ban', 'cat' => array('MCP_BAN')),
'ip' => array('title' => 'MCP_BAN_IPS', 'auth' => 'acl_m_ban', 'cat' => array('MCP_BAN')),
'email' => array('title' => 'MCP_BAN_EMAILS', 'auth' => 'acl_m_ban', 'cat' => array('MCP_BAN')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,36 @@
<?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.
*
*/
class mcp_logs_info
{
function module()
{
return array(
'filename' => 'mcp_logs',
'title' => 'MCP_LOGS',
'modes' => array(
'front' => array('title' => 'MCP_LOGS_FRONT', 'auth' => 'acl_m_ || aclf_m_', 'cat' => array('MCP_LOGS')),
'forum_logs' => array('title' => 'MCP_LOGS_FORUM_VIEW', 'auth' => 'acl_m_,$id', 'cat' => array('MCP_LOGS')),
'topic_logs' => array('title' => 'MCP_LOGS_TOPIC_VIEW', 'auth' => 'acl_m_,$id', 'cat' => array('MCP_LOGS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,37 @@
<?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.
*
*/
class mcp_main_info
{
function module()
{
return array(
'filename' => 'mcp_main',
'title' => 'MCP_MAIN',
'modes' => array(
'front' => array('title' => 'MCP_MAIN_FRONT', 'auth' => '', 'cat' => array('MCP_MAIN')),
'forum_view' => array('title' => 'MCP_MAIN_FORUM_VIEW', 'auth' => 'acl_m_,$id', 'cat' => array('MCP_MAIN')),
'topic_view' => array('title' => 'MCP_MAIN_TOPIC_VIEW', 'auth' => 'acl_m_,$id', 'cat' => array('MCP_MAIN')),
'post_details' => array('title' => 'MCP_MAIN_POST_DETAILS', 'auth' => 'acl_m_,$id || (!$id && aclf_m_)', 'cat' => array('MCP_MAIN')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,35 @@
<?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.
*
*/
class mcp_notes_info
{
function module()
{
return array(
'filename' => 'mcp_notes',
'title' => 'MCP_NOTES',
'modes' => array(
'front' => array('title' => 'MCP_NOTES_FRONT', 'auth' => '', 'cat' => array('MCP_NOTES')),
'user_notes' => array('title' => 'MCP_NOTES_USER', 'auth' => '', 'cat' => array('MCP_NOTES')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,36 @@
<?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.
*
*/
class mcp_pm_reports_info
{
function module()
{
return array(
'filename' => 'mcp_pm_reports',
'title' => 'MCP_PM_REPORTS',
'modes' => array(
'pm_reports' => array('title' => 'MCP_PM_REPORTS_OPEN', 'auth' => 'acl_m_pm_report', 'cat' => array('MCP_REPORTS')),
'pm_reports_closed' => array('title' => 'MCP_PM_REPORTS_CLOSED', 'auth' => 'acl_m_pm_report', 'cat' => array('MCP_REPORTS')),
'pm_report_details' => array('title' => 'MCP_PM_REPORT_DETAILS', 'auth' => 'acl_m_pm_report', 'cat' => array('MCP_REPORTS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,38 @@
<?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.
*
*/
class mcp_queue_info
{
function module()
{
return array(
'filename' => 'mcp_queue',
'title' => 'MCP_QUEUE',
'modes' => array(
'unapproved_topics' => array('title' => 'MCP_QUEUE_UNAPPROVED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'unapproved_posts' => array('title' => 'MCP_QUEUE_UNAPPROVED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'deleted_topics' => array('title' => 'MCP_QUEUE_DELETED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'deleted_posts' => array('title' => 'MCP_QUEUE_DELETED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'approve_details' => array('title' => 'MCP_QUEUE_APPROVE_DETAILS', 'auth' => 'acl_m_approve,$id || (!$id && aclf_m_approve)', 'cat' => array('MCP_QUEUE')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

View File

@@ -0,0 +1,36 @@
<?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.
*
*/
class mcp_reports_info
{
function module()
{
return array(
'filename' => 'mcp_reports',
'title' => 'MCP_REPORTS',
'modes' => array(
'reports' => array('title' => 'MCP_REPORTS_OPEN', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')),
'reports_closed' => array('title' => 'MCP_REPORTS_CLOSED', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')),
'report_details' => array('title' => 'MCP_REPORT_DETAILS', 'auth' => 'acl_m_report,$id || (!$id && aclf_m_report)', 'cat' => array('MCP_REPORTS')),
),
);
}
function install()
{
}
function uninstall()
{
}
}

Some files were not shown because too many files have changed in this diff Show More