Beispiel #1
0
 /**
  * Constructor
  *
  * @param	\src\event\dispatcher_interface	$src_dispatcher	Event dispatcher
  * @param	\src\user				$user				User Object
  */
 public function __construct(\src\event\dispatcher_interface $src_dispatcher, \src\user $user)
 {
     $this->dispatcher = $src_dispatcher;
     $this->user = $user;
     $categories = $this->categories;
     $types = $this->types;
     $permissions = $this->permissions;
     /**
      * Allows to specify additional permission categories, types and permissions
      *
      * @event core.permissions
      * @var	array	types			Array with permission types (a_, u_, m_, etc.)
      * @var	array	categories		Array with permission categories (pm, post, settings, misc, etc.)
      * @var	array	permissions		Array with permissions. Each Permission has the following layout:
      *		'<type><permission>' => array(
      *			'lang'	=> 'Language Key with a Short description', // Optional, if not set,
      *						// the permissions identifier '<type><permission>' is used with
      *						// all uppercase.
      *			'cat'	=> 'Identifier of the category, the permission should be displayed in',
      *		),
      *		Example:
      *		'u_viewprofile' => array(
      *			'lang'	=> 'ACL_U_VIEWPROFILE',
      *			'cat'	=> 'profile',
      *		),
      * @since 3.1.0-a1
      */
     $vars = array('types', 'categories', 'permissions');
     extract($src_dispatcher->trigger_event('core.permissions', compact($vars)));
     $this->categories = $categories;
     $this->types = $types;
     $this->permissions = $permissions;
 }
Beispiel #2
0
    /**
     * Create topic/post visibility SQL for all forums on the srcrd
     *
     * Note: Read permissions are not checked. Forums without read permissions
     *		should be in $exclude_forum_ids
     *
     * @param $mode				string	Either "topic" or "post"
     * @param $exclude_forum_ids	array	Array of forum ids which are excluded
     * @param $table_alias		string	Table alias to prefix in SQL queries
     * @return string	The appropriate combination SQL logic for topic/post_visibility
     */
    public function get_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '')
    {
        $where_sqls = array();
        $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids);
        $visibility_sql_overwrite = null;
        /**
         * Allow changing the result of calling get_global_visibility_sql
         *
         * @event core.src_content_visibility_get_global_visibility_before
         * @var	array		where_sqls							The action the user tried to execute
         * @var	string		mode								Either "topic" or "post" depending on the query this is being used in
         * @var	array		exclude_forum_ids					Array of forum ids the current user doesn't have access to
         * @var	string		table_alias							Table alias to prefix in SQL queries
         * @var	array		approve_forums						Array of forums where the user has m_approve permissions
         * @var	string		visibility_sql_overwrite	Forces the function to return an implosion of where_sqls (joined by "OR")
         * @since 3.1.3-RC1
         */
        $vars = array('where_sqls', 'mode', 'exclude_forum_ids', 'table_alias', 'approve_forums', 'visibility_sql_overwrite');
        extract($this->src_dispatcher->trigger_event('core.src_content_visibility_get_global_visibility_before', compact($vars)));
        if ($visibility_sql_overwrite) {
            return $visibility_sql_overwrite;
        }
        if (sizeof($exclude_forum_ids)) {
            $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . '
				AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
        } else {
            $where_sqls[] = $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
        }
        if (sizeof($approve_forums)) {
            $where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums);
            return '(' . implode(' OR ', $where_sqls) . ')';
        }
        // There is only one element, so we just return that one
        return $where_sqls[0];
    }
Beispiel #3
0
 /**
  * Add a notification
  *
  * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
  *			Note: If you send an array of types, any user who could receive multiple notifications from this single item will only receive
  * 			a single notification. If they MUST receive multiple notifications, call this function multiple times instead of sending an array
  * @param array $data Data specific for this type that will be inserted
  * @param array $options Optional options to control what notifications are loaded
  * 			ignore_users	array of data to specify which users should not receive certain types of notifications
  * @return array Information about what users were notified and how they were notified
  */
 public function add_notifications($notification_type_name, $data, array $options = array())
 {
     $options = array_merge(array('ignore_users' => array()), $options);
     if (is_array($notification_type_name)) {
         $notified_users = array();
         $temp_options = $options;
         foreach ($notification_type_name as $type) {
             $temp_options['ignore_users'] = $options['ignore_users'] + $notified_users;
             $notified_users += $this->add_notifications($type, $data, $temp_options);
         }
         return $notified_users;
     }
     $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
     // find out which users want to receive this type of notification
     $notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options);
     /**
      * Allow filtering the notify_users array for a notification that is about to be sent.
      * Here, $notify_users is already filtered by f_read and the ignored list included in the options variable
      *
      * @event core.notification_manager_add_notifications
      * @var	string	notification_type_name		The forum id from where the topic belongs
      * @var	array 	data						Data specific for the notification_type_name used will be inserted
      * @var	array 	notify_users				The array of userid that are going to be notified for this notification. Set to array() to cancel.
      * @var	array 	options						The options that were used when this method was called (read only)
      *
      * @since 3.1.3-RC1
      */
     $vars = array('notification_type_name', 'data', 'notify_users', 'options');
     extract($this->src_dispatcher->trigger_event('core.notification_manager_add_notifications', compact($vars)));
     $this->add_notifications_for_users($notification_type_name, $data, $notify_users);
     return $notify_users;
 }
Beispiel #4
0
 /**
  * Generate a pagination link based on the url and the page information
  *
  * @param string $base_url is url prepended to all links generated within the function
  *							If you use page numbers inside your controller route, base_url should contains a placeholder (%d)
  *							for the page. Also be sure to specify the pagination path information into the start_name argument
  * @param string $on_page is the page for which we want to generate the link
  * @param string $start_name is the name of the parameter containing the first item of the given page (example: start=20)
  *							If you use page numbers inside your controller route, start name should be the string
  *							that should be removed for the first page (example: /page/%d)
  * @param int $per_page the number of items, posts, etc. to display per page, used to determine the number of pages to produce
  * @return string URL for the requested page
  */
 protected function generate_page_link($base_url, $on_page, $start_name, $per_page)
 {
     // A listener can set this variable to the new pagination URL
     // to override the generate_page_link() function generated value
     $generate_page_link_override = false;
     /**
      * Execute code and/or override generate_page_link()
      *
      * To override the generate_page_link() function generated value
      * set $generate_page_link_override to the new URL value
      *
      * @event core.pagination_generate_page_link
      * @var string base_url is url prepended to all links generated within the function
      *							If you use page numbers inside your controller route, base_url should contains a placeholder (%d)
      *							for the page. Also be sure to specify the pagination path information into the start_name argument
      * @var string on_page is the page for which we want to generate the link
      * @var string start_name is the name of the parameter containing the first item of the given page (example: start=20)
      *							If you use page numbers inside your controller route, start name should be the string
      *							that should be removed for the first page (example: /page/%d)
      * @var int per_page the number of items, posts, etc. to display per page, used to determine the number of pages to produce
      * @var bool|string generate_page_link_override Shall we return custom pagination link (string URL) or not (false)
      * @since 3.1.0-RC5
      */
     $vars = array('base_url', 'on_page', 'start_name', 'per_page', 'generate_page_link_override');
     extract($this->src_dispatcher->trigger_event('core.pagination_generate_page_link', compact($vars)));
     if ($generate_page_link_override) {
         return $generate_page_link_override;
     }
     if (!is_string($base_url)) {
         if (is_array($base_url['routes'])) {
             $route = $on_page > 1 ? $base_url['routes'][1] : $base_url['routes'][0];
         } else {
             $route = $base_url['routes'];
         }
         $params = isset($base_url['params']) ? $base_url['params'] : array();
         $is_amp = isset($base_url['is_amp']) ? $base_url['is_amp'] : true;
         $session_id = isset($base_url['session_id']) ? $base_url['session_id'] : false;
         if ($on_page > 1 || !is_array($base_url['routes'])) {
             $params[$start_name] = (int) $on_page;
         }
         return $this->helper->route($route, $params, $is_amp, $session_id);
     } else {
         $url_delim = strpos($base_url, '?') === false ? '?' : (strpos($base_url, '?') === strlen($base_url) - 1 ? '' : '&amp;');
         return $on_page > 1 ? $base_url . $url_delim . $start_name . '=' . ($on_page - 1) * $per_page : $base_url;
     }
 }
Beispiel #5
0
 /**
  * Assign the user's profile fields data to the template
  *
  * @param array	$profile_row		Array with users profile field data
  * @param bool	$use_contact_fields	Should we display contact fields as such?
  *			This requires special treatments (links should not be parsed in the values, and more)
  * @return array
  */
 public function generate_profile_fields_template_data($profile_row, $use_contact_fields = true)
 {
     // $profile_row == $user_fields[$row['user_id']];
     $tpl_fields = array();
     $tpl_fields['row'] = $tpl_fields['blockrow'] = array();
     /**
      * Event to modify data of the generated profile fields, before the template assignment loop
      *
      * @event core.generate_profile_fields_template_data_before
      * @var	array	profile_row		Array with users profile field data
      * @var	array	tpl_fields		Array with template data fields
      * @var	bool	use_contact_fields	Should we display contact fields as such?
      * @since 3.1.0-b3
      */
     $vars = array('profile_row', 'tpl_fields', 'use_contact_fields');
     extract($this->dispatcher->trigger_event('core.generate_profile_fields_template_data_before', compact($vars)));
     foreach ($profile_row as $ident => $ident_ary) {
         $profile_field = $this->type_collection[$ident_ary['data']['field_type']];
         $value = $profile_field->get_profile_value($ident_ary['value'], $ident_ary['data']);
         $value_raw = $profile_field->get_profile_value_raw($ident_ary['value'], $ident_ary['data']);
         if ($value === null) {
             continue;
         }
         $field_desc = $contact_url = '';
         if ($use_contact_fields && $ident_ary['data']['field_is_contact']) {
             $value = $profile_field->get_profile_contact_value($ident_ary['value'], $ident_ary['data']);
             $field_desc = $this->user->lang($ident_ary['data']['field_contact_desc']);
             if (strpos($field_desc, '%s') !== false) {
                 $field_desc = sprintf($field_desc, $value);
             }
             $contact_url = '';
             if (strpos($ident_ary['data']['field_contact_url'], '%s') !== false) {
                 $contact_url = sprintf($ident_ary['data']['field_contact_url'], $value);
             }
         }
         $tpl_fields['row'] += array('PROFILE_' . strtoupper($ident) . '_IDENT' => $ident, 'PROFILE_' . strtoupper($ident) . '_VALUE' => $value, 'PROFILE_' . strtoupper($ident) . '_VALUE_RAW' => $value_raw, 'PROFILE_' . strtoupper($ident) . '_CONTACT' => $contact_url, 'PROFILE_' . strtoupper($ident) . '_DESC' => $field_desc, 'PROFILE_' . strtoupper($ident) . '_TYPE' => $ident_ary['data']['field_type'], 'PROFILE_' . strtoupper($ident) . '_NAME' => $this->user->lang($ident_ary['data']['lang_name']), 'PROFILE_' . strtoupper($ident) . '_EXPLAIN' => $this->user->lang($ident_ary['data']['lang_explain']), 'S_PROFILE_' . strtoupper($ident) . '_CONTACT' => $ident_ary['data']['field_is_contact'], 'S_PROFILE_' . strtoupper($ident) => true);
         $tpl_fields['blockrow'][] = array('PROFILE_FIELD_IDENT' => $ident, 'PROFILE_FIELD_VALUE' => $value, 'PROFILE_FIELD_VALUE_RAW' => $value_raw, 'PROFILE_FIELD_CONTACT' => $contact_url, 'PROFILE_FIELD_DESC' => $field_desc, 'PROFILE_FIELD_TYPE' => $ident_ary['data']['field_type'], 'PROFILE_FIELD_NAME' => $this->user->lang($ident_ary['data']['lang_name']), 'PROFILE_FIELD_EXPLAIN' => $this->user->lang($ident_ary['data']['lang_explain']), 'S_PROFILE_CONTACT' => $ident_ary['data']['field_is_contact'], 'S_PROFILE_' . strtoupper($ident) => true);
     }
     /**
      * Event to modify template data of the generated profile fields
      *
      * @event core.generate_profile_fields_template_data
      * @var	array	profile_row		Array with users profile field data
      * @var	array	tpl_fields		Array with template data fields
      * @var	bool	use_contact_fields	Should we display contact fields as such?
      * @since 3.1.0-b3
      */
     $vars = array('profile_row', 'tpl_fields', 'use_contact_fields');
     extract($this->dispatcher->trigger_event('core.generate_profile_fields_template_data', compact($vars)));
     return $tpl_fields;
 }
Beispiel #6
0
/**
* Generate the debug output string
*
* @param \src\db\driver\driver_interface	$db			Database connection
* @param \src\config\config				$config		Config object
* @param \src\auth\auth					$auth		Auth object
* @param \src\user						$user		User object
* @param \src\event\dispatcher_interface	$src_dispatcher	Event dispatcher
* @return string
*/
function src_generate_debug_output(\src\db\driver\driver_interface $db, \src\config\config $config, \src\auth\auth $auth, \src\user $user, \src\event\dispatcher_interface $src_dispatcher)
{
    $debug_info = array();
    // Output page creation time
    if (defined('src_DISPLAY_LOAD_TIME')) {
        if (isset($GLOBALS['starttime'])) {
            $totaltime = microtime(true) - $GLOBALS['starttime'];
            $debug_info[] = sprintf('<abbr title="SQL time: %.3fs / PHP time: %.3fs">Time: %.3fs</abbr>', $db->get_sql_time(), $totaltime - $db->get_sql_time(), $totaltime);
        }
        $debug_info[] = sprintf('<abbr title="Cached: %d">Queries: %d</abbr>', $db->sql_num_queries(true), $db->sql_num_queries());
        $memory_usage = memory_get_peak_usage();
        if ($memory_usage) {
            $memory_usage = get_formatted_filesize($memory_usage);
            $debug_info[] = 'Peak Memory Usage: ' . $memory_usage;
        }
    }
    if (defined('DEBUG')) {
        $debug_info[] = 'GZIP: ' . ($config['gzip_compress'] && @extension_loaded('zlib') ? 'On' : 'Off');
        if ($user->load) {
            $debug_info[] = 'Load: ' . $user->load;
        }
        if ($auth->acl_get('a_')) {
            $debug_info[] = '<a href="' . build_url() . '&amp;explain=1">SQL Explain</a>';
        }
    }
    /**
     * Modify debug output information
     *
     * @event core.src_generate_debug_output
     * @var	array	debug_info		Array of strings with debug information
     *
     * @since 3.1.0-RC3
     */
    $vars = array('debug_info');
    extract($src_dispatcher->trigger_event('core.src_generate_debug_output', compact($vars)));
    return implode(' | ', $debug_info);
}
Beispiel #7
0
 /**
  * Performs a search on an author's posts without caring about message contents. Depends on display specific params
  *
  * @param	string		$type				contains either posts or topics depending on what should be searched for
  * @param	boolean		$firstpost_only		if true, only topic starting posts will be considered
  * @param	array		$sort_by_sql		contains SQL code for the ORDER BY part of a query
  * @param	string		$sort_key			is the key of $sort_by_sql for the selected sorting
  * @param	string		$sort_dir			is either a or d representing ASC and DESC
  * @param	string		$sort_days			specifies the maximum amount of days a post may be old
  * @param	array		$ex_fid_ary			specifies an array of forum ids which should not be searched
  * @param	string		$post_visibility	specifies which types of posts the user can view in which forums
  * @param	int			$topic_id			is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched
  * @param	array		$author_ary			an array of author ids
  * @param	string		$author_name		specifies the author match, when ANONYMOUS is also a search-match
  * @param	array		&$id_ary			passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered
  * @param	int			$start				indicates the first index of the page
  * @param	int			$per_page			number of ids each page is supposed to contain
  * @return	boolean|int						total number of results
  */
 public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page)
 {
     // No author? No posts
     if (!sizeof($author_ary)) {
         return 0;
     }
     // generate a search_key from all the options to identify the results
     $search_key = md5(implode('#', array('', $type, $firstpost_only ? 'firstpost' : '', '', '', $sort_days, $sort_key, $topic_id, implode(',', $ex_fid_ary), $post_visibility, implode(',', $author_ary), $author_name)));
     if ($start < 0) {
         $start = 0;
     }
     // try reading the results from cache
     $result_count = 0;
     if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) {
         return $result_count;
     }
     $id_ary = array();
     // Create some display specific sql strings
     if ($author_name) {
         // first one matches post of registered users, second one guests and deleted users
         $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
     } else {
         $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
     }
     $sql_fora = sizeof($ex_fid_ary) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
     $sql_topic_id = $topic_id ? ' AND p.topic_id = ' . (int) $topic_id : '';
     $sql_time = $sort_days ? ' AND p.post_time >= ' . (time() - $sort_days * 86400) : '';
     $sql_firstpost = $firstpost_only ? ' AND p.post_id = t.topic_first_post_id' : '';
     // Build sql strings for sorting
     $sql_sort = $sort_by_sql[$sort_key] . ($sort_dir == 'a' ? ' ASC' : ' DESC');
     $sql_sort_table = $sql_sort_join = '';
     switch ($sql_sort[0]) {
         case 'u':
             $sql_sort_table = USERS_TABLE . ' u, ';
             $sql_sort_join = $type == 'posts' ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
             break;
         case 't':
             $sql_sort_table = $type == 'posts' && !$firstpost_only ? TOPICS_TABLE . ' t, ' : '';
             $sql_sort_join = $type == 'posts' && !$firstpost_only ? ' AND t.topic_id = p.topic_id ' : '';
             break;
         case 'f':
             $sql_sort_table = FORUMS_TABLE . ' f, ';
             $sql_sort_join = ' AND f.forum_id = p.forum_id ';
             break;
     }
     $m_approve_fid_sql = ' AND ' . $post_visibility;
     /**
      * Allow changing the query used to search for posts by author in fulltext_mysql
      *
      * @event core.search_mysql_author_query_before
      * @var	int		result_count		The previous result count for the format of the query.
      *									Set to 0 to force a re-count
      * @var	string	sql_sort_table		CROSS JOIN'ed table to allow doing the sort chosen
      * @var	string	sql_sort_join		Condition to define how to join the CROSS JOIN'ed table specifyed in sql_sort_table
      * @var	array	author_ary			Array of user_id containing the users to filter the results to
      * @var	string	author_name			An extra username to search on
      * @var	string	sql_author			SQL WHERE condition for the post author ids
      * @var	int		topic_id			Limit the search to this topic_id only
      * @var	string	sql_topic_id		SQL of topic_id
      * @var	string	sort_by_sql			The possible predefined sort types
      * @var	string	sort_key			The sort type used from the possible sort types
      * @var	string	sort_dir			"a" for ASC or "d" dor DESC for the sort order used
      * @var	string	sql_sort			The result SQL when processing sort_by_sql + sort_key + sort_dir
      * @var	string	sort_days			Time, in days, that the oldest post showing can have
      * @var	string	sql_time			The SQL to search on the time specifyed by sort_days
      * @var	bool	firstpost_only		Wether or not to search only on the first post of the topics
      * @var	array	ex_fid_ary			Forum ids that must not be searched on
      * @var	array	sql_fora			SQL query for ex_fid_ary
      * @var	string	m_approve_fid_sql	WHERE clause condition on post_visibility restrictions
      * @var	int		start				How many posts to skip in the search results (used for pagination)
      * @since 3.1.5-RC1
      */
     $vars = array('result_count', 'sql_sort_table', 'sql_sort_join', 'author_ary', 'author_name', 'sql_author', 'topic_id', 'sql_topic_id', 'sort_by_sql', 'sort_key', 'sort_dir', 'sql_sort', 'sort_days', 'sql_time', 'firstpost_only', 'ex_fid_ary', 'sql_fora', 'm_approve_fid_sql', 'start');
     extract($this->src_dispatcher->trigger_event('core.search_mysql_author_query_before', compact($vars)));
     // If the cache was completely empty count the results
     $calc_results = $result_count ? '' : 'SQL_CALC_FOUND_ROWS ';
     // Build the query for really selecting the post_ids
     if ($type == 'posts') {
         $sql = "SELECT {$calc_results}p.post_id\n\t\t\t\tFROM " . $sql_sort_table . POSTS_TABLE . ' p' . ($firstpost_only ? ', ' . TOPICS_TABLE . ' t ' : ' ') . "\n\t\t\t\tWHERE {$sql_author}\n\t\t\t\t\t{$sql_topic_id}\n\t\t\t\t\t{$sql_firstpost}\n\t\t\t\t\t{$m_approve_fid_sql}\n\t\t\t\t\t{$sql_fora}\n\t\t\t\t\t{$sql_sort_join}\n\t\t\t\t\t{$sql_time}\n\t\t\t\tORDER BY {$sql_sort}";
         $field = 'post_id';
     } else {
         $sql = "SELECT {$calc_results}t.topic_id\n\t\t\t\tFROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p\n\t\t\t\tWHERE {$sql_author}\n\t\t\t\t\t{$sql_topic_id}\n\t\t\t\t\t{$sql_firstpost}\n\t\t\t\t\t{$m_approve_fid_sql}\n\t\t\t\t\t{$sql_fora}\n\t\t\t\t\tAND t.topic_id = p.topic_id\n\t\t\t\t\t{$sql_sort_join}\n\t\t\t\t\t{$sql_time}\n\t\t\t\tGROUP BY t.topic_id\n\t\t\t\tORDER BY {$sql_sort}";
         $field = 'topic_id';
     }
     // Only read one block of posts from the db and then cache it
     $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
     while ($row = $this->db->sql_fetchrow($result)) {
         $id_ary[] = (int) $row[$field];
     }
     $this->db->sql_freeresult($result);
     // retrieve the total result count if needed
     if (!$result_count) {
         $sql_found_rows = 'SELECT FOUND_ROWS() as result_count';
         $result = $this->db->sql_query($sql_found_rows);
         $result_count = (int) $this->db->sql_fetchfield('result_count');
         $this->db->sql_freeresult($result);
         if (!$result_count) {
             return false;
         }
     }
     if ($start >= $result_count) {
         $start = floor(($result_count - 1) / $per_page) * $per_page;
         $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
         while ($row = $this->db->sql_fetchrow($result)) {
             $id_ary[] = (int) $row[$field];
         }
         $this->db->sql_freeresult($result);
         $id_ary = array_unique($id_ary);
     }
     if (sizeof($id_ary)) {
         $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir);
         $id_ary = array_slice($id_ary, 0, $per_page);
         return $result_count;
     }
     return false;
 }
Beispiel #8
0
    /**
     * {@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->src_admin_path ? append_sid("{$this->src_admin_path}index.{$this->php_ext}", 'i=users&amp;mode=overview') : append_sid("{$this->src_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.0-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', compact($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);
        }
        $get_logs_sql_ary = array('SELECT' => 'l.*, u.username, u.username_clean, u.user_colour', 'FROM' => array($this->log_table => 'l', USERS_TABLE => 'u'), 'WHERE' => 'l.log_type = ' . (int) $log_type . "\n\t\t\t\t\tAND l.user_id = u.user_id\n\t\t\t\t\t{$sql_keywords}\n\t\t\t\t\t{$sql_additional}", 'ORDER_BY' => $sort_by);
        if ($log_time) {
            $get_logs_sql_ary['WHERE'] = 'l.log_time >= ' . (int) $log_time . '
					AND ' . $get_logs_sql_ary['WHERE'];
        }
        /**
         * Modify the query to obtain the logs data
         *
         * @event core.get_logs_main_query_before
         * @var	array	get_logs_sql_ary	The array in the format of the query builder with the query
         *									to get the log count and the log list
         * @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.5-RC1
         */
        $vars = array('get_logs_sql_ary', '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_main_query_before', compact($vars)));
        if ($count_logs) {
            $count_logs_sql_ary = $get_logs_sql_ary;
            $count_logs_sql_ary['SELECT'] = 'COUNT(l.log_id) AS total_entries';
            unset($count_logs_sql_ary['ORDER_BY']);
            $sql = $this->db->sql_build_query('SELECT', $count_logs_sql_ary);
            $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 = $this->db->sql_build_query('SELECT', $get_logs_sql_ary);
        $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->src_root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']) : false, 'action' => isset($this->user->lang[$row['log_operation']]) ? $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.0-a1
             */
            $vars = array('row', 'log_entry_data');
            extract($this->dispatcher->trigger_event('core.get_logs_modify_entry_data', compact($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.
                    $num_args = 0;
                    if (!is_array($this->user->lang[$row['log_operation']])) {
                        $num_args = substr_count($this->user->lang[$row['log_operation']], '%');
                    } else {
                        foreach ($this->user->lang[$row['log_operation']] as $case => $plural_string) {
                            $num_args = max($num_args, substr_count($plural_string, '%'));
                        }
                    }
                    if ($num_args - sizeof($log_data_ary) > 0) {
                        $log_data_ary = array_merge($log_data_ary, array_fill(0, $num_args - sizeof($log_data_ary), ''));
                    }
                    $lang_arguments = array_merge(array($log[$i]['action']), $log_data_ary);
                    $log[$i]['action'] = call_user_func_array(array($this->user, 'lang'), $lang_arguments);
                    // 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']);
                			*/
            } else {
                $log[$i]['action'] = $this->user->lang($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.0-a1
         */
        $vars = array('log', 'topic_id_list', 'reportee_id_list');
        extract($this->dispatcher->trigger_event('core.get_logs_get_additional_data', compact($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->src_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->src_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);
            }
        }
        /**
         * Allow modifying or execute extra final filter on log entries
         *
         * @event core.get_logs_after
         * @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
         * @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	The type of logs it was filtered
         * @since 3.1.3-RC1
         */
        $vars = array('log', 'topic_id_list', 'reportee_id_list', 'mode', 'count_logs', 'limit', 'offset', 'forum_id', 'topic_id', 'user_id', 'log_time', 'sort_by', 'keywords', 'profile_url', 'log_type');
        extract($this->dispatcher->trigger_event('core.get_logs_after', compact($vars)));
        return $log;
    }