Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

session.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 60.83 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * @package phpBB3
 0005  * @version $Id$
 0006  * @copyright (c) 2005 phpBB Group
 0007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 0008  *
 0009  */
 0010   
 0011  /**
 0012  * @ignore
 0013  */
 0014  if (!defined('IN_PHPBB'))
 0015  {
 0016      exit;
 0017  }
 0018   
 0019  /**
 0020  * Session class
 0021  * @package phpBB3
 0022  */
 0023  class session
 0024  {
 0025      var $cookie_data = array();
 0026      var $page = array();
 0027      var $data = array();
 0028      var $browser = '';
 0029      var $forwarded_for = '';
 0030      var $host = '';
 0031      var $session_id = '';
 0032      var $ip = '';
 0033      var $load = 0;
 0034      var $time_now = 0;
 0035      var $update_session_page = true;
 0036   
 0037      /**
 0038      * Extract current session page
 0039      *
 0040      * @param string $root_path current root path (phpbb_root_path)
 0041      */
 0042      function extract_current_page($root_path)
 0043      {
 0044          $page_array = array();
 0045   
 0046          // First of all, get the request uri...
 0047          $script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF');
 0048          $args = (!empty($_SERVER['QUERY_STRING'])) ? explode('&', $_SERVER['QUERY_STRING']) : explode('&', getenv('QUERY_STRING'));
 0049   
 0050          // 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...
 0051          if (!$script_name)
 0052          {
 0053              $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI');
 0054              $script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name;
 0055              $page_array['failover'] = 1;
 0056          }
 0057   
 0058          // Replace backslashes and doubled slashes (could happen on some proxy setups)
 0059          $script_name = str_replace(array('\\', '//'), '/', $script_name);
 0060   
 0061          // Now, remove the sid and let us get a clean query string...
 0062          $use_args = array();
 0063   
 0064          // Since some browser do not encode correctly we need to do this with some "special" characters...
 0065          // " -> %22, ' => %27, < -> %3C, > -> %3E
 0066          $find = array('"', "'", '<', '>');
 0067          $replace = array('%22', '%27', '%3C', '%3E');
 0068   
 0069          foreach ($args as $key => $argument)
 0070          {
 0071              if (strpos($argument, 'sid=') === 0 || strpos($argument, '_f_=') === 0)
 0072              {
 0073                  continue;
 0074              }
 0075   
 0076              $use_args[str_replace($find, $replace, $key)] = str_replace($find, $replace, $argument);
 0077          }
 0078          unset($args);
 0079   
 0080          // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2
 0081   
 0082          // The current query string
 0083          $query_string = trim(implode('&', $use_args));
 0084   
 0085          // basenamed page name (for example: index.php)
 0086          $page_name = basename($script_name);
 0087          $page_name = urlencode(htmlspecialchars($page_name));
 0088   
 0089          // current directory within the phpBB root (for example: adm)
 0090          $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path)));
 0091          $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
 0092          $intersection = array_intersect_assoc($root_dirs, $page_dirs);
 0093   
 0094          $root_dirs = array_diff_assoc($root_dirs, $intersection);
 0095          $page_dirs = array_diff_assoc($page_dirs, $intersection);
 0096   
 0097          $page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
 0098   
 0099          if ($page_dir && substr($page_dir, -1, 1) == '/')
 0100          {
 0101              $page_dir = substr($page_dir, 0, -1);
 0102          }
 0103   
 0104          // Current page from phpBB root (for example: adm/index.php?i=10&b=2)
 0105          $page = (($page_dir) ? $page_dir . '/' : '') . $page_name . (($query_string) ? "?$query_string" : '');
 0106   
 0107          // The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in /
 0108          $script_path = trim(str_replace('\\', '/', dirname($script_name)));
 0109   
 0110          // The script path from the webroot to the phpBB root (for example: /phpBB3/)
 0111          $script_dirs = explode('/', $script_path);
 0112          array_splice($script_dirs, -sizeof($page_dirs));
 0113          $root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : '');
 0114   
 0115          // We are on the base level (phpBB root == webroot), lets adjust the variables a bit...
 0116          if (!$root_script_path)
 0117          {
 0118              $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path;
 0119          }
 0120   
 0121          $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/';
 0122          $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/';
 0123   
 0124          $page_array += array(
 0125              'page_name'            => $page_name,
 0126              'page_dir'            => $page_dir,
 0127   
 0128              'query_string'        => $query_string,
 0129              'script_path'        => str_replace(' ', '%20', htmlspecialchars($script_path)),
 0130              'root_script_path'    => str_replace(' ', '%20', htmlspecialchars($root_script_path)),
 0131   
 0132              'page'                => $page
 0133          );
 0134   
 0135          return $page_array;
 0136      }
 0137   
 0138      /**
 0139      * Start session management
 0140      *
 0141      * This is where all session activity begins. We gather various pieces of
 0142      * information from the client and server. We test to see if a session already
 0143      * exists. If it does, fine and dandy. If it doesn't we'll go on to create a
 0144      * new one ... pretty logical heh? We also examine the system load (if we're
 0145      * running on a system which makes such information readily available) and
 0146      * halt if it's above an admin definable limit.
 0147      *
 0148      * @param bool $update_session_page if true the session page gets updated.
 0149      *            This can be set to circumvent certain scripts to update the users last visited page.
 0150      */
 0151      function session_begin($update_session_page = true)
 0152      {
 0153          global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path;
 0154   
 0155          // Give us some basic information
 0156          $this->time_now                = time();
 0157          $this->cookie_data            = array('u' => 0, 'k' => '');
 0158          $this->update_session_page    = $update_session_page;
 0159          $this->browser                = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';
 0160          $this->forwarded_for        = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? (string) $_SERVER['HTTP_X_FORWARDED_FOR'] : '';
 0161          $this->host                    = (!empty($_SERVER['HTTP_HOST'])) ? (string) $_SERVER['HTTP_HOST'] : 'localhost';
 0162          $this->page                    = $this->extract_current_page($phpbb_root_path);
 0163   
 0164          // if the forwarded for header shall be checked we have to validate its contents
 0165          if ($config['forwarded_for_check'])
 0166          {
 0167              $this->forwarded_for = preg_replace('#, +#', ', ', $this->forwarded_for);
 0168   
 0169              // split the list of IPs
 0170              $ips = explode(', ', $this->forwarded_for);
 0171              foreach ($ips as $ip)
 0172              {
 0173                  // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly
 0174                  if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip))
 0175                  {
 0176                      // contains invalid data, don't use the forwarded for header
 0177                      $this->forwarded_for = '';
 0178                      break;
 0179                  }
 0180              }
 0181          }
 0182   
 0183          // Add forum to the page for tracking online users - also adding a "x" to the end to properly identify the number
 0184          $this->page['page'] .= (isset($_REQUEST['f'])) ? ((strpos($this->page['page'], '?') !== false) ? '&' : '?') . '_f_=' . (int) $_REQUEST['f'] . 'x' : '';
 0185   
 0186          if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u']))
 0187          {
 0188              $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
 0189              $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
 0190              $this->session_id         = request_var($config['cookie_name'] . '_sid', '', false, true);
 0191   
 0192              $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
 0193              $_SID = (defined('NEED_SID')) ? $this->session_id : '';
 0194   
 0195              if (empty($this->session_id))
 0196              {
 0197                  $this->session_id = $_SID = request_var('sid', '');
 0198                  $SID = '?sid=' . $this->session_id;
 0199                  $this->cookie_data = array('u' => 0, 'k' => '');
 0200              }
 0201          }
 0202          else
 0203          {
 0204              $this->session_id = $_SID = request_var('sid', '');
 0205              $SID = '?sid=' . $this->session_id;
 0206          }
 0207   
 0208          $_EXTRA_URL = array();
 0209   
 0210          // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests
 0211          // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip.
 0212          $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '';
 0213          $this->load = false;
 0214   
 0215          // Load limit check (if applicable)
 0216          if ($config['limit_load'] || $config['limit_search_load'])
 0217          {
 0218              if ($load = @file_get_contents('/proc/loadavg'))
 0219              {
 0220                  $this->load = array_slice(explode(' ', $load), 0, 1);
 0221                  $this->load = floatval($this->load[0]);
 0222              }
 0223              else
 0224              {
 0225                  set_config('limit_load', '0');
 0226                  set_config('limit_search_load', '0');
 0227              }
 0228          }
 0229   
 0230          // Is session_id is set or session_id is set and matches the url param if required
 0231          if (!empty($this->session_id) && (!defined('NEED_SID') || (isset($_GET['sid']) && $this->session_id === $_GET['sid'])))
 0232          {
 0233              $sql = 'SELECT u.*, s.*
 0234                  FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u
 0235                  WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "'
 0236                      AND u.user_id = s.session_user_id";
 0237              $result = $db->sql_query($sql);
 0238              $this->data = $db->sql_fetchrow($result);
 0239              $db->sql_freeresult($result);
 0240   
 0241              // Did the session exist in the DB?
 0242              if (isset($this->data['user_id']))
 0243              {
 0244                  // Validate IP length according to admin ... enforces an IP
 0245                  // check on bots if admin requires this
 0246  //                $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check'];
 0247   
 0248                  if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
 0249                  {
 0250                      $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
 0251                      $u_ip = short_ipv6($this->ip, $config['ip_check']);
 0252                  }
 0253                  else
 0254                  {
 0255                      $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
 0256                      $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
 0257                  }
 0258   
 0259                  $s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : '';
 0260                  $u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : '';
 0261   
 0262                  $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
 0263                  $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
 0264   
 0265                  if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for)
 0266                  {
 0267                      $session_expired = false;
 0268   
 0269                      // Check whether the session is still valid if we have one
 0270                      $method = basename(trim($config['auth_method']));
 0271                      include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
 0272   
 0273                      $method = 'validate_session_' . $method;
 0274                      if (function_exists($method))
 0275                      {
 0276                          if (!$method($this->data))
 0277                          {
 0278                              $session_expired = true;
 0279                          }
 0280                      }
 0281   
 0282                      if (!$session_expired)
 0283                      {
 0284                          // Check the session length timeframe if autologin is not enabled.
 0285                          // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide.
 0286                          if (!$this->data['session_autologin'])
 0287                          {
 0288                              if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60))
 0289                              {
 0290                                  $session_expired = true;
 0291                              }
 0292                          }
 0293                          else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60))
 0294                          {
 0295                              $session_expired = true;
 0296                          }
 0297                      }
 0298   
 0299                      if (!$session_expired)
 0300                      {
 0301                          // Only update session DB a minute or so after last update or if page changes
 0302                          if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
 0303                          {
 0304                              $sql_ary = array('session_time' => $this->time_now);
 0305   
 0306                              if ($this->update_session_page)
 0307                              {
 0308                                  $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
 0309                              }
 0310   
 0311                              $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
 0312                                  WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
 0313                              $db->sql_query($sql);
 0314                          }
 0315   
 0316                          $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
 0317                          $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false;
 0318                          $this->data['user_lang'] = basename($this->data['user_lang']);
 0319   
 0320                          return true;
 0321                      }
 0322                  }
 0323                  else
 0324                  {
 0325                      // Added logging temporarly to help debug bugs...
 0326                      if (defined('DEBUG_EXTRA') && $this->data['user_id'] != ANONYMOUS)
 0327                      {
 0328                          add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for));
 0329                      }
 0330                  }
 0331              }
 0332          }
 0333   
 0334          // If we reach here then no (valid) session exists. So we'll create a new one
 0335          return $this->session_create();
 0336      }
 0337   
 0338      /**
 0339      * Create a new session
 0340      *
 0341      * If upon trying to start a session we discover there is nothing existing we
 0342      * jump here. Additionally this method is called directly during login to regenerate
 0343      * the session for the specific user. In this method we carry out a number of tasks;
 0344      * garbage collection, (search)bot checking, banned user comparison. Basically
 0345      * though this method will result in a new session for a specific user.
 0346      */
 0347      function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
 0348      {
 0349          global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx;
 0350   
 0351          $this->data = array();
 0352   
 0353          /* Garbage collection ... remove old sessions updating user information
 0354          // if necessary. It means (potentially) 11 queries but only infrequently
 0355          if ($this->time_now > $config['session_last_gc'] + $config['session_gc'])
 0356          {
 0357              $this->session_gc();
 0358          }*/
 0359   
 0360          // Do we allow autologin on this board? No? Then override anything
 0361          // that may be requested here
 0362          if (!$config['allow_autologin'])
 0363          {
 0364              $this->cookie_data['k'] = $persist_login = false;
 0365          }
 0366   
 0367          /**
 0368          * Here we do a bot check, oh er saucy! No, not that kind of bot
 0369          * check. We loop through the list of bots defined by the admin and
 0370          * see if we have any useragent and/or IP matches. If we do, this is a
 0371          * bot, act accordingly
 0372          */
 0373          $bot = false;
 0374          $active_bots = $cache->obtain_bots();
 0375   
 0376          foreach ($active_bots as $row)
 0377          {
 0378              if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser))
 0379              {
 0380                  $bot = $row['user_id'];
 0381              }
 0382   
 0383              // If ip is supplied, we will make sure the ip is matching too...
 0384              if ($row['bot_ip'] && ($bot || !$row['bot_agent']))
 0385              {
 0386                  // Set bot to false, then we only have to set it to true if it is matching
 0387                  $bot = false;
 0388   
 0389                  foreach (explode(',', $row['bot_ip']) as $bot_ip)
 0390                  {
 0391                      if (strpos($this->ip, $bot_ip) === 0)
 0392                      {
 0393                          $bot = (int) $row['user_id'];
 0394                          break;
 0395                      }
 0396                  }
 0397              }
 0398   
 0399              if ($bot)
 0400              {
 0401                  break;
 0402              }
 0403          }
 0404   
 0405          $method = basename(trim($config['auth_method']));
 0406          include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
 0407   
 0408          $method = 'autologin_' . $method;
 0409          if (function_exists($method))
 0410          {
 0411              $this->data = $method();
 0412   
 0413              if (sizeof($this->data))
 0414              {
 0415                  $this->cookie_data['k'] = '';
 0416                  $this->cookie_data['u'] = $this->data['user_id'];
 0417              }
 0418          }
 0419   
 0420          // If we're presented with an autologin key we'll join against it.
 0421          // Else if we've been passed a user_id we'll grab data based on that
 0422          if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
 0423          {
 0424              $sql = 'SELECT u.*
 0425                  FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k
 0426                  WHERE u.user_id = ' . (int) $this->cookie_data['u'] . '
 0427                      AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ")
 0428                      AND k.user_id = u.user_id
 0429                      AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
 0430              $result = $db->sql_query($sql);
 0431              $this->data = $db->sql_fetchrow($result);
 0432              $db->sql_freeresult($result);
 0433              $bot = false;
 0434          }
 0435          else if ($user_id !== false && !sizeof($this->data))
 0436          {
 0437              $this->cookie_data['k'] = '';
 0438              $this->cookie_data['u'] = $user_id;
 0439   
 0440              $sql = 'SELECT *
 0441                  FROM ' . USERS_TABLE . '
 0442                  WHERE user_id = ' . (int) $this->cookie_data['u'] . '
 0443                      AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
 0444              $result = $db->sql_query($sql);
 0445              $this->data = $db->sql_fetchrow($result);
 0446              $db->sql_freeresult($result);
 0447              $bot = false;
 0448          }
 0449   
 0450          // If no data was returned one or more of the following occurred:
 0451          // Key didn't match one in the DB
 0452          // User does not exist
 0453          // User is inactive
 0454          // User is bot
 0455          if (!sizeof($this->data) || !is_array($this->data))
 0456          {
 0457              $this->cookie_data['k'] = '';
 0458              $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS;
 0459   
 0460              if (!$bot)
 0461              {
 0462                  $sql = 'SELECT *
 0463                      FROM ' . USERS_TABLE . '
 0464                      WHERE user_id = ' . (int) $this->cookie_data['u'];
 0465              }
 0466              else
 0467              {
 0468                  // We give bots always the same session if it is not yet expired.
 0469                  $sql = 'SELECT u.*, s.*
 0470                      FROM ' . USERS_TABLE . ' u
 0471                      LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id)
 0472                      WHERE u.user_id = ' . (int) $bot;
 0473              }
 0474   
 0475              $result = $db->sql_query($sql);
 0476              $this->data = $db->sql_fetchrow($result);
 0477              $db->sql_freeresult($result);
 0478          }
 0479   
 0480          if ($this->data['user_id'] != ANONYMOUS && !$bot)
 0481          {
 0482              $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time());
 0483          }
 0484          else
 0485          {
 0486              $this->data['session_last_visit'] = $this->time_now;
 0487          }
 0488   
 0489          // Force user id to be integer...
 0490          $this->data['user_id'] = (int) $this->data['user_id'];
 0491   
 0492          // At this stage we should have a filled data array, defined cookie u and k data.
 0493          // data array should contain recent session info if we're a real user and a recent
 0494          // session exists in which case session_id will also be set
 0495   
 0496          // Is user banned? Are they excluded? Won't return on ban, exists within method
 0497          if ($this->data['user_type'] != USER_FOUNDER)
 0498          {
 0499              if (!$config['forwarded_for_check'])
 0500              {
 0501                  $this->check_ban($this->data['user_id'], $this->ip);
 0502              }
 0503              else
 0504              {
 0505                  $ips = explode(', ', $this->forwarded_for);
 0506                  $ips[] = $this->ip;
 0507                  $this->check_ban($this->data['user_id'], $ips);
 0508              }
 0509          }
 0510   
 0511          $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
 0512          $this->data['is_bot'] = ($bot) ? true : false;
 0513   
 0514          // If our friend is a bot, we re-assign a previously assigned session
 0515          if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id'])
 0516          {
 0517              // Only assign the current session if the ip, browser and forwarded_for match...
 0518              if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
 0519              {
 0520                  $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
 0521                  $u_ip = short_ipv6($this->ip, $config['ip_check']);
 0522              }
 0523              else
 0524              {
 0525                  $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
 0526                  $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
 0527              }
 0528   
 0529              $s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : '';
 0530              $u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : '';
 0531   
 0532              $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
 0533              $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
 0534   
 0535              if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for)
 0536              {
 0537                  $this->session_id = $this->data['session_id'];
 0538   
 0539                  // Only update session DB a minute or so after last update or if page changes
 0540                  if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
 0541                  {
 0542                      $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
 0543   
 0544                      $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0);
 0545   
 0546                      if ($this->update_session_page)
 0547                      {
 0548                          $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
 0549                      }
 0550   
 0551                      $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
 0552                          WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
 0553                      $db->sql_query($sql);
 0554   
 0555                      // Update the last visit time
 0556                      $sql = 'UPDATE ' . USERS_TABLE . '
 0557                          SET user_lastvisit = ' . (int) $this->data['session_time'] . '
 0558                          WHERE user_id = ' . (int) $this->data['user_id'];
 0559                      $db->sql_query($sql);
 0560                  }
 0561   
 0562                  $SID = '?sid=';
 0563                  $_SID = '';
 0564                  return true;
 0565              }
 0566              else
 0567              {
 0568                  // If the ip and browser does not match make sure we only have one bot assigned to one session
 0569                  $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']);
 0570              }
 0571          }
 0572   
 0573          $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false;
 0574          $set_admin = ($set_admin && $this->data['is_registered']) ? true : false;
 0575   
 0576          // Create or update the session
 0577          $sql_ary = array(
 0578              'session_user_id'        => (int) $this->data['user_id'],
 0579              'session_start'            => (int) $this->time_now,
 0580              'session_last_visit'    => (int) $this->data['session_last_visit'],
 0581              'session_time'            => (int) $this->time_now,
 0582              'session_browser'        => (string) substr($this->browser, 0, 149),
 0583              'session_forwarded_for'    => (string) $this->forwarded_for,
 0584              'session_ip'            => (string) $this->ip,
 0585              'session_autologin'        => ($session_autologin) ? 1 : 0,
 0586              'session_admin'            => ($set_admin) ? 1 : 0,
 0587              'session_viewonline'    => ($viewonline) ? 1 : 0,
 0588          );
 0589   
 0590          if ($this->update_session_page)
 0591          {
 0592              $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
 0593          }
 0594   
 0595          $db->sql_return_on_error(true);
 0596   
 0597          $sql = 'DELETE
 0598              FROM ' . SESSIONS_TABLE . '
 0599              WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\'
 0600                  AND session_user_id = ' . ANONYMOUS;
 0601   
 0602          if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows()))
 0603          {
 0604              // Limit new sessions in 1 minute period (if required)
 0605              if (empty($this->data['session_time']) && $config['active_sessions'])
 0606              {
 0607                  $sql = 'SELECT COUNT(session_id) AS sessions
 0608                      FROM ' . SESSIONS_TABLE . '
 0609                      WHERE session_time >= ' . ($this->time_now - 60);
 0610                  $result = $db->sql_query($sql);
 0611                  $row = $db->sql_fetchrow($result);
 0612                  $db->sql_freeresult($result);
 0613   
 0614                  if ((int) $row['sessions'] > (int) $config['active_sessions'])
 0615                  {
 0616                      header('HTTP/1.1 503 Service Unavailable');
 0617                      trigger_error('BOARD_UNAVAILABLE');
 0618                  }
 0619              }
 0620          }
 0621   
 0622          $this->session_id = $this->data['session_id'] = md5(unique_id());
 0623   
 0624          $sql_ary['session_id'] = (string) $this->session_id;
 0625          $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
 0626   
 0627          $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
 0628          $db->sql_query($sql);
 0629   
 0630          $db->sql_return_on_error(false);
 0631   
 0632          // Regenerate autologin/persistent login key
 0633          if ($session_autologin)
 0634          {
 0635              $this->set_login_key();
 0636          }
 0637   
 0638          // refresh data
 0639          $SID = '?sid=' . $this->session_id;
 0640          $_SID = $this->session_id;
 0641          $this->data = array_merge($this->data, $sql_ary);
 0642   
 0643          if (!$bot)
 0644          {
 0645              $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000);
 0646   
 0647              $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire);
 0648              $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire);
 0649              $this->set_cookie('sid', $this->session_id, $cookie_expire);
 0650   
 0651              unset($cookie_expire);
 0652              
 0653              $sql = 'SELECT COUNT(session_id) AS sessions
 0654                      FROM ' . SESSIONS_TABLE . '
 0655                      WHERE session_user_id = ' . (int) $this->data['user_id'] . '
 0656                      AND session_time >= ' . ($this->time_now - $config['form_token_lifetime']);
 0657              $result = $db->sql_query($sql);
 0658              $row = $db->sql_fetchrow($result);
 0659              $db->sql_freeresult($result);
 0660   
 0661              if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt']))
 0662              {
 0663                  $this->data['user_form_salt'] = unique_id();
 0664                  // Update the form key
 0665                  $sql = 'UPDATE ' . USERS_TABLE . '
 0666                      SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\'
 0667                      WHERE user_id = ' . (int) $this->data['user_id'];
 0668                  $db->sql_query($sql);
 0669              }
 0670          }
 0671          else
 0672          {
 0673              $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
 0674   
 0675              // Update the last visit time
 0676              $sql = 'UPDATE ' . USERS_TABLE . '
 0677                  SET user_lastvisit = ' . (int) $this->data['session_time'] . '
 0678                  WHERE user_id = ' . (int) $this->data['user_id'];
 0679              $db->sql_query($sql);
 0680   
 0681              $SID = '?sid=';
 0682              $_SID = '';
 0683          }
 0684   
 0685          return true;
 0686      }
 0687   
 0688      /**
 0689      * Kills a session
 0690      *
 0691      * This method does what it says on the tin. It will delete a pre-existing session.
 0692      * It resets cookie information (destroying any autologin key within that cookie data)
 0693      * and update the users information from the relevant session data. It will then
 0694      * grab guest user information.
 0695      */
 0696      function session_kill($new_session = true)
 0697      {
 0698          global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx;
 0699   
 0700          $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
 0701              WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
 0702                  AND session_user_id = " . (int) $this->data['user_id'];
 0703          $db->sql_query($sql);
 0704   
 0705          // Allow connecting logout with external auth method logout
 0706          $method = basename(trim($config['auth_method']));
 0707          include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
 0708   
 0709          $method = 'logout_' . $method;
 0710          if (function_exists($method))
 0711          {
 0712              $method($this->data, $new_session);
 0713          }
 0714   
 0715          if ($this->data['user_id'] != ANONYMOUS)
 0716          {
 0717              // Delete existing session, update last visit info first!
 0718              if (!isset($this->data['session_time']))
 0719              {
 0720                  $this->data['session_time'] = time();
 0721              }
 0722   
 0723              $sql = 'UPDATE ' . USERS_TABLE . '
 0724                  SET user_lastvisit = ' . (int) $this->data['session_time'] . '
 0725                  WHERE user_id = ' . (int) $this->data['user_id'];
 0726              $db->sql_query($sql);
 0727   
 0728              if ($this->cookie_data['k'])
 0729              {
 0730                  $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
 0731                      WHERE user_id = ' . (int) $this->data['user_id'] . "
 0732                          AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
 0733                  $db->sql_query($sql);
 0734              }
 0735   
 0736              // Reset the data array
 0737              $this->data = array();
 0738   
 0739              $sql = 'SELECT *
 0740                  FROM ' . USERS_TABLE . '
 0741                  WHERE user_id = ' . ANONYMOUS;
 0742              $result = $db->sql_query($sql);
 0743              $this->data = $db->sql_fetchrow($result);
 0744              $db->sql_freeresult($result);
 0745          }
 0746   
 0747          $cookie_expire = $this->time_now - 31536000;
 0748          $this->set_cookie('u', '', $cookie_expire);
 0749          $this->set_cookie('k', '', $cookie_expire);
 0750          $this->set_cookie('sid', '', $cookie_expire);
 0751          unset($cookie_expire);
 0752   
 0753          $SID = '?sid=';
 0754          $this->session_id = $_SID = '';
 0755   
 0756          // To make sure a valid session is created we create one for the anonymous user
 0757          if ($new_session)
 0758          {
 0759              $this->session_create(ANONYMOUS);
 0760          }
 0761   
 0762          return true;
 0763      }
 0764   
 0765      /**
 0766      * Session garbage collection
 0767      *
 0768      * This looks a lot more complex than it really is. Effectively we are
 0769      * deleting any sessions older than an admin definable limit. Due to the
 0770      * way in which we maintain session data we have to ensure we update user
 0771      * data before those sessions are destroyed. In addition this method
 0772      * removes autologin key information that is older than an admin defined
 0773      * limit.
 0774      */
 0775      function session_gc()
 0776      {
 0777          global $db, $config;
 0778   
 0779          $batch_size = 10;
 0780          
 0781          if (!$this->time_now)
 0782          {
 0783              $this->time_now = time();
 0784          }
 0785   
 0786          // Firstly, delete guest sessions
 0787          $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
 0788              WHERE session_user_id = ' . ANONYMOUS . '
 0789                  AND session_time < ' . (int) ($this->time_now - $config['session_length']);
 0790          $db->sql_query($sql);
 0791   
 0792          // Get expired sessions, only most recent for each user
 0793          $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time
 0794              FROM ' . SESSIONS_TABLE . '
 0795              WHERE session_time < ' . ($this->time_now - $config['session_length']) . '
 0796              GROUP BY session_user_id, session_page';
 0797          $result = $db->sql_query_limit($sql, $batch_size);
 0798   
 0799          $del_user_id = array();
 0800          $del_sessions = 0;
 0801   
 0802          while ($row = $db->sql_fetchrow($result))
 0803          {
 0804              $sql = 'UPDATE ' . USERS_TABLE . '
 0805                  SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "'
 0806                  WHERE user_id = " . (int) $row['session_user_id'];
 0807              $db->sql_query($sql);
 0808   
 0809              $del_user_id[] = (int) $row['session_user_id'];
 0810              $del_sessions++;
 0811          }
 0812          $db->sql_freeresult($result);
 0813   
 0814          if (sizeof($del_user_id))
 0815          {
 0816              // Delete expired sessions
 0817              $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
 0818                  WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . '
 0819                      AND session_time < ' . ($this->time_now - $config['session_length']);
 0820              $db->sql_query($sql);
 0821          }
 0822   
 0823          if ($del_sessions < $batch_size)
 0824          {
 0825              // Less than 10 users, update gc timer ... else we want gc
 0826              // called again to delete other sessions
 0827              set_config('session_last_gc', $this->time_now, true);
 0828              
 0829              if ($config['max_autologin_time'])
 0830              {
 0831                  $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
 0832                      WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time']));
 0833                  $db->sql_query($sql);
 0834              }
 0835              $this->confirm_gc();
 0836          }
 0837          
 0838          return;
 0839      }
 0840      
 0841      function confirm_gc($type = 0)
 0842      {
 0843          global $db, $config;
 0844          
 0845          $sql = 'SELECT DISTINCT c.session_id
 0846                  FROM ' . CONFIRM_TABLE . ' c
 0847                  LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id)
 0848                  WHERE s.session_id IS NULL' .
 0849                      ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type);
 0850          $result = $db->sql_query($sql);
 0851   
 0852          if ($row = $db->sql_fetchrow($result))
 0853          {
 0854              $sql_in = array();
 0855              do
 0856              {
 0857                  $sql_in[] = (string) $row['session_id'];
 0858              }
 0859              while ($row = $db->sql_fetchrow($result));
 0860   
 0861              if (sizeof($sql_in))
 0862              {
 0863                  $sql = 'DELETE FROM ' . CONFIRM_TABLE . '
 0864                      WHERE ' . $db->sql_in_set('session_id', $sql_in);
 0865                  $db->sql_query($sql);
 0866              }
 0867          }
 0868          $db->sql_freeresult($result);
 0869      }
 0870      
 0871      
 0872      /**
 0873      * Sets a cookie
 0874      *
 0875      * Sets a cookie of the given name with the specified data for the given length of time.
 0876      */
 0877      function set_cookie($name, $cookiedata, $cookietime)
 0878      {
 0879          global $config;
 0880   
 0881          $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
 0882          $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
 0883          $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
 0884   
 0885          header('Set-Cookie: ' . $name_data . '; expires=' . $expire . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
 0886      }
 0887   
 0888      /**
 0889      * Check for banned user
 0890      *
 0891      * Checks whether the supplied user is banned by id, ip or email. If no parameters
 0892      * are passed to the method pre-existing session data is used. If $return is false
 0893      * this routine does not return on finding a banned user, it outputs a relevant
 0894      * message and stops execution.
 0895      *
 0896      * @param string|array    $user_ips    Can contain a string with one IP or an array of multiple IPs
 0897      */
 0898      function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
 0899      {
 0900          global $config, $db;
 0901   
 0902          if (defined('IN_CHECK_BAN'))
 0903          {
 0904              return;
 0905          }
 0906   
 0907          $banned = false;
 0908          $cache_ttl = 3600;
 0909          $where_sql = array();
 0910   
 0911          $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end
 0912              FROM ' . BANLIST_TABLE . '
 0913              WHERE ';
 0914   
 0915          // Determine which entries to check, only return those
 0916          if ($user_email === false)
 0917          {
 0918              $where_sql[] = "ban_email = ''";
 0919          }
 0920   
 0921          if ($user_ips === false)
 0922          {
 0923              $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)";
 0924          }
 0925   
 0926          if ($user_id === false)
 0927          {
 0928              $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)';
 0929          }
 0930          else
 0931          {
 0932              $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0;
 0933              $_sql = '(ban_userid = ' . $user_id;
 0934   
 0935              if ($user_email !== false)
 0936              {
 0937                  $_sql .= " OR ban_email <> ''";
 0938              }
 0939   
 0940              if ($user_ips !== false)
 0941              {
 0942                  $_sql .= " OR ban_ip <> ''";
 0943              }
 0944   
 0945              $_sql .= ')';
 0946   
 0947              $where_sql[] = $_sql;
 0948          }
 0949   
 0950          $sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : '';
 0951          $result = $db->sql_query($sql, $cache_ttl);
 0952   
 0953          $ban_triggered_by = 'user';
 0954          while ($row = $db->sql_fetchrow($result))
 0955          {
 0956              if ($row['ban_end'] && $row['ban_end'] < time())
 0957              {
 0958                  continue;
 0959              }
 0960   
 0961              $ip_banned = false;
 0962              if (!empty($row['ban_ip']))
 0963              {
 0964                  if (!is_array($user_ips))
 0965                  {
 0966                      $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips);
 0967                  }
 0968                  else
 0969                  {
 0970                      foreach ($user_ips as $user_ip)
 0971                      {
 0972                          if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip))
 0973                          {
 0974                              $ip_banned = true;
 0975                              break;
 0976                          }
 0977                      }
 0978                  }
 0979              }
 0980   
 0981              if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) ||
 0982                  $ip_banned ||
 0983                  (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email)))
 0984              {
 0985                  if (!empty($row['ban_exclude']))
 0986                  {
 0987                      $banned = false;
 0988                      break;
 0989                  }
 0990                  else
 0991                  {
 0992                      $banned = true;
 0993                      $ban_row = $row;
 0994   
 0995                      if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id)
 0996                      {
 0997                          $ban_triggered_by = 'user';
 0998                      }
 0999                      else if ($ip_banned)
 1000                      {
 1001                          $ban_triggered_by = 'ip';
 1002                      }
 1003                      else
 1004                      {
 1005                          $ban_triggered_by = 'email';
 1006                      }
 1007   
 1008                      // Don't break. Check if there is an exclude rule for this user
 1009                  }
 1010              }
 1011          }
 1012          $db->sql_freeresult($result);
 1013   
 1014          if ($banned && !$return)
 1015          {
 1016              global $template;
 1017   
 1018              // If the session is empty we need to create a valid one...
 1019              if (empty($this->session_id))
 1020              {
 1021                  // This seems to be no longer needed? - #14971
 1022  //                $this->session_create(ANONYMOUS);
 1023              }
 1024   
 1025              // Initiate environment ... since it won't be set at this stage
 1026              $this->setup();
 1027   
 1028              // Logout the user, banned users are unable to use the normal 'logout' link
 1029              if ($this->data['user_id'] != ANONYMOUS)
 1030              {
 1031                  $this->session_kill();
 1032              }
 1033   
 1034              // We show a login box here to allow founders accessing the board if banned by IP
 1035              if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS)
 1036              {
 1037                  global $phpEx;
 1038   
 1039                  $this->setup('ucp');
 1040                  $this->data['is_registered'] = $this->data['is_bot'] = false;
 1041   
 1042                  // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again.
 1043                  define('IN_CHECK_BAN', 1);
 1044   
 1045                  login_box("index.$phpEx");
 1046   
 1047                  // The false here is needed, else the user is able to circumvent the ban.
 1048                  $this->session_kill(false);
 1049              }
 1050   
 1051              // Ok, we catch the case of an empty session id for the anonymous user...
 1052              // This can happen if the user is logging in, banned by username and the login_box() being called "again".
 1053              if (empty($this->session_id) && defined('IN_CHECK_BAN'))
 1054              {
 1055                  $this->session_create(ANONYMOUS);
 1056              }
 1057   
 1058   
 1059              // Determine which message to output
 1060              $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : '';
 1061              $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
 1062   
 1063              $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>');
 1064              $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : '';
 1065              $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>';
 1066   
 1067              // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again
 1068              $this->session_kill(false);
 1069   
 1070              trigger_error($message);
 1071          }
 1072   
 1073          return ($banned) ? true : false;
 1074      }
 1075   
 1076      /**
 1077      * Check if ip is blacklisted
 1078      * This should be called only where absolutly necessary
 1079      *
 1080      * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
 1081      *
 1082      * @author satmd (from the php manual)
 1083      * @param string $mode register/post - spamcop for example is ommitted for posting
 1084      * @return false if ip is not blacklisted, else an array([checked server], [lookup])
 1085      */
 1086      function check_dnsbl($mode, $ip = false)
 1087      {
 1088          if ($ip === false)
 1089          {
 1090              $ip = $this->ip;
 1091          }
 1092   
 1093          $dnsbl_check = array(
 1094              'list.dsbl.org'            => 'http://dsbl.org/listing?',
 1095              'sbl-xbl.spamhaus.org'    => 'http://www.spamhaus.org/query/bl?ip=',
 1096          );
 1097   
 1098          if ($mode == 'register')
 1099          {
 1100              $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?';
 1101          }
 1102   
 1103          if ($ip)
 1104          {
 1105              $quads = explode('.', $ip);
 1106              $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0];
 1107   
 1108              // Need to be listed on all servers...
 1109              $listed = true;
 1110              $info = array();
 1111   
 1112              foreach ($dnsbl_check as $dnsbl => $lookup)
 1113              {
 1114                  if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true)
 1115                  {
 1116                      $info = array($dnsbl, $lookup . $ip);
 1117                  }
 1118                  else
 1119                  {
 1120                      $listed = false;
 1121                  }
 1122              }
 1123   
 1124              if ($listed)
 1125              {
 1126                  return $info;
 1127              }
 1128          }
 1129   
 1130          return false;
 1131      }
 1132   
 1133      /**
 1134      * Check if URI is blacklisted
 1135      * This should be called only where absolutly necessary, for example on the submitted website field
 1136      * This function is not in use at the moment and is only included for testing purposes, it may not work at all!
 1137      * This means it is untested at the moment and therefore commented out
 1138      *
 1139      * @param string $uri URI to check
 1140      * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists
 1141      function check_uribl($uri)
 1142      {
 1143          // Normally parse_url() is not intended to parse uris
 1144          // We need to get the top-level domain name anyway... change.
 1145          $uri = parse_url($uri);
 1146   
 1147          if ($uri === false || empty($uri['host']))
 1148          {
 1149              return false;
 1150          }
 1151   
 1152          $uri = trim($uri['host']);
 1153   
 1154          if ($uri)
 1155          {
 1156              // One problem here... the return parameter for the "windows" method is different from what
 1157              // we expect... this may render this check useless...
 1158              if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true)
 1159              {
 1160                  return true;
 1161              }
 1162          }
 1163   
 1164          return false;
 1165      }
 1166      */
 1167   
 1168      /**
 1169      * Set/Update a persistent login key
 1170      *
 1171      * This method creates or updates a persistent session key. When a user makes
 1172      * use of persistent (formerly auto-) logins a key is generated and stored in the
 1173      * DB. When they revisit with the same key it's automatically updated in both the
 1174      * DB and cookie. Multiple keys may exist for each user representing different
 1175      * browsers or locations. As with _any_ non-secure-socket no passphrase login this
 1176      * remains vulnerable to exploit.
 1177      */
 1178      function set_login_key($user_id = false, $key = false, $user_ip = false)
 1179      {
 1180          global $config, $db;
 1181   
 1182          $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
 1183          $user_ip = ($user_ip === false) ? $this->ip : $user_ip;
 1184          $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key;
 1185   
 1186          $key_id = unique_id(hexdec(substr($this->session_id, 0, 8)));
 1187   
 1188          $sql_ary = array(
 1189              'key_id'        => (string) md5($key_id),
 1190              'last_ip'        => (string) $this->ip,
 1191              'last_login'    => (int) time()
 1192          );
 1193   
 1194          if (!$key)
 1195          {
 1196              $sql_ary += array(
 1197                  'user_id'    => (int) $user_id
 1198              );
 1199          }
 1200   
 1201          if ($key)
 1202          {
 1203              $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . '
 1204                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 1205                  WHERE user_id = ' . (int) $user_id . "
 1206                      AND key_id = '" . $db->sql_escape(md5($key)) . "'";
 1207          }
 1208          else
 1209          {
 1210              $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
 1211          }
 1212          $db->sql_query($sql);
 1213   
 1214          $this->cookie_data['k'] = $key_id;
 1215   
 1216          return false;
 1217      }
 1218   
 1219      /**
 1220      * Reset all login keys for the specified user
 1221      *
 1222      * This method removes all current login keys for a specified (or the current)
 1223      * user. It will be called on password change to render old keys unusable
 1224      */
 1225      function reset_login_keys($user_id = false)
 1226      {
 1227          global $config, $db;
 1228   
 1229          $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
 1230   
 1231          $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
 1232              WHERE user_id = ' . (int) $user_id;
 1233          $db->sql_query($sql);
 1234   
 1235          // Let's also clear any current sessions for the specified user_id
 1236          // If it's the current user then we'll leave this session intact
 1237          $sql_where = 'session_user_id = ' . (int) $user_id;
 1238          $sql_where .= ($user_id === $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : '';
 1239   
 1240          $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
 1241              WHERE $sql_where";
 1242          $db->sql_query($sql);
 1243   
 1244          // We're changing the password of the current user and they have a key
 1245          // Lets regenerate it to be safe
 1246          if ($user_id === $this->data['user_id'] && $this->cookie_data['k'])
 1247          {
 1248              $this->set_login_key($user_id);
 1249          }
 1250      }
 1251  }
 1252   
 1253   
 1254  /**
 1255  * Base user class
 1256  *
 1257  * This is the overarching class which contains (through session extend)
 1258  * all methods utilised for user functionality during a session.
 1259  *
 1260  * @package phpBB3
 1261  */
 1262  class user extends session
 1263  {
 1264      var $lang = array();
 1265      var $help = array();
 1266      var $theme = array();
 1267      var $date_format;
 1268      var $timezone;
 1269      var $dst;
 1270   
 1271      var $lang_name;
 1272      var $lang_id = false;
 1273      var $lang_path;
 1274      var $img_lang;
 1275      var $img_array = array();
 1276   
 1277      // Able to add new option (id 7)
 1278      var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10);
 1279      var $keyvalues = array();
 1280   
 1281      /**
 1282      * Setup basic user-specific items (style, language, ...)
 1283      */
 1284      function setup($lang_set = false, $style = false)
 1285      {
 1286          global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
 1287   
 1288          if ($this->data['user_id'] != ANONYMOUS)
 1289          {
 1290              $this->lang_name = (file_exists($phpbb_root_path . 'language/' . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
 1291              $this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/';
 1292   
 1293              $this->date_format = $this->data['user_dateformat'];
 1294              $this->timezone = $this->data['user_timezone'] * 3600;
 1295              $this->dst = $this->data['user_dst'] * 3600;
 1296          }
 1297          else
 1298          {
 1299              $this->lang_name = basename($config['default_lang']);
 1300              $this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/';
 1301              $this->date_format = $config['default_dateformat'];
 1302              $this->timezone = $config['board_timezone'] * 3600;
 1303              $this->dst = $config['board_dst'] * 3600;
 1304   
 1305              /**
 1306              * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language
 1307              * If re-enabled we need to make sure only those languages installed are checked
 1308              * Commented out so we do not loose the code.
 1309   
 1310              if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
 1311              {
 1312                  $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
 1313   
 1314                  foreach ($accept_lang_ary as $accept_lang)
 1315                  {
 1316                      // Set correct format ... guess full xx_YY form
 1317                      $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2));
 1318                      $accept_lang = basename($accept_lang);
 1319   
 1320                      if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx"))
 1321                      {
 1322                          $this->lang_name = $config['default_lang'] = $accept_lang;
 1323                          $this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/';
 1324                          break;
 1325                      }
 1326                      else
 1327                      {
 1328                          // No match on xx_YY so try xx
 1329                          $accept_lang = substr($accept_lang, 0, 2);
 1330                          $accept_lang = basename($accept_lang);
 1331   
 1332                          if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx"))
 1333                          {
 1334                              $this->lang_name = $config['default_lang'] = $accept_lang;
 1335                              $this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/';
 1336                              break;
 1337                          }
 1338                      }
 1339                  }
 1340              }
 1341              */
 1342          }
 1343   
 1344          // We include common language file here to not load it every time a custom language file is included
 1345          $lang = &$this->lang;
 1346   
 1347          if ((@include $this->lang_path . "common.$phpEx") === false)
 1348          {
 1349              die('Language file ' . $this->lang_name . "/common.$phpEx" . " couldn't be opened.");
 1350          }
 1351   
 1352          $this->add_lang($lang_set);
 1353          unset($lang_set);
 1354   
 1355          if (!empty($_GET['style']) && $auth->acl_get('a_styles'))
 1356          {
 1357              global $SID, $_EXTRA_URL;
 1358   
 1359              $style = request_var('style', 0);
 1360              $SID .= '&amp;style=' . $style;
 1361              $_EXTRA_URL = array('style=' . $style);
 1362          }
 1363          else
 1364          {
 1365              // Set up style
 1366              $style = ($style) ? $style : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']);
 1367          }
 1368   
 1369          $sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name
 1370              FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i
 1371              WHERE s.style_id = $style
 1372                  AND t.template_id = s.template_id
 1373                  AND c.theme_id = s.theme_id
 1374                  AND i.imageset_id = s.imageset_id";
 1375          $result = $db->sql_query($sql, 3600);
 1376          $this->theme = $db->sql_fetchrow($result);
 1377          $db->sql_freeresult($result);
 1378   
 1379          // User has wrong style
 1380          if (!$this->theme && $style == $this->data['user_style'])
 1381          {
 1382              $style = $this->data['user_style'] = $config['default_style'];
 1383   
 1384              $sql = 'UPDATE ' . USERS_TABLE . "
 1385                  SET user_style = $style
 1386                  WHERE user_id = {$this->data['user_id']}";
 1387              $db->sql_query($sql);
 1388   
 1389              $sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name
 1390                  FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i
 1391                  WHERE s.style_id = $style
 1392                      AND t.template_id = s.template_id
 1393                      AND c.theme_id = s.theme_id
 1394                      AND i.imageset_id = s.imageset_id";
 1395              $result = $db->sql_query($sql, 3600);
 1396              $this->theme = $db->sql_fetchrow($result);
 1397              $db->sql_freeresult($result);
 1398          }
 1399   
 1400          if (!$this->theme)
 1401          {
 1402              trigger_error('Could not get style data', E_USER_ERROR);
 1403          }
 1404   
 1405          // Now parse the cfg file and cache it
 1406          $parsed_items = $cache->obtain_cfg_items($this->theme);
 1407   
 1408          // We are only interested in the theme configuration for now
 1409          $parsed_items = $parsed_items['theme'];
 1410   
 1411          $check_for = array(
 1412              'parse_css_file'    => (int) 0,
 1413              'pagination_sep'    => (string) ', '
 1414          );
 1415   
 1416          foreach ($check_for as $key => $default_value)
 1417          {
 1418              $this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value;
 1419              settype($this->theme[$key], gettype($default_value));
 1420   
 1421              if (is_string($default_value))
 1422              {
 1423                  $this->theme[$key] = htmlspecialchars($this->theme[$key]);
 1424              }
 1425          }
 1426   
 1427          // If the style author specified the theme needs to be cached
 1428          // (because of the used paths and variables) than make sure it is the case.
 1429          // For example, if the theme uses language-specific images it needs to be stored in db.
 1430          if (!$this->theme['theme_storedb'] && $this->theme['parse_css_file'])
 1431          {
 1432              $this->theme['theme_storedb'] = 1;
 1433   
 1434              $stylesheet = file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/stylesheet.css");
 1435              // Match CSS imports
 1436              $matches = array();
 1437              preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches);
 1438   
 1439              if (sizeof($matches))
 1440              {
 1441                  $content = '';
 1442                  foreach ($matches[0] as $idx => $match)
 1443                  {
 1444                      if ($content = @file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/" . $matches[1][$idx]))
 1445                      {
 1446                          $content = trim($content);
 1447                      }
 1448                      else
 1449                      {
 1450                          $content = '';
 1451                      }
 1452                      $stylesheet = str_replace($match, $content, $stylesheet);
 1453                  }
 1454                  unset($content);
 1455              }
 1456   
 1457              $stylesheet = str_replace('./', 'styles/' . $this->theme['theme_path'] . '/theme/', $stylesheet);
 1458   
 1459              $sql_ary = array(
 1460                  'theme_data'    => $stylesheet,
 1461                  'theme_mtime'    => time(),
 1462                  'theme_storedb'    => 1
 1463              );
 1464   
 1465              $sql = 'UPDATE ' . STYLES_THEME_TABLE . '
 1466                  SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
 1467                  WHERE theme_id = ' . $this->theme['theme_id'];
 1468              $db->sql_query($sql);
 1469   
 1470              unset($sql_ary);
 1471          }
 1472   
 1473          $template->set_template();
 1474   
 1475          $this->img_lang = (file_exists($phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . $this->lang_name)) ? $this->lang_name : $config['default_lang'];
 1476   
 1477          $sql = 'SELECT image_name, image_filename, image_lang, image_height, image_width
 1478              FROM ' . STYLES_IMAGESET_DATA_TABLE . '
 1479              WHERE imageset_id = ' . $this->theme['imageset_id'] . "
 1480              AND image_lang IN ('" . $db->sql_escape($this->img_lang) . "', '')";
 1481          $result = $db->sql_query($sql, 3600);
 1482   
 1483          $localised_images = false;
 1484          while ($row = $db->sql_fetchrow($result))
 1485          {
 1486              if ($row['image_lang'])
 1487              {
 1488                  $localised_images = true;
 1489              }
 1490   
 1491              $this->img_array[$row['image_name']] = $row;
 1492          }
 1493          $db->sql_freeresult($result);
 1494   
 1495          // there were no localised images, try to refresh the localised imageset for the user's language
 1496          if (!$localised_images)
 1497          {
 1498              // Attention: this code ignores the image definition list from acp_styles and just takes everything
 1499              // that the config file contains
 1500              $sql_ary = array();
 1501   
 1502              $db->sql_transaction('begin');
 1503   
 1504              $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . '
 1505                  WHERE imageset_id = ' . $this->theme['imageset_id'] . '
 1506                      AND image_lang = \'' . $db->sql_escape($this->img_lang) . '\'';
 1507              $result = $db->sql_query($sql);
 1508   
 1509              if (@file_exists("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg"))
 1510              {
 1511                  $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg");
 1512                  foreach ($cfg_data_imageset_data as $image_name => $value)
 1513                  {
 1514                      if (strpos($value, '*') !== false)
 1515                      {
 1516                          if (substr($value, -1, 1) === '*')
 1517                          {
 1518                              list($image_filename, $image_height) = explode('*', $value);
 1519                              $image_width = 0;
 1520                          }
 1521                          else
 1522                          {
 1523                              list($image_filename, $image_height, $image_width) = explode('*', $value);
 1524                          }
 1525                      }
 1526                      else
 1527                      {
 1528                          $image_filename = $value;
 1529                          $image_height = $image_width = 0;
 1530                      }
 1531   
 1532                      if (strpos($image_name, 'img_') === 0 && $image_filename)
 1533                      {
 1534                          $image_name = substr($image_name, 4);
 1535                          $sql_ary[] = array(
 1536                              'image_name'        => (string) $image_name,
 1537                              'image_filename'    => (string) $image_filename,
 1538                              'image_height'        => (int) $image_height,
 1539                              'image_width'        => (int) $image_width,
 1540                              'imageset_id'        => (int) $this->theme['imageset_id'],
 1541                              'image_lang'        => (string) $this->img_lang,
 1542                          );
 1543                      }
 1544                  }
 1545              }
 1546   
 1547              if (sizeof($sql_ary))
 1548              {
 1549                  $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary);
 1550                  $db->sql_transaction('commit');
 1551                  $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE);
 1552   
 1553                  add_log('admin', 'LOG_IMAGESET_LANG_REFRESHED', $this->theme['imageset_name'], $this->img_lang);
 1554              }
 1555              else
 1556              {
 1557                  $db->sql_transaction('commit');
 1558                  add_log('admin', 'LOG_IMAGESET_LANG_MISSING', $this->theme['imageset_name'], $this->img_lang);
 1559              }
 1560          }
 1561   
 1562          // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes...
 1563          // After calling it we continue script execution...
 1564          phpbb_user_session_handler();
 1565   
 1566          // If this function got called from the error handler we are finished here.
 1567          if (defined('IN_ERROR_HANDLER'))
 1568          {
 1569              return;
 1570          }
 1571   
 1572          // Disable board if the install/ directory is still present
 1573          // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally
 1574          if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install'))
 1575          {
 1576              // Adjust the message slightly according to the permissions
 1577              if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))
 1578              {
 1579                  $message = 'REMOVE_INSTALL';
 1580              }
 1581              else
 1582              {
 1583                  $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
 1584              }
 1585              trigger_error($message);
 1586          }
 1587   
 1588          // Is board disabled and user not an admin or moderator?
 1589          if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
 1590          {
 1591              header('HTTP/1.1 503 Service Unavailable');
 1592   
 1593              $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
 1594              trigger_error($message);
 1595          }
 1596   
 1597          // Is load exceeded?
 1598          if ($config['limit_load'] && $this->load !== false)
 1599          {
 1600              if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN'))
 1601              {
 1602                  // Set board disabled to true to let the admins/mods get the proper notification
 1603                  $config['board_disable'] = '1';
 1604   
 1605                  if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
 1606                  {
 1607                      header('HTTP/1.1 503 Service Unavailable');
 1608                      trigger_error('BOARD_UNAVAILABLE');
 1609                  }
 1610              }
 1611          }
 1612   
 1613          if (isset($this->data['session_viewonline']))
 1614          {
 1615              // Make sure the user is able to hide his session
 1616              if (!$this->data['session_viewonline'])
 1617              {
 1618                  // Reset online status if not allowed to hide the session...
 1619                  if (!$auth->acl_get('u_hideonline'))
 1620                  {
 1621                      $sql = 'UPDATE ' . SESSIONS_TABLE . '
 1622                          SET session_viewonline = 1
 1623                          WHERE session_user_id = ' . $this->data['user_id'];
 1624                      $db->sql_query($sql);
 1625                      $this->data['session_viewonline'] = 1;
 1626                  }
 1627              }
 1628              else if (!$this->data['user_allow_viewonline'])
 1629              {
 1630                  // the user wants to hide and is allowed to  -> cloaking device on.
 1631                  if ($auth->acl_get('u_hideonline'))
 1632                  {
 1633                      $sql = 'UPDATE ' . SESSIONS_TABLE . '
 1634                          SET session_viewonline = 0
 1635                          WHERE session_user_id = ' . $this->data['user_id'];
 1636                      $db->sql_query($sql);
 1637                      $this->data['session_viewonline'] = 0;
 1638                  }
 1639              }
 1640          }
 1641   
 1642   
 1643          // Does the user need to change their password? If so, redirect to the
 1644          // ucp profile reg_details page ... of course do not redirect if we're already in the ucp
 1645          if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && $this->data['is_registered'] && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400))
 1646          {
 1647              if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx")
 1648              {
 1649                  redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&amp;mode=reg_details'));
 1650              }
 1651          }
 1652   
 1653          return;
 1654      }
 1655   
 1656      /**
 1657      * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
 1658      *
 1659      * @param mixed $lang_set specifies the language entries to include
 1660      * @param bool $use_db internal variable for recursion, do not use
 1661      * @param bool $use_help internal variable for recursion, do not use
 1662      *
 1663      * Examples:
 1664      * <code>
 1665      * $lang_set = array('posting', 'help' => 'faq');
 1666      * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq'))
 1667      * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq'))
 1668      * $lang_set = 'posting'
 1669      * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
 1670      * </code>
 1671      */
 1672      function add_lang($lang_set, $use_db = false, $use_help = false)
 1673      {
 1674          global $phpEx;
 1675   
 1676          if (is_array($lang_set))
 1677          {
 1678              foreach ($lang_set as $key => $lang_file)
 1679              {
 1680                  // Please do not delete this line.
 1681                  // We have to force the type here, else [array] language inclusion will not work
 1682                  $key = (string) $key;
 1683   
 1684                  if ($key == 'db')
 1685                  {
 1686                      $this->add_lang($lang_file, true, $use_help);
 1687                  }
 1688                  else if ($key == 'help')
 1689                  {
 1690                      $this->add_lang($lang_file, $use_db, true);
 1691                  }
 1692                  else if (!is_array($lang_file))
 1693                  {
 1694                      $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help);
 1695                  }
 1696                  else
 1697                  {
 1698                      $this->add_lang($lang_file, $use_db, $use_help);
 1699                  }
 1700              }
 1701              unset($lang_set);
 1702          }
 1703          else if ($lang_set)
 1704          {
 1705              $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help);
 1706          }
 1707      }
 1708   
 1709      /**
 1710      * Set language entry (called by add_lang)
 1711      * @access private
 1712      */
 1713      function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false)
 1714      {
 1715          global $phpEx;
 1716   
 1717          // Make sure the language path is set (if the user setup did not happen it is not set)
 1718          if (!$this->lang_path)
 1719          {
 1720              global $phpbb_root_path, $config;
 1721   
 1722              $this->lang_path = $phpbb_root_path . 'language/' . basename($config['default_lang']) . '/';
 1723          }
 1724   
 1725          // $lang == $this->lang
 1726          // $help == $this->help
 1727          // - add appropriate variables here, name them as they are used within the language file...
 1728          if (!$use_db)
 1729          {
 1730              if ($use_help && strpos($lang_file, '/') !== false)
 1731              {
 1732                  $language_filename = $this->lang_path . substr($lang_file, 0, stripos($lang_file, '/') + 1) . 'help_' . substr($lang_file, stripos($lang_file, '/') + 1) . '.' . $phpEx;
 1733              }
 1734              else
 1735              {
 1736                  $language_filename = $this->lang_path . (($use_help) ? 'help_' : '') . $lang_file . '.' . $phpEx;
 1737              }
 1738   
 1739              if ((@include $language_filename) === false)
 1740              {
 1741                  trigger_error('Language file ' . basename($language_filename) . ' couldn\'t be opened.', E_USER_ERROR);
 1742              }
 1743          }
 1744          else if ($use_db)
 1745          {
 1746              // Get Database Language Strings
 1747              // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
 1748              // For example: help:faq, posting
 1749          }
 1750      }
 1751   
 1752      /**
 1753      * Format user date
 1754      */
 1755      function format_date($gmepoch, $format = false, $forcedate = false)
 1756      {
 1757          static $midnight;
 1758   
 1759          $lang_dates = $this->lang['datetime'];
 1760          $format = (!$format) ? $this->date_format : $format;
 1761   
 1762          // Short representation of month in format
 1763          if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false))
 1764          {
 1765              $lang_dates['May'] = $lang_dates['May_short'];
 1766          }
 1767   
 1768          unset($lang_dates['May_short']);
 1769   
 1770          if (!$midnight)
 1771          {
 1772              list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $this->timezone + $this->dst));
 1773              $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $this->timezone - $this->dst;
 1774          }
 1775   
 1776          if (strpos($format, '|') === false || ($gmepoch < $midnight - 86400 && !$forcedate) || ($gmepoch > $midnight + 172800 && !$forcedate))
 1777          {
 1778              return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates);
 1779          }
 1780   
 1781          if ($gmepoch > $midnight + 86400 && !$forcedate)
 1782          {
 1783              $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
 1784              return str_replace('||', $this->lang['datetime']['TOMORROW'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
 1785          }
 1786          else if ($gmepoch > $midnight && !$forcedate)
 1787          {
 1788              $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
 1789              return str_replace('||', $this->lang['datetime']['TODAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
 1790          }
 1791          else if ($gmepoch > $midnight - 86400 && !$forcedate)
 1792          {
 1793              $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1);
 1794              return str_replace('||', $this->lang['datetime']['YESTERDAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates));
 1795          }
 1796   
 1797          return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates);
 1798      }
 1799   
 1800      /**
 1801      * Get language id currently used by the user
 1802      */
 1803      function get_iso_lang_id()
 1804      {
 1805          global $config, $db;
 1806   
 1807          if (!empty($this->lang_id))
 1808          {
 1809              return $this->lang_id;
 1810          }
 1811   
 1812          if (!$this->lang_name)
 1813          {
 1814              $this->lang_name = $config['default_lang'];
 1815          }
 1816   
 1817          $sql = 'SELECT lang_id
 1818              FROM ' . LANG_TABLE . "
 1819              WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'";
 1820          $result = $db->sql_query($sql);
 1821          $this->lang_id = (int) $db->sql_fetchfield('lang_id');
 1822          $db->sql_freeresult($result);
 1823   
 1824          return $this->lang_id;
 1825      }
 1826   
 1827      /**
 1828      * Get users profile fields
 1829      */
 1830      function get_profile_fields($user_id)
 1831      {
 1832          global $db;
 1833   
 1834          if (isset($this->profile_fields))
 1835          {
 1836              return;
 1837          }
 1838   
 1839          $sql = 'SELECT *
 1840              FROM ' . PROFILE_FIELDS_DATA_TABLE . "
 1841              WHERE user_id = $user_id";
 1842          $result = $db->sql_query_limit($sql, 1);
 1843          $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row;
 1844          $db->sql_freeresult($result);
 1845      }
 1846   
 1847      /**
 1848      * Specify/Get image
 1849      */
 1850      function img($img, $alt = '', $width = false, $suffix = '', $type = 'full_tag')
 1851      {
 1852          static $imgs;
 1853          global $phpbb_root_path;
 1854   
 1855          $img_data = &$imgs[$img];
 1856   
 1857          if (empty($img_data))
 1858          {
 1859              if (!isset($this->img_array[$img]))
 1860              {
 1861                  // Do not fill the image to let designers decide what to do if the image is empty
 1862                  $img_data = '';
 1863                  return $img_data;
 1864              }
 1865   
 1866              $img_data['src'] = $phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename'];
 1867              $img_data['width'] = $this->img_array[$img]['image_width'];
 1868              $img_data['height'] = $this->img_array[$img]['image_height'];
 1869          }
 1870   
 1871          $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt;
 1872   
 1873          switch ($type)
 1874          {
 1875              case 'src':
 1876                  return $img_data['src'];
 1877              break;
 1878   
 1879              case 'width':
 1880                  return ($width === false) ? $img_data['width'] : $width;
 1881              break;
 1882   
 1883              case 'height':
 1884                  return $img_data['height'];
 1885              break;
 1886   
 1887              default:
 1888                  $use_width = ($width === false) ? $img_data['width'] : $width;
 1889   
 1890                  return '<img src="' . $img_data['src'] . '"' . (($use_width) ? ' width="' . $use_width . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />';
 1891              break;
 1892          }
 1893      }
 1894   
 1895      /**
 1896      * Get option bit field from user options
 1897      */
 1898      function optionget($key, $data = false)
 1899      {
 1900          if (!isset($this->keyvalues[$key]))
 1901          {
 1902              $var = ($data) ? $data : $this->data['user_options'];
 1903              $this->keyvalues[$key] = ($var & 1 << $this->keyoptions[$key]) ? true : false;
 1904          }
 1905   
 1906          return $this->keyvalues[$key];
 1907      }
 1908   
 1909      /**
 1910      * Set option bit field for user options
 1911      */
 1912      function optionset($key, $value, $data = false)
 1913      {
 1914          $var = ($data) ? $data : $this->data['user_options'];
 1915   
 1916          if ($value && !($var & 1 << $this->keyoptions[$key]))
 1917          {
 1918              $var += 1 << $this->keyoptions[$key];
 1919          }
 1920          else if (!$value && ($var & 1 << $this->keyoptions[$key]))
 1921          {
 1922              $var -= 1 << $this->keyoptions[$key];
 1923          }
 1924          else
 1925          {
 1926              return ($data) ? $var : false;
 1927          }
 1928   
 1929          if (!$data)
 1930          {
 1931              $this->data['user_options'] = $var;
 1932              return true;
 1933          }
 1934          else
 1935          {
 1936              return $var;
 1937          }
 1938      }
 1939  }
 1940   
 1941  ?>