aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb/session.php
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/phpbb/session.php')
-rw-r--r--phpBB/phpbb/session.php309
1 files changed, 199 insertions, 110 deletions
diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php
index f530d30f1f..3f7146c59b 100644
--- a/phpBB/phpbb/session.php
+++ b/phpBB/phpbb/session.php
@@ -1,9 +1,13 @@
<?php
/**
*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+* 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.
*
*/
@@ -11,7 +15,6 @@ namespace phpbb;
/**
* Session class
-* @package phpBB3
*/
class session
{
@@ -28,10 +31,11 @@ class session
var $update_session_page = true;
/**
- * Extract current session page
- *
- * @param string $root_path current root path (phpbb_root_path)
- */
+ * Extract current session page
+ *
+ * @param string $root_path current root path (phpbb_root_path)
+ * @return array
+ */
static function extract_current_page($root_path)
{
global $request, $symfony_request, $phpbb_filesystem;
@@ -39,8 +43,8 @@ class session
$page_array = array();
// First of all, get the request uri...
- $script_name = $symfony_request->getScriptName();
- $args = explode('&', $symfony_request->getQueryString());
+ $script_name = $request->escape($symfony_request->getScriptName(), true);
+ $args = $request->escape(explode('&', $symfony_request->getQueryString()), true);
// If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support...
if (!$script_name)
@@ -58,8 +62,8 @@ class session
// Since some browser do not encode correctly we need to do this with some "special" characters...
// " -> %22, ' => %27, < -> %3C, > -> %3E
- $find = array('"', "'", '<', '>');
- $replace = array('%22', '%27', '%3C', '%3E');
+ $find = array('"', "'", '<', '>', '&quot;', '&lt;', '&gt;');
+ $replace = array('%22', '%27', '%3C', '%3E', '%22', '%3C', '%3E');
foreach ($args as $key => $argument)
{
@@ -84,12 +88,12 @@ class session
$symfony_request_path = $phpbb_filesystem->clean_path($symfony_request->getPathInfo());
if ($symfony_request_path !== '/')
{
- $page_name .= $symfony_request_path;
+ $page_name .= str_replace('%2F', '/', urlencode($symfony_request_path));
}
// current directory within the phpBB root (for example: adm)
- $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path)));
- $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
+ $root_dirs = explode('/', str_replace('\\', '/', $phpbb_filesystem->realpath($root_path)));
+ $page_dirs = explode('/', str_replace('\\', '/', $phpbb_filesystem->realpath('./')));
$intersection = array_intersect_assoc($root_dirs, $page_dirs);
$root_dirs = array_diff_assoc($root_dirs, $intersection);
@@ -126,6 +130,10 @@ class session
$script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/';
$root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/';
+ $forum_id = $request->variable('f', 0);
+ // maximum forum id value is maximum value of mediumint unsigned column
+ $forum_id = ($forum_id > 0 && $forum_id < 16777215) ? $forum_id : 0;
+
$page_array += array(
'page_name' => $page_name,
'page_dir' => $page_dir,
@@ -135,7 +143,7 @@ class session
'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)),
'page' => $page,
- 'forum' => request_var('f', 0),
+ 'forum' => $forum_id,
);
return $page_array;
@@ -211,7 +219,7 @@ class session
function session_begin($update_session_page = true)
{
global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path;
- global $request, $phpbb_container;
+ global $request, $phpbb_container, $user, $phpbb_log;
// Give us some basic information
$this->time_now = time();
@@ -249,23 +257,23 @@ class session
if ($request->is_set($config['cookie_name'] . '_sid', \phpbb\request\request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', \phpbb\request\request_interface::COOKIE))
{
- $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
- $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
- $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true);
+ $this->cookie_data['u'] = $request->variable($config['cookie_name'] . '_u', 0, false, \phpbb\request\request_interface::COOKIE);
+ $this->cookie_data['k'] = $request->variable($config['cookie_name'] . '_k', '', false, \phpbb\request\request_interface::COOKIE);
+ $this->session_id = $request->variable($config['cookie_name'] . '_sid', '', false, \phpbb\request\request_interface::COOKIE);
$SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
$_SID = (defined('NEED_SID')) ? $this->session_id : '';
if (empty($this->session_id))
{
- $this->session_id = $_SID = request_var('sid', '');
+ $this->session_id = $_SID = $request->variable('sid', '');
$SID = '?sid=' . $this->session_id;
$this->cookie_data = array('u' => 0, 'k' => '');
}
}
else
{
- $this->session_id = $_SID = request_var('sid', '');
+ $this->session_id = $_SID = $request->variable('sid', '');
$SID = '?sid=' . $this->session_id;
}
@@ -341,8 +349,8 @@ class session
}
else
{
- set_config('limit_load', '0');
- set_config('limit_search_load', '0');
+ $config->set('limit_load', '0');
+ $config->set('limit_search_load', '0');
}
}
@@ -405,9 +413,9 @@ class session
$session_expired = false;
// Check whether the session is still valid if we have one
- $method = basename(trim($config['auth_method']));
-
- $provider = $phpbb_container->get('auth.provider.' . $method);
+ /* @var $provider_collection \phpbb\auth\provider_collection */
+ $provider_collection = $phpbb_container->get('auth.provider_collection');
+ $provider = $provider_collection->get_provider();
if (!($provider instanceof \phpbb\auth\provider\provider_interface))
{
@@ -439,38 +447,6 @@ class session
if (!$session_expired)
{
- // Only update session DB a minute or so after last update or if page changes
- if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
- {
- $sql_ary = array('session_time' => $this->time_now);
-
- if ($this->update_session_page)
- {
- $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
- $sql_ary['session_forum_id'] = $this->page['forum'];
- }
-
- $db->sql_return_on_error(true);
-
- $this->update_session($sql_ary);
-
- $db->sql_return_on_error(false);
-
- // If the database is not yet updated, there will be an error due to the session_forum_id
- // @todo REMOVE for 3.0.2
- if ($result === false)
- {
- unset($sql_ary['session_forum_id']);
-
- $this->update_session($sql_ary);
- }
-
- if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
- {
- $this->leave_newly_registered();
- }
- }
-
$this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
$this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false;
$this->data['user_lang'] = basename($this->data['user_lang']);
@@ -485,11 +461,18 @@ class session
{
if ($referer_valid)
{
- add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for));
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_IP_BROWSER_FORWARDED_CHECK', false, array(
+ $u_ip,
+ $s_ip,
+ $u_browser,
+ $s_browser,
+ htmlspecialchars($u_forwarded_for),
+ htmlspecialchars($s_forwarded_for)
+ ));
}
else
{
- add_log('critical', 'LOG_REFERER_INVALID', $this->referer);
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_REFERER_INVALID', false, array($this->referer));
}
}
}
@@ -511,7 +494,7 @@ class session
*/
function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
{
- global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx, $phpbb_container;
+ global $SID, $_SID, $db, $config, $cache, $phpbb_container, $phpbb_dispatcher;
$this->data = array();
@@ -574,11 +557,16 @@ class session
}
}
- $method = basename(trim($config['auth_method']));
-
- $provider = $phpbb_container->get('auth.provider.' . $method);
+ /* @var $provider_collection \phpbb\auth\provider_collection */
+ $provider_collection = $phpbb_container->get('auth.provider_collection');
+ $provider = $provider_collection->get_provider();
$this->data = $provider->autologin();
+ if ($user_id !== false && sizeof($this->data) && $this->data['user_id'] != $user_id)
+ {
+ $this->data = array();
+ }
+
if (sizeof($this->data))
{
$this->cookie_data['k'] = '';
@@ -596,11 +584,18 @@ class session
AND k.user_id = u.user_id
AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
$result = $db->sql_query($sql);
- $this->data = $db->sql_fetchrow($result);
+ $user_data = $db->sql_fetchrow($result);
+
+ if ($user_id === false || (isset($user_data['user_id']) && $user_id == $user_data['user_id']))
+ {
+ $this->data = $user_data;
+ $bot = false;
+ }
+
$db->sql_freeresult($result);
- $bot = false;
}
- else if ($user_id !== false && !sizeof($this->data))
+
+ if ($user_id !== false && !sizeof($this->data))
{
$this->cookie_data['k'] = '';
$this->cookie_data['u'] = $user_id;
@@ -715,18 +710,6 @@ class session
// Only update session DB a minute or so after last update or if page changes
if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
{
- $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
-
- $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0);
-
- if ($this->update_session_page)
- {
- $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
- $sql_ary['session_forum_id'] = $this->page['forum'];
- }
-
- $this->update_session($sql_ary);
-
// Update the last visit time
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_lastvisit = ' . (int) $this->data['session_time'] . '
@@ -874,6 +857,19 @@ class session
$_SID = '';
}
+ $session_data = $sql_ary;
+ /**
+ * Event to send new session data to extension
+ * Read-only event
+ *
+ * @event core.session_create_after
+ * @var array session_data Associative array of session keys to be updated
+ * @since 3.1.6-RC1
+ */
+ $vars = array('session_data');
+ extract($phpbb_dispatcher->trigger_event('core.session_create_after', compact($vars)));
+ unset($session_data);
+
return true;
}
@@ -887,17 +883,34 @@ class session
*/
function session_kill($new_session = true)
{
- global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx, $phpbb_container;
+ global $SID, $_SID, $db, $phpbb_container, $phpbb_dispatcher;
$sql = 'DELETE FROM ' . SESSIONS_TABLE . "
WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
AND session_user_id = " . (int) $this->data['user_id'];
$db->sql_query($sql);
- // Allow connecting logout with external auth method logout
- $method = basename(trim($config['auth_method']));
+ $user_id = (int) $this->data['user_id'];
+ $session_id = $this->session_id;
+ /**
+ * Event to send session kill information to extension
+ * Read-only event
+ *
+ * @event core.session_kill_after
+ * @var int user_id user_id of the session user.
+ * @var string session_id current user's session_id
+ * @var bool new_session should we create new session for user
+ * @since 3.1.6-RC1
+ */
+ $vars = array('user_id', 'session_id', 'new_session');
+ extract($phpbb_dispatcher->trigger_event('core.session_kill_after', compact($vars)));
+ unset($user_id);
+ unset($session_id);
- $provider = $phpbb_container->get('auth.provider.' . $method);
+ // Allow connecting logout with external auth method logout
+ /* @var $provider_collection \phpbb\auth\provider_collection */
+ $provider_collection = $phpbb_container->get('auth.provider_collection');
+ $provider = $provider_collection->get_provider();
$provider->logout($this->data, $new_session);
if ($this->data['user_id'] != ANONYMOUS)
@@ -962,7 +975,7 @@ class session
*/
function session_gc()
{
- global $db, $config, $phpbb_root_path, $phpEx;
+ global $db, $config, $phpbb_container, $phpbb_dispatcher;
$batch_size = 10;
@@ -1012,7 +1025,7 @@ class session
{
// Less than 10 users, update gc timer ... else we want gc
// called again to delete other sessions
- set_config('session_last_gc', $this->time_now, true);
+ $config->set('session_last_gc', $this->time_now, false);
if ($config['max_autologin_time'])
{
@@ -1022,11 +1035,8 @@ class session
}
// only called from CRON; should be a safe workaround until the infrastructure gets going
- if (!class_exists('phpbb_captcha_factory', false))
- {
- include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx);
- }
- $captcha_factory = new \phpbb_captcha_factory();
+ /* @var $captcha_factory \phpbb\captcha\factory */
+ $captcha_factory = $phpbb_container->get('captcha.factory');
$captcha_factory->garbage_collect($config['captcha_plugin']);
$sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
@@ -1034,6 +1044,14 @@ class session
$db->sql_query($sql);
}
+ /**
+ * Event to trigger extension on session_gc
+ *
+ * @event core.session_gc_after
+ * @since 3.1.6-RC1
+ */
+ $phpbb_dispatcher->dispatch('core.session_gc_after');
+
return;
}
@@ -1045,33 +1063,42 @@ class session
* @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then.
* @param string $cookiedata The data to hold within the cookie
* @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set.
+ * @param bool $httponly Use HttpOnly. Defaults to true. Use false to make cookie accessible by client-side scripts.
*/
- function set_cookie($name, $cookiedata, $cookietime)
+ function set_cookie($name, $cookiedata, $cookietime, $httponly = true)
{
global $config;
+ // If headers are already set, we just return
+ if (headers_sent())
+ {
+ return;
+ }
+
$name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
$expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
- $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
+ $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain'];
- header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
+ header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false);
}
/**
* Check for banned user
*
* Checks whether the supplied user is banned by id, ip or email. If no parameters
- * are passed to the method pre-existing session data is used. If $return is false
- * this routine does not return on finding a banned user, it outputs a relevant
- * message and stops execution.
+ * are passed to the method pre-existing session data is used.
*
- * @param string|array $user_ips Can contain a string with one IP or an array of multiple IPs
+ * @param int|false $user_id The user id
+ * @param mixed $user_ips Can contain a string with one IP or an array of multiple IPs
+ * @param string|false $user_email The user email
+ * @param bool $return If $return is false this routine does not return on finding a banned user,
+ * it outputs a relevant message and stops execution.
*/
function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
{
- global $config, $db;
+ global $config, $db, $phpbb_dispatcher;
- if (defined('IN_CHECK_BAN'))
+ if (defined('IN_CHECK_BAN') || defined('SKIP_CHECK_BAN'))
{
return;
}
@@ -1183,9 +1210,23 @@ class session
}
$db->sql_freeresult($result);
+ /**
+ * Event to set custom ban type
+ *
+ * @event core.session_set_custom_ban
+ * @var bool return If $return is false this routine does not return on finding a banned user, it outputs a relevant message and stops execution
+ * @var bool banned Check if user already banned
+ * @var array|false ban_row Ban data
+ * @var string ban_triggered_by Method that caused ban, can be your custom method
+ * @since 3.1.3-RC1
+ */
+ $ban_row = isset($ban_row) ? $ban_row : false;
+ $vars = array('return', 'banned', 'ban_row', 'ban_triggered_by');
+ extract($phpbb_dispatcher->trigger_event('core.session_set_custom_ban', compact($vars)));
+
if ($banned && !$return)
{
- global $template;
+ global $phpbb_root_path, $phpEx;
// If the session is empty we need to create a valid one...
if (empty($this->session_id))
@@ -1206,8 +1247,6 @@ class session
// We show a login box here to allow founders accessing the board if banned by IP
if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS)
{
- global $phpEx;
-
$this->setup('ucp');
$this->data['is_registered'] = $this->data['is_bot'] = false;
@@ -1231,7 +1270,8 @@ class session
$till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : '';
$message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
- $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>');
+ $contact_link = phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx);
+ $message = sprintf($this->lang[$message], $till_date, '<a href="' . $contact_link . '">', '</a>');
$message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : '';
$message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>';
@@ -1254,12 +1294,14 @@ class session
/**
* Check if ip is blacklisted
- * This should be called only where absolutly necessary
+ * This should be called only where absolutely necessary
*
* Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
*
* @author satmd (from the php manual)
- * @param string $mode register/post - spamcop for example is ommitted for posting
+ * @param string $mode register/post - spamcop for example is ommitted for posting
+ * @param string|false $ip the IPv4 address to check
+ *
* @return false if ip is not blacklisted, else an array([checked server], [lookup])
*/
function check_dnsbl($mode, $ip = false)
@@ -1361,7 +1403,7 @@ class session
*/
function set_login_key($user_id = false, $key = false, $user_ip = false)
{
- global $config, $db;
+ global $db;
$user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
$user_ip = ($user_ip === false) ? $this->ip : $user_ip;
@@ -1371,7 +1413,7 @@ class session
$sql_ary = array(
'key_id' => (string) md5($key_id),
- 'last_ip' => (string) $this->ip,
+ 'last_ip' => (string) $user_ip,
'last_login' => (int) time()
);
@@ -1408,7 +1450,7 @@ class session
*/
function reset_login_keys($user_id = false)
{
- global $config, $db;
+ global $db;
$user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id;
@@ -1509,12 +1551,59 @@ class session
*/
public function update_session($session_data, $session_id = null)
{
- global $db;
+ global $db, $phpbb_dispatcher;
$session_id = ($session_id) ? $session_id : $this->session_id;
$sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $session_data) . "
WHERE session_id = '" . $db->sql_escape($session_id) . "'";
$db->sql_query($sql);
+
+ /**
+ * Event to send update session information to extension
+ * Read-only event
+ *
+ * @event core.update_session_after
+ * @var array session_data Associative array of session keys to be updated
+ * @var string session_id current user's session_id
+ * @since 3.1.6-RC1
+ */
+ $vars = array('session_data', 'session_id');
+ extract($phpbb_dispatcher->trigger_event('core.update_session_after', compact($vars)));
+ }
+
+ public function update_session_infos()
+ {
+ global $config, $db, $request;
+
+ // No need to update if it's a new session. Informations are already inserted by session_create()
+ if (isset($this->data['session_created']) && $this->data['session_created'])
+ {
+ return;
+ }
+
+ // Only update session DB a minute or so after last update or if page changes
+ if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
+ {
+ $sql_ary = array('session_time' => $this->time_now);
+
+ // Do not update the session page for ajax requests, so the view online still works as intended
+ if ($this->update_session_page && !$request->is_ajax())
+ {
+ $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
+ $sql_ary['session_forum_id'] = $this->page['forum'];
+ }
+
+ $db->sql_return_on_error(true);
+
+ $this->update_session($sql_ary);
+
+ $db->sql_return_on_error(false);
+
+ if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
+ {
+ $this->leave_newly_registered();
+ }
+ }
}
}