[ Index ] |
PHP Cross Reference of phpBB 3.0 Beta 3 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package phpBB3 5 * @version $Id: session.php,v 1.242 2006/11/12 15:35:43 acydburn Exp $ 6 * @copyright (c) 2005 phpBB Group 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * Session class 13 * @package phpBB3 14 */ 15 class session 16 { 17 var $cookie_data = array(); 18 var $page = array(); 19 var $data = array(); 20 var $browser = ''; 21 var $host = ''; 22 var $session_id = ''; 23 var $ip = ''; 24 var $load = 0; 25 var $time_now = 0; 26 var $update_session_page = true; 27 28 /** 29 * Extract current session page 30 * 31 * @param string $root_path current root path (phpbb_root_path) 32 */ 33 function extract_current_page($root_path) 34 { 35 $page_array = array(); 36 37 // First of all, get the request uri... 38 $script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF'); 39 $args = (!empty($_SERVER['QUERY_STRING'])) ? explode('&', $_SERVER['QUERY_STRING']) : explode('&', getenv('QUERY_STRING')); 40 41 // 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... 42 if (!$script_name) 43 { 44 $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI'); 45 $page_array['failover'] = 1; 46 } 47 48 // Replace backslashes and doubled slashes (could happen on some proxy setups) 49 $script_name = str_replace(array('\\', '//'), '/', $script_name); 50 51 // Now, remove the sid and let us get a clean query string... 52 foreach ($args as $key => $argument) 53 { 54 if (strpos($argument, 'sid=') === 0 || strpos($argument, '_f_=') === 0) 55 { 56 unset($args[$key]); 57 break; 58 } 59 } 60 61 // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2 62 63 // The current query string 64 $query_string = trim(implode('&', $args)); 65 66 // basenamed page name (for example: index.php) 67 $page_name = basename($script_name); 68 $page_name = urlencode(htmlspecialchars($page_name)); 69 70 // current directory within the phpBB root (for example: adm) 71 $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path))); 72 $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./'))); 73 $intersection = array_intersect_assoc($root_dirs, $page_dirs); 74 75 $root_dirs = array_diff_assoc($root_dirs, $intersection); 76 $page_dirs = array_diff_assoc($page_dirs, $intersection); 77 78 $page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs); 79 80 if ($page_dir && substr($page_dir, -1, 1) == '/') 81 { 82 $page_dir = substr($page_dir, 0, -1); 83 } 84 85 // Current page from phpBB root (for example: adm/index.php?i=10&b=2) 86 $page = (($page_dir) ? $page_dir . '/' : '') . $page_name . (($query_string) ? "?$query_string" : ''); 87 88 // The script path from the webroot to the current directory (for example: /phpBB2/adm/) : always prefixed with / and ends in / 89 $script_path = trim(str_replace('\\', '/', dirname($script_name))); 90 91 // The script path from the webroot to the phpBB root (for example: /phpBB2/) 92 $script_dirs = explode('/', $script_path); 93 array_splice($script_dirs, -sizeof($page_dirs)); 94 $root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : ''); 95 96 // We are on the base level (phpBB root == webroot), lets adjust the variables a bit... 97 if (!$root_script_path) 98 { 99 $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path; 100 } 101 102 $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/'; 103 $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/'; 104 105 $page_array += array( 106 'page_name' => $page_name, 107 'page_dir' => $page_dir, 108 109 'query_string' => $query_string, 110 'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)), 111 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), 112 113 'page' => $page 114 ); 115 116 /* 117 if (!file_exists($page_name)) 118 { 119 trigger_error('You are on a page that does not exist!', E_USER_ERROR); 120 } 121 */ 122 123 return $page_array; 124 } 125 126 /** 127 * Start session management 128 * 129 * This is where all session activity begins. We gather various pieces of 130 * information from the client and server. We test to see if a session already 131 * exists. If it does, fine and dandy. If it doesn't we'll go on to create a 132 * new one ... pretty logical heh? We also examine the system load (if we're 133 * running on a system which makes such information readily available) and 134 * halt if it's above an admin definable limit. 135 * 136 * @param bool $update_session_page if true the session page gets updated. 137 * This can be set to circumvent certain scripts to update the users last visited page. 138 */ 139 function session_begin($update_session_page = true) 140 { 141 global $phpEx, $SID, $_SID, $db, $config, $phpbb_root_path; 142 143 // Give us some basic informations 144 $this->time_now = time(); 145 $this->cookie_data = array('u' => 0, 'k' => ''); 146 $this->update_session_page = $update_session_page; 147 $this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? (string) $_SERVER['HTTP_USER_AGENT'] : ''; 148 $this->host = (!empty($_SERVER['HTTP_HOST'])) ? (string) $_SERVER['HTTP_HOST'] : 'localhost'; 149 $this->page = $this->extract_current_page($phpbb_root_path); 150 151 // Add forum to the page for tracking online users - also adding a "x" to the end to properly identify the number 152 $this->page['page'] .= (isset($_REQUEST['f'])) ? ((strpos($this->page['page'], '?') !== false) ? '&' : '?') . '_f_=' . (int) $_REQUEST['f'] . 'x' : ''; 153 154 if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u'])) 155 { 156 $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true); 157 $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true); 158 $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true); 159 160 $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid='; 161 $_SID = (defined('NEED_SID')) ? $this->session_id : ''; 162 163 if (empty($this->session_id)) 164 { 165 $this->session_id = $_SID = request_var('sid', ''); 166 $SID = '?sid=' . $this->session_id; 167 $this->cookie_data = array('u' => 0, 'k' => ''); 168 } 169 } 170 else 171 { 172 $this->session_id = $_SID = request_var('sid', ''); 173 $SID = '?sid=' . $this->session_id; 174 } 175 176 // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests 177 // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. 178 $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; 179 $this->load = false; 180 181 // Load limit check (if applicable) 182 if ($config['limit_load']) 183 { 184 if ($load = @file_get_contents('/proc/loadavg')) 185 { 186 $this->load = array_slice(explode(' ', $load), 0, 1); 187 $this->load = floatval($this->load[0]); 188 } 189 else 190 { 191 set_config('limit_load', '0'); 192 } 193 } 194 195 // Is session_id is set or session_id is set and matches the url param if required 196 if (!empty($this->session_id) && (!defined('NEED_SID') || (isset($_GET['sid']) && $this->session_id === $_GET['sid']))) 197 { 198 $sql = 'SELECT u.*, s.* 199 FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u 200 WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "' 201 AND u.user_id = s.session_user_id"; 202 $result = $db->sql_query($sql); 203 $this->data = $db->sql_fetchrow($result); 204 $db->sql_freeresult($result); 205 206 // Did the session exist in the DB? 207 if (isset($this->data['user_id'])) 208 { 209 // Validate IP length according to admin ... enforces an IP 210 // check on bots if admin requires this 211 // $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check']; 212 213 $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); 214 $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); 215 216 $s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : ''; 217 $u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : ''; 218 219 if ($u_ip === $s_ip && $s_browser === $u_browser) 220 { 221 $session_expired = false; 222 223 // Check whether the session is still valid if we have one 224 $method = basename(trim($config['auth_method'])); 225 include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); 226 227 $method = 'validate_session_' . $method; 228 if (function_exists($method)) 229 { 230 if (!$method($this->data)) 231 { 232 $session_expired = true; 233 } 234 } 235 236 if (!$session_expired) 237 { 238 // Check the session length timeframe if autologin is not enabled. 239 // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide. 240 if (!$this->data['session_autologin']) 241 { 242 if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60)) 243 { 244 $session_expired = true; 245 } 246 } 247 else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60)) 248 { 249 $session_expired = true; 250 } 251 } 252 253 if (!$session_expired) 254 { 255 // Only update session DB a minute or so after last update or if page changes 256 if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) 257 { 258 $sql_ary = array('session_time' => $this->time_now); 259 260 if ($this->update_session_page) 261 { 262 $sql_ary['session_page'] = substr($this->page['page'], 0, 199); 263 } 264 265 $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " 266 WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; 267 $db->sql_query($sql); 268 } 269 270 $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; 271 $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; 272 273 return true; 274 } 275 } 276 else 277 { 278 // Added logging temporarly to help debug bugs... 279 if (defined('DEBUG_EXTRA')) 280 { 281 add_log('critical', 'LOG_IP_BROWSER_CHECK', $u_ip, $s_ip, $u_browser, $s_browser); 282 } 283 } 284 } 285 } 286 287 // If we reach here then no (valid) session exists. So we'll create a new one 288 return $this->session_create(); 289 } 290 291 /** 292 * Create a new session 293 * 294 * If upon trying to start a session we discover there is nothing existing we 295 * jump here. Additionally this method is called directly during login to regenerate 296 * the session for the specific user. In this method we carry out a number of tasks; 297 * garbage collection, (search)bot checking, banned user comparison. Basically 298 * though this method will result in a new session for a specific user. 299 */ 300 function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true) 301 { 302 global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx; 303 304 $this->data = array(); 305 306 /* Garbage collection ... remove old sessions updating user information 307 // if necessary. It means (potentially) 11 queries but only infrequently 308 if ($this->time_now > $config['session_last_gc'] + $config['session_gc']) 309 { 310 $this->session_gc(); 311 }*/ 312 313 // Do we allow autologin on this board? No? Then override anything 314 // that may be requested here 315 if (!$config['allow_autologin']) 316 { 317 $this->cookie_data['k'] = $persist_login = false; 318 } 319 320 /** 321 * Here we do a bot check, oh er saucy! No, not that kind of bot 322 * check. We loop through the list of bots defined by the admin and 323 * see if we have any useragent and/or IP matches. If we do, this is a 324 * bot, act accordingly 325 */ 326 $bot = false; 327 $active_bots = $cache->obtain_bots(); 328 329 foreach ($active_bots as $row) 330 { 331 if ($row['bot_agent'] && strpos(strtolower($this->browser), strtolower($row['bot_agent'])) !== false) 332 { 333 $bot = $row['user_id']; 334 } 335 336 // If ip is supplied, we will make sure the ip is matching too... 337 if ($row['bot_ip'] && ($bot || !$row['bot_agent'])) 338 { 339 // Set bot to false, then we only have to set it to true if it is matching 340 $bot = false; 341 342 foreach (explode(',', $row['bot_ip']) as $bot_ip) 343 { 344 if (strpos($this->ip, $bot_ip) === 0) 345 { 346 $bot = (int) $row['user_id']; 347 break; 348 } 349 } 350 } 351 352 if ($bot) 353 { 354 break; 355 } 356 } 357 358 $method = basename(trim($config['auth_method'])); 359 include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); 360 361 $method = 'autologin_' . $method; 362 if (function_exists($method)) 363 { 364 $this->data = $method(); 365 366 if (sizeof($this->data)) 367 { 368 $this->cookie_data['k'] = ''; 369 $this->cookie_data['u'] = $this->data['user_id']; 370 } 371 } 372 373 // If we're presented with an autologin key we'll join against it. 374 // Else if we've been passed a user_id we'll grab data based on that 375 if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data)) 376 { 377 $sql = 'SELECT u.* 378 FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k 379 WHERE u.user_id = ' . (int) $this->cookie_data['u'] . ' 380 AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ") 381 AND k.user_id = u.user_id 382 AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; 383 $result = $db->sql_query($sql); 384 $this->data = $db->sql_fetchrow($result); 385 $db->sql_freeresult($result); 386 } 387 else if ($user_id !== false && !sizeof($this->data)) 388 { 389 $this->cookie_data['k'] = ''; 390 $this->cookie_data['u'] = $user_id; 391 392 $sql = 'SELECT * 393 FROM ' . USERS_TABLE . ' 394 WHERE user_id = ' . (int) $this->cookie_data['u'] . ' 395 AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; 396 $result = $db->sql_query($sql); 397 $this->data = $db->sql_fetchrow($result); 398 $db->sql_freeresult($result); 399 } 400 401 // If no data was returned one or more of the following occured: 402 // Key didn't match one in the DB 403 // User does not exist 404 // User is inactive 405 // User is bot 406 if (!sizeof($this->data) || !is_array($this->data)) 407 { 408 $this->cookie_data['k'] = ''; 409 $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS; 410 411 if (!$bot) 412 { 413 $sql = 'SELECT * 414 FROM ' . USERS_TABLE . ' 415 WHERE user_id = ' . (int) $this->cookie_data['u']; 416 } 417 else 418 { 419 // We give bots always the same session if it is not yet expired. 420 $sql = 'SELECT u.*, s.* 421 FROM ' . USERS_TABLE . ' u 422 LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) 423 WHERE u.user_id = ' . (int) $bot; 424 } 425 426 $result = $db->sql_query($sql); 427 $this->data = $db->sql_fetchrow($result); 428 $db->sql_freeresult($result); 429 } 430 431 if ($this->data['user_id'] != ANONYMOUS && !$bot) 432 { 433 $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()); 434 } 435 else 436 { 437 $this->data['session_last_visit'] = $this->time_now; 438 } 439 440 // Force user id to be integer... 441 $this->data['user_id'] = (int) $this->data['user_id']; 442 443 // At this stage we should have a filled data array, defined cookie u and k data. 444 // data array should contain recent session info if we're a real user and a recent 445 // session exists in which case session_id will also be set 446 447 // Is user banned? Are they excluded? Won't return on ban, exists within method 448 if ($this->data['user_type'] != USER_FOUNDER) 449 { 450 $this->check_ban($this->data['user_id'], $this->ip); 451 } 452 453 454 $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; 455 $this->data['is_bot'] = ($bot) ? true : false; 456 457 // If our friend is a bot, we re-assign a previously assigned session 458 if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id']) 459 { 460 // Only assign the current session if the ip and browser match... 461 $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); 462 $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); 463 464 $s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : ''; 465 $u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : ''; 466 467 if ($u_ip === $s_ip && $s_browser === $u_browser) 468 { 469 $this->session_id = $this->data['session_id']; 470 471 // Only update session DB a minute or so after last update or if page changes 472 if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) 473 { 474 $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0); 475 476 if ($this->update_session_page) 477 { 478 $sql_ary['session_page'] = substr($this->page['page'], 0, 199); 479 } 480 481 $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " 482 WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; 483 $db->sql_query($sql); 484 } 485 486 $SID = '?sid='; 487 $_SID = ''; 488 489 return true; 490 } 491 else 492 { 493 // If the ip and browser does not match make sure we only have one bot assigned to one session 494 $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']); 495 } 496 } 497 498 $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false; 499 $set_admin = ($set_admin && $this->data['is_registered']) ? true : false; 500 501 // Create or update the session 502 $sql_ary = array( 503 'session_user_id' => (int) $this->data['user_id'], 504 'session_start' => (int) $this->time_now, 505 'session_last_visit' => (int) $this->data['session_last_visit'], 506 'session_time' => (int) $this->time_now, 507 'session_browser' => (string) $this->browser, 508 'session_ip' => (string) $this->ip, 509 'session_autologin' => ($session_autologin) ? 1 : 0, 510 'session_admin' => ($set_admin) ? 1 : 0, 511 'session_viewonline' => ($viewonline) ? 1 : 0, 512 ); 513 514 if ($this->update_session_page) 515 { 516 $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); 517 } 518 519 $db->sql_return_on_error(true); 520 521 $sql = 'DELETE 522 FROM ' . SESSIONS_TABLE . ' 523 WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\' 524 AND session_user_id = ' . ANONYMOUS; 525 526 if (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows()) 527 { 528 // Limit new sessions in 1 minute period (if required) 529 if ((!isset($this->data['session_time']) || !$this->data['session_time']) && $config['active_sessions']) 530 { 531 $sql = 'SELECT COUNT(session_id) AS sessions 532 FROM ' . SESSIONS_TABLE . ' 533 WHERE session_time >= ' . ($this->time_now - 60); 534 $result = $db->sql_query($sql); 535 $row = $db->sql_fetchrow($result); 536 $db->sql_freeresult($result); 537 538 if ((int) $row['sessions'] > (int) $config['active_sessions']) 539 { 540 trigger_error('BOARD_UNAVAILABLE'); 541 } 542 } 543 } 544 545 $this->session_id = $this->data['session_id'] = md5(unique_id()); 546 547 $sql_ary['session_id'] = (string) $this->session_id; 548 $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); 549 550 $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); 551 $db->sql_query($sql); 552 553 $db->sql_return_on_error(false); 554 555 // Regenerate autologin/persistent login key 556 if ($session_autologin) 557 { 558 $this->set_login_key(); 559 } 560 561 $SID = '?sid=' . $this->session_id; 562 $_SID = $this->session_id; 563 564 if (!$bot) 565 { 566 $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000); 567 568 $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire); 569 $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire); 570 $this->set_cookie('sid', $this->session_id, $cookie_expire); 571 572 unset($cookie_expire); 573 } 574 else 575 { 576 $SID = '?sid='; 577 $_SID = ''; 578 } 579 580 return true; 581 } 582 583 /** 584 * Kills a session 585 * 586 * This method does what it says on the tin. It will delete a pre-existing session. 587 * It resets cookie information (destroying any autologin key within that cookie data) 588 * and update the users information from the relevant session data. It will then 589 * grab guest user information. 590 */ 591 function session_kill() 592 { 593 global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx; 594 595 $sql = 'DELETE FROM ' . SESSIONS_TABLE . " 596 WHERE session_id = '" . $db->sql_escape($this->session_id) . "' 597 AND session_user_id = " . (int) $this->data['user_id']; 598 $db->sql_query($sql); 599 600 // Allow connecting logout with external auth method logout 601 $method = basename(trim($config['auth_method'])); 602 include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); 603 604 $method = 'logout_' . $method; 605 if (function_exists($method)) 606 { 607 $method($this->data); 608 } 609 610 if ($this->data['user_id'] != ANONYMOUS) 611 { 612 // Delete existing session, update last visit info first! 613 if (!isset($this->data['session_time'])) 614 { 615 $this->data['session_time'] = time(); 616 } 617 618 $sql = 'UPDATE ' . USERS_TABLE . ' 619 SET user_lastvisit = ' . (int) $this->data['session_time'] . ' 620 WHERE user_id = ' . (int) $this->data['user_id']; 621 $db->sql_query($sql); 622 623 if ($this->cookie_data['k']) 624 { 625 $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' 626 WHERE user_id = ' . (int) $this->data['user_id'] . " 627 AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; 628 $db->sql_query($sql); 629 } 630 631 // Reset the data array 632 $this->data = array(); 633 634 $sql = 'SELECT * 635 FROM ' . USERS_TABLE . ' 636 WHERE user_id = ' . ANONYMOUS; 637 $result = $db->sql_query($sql); 638 $this->data = $db->sql_fetchrow($result); 639 $db->sql_freeresult($result); 640 } 641 642 $cookie_expire = $this->time_now - 31536000; 643 $this->set_cookie('u', '', $cookie_expire); 644 $this->set_cookie('k', '', $cookie_expire); 645 $this->set_cookie('sid', '', $cookie_expire); 646 unset($cookie_expire); 647 648 $SID = '?sid='; 649 $this->session_id = $_SID = ''; 650 651 // To make sure a valid session is created we create one for the anonymous user 652 $this->session_create(ANONYMOUS); 653 654 return true; 655 } 656 657 /** 658 * Session garbage collection 659 * 660 * This looks a lot more complex than it really is. Effectively we are 661 * deleting any sessions older than an admin definable limit. Due to the 662 * way in which we maintain session data we have to ensure we update user 663 * data before those sessions are destroyed. In addition this method 664 * removes autologin key information that is older than an admin defined 665 * limit. 666 */ 667 function session_gc() 668 { 669 global $db, $config; 670 671 if (!$this->time_now) 672 { 673 $this->time_now = time(); 674 } 675 676 // Firstly, delete guest sessions 677 $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' 678 WHERE session_user_id = ' . ANONYMOUS . ' 679 AND session_time < ' . (int) ($this->time_now - $config['session_length']); 680 $db->sql_query($sql); 681 682 // Get expired sessions, only most recent for each user 683 $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time 684 FROM ' . SESSIONS_TABLE . ' 685 WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' 686 GROUP BY session_user_id, session_page'; 687 $result = $db->sql_query_limit($sql, 10); 688 689 $del_user_id = array(); 690 $del_sessions = 0; 691 692 while ($row = $db->sql_fetchrow($result)) 693 { 694 $sql = 'UPDATE ' . USERS_TABLE . ' 695 SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' 696 WHERE user_id = " . (int) $row['session_user_id']; 697 $db->sql_query($sql); 698 699 $del_user_id[] = (int) $row['session_user_id']; 700 $del_sessions++; 701 } 702 $db->sql_freeresult($result); 703 704 if (sizeof($del_user_id)) 705 { 706 // Delete expired sessions 707 $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' 708 WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' 709 AND session_time < ' . ($this->time_now - $config['session_length']); 710 $db->sql_query($sql); 711 } 712 713 if ($del_sessions < 10) 714 { 715 // Less than 10 sessions, update gc timer ... else we want gc 716 // called again to delete other sessions 717 set_config('session_last_gc', $this->time_now, true); 718 } 719 720 if ($config['max_autologin_time']) 721 { 722 $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' 723 WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); 724 $db->sql_query($sql); 725 } 726 727 return; 728 } 729 730 /** 731 * Sets a cookie 732 * 733 * Sets a cookie of the given name with the specified data for the given length of time. 734 */ 735 function set_cookie($name, $cookiedata, $cookietime) 736 { 737 global $config; 738 739 $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); 740 $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); 741 $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']; 742 743 header('Set-Cookie: ' . $name_data . '; expires=' . $expire . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false); 744 } 745 746 /** 747 * Check for banned user 748 * 749 * Checks whether the supplied user is banned by id, ip or email. If no parameters 750 * are passed to the method pre-existing session data is used. If $return is false 751 * this routine does not return on finding a banned user, it outputs a relevant 752 * message and stops execution. 753 */ 754 function check_ban($user_id = false, $user_ip = false, $user_email = false, $return = false) 755 { 756 global $config, $db; 757 758 $banned = false; 759 760 $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end 761 FROM ' . BANLIST_TABLE . ' 762 WHERE (ban_end >= ' . time() . ' OR ban_end = 0)'; 763 764 // Determine which entries to check, only return those 765 if ($user_email === false) 766 { 767 $sql .= " AND ban_email = ''"; 768 } 769 770 if ($user_ip === false) 771 { 772 $sql .= " AND (ban_ip = '' OR (ban_ip <> '' AND ban_exclude = 1))"; 773 } 774 775 if ($user_id === false) 776 { 777 $sql .= ' AND (ban_userid = 0 OR (ban_userid <> 0 AND ban_exclude = 1))'; 778 } 779 else 780 { 781 $sql .= ' AND (ban_userid = ' . $user_id; 782 783 if ($user_email !== false) 784 { 785 $sql .= " OR ban_email <> ''"; 786 } 787 788 if ($user_ip !== false) 789 { 790 $sql .= " OR ban_ip <> ''"; 791 } 792 793 $sql .= ')'; 794 } 795 796 $result = $db->sql_query($sql); 797 798 $ban_triggered_by = 'user'; 799 while ($row = $db->sql_fetchrow($result)) 800 { 801 if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) || 802 (!empty($row['ban_ip']) && preg_match('#^' . str_replace('*', '.*?', $row['ban_ip']) . '$#i', $user_ip)) || 803 (!empty($row['ban_email']) && preg_match('#^' . str_replace('*', '.*?', $row['ban_email']) . '$#i', $user_email))) 804 { 805 if (!empty($row['ban_exclude'])) 806 { 807 $banned = false; 808 break; 809 } 810 else 811 { 812 $banned = true; 813 $ban_row = $row; 814 815 if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) 816 { 817 $ban_triggered_by = 'user'; 818 } 819 else if (!empty($row['ban_ip']) && preg_match('#^' . str_replace('*', '.*?', $row['ban_ip']) . '$#i', $user_ip)) 820 { 821 $ban_triggered_by = 'ip'; 822 } 823 else 824 { 825 $ban_triggered_by = 'email'; 826 } 827 828 // Don't break. Check if there is an exclude rule for this user 829 } 830 } 831 } 832 $db->sql_freeresult($result); 833 834 if ($banned && !$return) 835 { 836 // Initiate environment ... since it won't be set at this stage 837 $this->setup(); 838 839 // Logout the user, banned users are unable to use the normal 'logout' link 840 if ($this->data['user_id'] != ANONYMOUS) 841 { 842 $this->session_kill(); 843 } 844 845 // Determine which message to output 846 $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : ''; 847 $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; 848 849 $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>'); 850 $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; 851 $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>'; 852 853 trigger_error($message); 854 } 855 856 return ($banned) ? true : false; 857 } 858 859 /** 860 * Check if ip is blacklisted 861 * This should be called only where absolutly necessary 862 * 863 * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups) 864 * 865 * @author satmd (from the php manual) 866 * @return false if ip is not blacklisted, else an array([checked server], [lookup]) 867 */ 868 function check_dnsbl($ip = false) 869 { 870 if ($ip === false) 871 { 872 $ip = $this->ip; 873 } 874 875 $dnsbl_check = array( 876 'bl.spamcop.net' => 'http://spamcop.net/bl.shtml?', 877 'list.dsbl.org' => 'http://dsbl.org/listing?', 878 'sbl-xbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', 879 ); 880 881 if ($ip) 882 { 883 $quads = explode('.', $ip); 884 $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0]; 885 886 foreach ($dnsbl_check as $dnsbl => $lookup) 887 { 888 if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) 889 { 890 return array($dnsbl, $lookup . $ip); 891 } 892 } 893 } 894 895 return false; 896 } 897 898 /** 899 * Set/Update a persistent login key 900 * 901 * This method creates or updates a persistent session key. When a user makes 902 * use of persistent (formerly auto-) logins a key is generated and stored in the 903 * DB. When they revisit with the same key it's automatically updated in both the 904 * DB and cookie. Multiple keys may exist for each user representing different 905 * browsers or locations. As with _any_ non-secure-socket no passphrase login this 906 * remains vulnerable to exploit. 907 */ 908 function set_login_key($user_id = false, $key = false, $user_ip = false) 909 { 910 global $config, $db; 911 912 $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; 913 $user_ip = ($user_ip === false) ? $this->ip : $user_ip; 914 $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key; 915 916 $key_id = unique_id(hexdec(substr($this->session_id, 0, 8))); 917 918 $sql_ary = array( 919 'key_id' => (string) md5($key_id), 920 'last_ip' => (string) $this->ip, 921 'last_login' => (int) time() 922 ); 923 924 if (!$key) 925 { 926 $sql_ary += array( 927 'user_id' => (int) $user_id 928 ); 929 } 930 931 if ($key) 932 { 933 $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . ' 934 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 935 WHERE user_id = ' . (int) $user_id . " 936 AND key_id = '" . $db->sql_escape(md5($key)) . "'"; 937 } 938 else 939 { 940 $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); 941 } 942 $db->sql_query($sql); 943 944 $this->cookie_data['k'] = $key_id; 945 946 return false; 947 } 948 949 /** 950 * Reset all login keys for the specified user 951 * 952 * This method removes all current login keys for a specified (or the current) 953 * user. It will be called on password change to render old keys unusable 954 */ 955 function reset_login_keys($user_id = false) 956 { 957 global $config, $db; 958 959 $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; 960 961 $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' 962 WHERE user_id = ' . (int) $user_id; 963 $db->sql_query($sql); 964 965 // Let's also clear any current sessions for the specified user_id 966 // If it's the current user then we'll leave this session intact 967 $sql_where = 'session_user_id = ' . (int) $user_id; 968 $sql_where .= ($user_id === $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : ''; 969 970 $sql = 'DELETE FROM ' . SESSIONS_TABLE . " 971 WHERE $sql_where"; 972 $db->sql_query($sql); 973 974 // We're changing the password of the current user and they have a key 975 // Lets regenerate it to be safe 976 if ($user_id === $this->data['user_id'] && $this->cookie_data['k']) 977 { 978 $this->set_login_key($user_id); 979 } 980 } 981 } 982 983 984 /** 985 * Base user class 986 * 987 * This is the overarching class which contains (through session extend) 988 * all methods utilised for user functionality during a session. 989 * 990 * @package phpBB3 991 */ 992 class user extends session 993 { 994 var $lang = array(); 995 var $help = array(); 996 var $theme = array(); 997 var $date_format; 998 var $timezone; 999 var $dst; 1000 1001 var $lang_name; 1002 var $lang_path; 1003 var $img_lang; 1004 1005 // Able to add new option (id 7) 1006 var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10); 1007 var $keyvalues = array(); 1008 1009 /** 1010 * Setup basic user-specific items (style, language, ...) 1011 */ 1012 function setup($lang_set = false, $style = false) 1013 { 1014 global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; 1015 1016 if ($this->data['user_id'] != ANONYMOUS) 1017 { 1018 $this->lang_name = (file_exists($phpbb_root_path . 'language/' . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : $config['default_lang']; 1019 $this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/'; 1020 1021 $this->date_format = $this->data['user_dateformat']; 1022 $this->timezone = $this->data['user_timezone'] * 3600; 1023 $this->dst = $this->data['user_dst'] * 3600; 1024 } 1025 else 1026 { 1027 $this->lang_name = $config['default_lang']; 1028 $this->lang_path = $phpbb_root_path . 'language/' . $this->lang_name . '/'; 1029 $this->date_format = $config['default_dateformat']; 1030 $this->timezone = $config['board_timezone'] * 3600; 1031 $this->dst = $config['board_dst'] * 3600; 1032 1033 /** 1034 * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language 1035 * @todo if re-enabled we need to make sure only those languages installed are checked 1036 1037 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) 1038 { 1039 $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); 1040 1041 foreach ($accept_lang_ary as $accept_lang) 1042 { 1043 // Set correct format ... guess full xx_YY form 1044 $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2)); 1045 $accept_lang = basename($accept_lang); 1046 1047 if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx")) 1048 { 1049 $this->lang_name = $config['default_lang'] = $accept_lang; 1050 $this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/'; 1051 break; 1052 } 1053 else 1054 { 1055 // No match on xx_YY so try xx 1056 $accept_lang = substr($accept_lang, 0, 2); 1057 $accept_lang = basename($accept_lang); 1058 1059 if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx")) 1060 { 1061 $this->lang_name = $config['default_lang'] = $accept_lang; 1062 $this->lang_path = $phpbb_root_path . 'language/' . $accept_lang . '/'; 1063 break; 1064 } 1065 } 1066 } 1067 } 1068 */ 1069 } 1070 1071 // We include common language file here to not load it every time a custom language file is included 1072 $lang = &$this->lang; 1073 if ((include $this->lang_path . "common.$phpEx") === false) 1074 { 1075 die("Language file " . $this->lang_path . "common.$phpEx" . " couldn't be opened."); 1076 } 1077 1078 $this->add_lang($lang_set); 1079 unset($lang_set); 1080 1081 if (!empty($_GET['style']) && $auth->acl_get('a_styles')) 1082 { 1083 global $SID, $_EXTRA_URL; 1084 1085 $style = request_var('style', 0); 1086 $SID .= '&style=' . $style; 1087 $_EXTRA_URL = array('style=' . $style); 1088 } 1089 else 1090 { 1091 // Set up style 1092 $style = ($style) ? $style : ((!$config['override_user_style'] && $this->data['user_id'] != ANONYMOUS) ? $this->data['user_style'] : $config['default_style']); 1093 } 1094 1095 $sql = 'SELECT s.style_id, t.*, c.*, i.* 1096 FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i 1097 WHERE s.style_id = $style 1098 AND t.template_id = s.template_id 1099 AND c.theme_id = s.theme_id 1100 AND i.imageset_id = s.imageset_id"; 1101 $result = $db->sql_query($sql, 3600); 1102 $this->theme = $db->sql_fetchrow($result); 1103 $db->sql_freeresult($result); 1104 1105 // User has wrong style 1106 if (!$this->theme && $style == $this->data['user_style']) 1107 { 1108 $style = $this->data['user_style'] = $config['default_style']; 1109 1110 $sql = 'UPDATE ' . USERS_TABLE . " 1111 SET user_style = $style 1112 WHERE user_id = {$this->data['user_id']}"; 1113 $db->sql_query($sql); 1114 1115 $sql = 'SELECT s.style_id, t.*, c.*, i.* 1116 FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i 1117 WHERE s.style_id = $style 1118 AND t.template_id = s.template_id 1119 AND c.theme_id = s.theme_id 1120 AND i.imageset_id = s.imageset_id"; 1121 $result = $db->sql_query($sql, 3600); 1122 $this->theme = $db->sql_fetchrow($result); 1123 $db->sql_freeresult($result); 1124 } 1125 1126 if (!$this->theme) 1127 { 1128 trigger_error('Could not get style data', E_USER_ERROR); 1129 } 1130 1131 // Now parse the cfg file and cache it 1132 $parsed_items = $cache->obtain_cfg_items($this->theme); 1133 1134 // We are only interested in the theme configuration for now 1135 $parsed_items = $parsed_items['theme']; 1136 1137 $check_for = array( 1138 'parse_css_file' => (int) 0, 1139 'pagination_sep' => (string) ', ' 1140 ); 1141 1142 foreach ($check_for as $key => $default_value) 1143 { 1144 $this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; 1145 settype($this->theme[$key], gettype($default_value)); 1146 1147 if (is_string($default_value)) 1148 { 1149 $this->theme[$key] = htmlspecialchars($this->theme[$key]); 1150 } 1151 } 1152 1153 // If the style author specified the theme needs to be cached 1154 // (because of the used paths and variables) than make sure it is the case. 1155 // For example, if the theme uses language-specific images it needs to be stored in db. 1156 if (!$this->theme['theme_storedb'] && $this->theme['parse_css_file']) 1157 { 1158 $this->theme['theme_storedb'] = 1; 1159 1160 $stylesheet = file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/stylesheet.css"); 1161 // Match CSS imports 1162 $matches = array(); 1163 preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches); 1164 1165 if (sizeof($matches)) 1166 { 1167 $content = ''; 1168 foreach ($matches[0] as $idx => $match) 1169 { 1170 if ($content = @file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/" . $matches[1][$idx])) 1171 { 1172 $content = trim($content); 1173 } 1174 else 1175 { 1176 $content = ''; 1177 } 1178 $stylesheet = str_replace($match, $content, $stylesheet); 1179 } 1180 unset ($content); 1181 } 1182 1183 $stylesheet = str_replace('./', 'styles/' . $this->theme['theme_path'] . '/theme/', $stylesheet); 1184 1185 $sql_ary = array( 1186 'theme_data' => $stylesheet, 1187 'theme_mtime' => time(), 1188 'theme_storedb' => 1 1189 ); 1190 1191 $sql = 'UPDATE ' . STYLES_THEME_TABLE . ' 1192 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' 1193 WHERE theme_id = ' . $this->theme['theme_id']; 1194 $db->sql_query($sql); 1195 1196 unset($sql_ary); 1197 } 1198 1199 $template->set_template(); 1200 1201 $this->img_lang = (file_exists($phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . $this->lang_name)) ? $this->lang_name : $config['default_lang']; 1202 1203 // Is board disabled and user not an admin or moderator? 1204 if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_')) 1205 { 1206 $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; 1207 trigger_error($message); 1208 } 1209 1210 // Is load exceeded? 1211 if ($config['limit_load'] && $this->load !== false) 1212 { 1213 if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_')) 1214 { 1215 trigger_error('BOARD_UNAVAILABLE'); 1216 } 1217 } 1218 1219 // Does the user need to change their password? If so, redirect to the 1220 // ucp profile reg_details page ... of course do not redirect if we're already in the ucp 1221 if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && $this->data['is_registered'] && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) 1222 { 1223 if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") 1224 { 1225 redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=reg_details')); 1226 } 1227 } 1228 1229 return; 1230 } 1231 1232 /** 1233 * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion) 1234 * 1235 * @param mixed $lang_set specifies the language entries to include 1236 * @param bool $use_db internal variable for recursion, do not use 1237 * @param bool $use_help internal variable for recursion, do not use 1238 * 1239 * Examples: 1240 * <code> 1241 * $lang_set = array('posting', 'help' => 'faq'); 1242 * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq')) 1243 * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq')) 1244 * $lang_set = 'posting' 1245 * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting')) 1246 * </code> 1247 */ 1248 function add_lang($lang_set, $use_db = false, $use_help = false) 1249 { 1250 global $phpEx; 1251 1252 if (is_array($lang_set)) 1253 { 1254 foreach ($lang_set as $key => $lang_file) 1255 { 1256 // Please do not delete this line. 1257 // We have to force the type here, else [array] language inclusion will not work 1258 $key = (string) $key; 1259 1260 if ($key == 'db') 1261 { 1262 $this->add_lang($lang_file, true, $use_help); 1263 } 1264 else if ($key == 'help') 1265 { 1266 $this->add_lang($lang_file, $use_db, true); 1267 } 1268 else if (!is_array($lang_file)) 1269 { 1270 $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help); 1271 } 1272 else 1273 { 1274 $this->add_lang($lang_file, $use_db, $use_help); 1275 } 1276 } 1277 unset($lang_set); 1278 } 1279 else if ($lang_set) 1280 { 1281 $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help); 1282 } 1283 } 1284 1285 /** 1286 * Set language entry (called by add_lang) 1287 * @access private 1288 */ 1289 function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false) 1290 { 1291 global $phpEx; 1292 1293 // Make sure the language path is set (if the user setup did not happen it is not set) 1294 if (!$this->lang_path) 1295 { 1296 global $phpbb_root_path, $config; 1297 1298 $this->lang_path = $phpbb_root_path . 'language/' . $config['default_lang'] . '/'; 1299 } 1300 1301 // $lang == $this->lang 1302 // $help == $this->help 1303 // - add appropiate variables here, name them as they are used within the language file... 1304 if (!$use_db) 1305 { 1306 if ((include($this->lang_path . (($use_help) ? 'help_' : '') . "$lang_file.$phpEx")) === false) 1307 { 1308 trigger_error("Language file {$this->lang_path}" . (($use_help) ? 'help_' : '') . "$lang_file.$phpEx couldn't be opened.", E_USER_ERROR); 1309 } 1310 } 1311 else if ($use_db) 1312 { 1313 // Get Database Language Strings 1314 // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed 1315 // For example: help:faq, posting 1316 } 1317 } 1318 1319 /** 1320 * Format user date 1321 */ 1322 function format_date($gmepoch, $format = false, $forcedate = false) 1323 { 1324 static $midnight; 1325 1326 $lang_dates = $this->lang['datetime']; 1327 $format = (!$format) ? $this->date_format : $format; 1328 1329 // Short representation of month in format 1330 if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false)) 1331 { 1332 $lang_dates['May'] = $lang_dates['May_short']; 1333 } 1334 1335 unset($lang_dates['May_short']); 1336 1337 if (!$midnight) 1338 { 1339 list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $this->timezone + $this->dst)); 1340 $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $this->timezone - $this->dst; 1341 } 1342 1343 if (strpos($format, '|') === false || ($gmepoch < $midnight - 86400 && !$forcedate) || ($gmepoch > $midnight + 172800 && !$forcedate)) 1344 { 1345 return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates); 1346 } 1347 1348 if ($gmepoch > $midnight + 86400 && !$forcedate) 1349 { 1350 $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); 1351 return str_replace('||', $this->lang['datetime']['TOMORROW'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); 1352 } 1353 else if ($gmepoch > $midnight && !$forcedate) 1354 { 1355 $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); 1356 return str_replace('||', $this->lang['datetime']['TODAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); 1357 } 1358 else if ($gmepoch > $midnight - 86400 && !$forcedate) 1359 { 1360 $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); 1361 return str_replace('||', $this->lang['datetime']['YESTERDAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); 1362 } 1363 1364 return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates); 1365 } 1366 1367 /** 1368 * Get language id currently used by the user 1369 */ 1370 function get_iso_lang_id() 1371 { 1372 global $config, $db; 1373 1374 if (isset($this->lang_id)) 1375 { 1376 return $this->lang_id; 1377 } 1378 1379 if (!$this->lang_name) 1380 { 1381 $this->lang_name = $config['default_lang']; 1382 } 1383 1384 $sql = 'SELECT lang_id 1385 FROM ' . LANG_TABLE . " 1386 WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'"; 1387 $result = $db->sql_query($sql); 1388 $lang_id = (int) $db->sql_fetchfield('lang_id'); 1389 $db->sql_freeresult($result); 1390 1391 return $lang_id; 1392 } 1393 1394 /** 1395 * Get users profile fields 1396 */ 1397 function get_profile_fields($user_id) 1398 { 1399 global $db; 1400 1401 if (isset($this->profile_fields)) 1402 { 1403 return; 1404 } 1405 1406 $sql = 'SELECT * 1407 FROM ' . PROFILE_FIELDS_DATA_TABLE . " 1408 WHERE user_id = $user_id"; 1409 $result = $db->sql_query_limit($sql, 1); 1410 $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row; 1411 $db->sql_freeresult($result); 1412 } 1413 1414 /** 1415 * Specify/Get image 1416 */ 1417 function img($img, $alt = '', $width = false, $suffix = '', $type = 'full_tag') 1418 { 1419 static $imgs; 1420 global $phpbb_root_path; 1421 1422 $img_data = &$imgs[$img . $suffix]; 1423 1424 if (empty($img_data) || $width !== false) 1425 { 1426 if (!isset($this->theme[$img]) || !$this->theme[$img]) 1427 { 1428 // Do not fill the image to let designers decide what to do if the image is empty 1429 $img_data = ''; 1430 return $img_data; 1431 } 1432 1433 // Do not include dimensions? 1434 if (strpos($this->theme[$img], '*') === false) 1435 { 1436 $imgsrc = trim($this->theme[$img]); 1437 $width = $height = false; 1438 } 1439 else 1440 { 1441 if ($width === false) 1442 { 1443 list($imgsrc, $height, $width) = explode('*', $this->theme[$img]); 1444 } 1445 else 1446 { 1447 list($imgsrc, $height) = explode('*', $this->theme[$img]); 1448 } 1449 } 1450 1451 if ($suffix !== '') 1452 { 1453 $imgsrc = str_replace('{SUFFIX}', $suffix, $imgsrc); 1454 } 1455 1456 $img_data['src'] = $phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . str_replace('{LANG}', $this->img_lang, $imgsrc); 1457 $img_data['width'] = $width; 1458 $img_data['height'] = $height; 1459 } 1460 1461 $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt; 1462 1463 switch ($type) 1464 { 1465 case 'src': 1466 return $img_data['src']; 1467 break; 1468 1469 case 'width': 1470 return $img_data['width']; 1471 break; 1472 1473 case 'height': 1474 return $img_data['height']; 1475 break; 1476 1477 default: 1478 return '<img src="' . $img_data['src'] . '"' . (($img_data['width']) ? ' width="' . $img_data['width'] . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; 1479 break; 1480 } 1481 } 1482 1483 /** 1484 * Get option bit field from user options 1485 */ 1486 function optionget($key, $data = false) 1487 { 1488 if (!isset($this->keyvalues[$key])) 1489 { 1490 $var = ($data) ? $data : $this->data['user_options']; 1491 $this->keyvalues[$key] = ($var & 1 << $this->keyoptions[$key]) ? true : false; 1492 } 1493 1494 return $this->keyvalues[$key]; 1495 } 1496 1497 /** 1498 * Set option bit field for user options 1499 */ 1500 function optionset($key, $value, $data = false) 1501 { 1502 $var = ($data) ? $data : $this->data['user_options']; 1503 1504 if ($value && !($var & 1 << $this->keyoptions[$key])) 1505 { 1506 $var += 1 << $this->keyoptions[$key]; 1507 } 1508 else if (!$value && ($var & 1 << $this->keyoptions[$key])) 1509 { 1510 $var -= 1 << $this->keyoptions[$key]; 1511 } 1512 else 1513 { 1514 return ($data) ? $var : false; 1515 } 1516 1517 if (!$data) 1518 { 1519 $this->data['user_options'] = $var; 1520 return true; 1521 } 1522 else 1523 { 1524 return $var; 1525 } 1526 } 1527 } 1528 1529 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 22 00:35:05 2006 | Cross-referenced by PHPXref 0.6 |