aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB')
-rw-r--r--phpBB/common.php2
-rw-r--r--phpBB/config/services.yml12
-rw-r--r--phpBB/config/tables.yml1
-rw-r--r--phpBB/download/file.php1
-rw-r--r--phpBB/includes/functions.php72
-rw-r--r--phpBB/includes/functions_admin.php281
-rw-r--r--phpBB/includes/functions_container.php1
-rw-r--r--phpBB/includes/functions_user.php8
-rw-r--r--phpBB/includes/log/interface.php106
-rw-r--r--phpBB/includes/log/log.php739
-rw-r--r--phpBB/install/database_update.php1
-rw-r--r--phpBB/install/install_install.php5
12 files changed, 917 insertions, 312 deletions
diff --git a/phpBB/common.php b/phpBB/common.php
index 5c0feb87db..c33e2cbb1f 100644
--- a/phpBB/common.php
+++ b/phpBB/common.php
@@ -111,6 +111,8 @@ $config = $phpbb_container->get('config');
set_config(null, null, null, $config);
set_config_count(null, null, null, $config);
+$phpbb_log = $phpbb_container->get('log');
+
// load extensions
$phpbb_extension_manager = $phpbb_container->get('ext.manager');
$phpbb_subscriber_loader = $phpbb_container->get('event.subscriber_loader');
diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml
index 24e80ddaf0..7b2a24b2b3 100644
--- a/phpBB/config/services.yml
+++ b/phpBB/config/services.yml
@@ -187,6 +187,18 @@ services:
tags:
- { name: kernel.event_subscriber }
+ log:
+ class: phpbb_log
+ arguments:
+ - @dbal.conn
+ - @user
+ - @auth
+ - @dispatcher
+ - %core.root_path%
+ - %core.adm_relative_path%
+ - %core.php_ext%
+ - %tables.log%
+
notification_manager:
class: phpbb_notification_manager
arguments:
diff --git a/phpBB/config/tables.yml b/phpBB/config/tables.yml
index 10db8fbab6..b3093abf0c 100644
--- a/phpBB/config/tables.yml
+++ b/phpBB/config/tables.yml
@@ -1,6 +1,7 @@
parameters:
tables.config: %core.table_prefix%config
tables.ext: %core.table_prefix%ext
+ tables.log: %core.table_prefix%log
tables.notification_types: %core.table_prefix%notification_types
tables.notifications: %core.table_prefix%notifications
tables.user_notifications: %core.table_prefix%user_notifications
diff --git a/phpBB/download/file.php b/phpBB/download/file.php
index 6537355bb0..91c05586a5 100644
--- a/phpBB/download/file.php
+++ b/phpBB/download/file.php
@@ -67,6 +67,7 @@ if (isset($_GET['avatar']))
$phpbb_dispatcher = $phpbb_container->get('dispatcher');
$request = $phpbb_container->get('request');
$db = $phpbb_container->get('dbal.conn');
+ $phpbb_log = $phpbb_container->get('log');
// Connect to DB
if (!@$db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false))
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index 6a1f144967..c0fd3918dc 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -3582,69 +3582,49 @@ function parse_cfg_file($filename, $lines = false)
}
/**
-* Add log event
+* 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 Use $phpbb_log->add() instead
*/
function add_log()
{
- global $db, $user;
-
- // In phpBB 3.1.x i want to have logging in a class to be able to control it
- // For now, we need a quite hakish approach to circumvent logging for some actions
- // @todo implement cleanly
- if (!empty($GLOBALS['skip_add_log']))
- {
- return false;
- }
+ global $phpbb_log, $user;
$args = func_get_args();
+ $mode = array_shift($args);
- $mode = array_shift($args);
- $reportee_id = ($mode == 'user') ? intval(array_shift($args)) : '';
- $forum_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $topic_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $action = array_shift($args);
- $data = (!sizeof($args)) ? '' : serialize($args);
-
- $sql_ary = array(
- 'user_id' => (empty($user->data)) ? ANONYMOUS : $user->data['user_id'],
- 'log_ip' => $user->ip,
- 'log_time' => time(),
- 'log_operation' => $action,
- 'log_data' => $data,
- );
-
+ // This looks kind of dirty, but add_log has some additional data before the log_operation
+ $additional_data = array();
switch ($mode)
{
case 'admin':
- $sql_ary['log_type'] = LOG_ADMIN;
+ case 'critical':
break;
-
case 'mod':
- $sql_ary += array(
- 'log_type' => LOG_MOD,
- 'forum_id' => $forum_id,
- 'topic_id' => $topic_id
- );
+ $additional_data['forum_id'] = array_shift($args);
+ $additional_data['topic_id'] = array_shift($args);
break;
-
case 'user':
- $sql_ary += array(
- 'log_type' => LOG_USERS,
- 'reportee_id' => $reportee_id
- );
- break;
-
- case 'critical':
- $sql_ary['log_type'] = LOG_CRITICAL;
+ $additional_data['reportee_id'] = array_shift($args);
break;
-
- default:
- return false;
}
- $db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
+ $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 $db->sql_nextid();
+ return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
}
/**
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index baf107bcda..d273b9fb3a 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -2506,273 +2506,32 @@ function cache_moderators()
/**
* View log
-* If $log_count is set to false, we will skip counting all entries in the database.
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param array &$log The result array with the logs
+* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database.
+* Otherwise an integer with the number of total matching entries is returned.
+* @param int $limit Limit the number of entries that are returned
+* @param int $offset Offset when fetching the log entries, f.e. when paginating
+* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids)
+* @param int $topic_id Restrict the log entries to the given topic_id
+* @param int $user_id Restrict the log entries to the given user_id
+* @param int $log_time Only get log entries newer than the given timestamp
+* @param string $sort_by SQL order option, e.g. 'l.log_time DESC'
+* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data
+*
+* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high)
*/
function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '')
{
- global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
-
- $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
-
- $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile');
-
- switch ($mode)
- {
- case 'admin':
- $log_type = LOG_ADMIN;
- $sql_forum = '';
- break;
-
- case 'mod':
- $log_type = LOG_MOD;
- $sql_forum = '';
-
- if ($topic_id)
- {
- $sql_forum = 'AND l.topic_id = ' . (int) $topic_id;
- }
- else if (is_array($forum_id))
- {
- $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
- }
- else if ($forum_id)
- {
- $sql_forum = 'AND l.forum_id = ' . (int) $forum_id;
- }
- break;
-
- case 'user':
- $log_type = LOG_USERS;
- $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
- break;
-
- case 'users':
- $log_type = LOG_USERS;
- $sql_forum = '';
- break;
-
- case 'critical':
- $log_type = LOG_CRITICAL;
- $sql_forum = '';
- break;
-
- default:
- return;
- }
-
- // Use no preg_quote for $keywords because this would lead to sole backslashes being added
- // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later).
- $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
- $sql_keywords = '';
-
- if (!empty($keywords))
- {
- $keywords_pattern = array();
-
- // Build pattern and keywords...
- for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
- {
- $keywords_pattern[] = preg_quote($keywords[$i], '#');
- $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char);
- }
+ global $phpbb_log;
- $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
+ $count_logs = ($log_count !== false);
- $operations = array();
- foreach ($user->lang as $key => $value)
- {
- if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
- {
- $operations[] = $key;
- }
- }
-
- $sql_keywords = 'AND (';
- if (!empty($operations))
- {
- $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR ';
- }
- $sql_lower = $db->sql_lower_text('l.log_data');
- $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
- }
-
- if ($log_count !== false)
- {
- $sql = 'SELECT COUNT(l.log_id) AS total_entries
- FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND l.user_id = u.user_id
- AND l.log_time >= $limit_days
- $sql_keywords
- $sql_forum";
- $result = $db->sql_query($sql);
- $log_count = (int) $db->sql_fetchfield('total_entries');
- $db->sql_freeresult($result);
- }
-
- // $log_count may be false here if false was passed in for it,
- // because in this case we did not run the COUNT() query above.
- // If we ran the COUNT() query and it returned zero rows, return;
- // otherwise query for logs below.
- if ($log_count === 0)
- {
- // Save the queries, because there are no logs to display
- return 0;
- }
-
- if ($offset >= $log_count)
- {
- $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
- }
-
- $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
- FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND u.user_id = l.user_id
- " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
- $sql_keywords
- $sql_forum
- ORDER BY $sort_by";
- $result = $db->sql_query_limit($sql, $limit, $offset);
-
- $i = 0;
- $log = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['topic_id'])
- {
- $topic_id_list[] = $row['topic_id'];
- }
-
- if ($row['reportee_id'])
- {
- $reportee_id_list[] = $row['reportee_id'];
- }
+ $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords);
+ $log_count = $phpbb_log->get_log_count();
- $log[$i] = array(
- 'id' => $row['log_id'],
-
- 'reportee_id' => $row['reportee_id'],
- 'reportee_username' => '',
- 'reportee_username_full'=> '',
-
- 'user_id' => $row['user_id'],
- 'username' => $row['username'],
- 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
-
- 'ip' => $row['log_ip'],
- 'time' => $row['log_time'],
- 'forum_id' => $row['forum_id'],
- 'topic_id' => $row['topic_id'],
-
- 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
- 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
- );
-
- if (!empty($row['log_data']))
- {
- $log_data_ary = @unserialize($row['log_data']);
- $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary;
-
- if (isset($user->lang[$row['log_operation']]))
- {
- // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array
- // It doesn't matter if we add more arguments than placeholders
- if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
- {
- $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
- }
-
- $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
-
- // If within the admin panel we do not censor text out
- if (defined('IN_ADMIN'))
- {
- $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
- }
- else
- {
- $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
- }
- }
- else if (!empty($log_data_ary))
- {
- $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
- }
-
- /* Apply make_clickable... has to be seen if it is for good. :/
- // Seems to be not for the moment, reconsider later...
- $log[$i]['action'] = make_clickable($log[$i]['action']);
- */
- }
-
- $i++;
- }
- $db->sql_freeresult($result);
-
- if (sizeof($topic_id_list))
- {
- $topic_id_list = array_unique($topic_id_list);
-
- // This query is not really needed if move_topics() updates the forum_id field,
- // although it's also used to determine if the topic still exists in the database
- $sql = 'SELECT topic_id, forum_id
- FROM ' . TOPICS_TABLE . '
- WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
- $result = $db->sql_query($sql);
-
- $default_forum_id = 0;
-
- while ($row = $db->sql_fetchrow($result))
- {
- if ($auth->acl_get('f_read', $row['forum_id']))
- {
- $is_auth[$row['topic_id']] = $row['forum_id'];
- }
-
- if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
- {
- $is_mod[$row['topic_id']] = $row['forum_id'];
- }
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
- $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $user->session_id) : false;
- }
- }
-
- if (sizeof($reportee_id_list))
- {
- $reportee_id_list = array_unique($reportee_id_list);
- $reportee_names_list = array();
-
- $sql = 'SELECT user_id, username, user_colour
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $reportee_names_list[$row['user_id']] = $row;
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- if (!isset($reportee_names_list[$row['reportee_id']]))
- {
- continue;
- }
-
- $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
- $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url);
- }
- }
-
- return $offset;
+ return $phpbb_log->get_valid_offset();
}
/**
diff --git a/phpBB/includes/functions_container.php b/phpBB/includes/functions_container.php
index a3ed21c35b..106b7d75cc 100644
--- a/phpBB/includes/functions_container.php
+++ b/phpBB/includes/functions_container.php
@@ -57,6 +57,7 @@ function phpbb_create_install_container($phpbb_root_path, $php_ext)
$container = phpbb_create_container(array($core), $phpbb_root_path, $php_ext);
$container->setParameter('core.root_path', $phpbb_root_path);
+ $container->setParameter('core.adm_relative_path', $phpbb_adm_relative_path);
$container->setParameter('core.php_ext', $php_ext);
$container->setParameter('core.table_prefix', '');
diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php
index f05bf76ed8..bc636acabb 100644
--- a/phpBB/includes/functions_user.php
+++ b/phpBB/includes/functions_user.php
@@ -310,8 +310,10 @@ function user_add($user_row, $cp_data = false)
if ($add_group_id)
{
- // Because these actions only fill the log unneccessarily we skip the add_log() entry with a little hack. :/
- $GLOBALS['skip_add_log'] = true;
+ global $phpbb_log;
+
+ // Because these actions only fill the log unneccessarily we skip the add_log() entry.
+ $phpbb_log->disable('admin');
// Add user to "newly registered users" group and set to default group if admin specified so.
if ($config['new_member_group_default'])
@@ -324,7 +326,7 @@ function user_add($user_row, $cp_data = false)
group_user_add($add_group_id, $user_id);
}
- unset($GLOBALS['skip_add_log']);
+ $phpbb_log->enable('admin');
}
}
diff --git a/phpBB/includes/log/interface.php b/phpBB/includes/log/interface.php
new file mode 100644
index 0000000000..3b459c9bdf
--- /dev/null
+++ b/phpBB/includes/log/interface.php
@@ -0,0 +1,106 @@
+<?php
+/**
+*
+* @package phpbb_log
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* The interface for the log-system.
+*
+* @package phpbb_log
+*/
+interface phpbb_log_interface
+{
+ /**
+ * This function returns the state of the log system.
+ *
+ * @param string $type The log type we want to check. Empty to get
+ * global log status.
+ *
+ * @return bool True if log for the type is enabled
+ */
+ public function is_enabled($type = '');
+
+ /**
+ * Disable log
+ *
+ * This function allows disabling the log system or parts of it, for this
+ * page call. When add_log is called and the type is disabled,
+ * the log will not be added to the database.
+ *
+ * @param mixed $type The log type we want to disable. Empty to
+ * disable all logs. Can also be an array of types.
+ *
+ * @return null
+ */
+ public function disable($type = '');
+
+ /**
+ * Enable log
+ *
+ * This function allows re-enabling the log system.
+ *
+ * @param mixed $type The log type we want to enable. Empty to
+ * enable all logs. Can also be an array of types.
+ *
+ * @return null
+ */
+ public function enable($type = '');
+
+ /**
+ * Adds a log entry to the database
+ *
+ * @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+ * @param int $user_id User ID of the user
+ * @param string $log_ip IP address of the user
+ * @param string $log_operation Name of the operation
+ * @param int $log_time Timestamp when the log entry was added, if empty time() will be used
+ * @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.
+ */
+ public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array());
+
+ /**
+ * Grab the logs from the database
+ *
+ * @param string $mode The mode defines which log_type is used and ifrom which log the entry is retrieved
+ * @param bool $count_logs Shall we count all matching log entries?
+ * @param int $limit Limit the number of entries that are returned
+ * @param int $offset Offset when fetching the log entries, f.e. when paginating
+ * @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids)
+ * @param int $topic_id Restrict the log entries to the given topic_id
+ * @param int $user_id Restrict the log entries to the given user_id
+ * @param int $log_time Only get log entries newer than the given timestamp
+ * @param string $sort_by SQL order option, e.g. 'l.log_time DESC'
+ * @param string $keywords Will only return log entries that have the keywords in log_operation or log_data
+ *
+ * @return array The result array with the logs
+ */
+ public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '');
+
+ /**
+ * Get total log count
+ *
+ * @return int Returns the number of matching logs from the last call to get_logs()
+ */
+ public function get_log_count();
+
+ /**
+ * Get offset of the last valid page
+ *
+ * @return int Returns the offset of the last valid page from the last call to get_logs()
+ */
+ public function get_valid_offset();
+}
diff --git a/phpBB/includes/log/log.php b/phpBB/includes/log/log.php
new file mode 100644
index 0000000000..7a26858348
--- /dev/null
+++ b/phpBB/includes/log/log.php
@@ -0,0 +1,739 @@
+<?php
+/**
+*
+* @package phpbb_log
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* This class is used to add entries into the log table.
+*
+* @package phpbb_log
+*/
+class phpbb_log implements phpbb_log_interface
+{
+ /**
+ * If set, administrative user profile links will be returned and messages
+ * will not be censored.
+ * @var bool
+ */
+ protected $is_in_admin;
+
+ /**
+ * An array with the disabled log types. Logs of such types will not be
+ * added when add_log() is called.
+ * @var array
+ */
+ protected $disabled_types;
+
+ /**
+ * Keeps the total log count of the last call to get_logs()
+ * @var int
+ */
+ protected $entry_count;
+
+ /**
+ * Keeps the offset of the last valid page of the last call to get_logs()
+ * @var int
+ */
+ protected $last_page_offset;
+
+ /**
+ * The table we use to store our logs.
+ * @var string
+ */
+ protected $log_table;
+
+ /**
+ * Database object
+ * @var phpbb_db_driver
+ */
+ protected $db;
+
+ /**
+ * User object
+ * @var phpbb_user
+ */
+ protected $user;
+
+ /**
+ * Auth object
+ * @var phpbb_auth
+ */
+ protected $auth;
+
+ /**
+ * Event dispatcher object
+ * @var phpbb_dispatcher
+ */
+ protected $dispatcher;
+
+ /**
+ * phpBB root path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Admin root path
+ * @var string
+ */
+ protected $phpbb_admin_path;
+
+ /**
+ * PHP Extension
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param phpbb_db_driver $db Database object
+ * @param phpbb_user $user User object
+ * @param phpbb_auth $auth Auth object
+ * @param phpbb_dispatcher $phpbb_dispatcher Event dispatcher
+ * @param string $phpbb_root_path Root path
+ * @param string $relative_admin_path Relative admin root path
+ * @param string $php_ext PHP Extension
+ * @param string $log_table Name of the table we use to store our logs
+ * @return null
+ */
+ public function __construct($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, $relative_admin_path, $php_ext, $log_table)
+ {
+ $this->db = $db;
+ $this->user = $user;
+ $this->auth = $auth;
+ $this->dispatcher = $phpbb_dispatcher;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->phpbb_admin_path = $this->phpbb_root_path . $relative_admin_path;
+ $this->php_ext = $php_ext;
+ $this->log_table = $log_table;
+
+ /*
+ * IN_ADMIN is set after the session is created,
+ * so we need to take ADMIN_START into account as well, otherwise
+ * it will not work for the phpbb_log object we create in common.php
+ */
+ $this->set_is_admin((defined('ADMIN_START') && ADMIN_START) || (defined('IN_ADMIN') && IN_ADMIN));
+ $this->enable();
+ }
+
+ /**
+ * Set is_in_admin in order to return administrative user profile links
+ * in get_logs()
+ *
+ * @param bool $is_in_admin Are we called from within the acp?
+ * @return null
+ */
+ public function set_is_admin($is_in_admin)
+ {
+ $this->is_in_admin = (bool) $is_in_admin;
+ }
+
+ /**
+ * Returns the is_in_admin option
+ *
+ * @return bool
+ */
+ public function get_is_admin()
+ {
+ return $this->is_in_admin;
+ }
+
+ /**
+ * Set table name
+ *
+ * @param string $log_table Can overwrite the table to use for the logs
+ * @return null
+ */
+ public function set_log_table($log_table)
+ {
+ $this->log_table = $log_table;
+ }
+
+ /**
+ * This function returns the state of the log system.
+ *
+ * {@inheritDoc}
+ */
+ public function is_enabled($type = '')
+ {
+ if ($type == '' || $type == 'all')
+ {
+ return !isset($this->disabled_types['all']);
+ }
+ return !isset($this->disabled_types[$type]) && !isset($this->disabled_types['all']);
+ }
+
+ /**
+ * Disable log
+ *
+ * This function allows disabling the log system or parts of it, for this
+ * page call. When add_log is called and the type is disabled,
+ * the log will not be added to the database.
+ *
+ * {@inheritDoc}
+ */
+ public function disable($type = '')
+ {
+ if (is_array($type))
+ {
+ foreach ($type as $disable_type)
+ {
+ $this->disable($disable_type);
+ }
+ return;
+ }
+
+ // Empty string is an equivalent for all types.
+ if ($type == '')
+ {
+ $type = 'all';
+ }
+ $this->disabled_types[$type] = true;
+ }
+
+ /**
+ * Enable log
+ *
+ * This function allows re-enabling the log system.
+ *
+ * {@inheritDoc}
+ */
+ public function enable($type = '')
+ {
+ if (is_array($type))
+ {
+ foreach ($type as $enable_type)
+ {
+ $this->enable($enable_type);
+ }
+ return;
+ }
+
+ if ($type == '' || $type == 'all')
+ {
+ $this->disabled_types = array();
+ return;
+ }
+ unset($this->disabled_types[$type]);
+ }
+
+ /**
+ * Adds a log to the database
+ *
+ * {@inheritDoc}
+ */
+ public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array())
+ {
+ if (!$this->is_enabled($mode))
+ {
+ return false;
+ }
+
+ if ($log_time == false)
+ {
+ $log_time = time();
+ }
+
+ $sql_ary = array(
+ 'user_id' => $user_id,
+ 'log_ip' => $log_ip,
+ 'log_time' => $log_time,
+ 'log_operation' => $log_operation,
+ );
+
+ switch ($mode)
+ {
+ case 'admin':
+ $sql_ary += array(
+ 'log_type' => LOG_ADMIN,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'mod':
+ $forum_id = (int) $additional_data['forum_id'];
+ unset($additional_data['forum_id']);
+ $topic_id = (int) $additional_data['topic_id'];
+ unset($additional_data['topic_id']);
+ $sql_ary += array(
+ 'log_type' => LOG_MOD,
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'user':
+ $reportee_id = (int) $additional_data['reportee_id'];
+ unset($additional_data['reportee_id']);
+
+ $sql_ary += array(
+ 'log_type' => LOG_USERS,
+ 'reportee_id' => $reportee_id,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'critical':
+ $sql_ary += array(
+ 'log_type' => LOG_CRITICAL,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+ }
+
+ /**
+ * Allows to modify log data before we add it to the database
+ *
+ * NOTE: if sql_ary does not contain a log_type value, the entry will
+ * not be stored in the database. So ensure to set it, if needed.
+ *
+ * @event core.add_log
+ * @var string mode Mode of the entry we log
+ * @var int user_id ID of the user who triggered the log
+ * @var string log_ip IP of the user who triggered the log
+ * @var string log_operation Language key of the log operation
+ * @var int log_time Timestamp, when the log was added
+ * @var array additional_data Array with additional log data
+ * @var array sql_ary Array with log data we insert into the
+ * database. If sql_ary[log_type] is not set,
+ * we won't add the entry to the database.
+ * @since 3.1-A1
+ */
+ $vars = array('mode', 'user_id', 'log_ip', 'log_operation', 'log_time', 'additional_data', 'sql_ary');
+ extract($this->dispatcher->trigger_event('core.add_log', $vars));
+
+ // We didn't find a log_type, so we don't save it in the database.
+ if (!isset($sql_ary['log_type']))
+ {
+ return false;
+ }
+
+ $this->db->sql_query('INSERT INTO ' . $this->log_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary));
+
+ return $this->db->sql_nextid();
+ }
+
+ /**
+ * Grab the logs from the database
+ *
+ * {@inheritDoc}
+ */
+ public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '')
+ {
+ $this->entry_count = 0;
+ $this->last_page_offset = $offset;
+
+ $topic_id_list = $reportee_id_list = array();
+
+ $profile_url = ($this->get_is_admin() && $this->phpbb_admin_path) ? append_sid("{$this->phpbb_admin_path}index.{$this->php_ext}", 'i=users&amp;mode=overview') : append_sid("{$this->phpbb_root_path}memberlist.{$this->php_ext}", 'mode=viewprofile');
+
+ switch ($mode)
+ {
+ case 'admin':
+ $log_type = LOG_ADMIN;
+ $sql_additional = '';
+ break;
+
+ case 'mod':
+ $log_type = LOG_MOD;
+ $sql_additional = '';
+
+ if ($topic_id)
+ {
+ $sql_additional = 'AND l.topic_id = ' . (int) $topic_id;
+ }
+ else if (is_array($forum_id))
+ {
+ $sql_additional = 'AND ' . $this->db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
+ }
+ else if ($forum_id)
+ {
+ $sql_additional = 'AND l.forum_id = ' . (int) $forum_id;
+ }
+ break;
+
+ case 'user':
+ $log_type = LOG_USERS;
+ $sql_additional = 'AND l.reportee_id = ' . (int) $user_id;
+ break;
+
+ case 'users':
+ $log_type = LOG_USERS;
+ $sql_additional = '';
+ break;
+
+ case 'critical':
+ $log_type = LOG_CRITICAL;
+ $sql_additional = '';
+ break;
+
+ default:
+ $log_type = false;
+ $sql_additional = '';
+ }
+
+ /**
+ * Overwrite log type and limitations before we count and get the logs
+ *
+ * NOTE: if log_type is false, no entries will be returned.
+ *
+ * @event core.get_logs_modify_type
+ * @var string mode Mode of the entries we display
+ * @var bool count_logs Do we count all matching entries?
+ * @var int limit Limit the number of entries
+ * @var int offset Offset when fetching the entries
+ * @var mixed forum_id Limit entries to the forum_id,
+ * can also be an array of forum_ids
+ * @var int topic_id Limit entries to the topic_id
+ * @var int user_id Limit entries to the user_id
+ * @var int log_time Limit maximum age of log entries
+ * @var string sort_by SQL order option
+ * @var string keywords Will only return entries that have the
+ * keywords in log_operation or log_data
+ * @var string profile_url URL to the users profile
+ * @var int log_type Limit logs to a certain type. If log_type
+ * is false, no entries will be returned.
+ * @var string sql_additional Additional conditions for the entries,
+ * e.g.: 'AND l.forum_id = 1'
+ * @since 3.1-A1
+ */
+ $vars = array('mode', 'count_logs', 'limit', 'offset', 'forum_id', 'topic_id', 'user_id', 'log_time', 'sort_by', 'keywords', 'profile_url', 'log_type', 'sql_additional');
+ extract($this->dispatcher->trigger_event('core.get_logs_modify_type', $vars));
+
+ if ($log_type === false)
+ {
+ $this->last_page_offset = 0;
+ return array();
+ }
+
+ $sql_keywords = '';
+ if (!empty($keywords))
+ {
+ // Get the SQL condition for our keywords
+ $sql_keywords = $this->generate_sql_keyword($keywords);
+ }
+
+ if ($count_logs)
+ {
+ $sql = 'SELECT COUNT(l.log_id) AS total_entries
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . ' u
+ WHERE l.log_type = ' . (int) $log_type . '
+ AND l.user_id = u.user_id
+ AND l.log_time >= ' . (int) $log_time . "
+ $sql_keywords
+ $sql_additional";
+ $result = $this->db->sql_query($sql);
+ $this->entry_count = (int) $this->db->sql_fetchfield('total_entries');
+ $this->db->sql_freeresult($result);
+
+ if ($this->entry_count == 0)
+ {
+ // Save the queries, because there are no logs to display
+ $this->last_page_offset = 0;
+ return array();
+ }
+
+ // Return the user to the last page that is valid
+ while ($this->last_page_offset >= $this->entry_count)
+ {
+ $this->last_page_offset = max(0, $this->last_page_offset - $limit);
+ }
+ }
+
+ $sql = 'SELECT l.*, u.username, u.username_clean, u.user_colour
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . ' u
+ WHERE l.log_type = ' . (int) $log_type . '
+ AND u.user_id = l.user_id
+ ' . (($log_time) ? 'AND l.log_time >= ' . (int) $log_time : '') . "
+ $sql_keywords
+ $sql_additional
+ ORDER BY $sort_by";
+ $result = $this->db->sql_query_limit($sql, $limit, $this->last_page_offset);
+
+ $i = 0;
+ $log = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['forum_id'] = (int) $row['forum_id'];
+ if ($row['topic_id'])
+ {
+ $topic_id_list[] = (int) $row['topic_id'];
+ }
+
+ if ($row['reportee_id'])
+ {
+ $reportee_id_list[] = (int) $row['reportee_id'];
+ }
+
+ $log_entry_data = array(
+ 'id' => (int) $row['log_id'],
+
+ 'reportee_id' => (int) $row['reportee_id'],
+ 'reportee_username' => '',
+ 'reportee_username_full'=> '',
+
+ 'user_id' => (int) $row['user_id'],
+ 'username' => $row['username'],
+ 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
+
+ 'ip' => $row['log_ip'],
+ 'time' => (int) $row['log_time'],
+ 'forum_id' => (int) $row['forum_id'],
+ 'topic_id' => (int) $row['topic_id'],
+
+ 'viewforum' => ($row['forum_id'] && $this->auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$this->phpbb_root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']) : false,
+ 'action' => (isset($this->user->lang[$row['log_operation']])) ? $this->user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
+ );
+
+ /**
+ * Modify the entry's data before it is returned
+ *
+ * @event core.get_logs_modify_entry_data
+ * @var array row Entry data from the database
+ * @var array log_entry_data Entry's data which is returned
+ * @since 3.1-A1
+ */
+ $vars = array('row', 'log_entry_data');
+ extract($this->dispatcher->trigger_event('core.get_logs_modify_entry_data', $vars));
+
+ $log[$i] = $log_entry_data;
+
+ if (!empty($row['log_data']))
+ {
+ $log_data_ary = unserialize($row['log_data']);
+ $log_data_ary = ($log_data_ary !== false) ? $log_data_ary : array();
+
+ if (isset($this->user->lang[$row['log_operation']]))
+ {
+ // Check if there are more occurrences of % than
+ // arguments, if there are we fill out the arguments
+ // array. It doesn't matter if we add more arguments than
+ // placeholders.
+ if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
+ {
+ $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
+ }
+
+ $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
+
+ // If within the admin panel we do not censor text out
+ if ($this->get_is_admin())
+ {
+ $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
+ }
+ else
+ {
+ $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
+ }
+ }
+ else if (!empty($log_data_ary))
+ {
+ $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
+ }
+
+ /* Apply make_clickable... has to be seen if it is for good. :/
+ // Seems to be not for the moment, reconsider later...
+ $log[$i]['action'] = make_clickable($log[$i]['action']);
+ */
+ }
+
+ $i++;
+ }
+ $this->db->sql_freeresult($result);
+
+ /**
+ * Get some additional data after we got all log entries
+ *
+ * @event core.get_logs_get_additional_data
+ * @var array log Array with all our log entries
+ * @var array topic_id_list Array of topic ids, for which we
+ * get the permission data
+ * @var array reportee_id_list Array of additional user IDs we
+ * get the username strings for
+ * @since 3.1-A1
+ */
+ $vars = array('log', 'topic_id_list', 'reportee_id_list');
+ extract($this->dispatcher->trigger_event('core.get_logs_get_additional_data', $vars));
+
+ if (sizeof($topic_id_list))
+ {
+ $topic_auth = $this->get_topic_auth($topic_id_list);
+
+ foreach ($log as $key => $row)
+ {
+ $log[$key]['viewtopic'] = (isset($topic_auth['f_read'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
+ $log[$key]['viewlogs'] = (isset($topic_auth['m_'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}mcp.{$this->php_ext}", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $this->user->session_id) : false;
+ }
+ }
+
+ if (sizeof($reportee_id_list))
+ {
+ $reportee_data_list = $this->get_reportee_data($reportee_id_list);
+
+ foreach ($log as $key => $row)
+ {
+ if (!isset($reportee_data_list[$row['reportee_id']]))
+ {
+ continue;
+ }
+
+ $log[$key]['reportee_username'] = $reportee_data_list[$row['reportee_id']]['username'];
+ $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_data_list[$row['reportee_id']]['username'], $reportee_data_list[$row['reportee_id']]['user_colour'], false, $profile_url);
+ }
+ }
+
+ return $log;
+ }
+
+ /**
+ * Generates a sql condition for the specified keywords
+ *
+ * @param string $keywords The keywords the user specified to search for
+ *
+ * @return string Returns the SQL condition searching for the keywords
+ */
+ protected function generate_sql_keyword($keywords)
+ {
+ // Use no preg_quote for $keywords because this would lead to sole
+ // backslashes being added. We also use an OR connection here for
+ // spaces and the | string. Currently, regex is not supported for
+ // searching (but may come later).
+ $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
+ $sql_keywords = '';
+
+ if (!empty($keywords))
+ {
+ $keywords_pattern = array();
+
+ // Build pattern and keywords...
+ for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
+ {
+ $keywords_pattern[] = preg_quote($keywords[$i], '#');
+ $keywords[$i] = $this->db->sql_like_expression($this->db->any_char . $keywords[$i] . $this->db->any_char);
+ }
+
+ $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
+
+ $operations = array();
+ foreach ($this->user->lang as $key => $value)
+ {
+ if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
+ {
+ $operations[] = $key;
+ }
+ }
+
+ $sql_keywords = 'AND (';
+ if (!empty($operations))
+ {
+ $sql_keywords .= $this->db->sql_in_set('l.log_operation', $operations) . ' OR ';
+ }
+ $sql_lower = $this->db->sql_lower_text('l.log_data');
+ $sql_keywords .= " $sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
+ }
+
+ return $sql_keywords;
+ }
+
+ /**
+ * Determine whether the user is allowed to read and/or moderate the forum of the topic
+ *
+ * @param array $topic_ids Array with the topic ids
+ *
+ * @return array Returns an array with two keys 'm_' and 'read_f' which are also an array of topic_id => forum_id sets when the permissions are given. Sample:
+ * array(
+ * 'permission' => array(
+ * topic_id => forum_id
+ * ),
+ * ),
+ */
+ protected function get_topic_auth(array $topic_ids)
+ {
+ $forum_auth = array('f_read' => array(), 'm_' => array());
+ $topic_ids = array_unique($topic_ids);
+
+ $sql = 'SELECT topic_id, forum_id
+ FROM ' . TOPICS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('topic_id', array_map('intval', $topic_ids));
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['topic_id'] = (int) $row['topic_id'];
+ $row['forum_id'] = (int) $row['forum_id'];
+
+ if ($this->auth->acl_get('f_read', $row['forum_id']))
+ {
+ $forum_auth['f_read'][$row['topic_id']] = $row['forum_id'];
+ }
+
+ if ($this->auth->acl_gets('a_', 'm_', $row['forum_id']))
+ {
+ $forum_auth['m_'][$row['topic_id']] = $row['forum_id'];
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return $forum_auth;
+ }
+
+ /**
+ * Get the data for all reportee from the database
+ *
+ * @param array $reportee_ids Array with the user ids of the reportees
+ *
+ * @return array Returns an array with the reportee data
+ */
+ protected function get_reportee_data(array $reportee_ids)
+ {
+ $reportee_ids = array_unique($reportee_ids);
+ $reportee_data_list = array();
+
+ $sql = 'SELECT user_id, username, user_colour
+ FROM ' . USERS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('user_id', $reportee_ids);
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $reportee_data_list[$row['user_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $reportee_data_list;
+ }
+
+ /**
+ * Get total log count
+ *
+ * {@inheritDoc}
+ */
+ public function get_log_count()
+ {
+ return ($this->entry_count) ? $this->entry_count : 0;
+ }
+
+ /**
+ * Get offset of the last valid log page
+ *
+ * {@inheritDoc}
+ */
+ public function get_valid_offset()
+ {
+ return ($this->last_page_offset) ? $this->last_page_offset : 0;
+ }
+}
diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php
index 3382e57e76..2ecddf49d4 100644
--- a/phpBB/install/database_update.php
+++ b/phpBB/install/database_update.php
@@ -123,6 +123,7 @@ $request = $phpbb_container->get('request');
$user = $phpbb_container->get('user');
$auth = $phpbb_container->get('auth');
$db = $phpbb_container->get('dbal.conn');
+$phpbb_log = $phpbb_container->get('log');
// make sure request_var uses this request instance
request_var('', 0, false, false, $request); // "dependency injection" for a function
diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php
index 4cc154509c..67e368e34d 100644
--- a/phpBB/install/install_install.php
+++ b/phpBB/install/install_install.php
@@ -53,7 +53,7 @@ class install_install extends module
function main($mode, $sub)
{
global $lang, $template, $language, $phpbb_root_path, $phpEx;
- global $phpbb_container, $cache;
+ global $phpbb_container, $cache, $phpbb_log;
switch ($sub)
{
@@ -105,8 +105,9 @@ class install_install extends module
// Create a normal container now
$phpbb_container = phpbb_create_default_container($phpbb_root_path, $phpEx);
- // Sets the global $cache variable
+ // Sets the global variables
$cache = $phpbb_container->get('cache');
+ $phpbb_log = $phpbb_container->get('log');
$this->build_search_index($mode, $sub);
$this->add_modules($mode, $sub);