Changeset 3 for branches/rsr.v5.1.dev/web/punbb/include/functions.php
- Timestamp:
- Nov 14, 2011, 11:17:15 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/rsr.v5.1.dev/web/punbb/include/functions.php
r1 r3 1 1 <?php 2 /*********************************************************************** 3 4 Copyright (C) 2002-2005 Rickard Andersson (rickard@punbb.org) 5 6 This file is part of PunBB. 7 8 PunBB is free software; you can redistribute it and/or modify it 9 under the terms of the GNU General Public License as published 10 by the Free Software Foundation; either version 2 of the License, 11 or (at your option) any later version. 12 13 PunBB is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 MA 02111-1307 USA 22 23 ************************************************************************/ 2 3 /** 4 * Copyright (C) 2008-2011 FluxBB 5 * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB 6 * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher 7 */ 8 9 10 // 11 // Return current timestamp (with microseconds) as a float 12 // 13 function get_microtime() 14 { 15 list($usec, $sec) = explode(' ', microtime()); 16 return ((float)$usec + (float)$sec); 17 } 24 18 25 19 // … … 28 22 function check_cookie(&$pun_user) 29 23 { 30 global $db, $ pun_config, $cookie_name, $cookie_seed;24 global $db, $db_type, $pun_config, $cookie_name, $cookie_seed; 31 25 32 26 $now = time(); 33 $expire = $now + 31536000; // The cookie expires after a year 34 35 // We assume it's a guest 36 $cookie = array('user_id' => 1, 'password_hash' => 'Invité'); 37 38 // If a cookie is set, we get the user_id and password hash from it 39 if (isset($_COOKIE[$cookie_name])) 40 list($cookie['user_id'], $cookie['password_hash']) = @unserialize($_COOKIE[$cookie_name]); 41 42 if ($cookie['user_id'] > 1) 43 { 27 28 // If the cookie is set and it matches the correct pattern, then read the values from it 29 if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches)) 30 { 31 $cookie = array( 32 'user_id' => intval($matches[1]), 33 'password_hash' => $matches[2], 34 'expiration_time' => intval($matches[3]), 35 'cookie_hash' => $matches[4], 36 ); 37 } 38 39 // If it has a non-guest user, and hasn't expired 40 if (isset($cookie) && $cookie['user_id'] > 1 && $cookie['expiration_time'] > $now) 41 { 42 // If the cookie has been tampered with 43 if (forum_hmac($cookie['user_id'].'|'.$cookie['expiration_time'], $cookie_seed.'_cookie_hash') != $cookie['cookie_hash']) 44 { 45 $expire = $now + 31536000; // The cookie expires after a year 46 pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire); 47 set_default_user(); 48 49 return; 50 } 51 44 52 // Check if there's a user with the user ID and password hash from the cookie 45 $_query = 'SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.intval($cookie['user_id']); 46 $result = $db->query($_query) or error('Impossible de retrouver les informations utilisateur', __FILE__, __LINE__, $db->error()); 53 $result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.intval($cookie['user_id'])) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error()); 47 54 $pun_user = $db->fetch_assoc($result); 48 55 49 56 // If user authorisation failed 50 if (!isset($pun_user['id']) || md5($cookie_seed.$pun_user['password']) !== $cookie['password_hash']) 51 { 52 pun_setcookie(0, random_pass(8), $expire); 57 if (!isset($pun_user['id']) || forum_hmac($pun_user['password'], $cookie_seed.'_password_hash') !== $cookie['password_hash']) 58 { 59 $expire = $now + 31536000; // The cookie expires after a year 60 pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire); 53 61 set_default_user(); 54 62 … … 56 64 } 57 65 66 // Send a new, updated cookie with a new expiration timestamp 67 $expire = ($cookie['expiration_time'] > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit']; 68 pun_setcookie($pun_user['id'], $pun_user['password'], $expire); 69 58 70 // Set a default language if the user selected language no longer exists 59 if (! $pun_user['language'] || !@file_exists(PUN_ROOT.'lang/'.$pun_user['language']))71 if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language'])) 60 72 $pun_user['language'] = $pun_config['o_default_lang']; 61 73 62 74 // Set a default style if the user selected style no longer exists 63 if (! @file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))75 if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css')) 64 76 $pun_user['style'] = $pun_config['o_default_style']; 65 77 … … 69 81 $pun_user['disp_posts'] = $pun_config['o_disp_posts_default']; 70 82 71 if ($pun_user['save_pass'] == '0')72 $expire = 0;73 74 83 // Define this if you want this visit to affect the online list and the users last visit data 75 84 if (!defined('PUN_QUIET_VISIT')) … … 77 86 // Update the online list 78 87 if (!$pun_user['logged']) 79 $db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$now.')') or error('Impossbile d\'insérer dans la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error()); 88 { 89 $pun_user['logged'] = $now; 90 91 // With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table 92 switch ($db_type) 93 { 94 case 'mysql': 95 case 'mysqli': 96 case 'mysql_innodb': 97 case 'mysqli_innodb': 98 case 'sqlite': 99 $db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error()); 100 break; 101 102 default: 103 $db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) SELECT '.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].' WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE user_id='.$pun_user['id'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error()); 104 break; 105 } 106 107 // Reset tracked topics 108 set_tracked_topics(null); 109 } 80 110 else 81 111 { … … 83 113 if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit'])) 84 114 { 85 $db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error(' Impossible de mettre à jour les données de visite de l\'utilisateur', __FILE__, __LINE__, $db->error());115 $db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error()); 86 116 $pun_user['last_visit'] = $pun_user['logged']; 87 117 } 88 118 89 119 $idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : ''; 90 $db->query('UPDATE '.$db->prefix.'online SET logged='.$now.$idle_sql.' WHERE user_id='.$pun_user['id']) or error('Impossible de mettre à jour la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error()); 120 $db->query('UPDATE '.$db->prefix.'online SET logged='.$now.$idle_sql.' WHERE user_id='.$pun_user['id']) or error('Unable to update online list', __FILE__, __LINE__, $db->error()); 121 122 // Update tracked topics with the current expire time 123 if (isset($_COOKIE[$cookie_name.'_track'])) 124 forum_setcookie($cookie_name.'_track', $_COOKIE[$cookie_name.'_track'], $now + $pun_config['o_timeout_visit']); 91 125 } 92 126 } 127 else 128 { 129 if (!$pun_user['logged']) 130 $pun_user['logged'] = $pun_user['last_visit']; 131 } 93 132 94 133 $pun_user['is_guest'] = false; 134 $pun_user['is_admmod'] = $pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1'; 95 135 } 96 136 else … … 100 140 101 141 // 142 // Converts the CDATA end sequence ]]> into ]]> 143 // 144 function escape_cdata($str) 145 { 146 return str_replace(']]>', ']]>', $str); 147 } 148 149 150 // 151 // Authenticates the provided username and password against the user database 152 // $user can be either a user ID (integer) or a username (string) 153 // $password can be either a plaintext password or a password hash including salt ($password_is_hash must be set accordingly) 154 // 155 function authenticate_user($user, $password, $password_is_hash = false) 156 { 157 global $db, $pun_user; 158 159 // Check if there's a user matching $user and $password 160 $result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE '.(is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$db->escape($user).'\'')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error()); 161 $pun_user = $db->fetch_assoc($result); 162 163 if (!isset($pun_user['id']) || 164 ($password_is_hash && $password != $pun_user['password']) || 165 (!$password_is_hash && pun_hash($password) != $pun_user['password'])) 166 set_default_user(); 167 else 168 $pun_user['is_guest'] = false; 169 } 170 171 172 // 173 // Try to determine the current URL 174 // 175 function get_current_url($max_length = 0) 176 { 177 $protocol = get_current_protocol(); 178 $port = (isset($_SERVER['SERVER_PORT']) && (($_SERVER['SERVER_PORT'] != '80' && $protocol == 'http') || ($_SERVER['SERVER_PORT'] != '443' && $protocol == 'https')) && strpos($_SERVER['HTTP_HOST'], ':') === false) ? ':'.$_SERVER['SERVER_PORT'] : ''; 179 180 $url = urldecode($protocol.'://'.$_SERVER['HTTP_HOST'].$port.$_SERVER['REQUEST_URI']); 181 182 if (strlen($url) <= $max_length || $max_length == 0) 183 return $url; 184 185 // We can't find a short enough url 186 return null; 187 } 188 189 190 // 191 // Fetch the current protocol in use - http or https 192 // 193 function get_current_protocol() 194 { 195 $protocol = 'http'; 196 197 // Check if the server is claiming to using HTTPS 198 if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') 199 $protocol = 'https'; 200 201 // If we are behind a reverse proxy try to decide which protocol it is using 202 if (defined('FORUM_BEHIND_REVERSE_PROXY')) 203 { 204 // Check if we are behind a Microsoft based reverse proxy 205 if (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) != 'off') 206 $protocol = 'https'; 207 208 // Check if we're behind a "proper" reverse proxy, and what protocol it's using 209 if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) 210 $protocol = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']); 211 } 212 213 return $protocol; 214 } 215 216 // 217 // Fetch the base_url, optionally support HTTPS and HTTP 218 // 219 function get_base_url($support_https = false) 220 { 221 global $pun_config; 222 static $base_url; 223 224 if (!$support_https) 225 return $pun_config['o_base_url']; 226 227 if (!isset($base_url)) 228 { 229 // Make sure we are using the correct protocol 230 $base_url = str_replace(array('http://', 'https://'), get_current_protocol().'://', $pun_config['o_base_url']); 231 } 232 233 return $base_url; 234 } 235 236 237 // 102 238 // Fill $pun_user with default values (for guests) 103 239 // 104 240 function set_default_user() 105 241 { 106 global $db, $ pun_user, $pun_config;242 global $db, $db_type, $pun_user, $pun_config; 107 243 108 244 $remote_addr = get_remote_address(); 109 245 110 246 // Fetch guest user 111 $result = $db->query('SELECT u.*, g.*, o.logged FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.ident=\''.$remote_addr.'\' WHERE u.id=1') or error('Impossible de retrouver les informations d\'invité', __FILE__, __LINE__, $db->error());247 $result = $db->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.ident=\''.$remote_addr.'\' WHERE u.id=1') or error('Unable to fetch guest information', __FILE__, __LINE__, $db->error()); 112 248 if (!$db->num_rows($result)) 113 exit(' Impossible de retrouver les informations invité. La table \''.$db->prefix.'users\' doit contenir une entrée avec un id = 1 qui représente les utilisateurs anonymes.');249 exit('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.'); 114 250 115 251 $pun_user = $db->fetch_assoc($result); … … 117 253 // Update online list 118 254 if (!$pun_user['logged']) 119 $db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.time().')') or error('Impossbile d\'insérer dans la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error()); 255 { 256 $pun_user['logged'] = time(); 257 258 // With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table 259 switch ($db_type) 260 { 261 case 'mysql': 262 case 'mysqli': 263 case 'mysql_innodb': 264 case 'mysqli_innodb': 265 case 'sqlite': 266 $db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error()); 267 break; 268 269 default: 270 $db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) SELECT 1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].' WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($remote_addr).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error()); 271 break; 272 } 273 } 120 274 else 121 $db->query('UPDATE '.$db->prefix.'online SET logged='.time().' WHERE ident=\''.$db->escape($remote_addr).'\'') or error(' Impossible de mettre à jour la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error());275 $db->query('UPDATE '.$db->prefix.'online SET logged='.time().' WHERE ident=\''.$db->escape($remote_addr).'\'') or error('Unable to update online list', __FILE__, __LINE__, $db->error()); 122 276 123 277 $pun_user['disp_topics'] = $pun_config['o_disp_topics_default']; 124 278 $pun_user['disp_posts'] = $pun_config['o_disp_posts_default']; 125 $pun_user['timezone'] = $pun_config['o_server_timezone']; 279 $pun_user['timezone'] = $pun_config['o_default_timezone']; 280 $pun_user['dst'] = $pun_config['o_default_dst']; 126 281 $pun_user['language'] = $pun_config['o_default_lang']; 127 282 $pun_user['style'] = $pun_config['o_default_style']; 128 283 $pun_user['is_guest'] = true; 129 130 } 131 132 133 // 134 // Set a cookie, PunBB style! 284 $pun_user['is_admmod'] = false; 285 } 286 287 288 // 289 // SHA1 HMAC with PHP 4 fallback 290 // 291 function forum_hmac($data, $key, $raw_output = false) 292 { 293 if (function_exists('hash_hmac')) 294 return hash_hmac('sha1', $data, $key, $raw_output); 295 296 // If key size more than blocksize then we hash it once 297 if (strlen($key) > 64) 298 $key = pack('H*', sha1($key)); // we have to use raw output here to match the standard 299 300 // Ensure we're padded to exactly one block boundary 301 $key = str_pad($key, 64, chr(0x00)); 302 303 $hmac_opad = str_repeat(chr(0x5C), 64); 304 $hmac_ipad = str_repeat(chr(0x36), 64); 305 306 // Do inner and outer padding 307 for ($i = 0;$i < 64;$i++) { 308 $hmac_opad[$i] = $hmac_opad[$i] ^ $key[$i]; 309 $hmac_ipad[$i] = $hmac_ipad[$i] ^ $key[$i]; 310 } 311 312 // Finally, calculate the HMAC 313 $hash = sha1($hmac_opad.pack('H*', sha1($hmac_ipad.$data))); 314 315 // If we want raw output then we need to pack the final result 316 if ($raw_output) 317 $hash = pack('H*', $hash); 318 319 return $hash; 320 } 321 322 323 // 324 // Set a cookie, FluxBB style! 325 // Wrapper for forum_setcookie 135 326 // 136 327 function pun_setcookie($user_id, $password_hash, $expire) 137 328 { 138 global $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $cookie_seed; 139 140 // Enable sending of a P3P header by removing // from the following line (try this if login is failing in IE6) 141 // @header('P3P: CP="CUR ADM"'); 142 143 setcookie($cookie_name, serialize(array($user_id, md5($cookie_seed.$password_hash))), $expire, $cookie_path, $cookie_domain, $cookie_secure); 329 global $cookie_name, $cookie_seed; 330 331 forum_setcookie($cookie_name, $user_id.'|'.forum_hmac($password_hash, $cookie_seed.'_password_hash').'|'.$expire.'|'.forum_hmac($user_id.'|'.$expire, $cookie_seed.'_cookie_hash'), $expire); 332 } 333 334 335 // 336 // Set a cookie, FluxBB style! 337 // 338 function forum_setcookie($name, $value, $expire) 339 { 340 global $cookie_path, $cookie_domain, $cookie_secure; 341 342 // Enable sending of a P3P header 343 header('P3P: CP="CUR ADM"'); 344 345 if (version_compare(PHP_VERSION, '5.2.0', '>=')) 346 setcookie($name, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, true); 347 else 348 setcookie($name, $value, $expire, $cookie_path.'; HttpOnly', $cookie_domain, $cookie_secure); 144 349 } 145 350 … … 152 357 global $db, $pun_config, $lang_common, $pun_user, $pun_bans; 153 358 154 // Admins a ren't affected155 if ($pun_user[' g_id'] == PUN_ADMIN|| !$pun_bans)359 // Admins and moderators aren't affected 360 if ($pun_user['is_admmod'] || !$pun_bans) 156 361 return; 157 362 158 // Add a dot at the end of the IP address to prevent banned address 192.168.0.5 from matching e.g. 192.168.0.50 159 $user_ip = get_remote_address().'.'; 363 // Add a dot or a colon (depending on IPv4/IPv6) at the end of the IP address to prevent banned address 364 // 192.168.0.5 from matching e.g. 192.168.0.50 365 $user_ip = get_remote_address(); 366 $user_ip .= (strpos($user_ip, '.') !== false) ? '.' : ':'; 367 160 368 $bans_altered = false; 369 $is_banned = false; 161 370 162 371 foreach ($pun_bans as $cur_ban) … … 165 374 if ($cur_ban['expire'] != '' && $cur_ban['expire'] <= time()) 166 375 { 167 $db->query('DELETE FROM '.$db->prefix.'bans WHERE id='.$cur_ban['id']) or error(' Impossible de supprimé le bannissement expiré', __FILE__, __LINE__, $db->error());376 $db->query('DELETE FROM '.$db->prefix.'bans WHERE id='.$cur_ban['id']) or error('Unable to delete expired ban', __FILE__, __LINE__, $db->error()); 168 377 $bans_altered = true; 169 378 continue; 170 379 } 171 380 172 if ($cur_ban['username'] != '' && !strcasecmp($pun_user['username'], $cur_ban['username'])) 173 { 174 $db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($pun_user['username']).'\'') or error('Impossible de supprimer de la liste des utilisateur en ligne', __FILE__, __LINE__, $db->error()); 175 message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? $lang_common['Ban message 2'].' '.strtolower(format_time($cur_ban['expire'], true)).'. ' : '').(($cur_ban['message'] != '') ? $lang_common['Ban message 3'].'<br /><br /><strong>'.pun_htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').$lang_common['Ban message 4'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.', true); 176 } 381 if ($cur_ban['username'] != '' && utf8_strtolower($pun_user['username']) == utf8_strtolower($cur_ban['username'])) 382 $is_banned = true; 177 383 178 384 if ($cur_ban['ip'] != '') … … 180 386 $cur_ban_ips = explode(' ', $cur_ban['ip']); 181 387 182 for ($i = 0; $i < count($cur_ban_ips); ++$i) 388 $num_ips = count($cur_ban_ips); 389 for ($i = 0; $i < $num_ips; ++$i) 183 390 { 184 $cur_ban_ips[$i] = $cur_ban_ips[$i].'.'; 391 // Add the proper ending to the ban 392 if (strpos($user_ip, '.') !== false) 393 $cur_ban_ips[$i] = $cur_ban_ips[$i].'.'; 394 else 395 $cur_ban_ips[$i] = $cur_ban_ips[$i].':'; 185 396 186 397 if (substr($user_ip, 0, strlen($cur_ban_ips[$i])) == $cur_ban_ips[$i]) 187 398 { 188 $ db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($pun_user['username']).'\'') or error('Impossible de supprimer de la liste des utilisateur en ligne', __FILE__, __LINE__, $db->error());189 message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? $lang_common['Ban message 2'].' '.strtolower(format_time($cur_ban['expire'], true)).'. ' : '').(($cur_ban['message'] != '') ? $lang_common['Ban message 3'].'<br /><br /><strong>'.pun_htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').$lang_common['Ban message 4'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.', true);399 $is_banned = true; 400 break; 190 401 } 191 402 } 192 403 } 404 405 if ($is_banned) 406 { 407 $db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($pun_user['username']).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error()); 408 message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? $lang_common['Ban message 2'].' '.strtolower(format_time($cur_ban['expire'], true)).'. ' : '').(($cur_ban['message'] != '') ? $lang_common['Ban message 3'].'<br /><br /><strong>'.pun_htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').$lang_common['Ban message 4'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.', true); 409 } 193 410 } 194 411 … … 196 413 if ($bans_altered) 197 414 { 198 require_once PUN_ROOT.'include/cache.php'; 415 if (!defined('FORUM_CACHE_FUNCTIONS_LOADED')) 416 require PUN_ROOT.'include/cache.php'; 417 199 418 generate_bans_cache(); 200 419 } … … 203 422 204 423 // 424 // Check username 425 // 426 function check_username($username, $exclude_id = null) 427 { 428 global $db, $pun_config, $errors, $lang_prof_reg, $lang_register, $lang_common, $pun_bans; 429 430 // Convert multiple whitespace characters into one (to prevent people from registering with indistinguishable usernames) 431 $username = preg_replace('%\s+%s', ' ', $username); 432 433 // Validate username 434 if (pun_strlen($username) < 2) 435 $errors[] = $lang_prof_reg['Username too short']; 436 else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters 437 $errors[] = $lang_prof_reg['Username too long']; 438 else if (!strcasecmp($username, 'Guest') || !strcasecmp($username, $lang_common['Guest'])) 439 $errors[] = $lang_prof_reg['Username guest']; 440 else if (preg_match('%[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}%', $username) || preg_match('%((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))%', $username)) 441 $errors[] = $lang_prof_reg['Username IP']; 442 else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false) 443 $errors[] = $lang_prof_reg['Username reserved chars']; 444 else if (preg_match('%(?:\[/?(?:b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*|topic|post|forum|user)\]|\[(?:img|url|quote|list)=)%i', $username)) 445 $errors[] = $lang_prof_reg['Username BBCode']; 446 447 // Check username for any censored words 448 if ($pun_config['o_censoring'] == '1' && censor_words($username) != $username) 449 $errors[] = $lang_register['Username censor']; 450 451 // Check that the username (or a too similar username) is not already registered 452 $query = ($exclude_id) ? ' AND id!='.$exclude_id : ''; 453 454 $result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(ucp_preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\')) AND id>1'.$query) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error()); 455 456 if ($db->num_rows($result)) 457 { 458 $busy = $db->result($result); 459 $errors[] = $lang_register['Username dupe 1'].' '.pun_htmlspecialchars($busy).'. '.$lang_register['Username dupe 2']; 460 } 461 462 // Check username for any banned usernames 463 foreach ($pun_bans as $cur_ban) 464 { 465 if ($cur_ban['username'] != '' && utf8_strtolower($username) == utf8_strtolower($cur_ban['username'])) 466 { 467 $errors[] = $lang_prof_reg['Banned username']; 468 break; 469 } 470 } 471 } 472 473 474 // 205 475 // Update "Users online" 206 476 // 207 477 function update_users_online() 208 478 { 209 global $db, $pun_config , $pun_user;479 global $db, $pun_config; 210 480 211 481 $now = time(); 212 482 213 483 // Fetch all online list entries that are older than "o_timeout_online" 214 $result = $db->query('SELECT * FROM '.$db->prefix.'online WHERE logged<'.($now-$pun_config['o_timeout_online'])) or error('Impossible de retrouver les anciennes entrées de la liste des utilisateurs', __FILE__, __LINE__, $db->error());484 $result = $db->query('SELECT user_id, ident, logged, idle FROM '.$db->prefix.'online WHERE logged<'.($now-$pun_config['o_timeout_online'])) or error('Unable to fetch old entries from online list', __FILE__, __LINE__, $db->error()); 215 485 while ($cur_user = $db->fetch_assoc($result)) 216 486 { 217 487 // If the entry is a guest, delete it 218 488 if ($cur_user['user_id'] == '1') 219 $db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($cur_user['ident']).'\'') or error(' Impossible de supprimer de la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error());489 $db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($cur_user['ident']).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error()); 220 490 else 221 491 { … … 223 493 if ($cur_user['logged'] < ($now-$pun_config['o_timeout_visit'])) 224 494 { 225 $db->query('UPDATE '.$db->prefix.'users SET last_visit='.$cur_user['logged'].' WHERE id='.$cur_user['user_id']) or error(' Impossible de mettre à jour les données de visite de l\'utilisateur', __FILE__, __LINE__, $db->error());226 $db->query('DELETE FROM '.$db->prefix.'online WHERE user_id='.$cur_user['user_id']) or error(' Impossible de supprimer de la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error());495 $db->query('UPDATE '.$db->prefix.'users SET last_visit='.$cur_user['logged'].' WHERE id='.$cur_user['user_id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error()); 496 $db->query('DELETE FROM '.$db->prefix.'online WHERE user_id='.$cur_user['user_id']) or error('Unable to delete from online list', __FILE__, __LINE__, $db->error()); 227 497 } 228 498 else if ($cur_user['idle'] == '0') 229 $db->query('UPDATE '.$db->prefix.'online SET idle=1 WHERE user_id='.$cur_user['user_id']) or error('Impossible d\'insérer à la liste des utilisateurs en ligne', __FILE__, __LINE__, $db->error()); 230 } 231 } 232 } 233 234 235 // 236 // Generate the "navigator" that appears at the top of every page 237 // 238 function generate_navlinks() 239 { 240 global $pun_config, $lang_common, $pun_user; 241 242 // Index and Userlist should always be displayed 243 $links[] = '<li id="navindex"><a href="index.php">'.$lang_common['Index'].'</a>'; 244 $links[] = '<li id="navuserlist"><a href="userlist.php">'.$lang_common['User list'].'</a>'; 245 246 if ($pun_config['o_rules'] == '1') 247 $links[] = '<li id="navrules"><a href="misc.php?action=rules">'.$lang_common['Rules'].'</a>'; 248 249 if ($pun_user['is_guest']) 250 { 251 if ($pun_user['g_search'] == '1') 252 $links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>'; 253 254 $links[] = '<li id="navregister"><a href="register.php">'.$lang_common['Register'].'</a>'; 255 $links[] = '<li id="navlogin"><a href="login.php">'.$lang_common['Login'].'</a>'; 256 257 $info = $lang_common['Not logged in']; 258 } 259 else 260 { 261 if ($pun_user['g_id'] > PUN_MOD) 262 { 263 if ($pun_user['g_search'] == '1') 264 $links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>'; 265 266 $links[] = '<li id="navprofile"><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a>'; 267 $links[] = '<li id="navlogout"><a href="login.php?action=out&id='.$pun_user['id'].'">'.$lang_common['Logout'].'</a>'; 268 } 269 else 270 { 271 $links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>'; 272 $links[] = '<li id="navprofile"><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a>'; 273 $links[] = '<li id="navadmin"><a href="admin_index.php">'.$lang_common['Admin'].'</a>'; 274 $links[] = '<li id="navlogout"><a href="login.php?action=out&id='.$pun_user['id'].'">'.$lang_common['Logout'].'</a>'; 275 } 276 } 277 278 // Are there any additional navlinks we should insert into the array before imploding it? 279 if ($pun_config['o_additional_navlinks'] != '') 280 { 281 if (preg_match_all('#([0-9]+)\s*=\s*(.*?)\n#s', $pun_config['o_additional_navlinks']."\n", $extra_links)) 282 { 283 // Insert any additional links into the $links array (at the correct index) 284 for ($i = 0; $i < count($extra_links[1]); ++$i) 285 array_splice($links, $extra_links[1][$i], 0, array('<li id="navextra'.($i + 1).'">'.$extra_links[2][$i])); 286 } 287 } 288 289 return '<ul>'."\n\t\t\t\t".implode($lang_common['Link separator'].'</li>'."\n\t\t\t\t", $links).'</li>'."\n\t\t\t".'</ul>'; 499 $db->query('UPDATE '.$db->prefix.'online SET idle=1 WHERE user_id='.$cur_user['user_id']) or error('Unable to insert into online list', __FILE__, __LINE__, $db->error()); 500 } 501 } 290 502 } 291 503 … … 308 520 <li<?php if ($page == 'personal') echo ' class="isactive"'; ?>><a href="profile.php?section=personal&id=<?php echo $id ?>"><?php echo $lang_profile['Section personal'] ?></a></li> 309 521 <li<?php if ($page == 'messaging') echo ' class="isactive"'; ?>><a href="profile.php?section=messaging&id=<?php echo $id ?>"><?php echo $lang_profile['Section messaging'] ?></a></li> 310 <li<?php if ($page == 'personality') echo ' class="isactive"'; ?>><a href="profile.php?section=personality&id=<?php echo $id ?>"><?php echo $lang_profile['Section personality'] ?></a></li>311 <li<?php if ($page == 'display') echo ' class="isactive"'; ?>><a href="profile.php?section=display&id=<?php echo $id ?>"><?php echo $lang_profile['Section display'] ?></a></li>522 <?php if ($pun_config['o_avatars'] == '1' || $pun_config['o_signatures'] == '1'): ?> <li<?php if ($page == 'personality') echo ' class="isactive"'; ?>><a href="profile.php?section=personality&id=<?php echo $id ?>"><?php echo $lang_profile['Section personality'] ?></a></li> 523 <?php endif; ?> <li<?php if ($page == 'display') echo ' class="isactive"'; ?>><a href="profile.php?section=display&id=<?php echo $id ?>"><?php echo $lang_profile['Section display'] ?></a></li> 312 524 <li<?php if ($page == 'privacy') echo ' class="isactive"'; ?>><a href="profile.php?section=privacy&id=<?php echo $id ?>"><?php echo $lang_profile['Section privacy'] ?></a></li> 313 <?php if ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_ id'] == PUN_MOD && $pun_config['p_mod_ban_users'] == '1')): ?> <li<?php if ($page == 'admin') echo ' class="isactive"'; ?>><a href="profile.php?section=admin&id=<?php echo $id ?>"><?php echo $lang_profile['Section admin'] ?></a></li>525 <?php if ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_moderator'] == '1' && $pun_user['g_mod_ban_users'] == '1')): ?> <li<?php if ($page == 'admin') echo ' class="isactive"'; ?>><a href="profile.php?section=admin&id=<?php echo $id ?>"><?php echo $lang_profile['Section admin'] ?></a></li> 314 526 <?php endif; ?> </ul> 315 527 </div> … … 322 534 323 535 // 324 // Update posts, topics, last_post, last_post_id and last_poster for a forum (redirect topics are not included) 536 // Outputs markup to display a user's avatar 537 // 538 function generate_avatar_markup($user_id) 539 { 540 global $pun_config; 541 542 $filetypes = array('jpg', 'gif', 'png'); 543 $avatar_markup = ''; 544 545 foreach ($filetypes as $cur_type) 546 { 547 $path = $pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type; 548 549 if (file_exists(PUN_ROOT.$path) && $img_size = getimagesize(PUN_ROOT.$path)) 550 { 551 $avatar_markup = '<img src="'.pun_htmlspecialchars(get_base_url(true).'/'.$path.'?m='.filemtime(PUN_ROOT.$path)).'" '.$img_size[3].' alt="" />'; 552 break; 553 } 554 } 555 556 return $avatar_markup; 557 } 558 559 560 // 561 // Generate browser's title 562 // 563 function generate_page_title($page_title, $p = null) 564 { 565 global $pun_config, $lang_common; 566 567 $page_title = array_reverse($page_title); 568 569 if ($p != null) 570 $page_title[0] .= ' ('.sprintf($lang_common['Page'], forum_number_format($p)).')'; 571 572 $crumbs = implode($lang_common['Title separator'], $page_title); 573 574 return $crumbs; 575 } 576 577 578 // 579 // Save array of tracked topics in cookie 580 // 581 function set_tracked_topics($tracked_topics) 582 { 583 global $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $pun_config; 584 585 $cookie_data = ''; 586 if (!empty($tracked_topics)) 587 { 588 // Sort the arrays (latest read first) 589 arsort($tracked_topics['topics'], SORT_NUMERIC); 590 arsort($tracked_topics['forums'], SORT_NUMERIC); 591 592 // Homebrew serialization (to avoid having to run unserialize() on cookie data) 593 foreach ($tracked_topics['topics'] as $id => $timestamp) 594 $cookie_data .= 't'.$id.'='.$timestamp.';'; 595 foreach ($tracked_topics['forums'] as $id => $timestamp) 596 $cookie_data .= 'f'.$id.'='.$timestamp.';'; 597 598 // Enforce a byte size limit (4096 minus some space for the cookie name - defaults to 4048) 599 if (strlen($cookie_data) > FORUM_MAX_COOKIE_SIZE) 600 { 601 $cookie_data = substr($cookie_data, 0, FORUM_MAX_COOKIE_SIZE); 602 $cookie_data = substr($cookie_data, 0, strrpos($cookie_data, ';')).';'; 603 } 604 } 605 606 forum_setcookie($cookie_name.'_track', $cookie_data, time() + $pun_config['o_timeout_visit']); 607 $_COOKIE[$cookie_name.'_track'] = $cookie_data; // Set it directly in $_COOKIE as well 608 } 609 610 611 // 612 // Extract array of tracked topics from cookie 613 // 614 function get_tracked_topics() 615 { 616 global $cookie_name; 617 618 $cookie_data = isset($_COOKIE[$cookie_name.'_track']) ? $_COOKIE[$cookie_name.'_track'] : false; 619 if (!$cookie_data) 620 return array('topics' => array(), 'forums' => array()); 621 622 if (strlen($cookie_data) > 4048) 623 return array('topics' => array(), 'forums' => array()); 624 625 // Unserialize data from cookie 626 $tracked_topics = array('topics' => array(), 'forums' => array()); 627 $temp = explode(';', $cookie_data); 628 foreach ($temp as $t) 629 { 630 $type = substr($t, 0, 1) == 'f' ? 'forums' : 'topics'; 631 $id = intval(substr($t, 1)); 632 $timestamp = intval(substr($t, strpos($t, '=') + 1)); 633 if ($id > 0 && $timestamp > 0) 634 $tracked_topics[$type][$id] = $timestamp; 635 } 636 637 return $tracked_topics; 638 } 639 640 641 // 642 // Update posts, topics, last_post, last_post_id and last_poster for a forum 325 643 // 326 644 function update_forum($forum_id) … … 328 646 global $db; 329 647 330 $result = $db->query('SELECT COUNT(id), SUM(num_replies) FROM '.$db->prefix.'topics WHERE moved_to IS NULL AND forum_id='.$forum_id) or error('Impossible de retrouver le total de discussions du forum', __FILE__, __LINE__, $db->error());648 $result = $db->query('SELECT COUNT(id), SUM(num_replies) FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id) or error('Unable to fetch forum topic count', __FILE__, __LINE__, $db->error()); 331 649 list($num_topics, $num_posts) = $db->fetch_row($result); 332 650 333 $num_posts = $num_posts + $num_topics; 334 335 $result = $db->query('SELECT last_post, last_post_id, last_poster FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id.' AND moved_to IS NULL ORDER BY last_post DESC LIMIT 1') or error(' Impossible de retrouverlast_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());336 if ($db->num_rows($result)) 651 $num_posts = $num_posts + $num_topics; // $num_posts is only the sum of all replies (we have to add the topic posts) 652 653 $result = $db->query('SELECT last_post, last_post_id, last_poster FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id.' AND moved_to IS NULL ORDER BY last_post DESC LIMIT 1') or error('Unable to fetch last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); 654 if ($db->num_rows($result)) // There are topics in the forum 337 655 { 338 656 list($last_post, $last_post_id, $last_poster) = $db->fetch_row($result); 339 657 340 $db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\' WHERE id='.$forum_id) or error('Impossible de mettre à jour last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); 341 } 342 else // There are no topics 343 $db->query('UPDATE '.$db->prefix.'forums SET num_topics=0, num_posts=0, last_post=NULL, last_post_id=NULL, last_poster=NULL WHERE id='.$forum_id) or error('Impossible de mettre à jour last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); 658 $db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); 659 } 660 else // There are no topics 661 $db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', last_post=NULL, last_post_id=NULL, last_poster=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); 662 } 663 664 665 // 666 // Deletes any avatars owned by the specified user ID 667 // 668 function delete_avatar($user_id) 669 { 670 global $pun_config; 671 672 $filetypes = array('jpg', 'gif', 'png'); 673 674 // Delete user avatar 675 foreach ($filetypes as $cur_type) 676 { 677 if (file_exists(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type)) 678 @unlink(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type); 679 } 344 680 } 345 681 … … 353 689 354 690 // Delete the topic and any redirect topics 355 $db->query('DELETE FROM '.$db->prefix.'topics WHERE id='.$topic_id.' OR moved_to='.$topic_id) or error(' Impossible de supprimer le sujet', __FILE__, __LINE__, $db->error());356 357 // Create a list of the post ID 's in this topic691 $db->query('DELETE FROM '.$db->prefix.'topics WHERE id='.$topic_id.' OR moved_to='.$topic_id) or error('Unable to delete topic', __FILE__, __LINE__, $db->error()); 692 693 // Create a list of the post IDs in this topic 358 694 $post_ids = ''; 359 $result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error(' Impossible de retrouver les messages', __FILE__, __LINE__, $db->error());695 $result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error()); 360 696 while ($row = $db->fetch_row($result)) 361 697 $post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0]; 362 698 363 // Make sure we have a list of post ID 's699 // Make sure we have a list of post IDs 364 700 if ($post_ids != '') 365 701 { … … 367 703 368 704 // Delete posts in topic 369 $db->query('DELETE FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error(' Impossible de supprimer les messages', __FILE__, __LINE__, $db->error());705 $db->query('DELETE FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to delete posts', __FILE__, __LINE__, $db->error()); 370 706 } 371 707 372 708 // Delete any subscriptions for this topic 373 $db->query('DELETE FROM '.$db->prefix.' subscriptions WHERE topic_id='.$topic_id) or error('Impossible de supprimer l\'abonnement', __FILE__, __LINE__, $db->error());709 $db->query('DELETE FROM '.$db->prefix.'topic_subscriptions WHERE topic_id='.$topic_id) or error('Unable to delete subscriptions', __FILE__, __LINE__, $db->error()); 374 710 } 375 711 … … 382 718 global $db; 383 719 384 $result = $db->query('SELECT id, poster, posted FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id.' ORDER BY id DESC LIMIT 2') or error(' Impossible de retrouver les informations du message', __FILE__, __LINE__, $db->error());720 $result = $db->query('SELECT id, poster, posted FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id.' ORDER BY id DESC LIMIT 2') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error()); 385 721 list($last_id, ,) = $db->fetch_row($result); 386 722 list($second_last_id, $second_poster, $second_posted) = $db->fetch_row($result); 387 723 388 724 // Delete the post 389 $db->query('DELETE FROM '.$db->prefix.'posts WHERE id='.$post_id) or error(' Impossible de supprimer le message', __FILE__, __LINE__, $db->error());725 $db->query('DELETE FROM '.$db->prefix.'posts WHERE id='.$post_id) or error('Unable to delete post', __FILE__, __LINE__, $db->error()); 390 726 391 727 strip_search_index($post_id); 392 728 393 729 // Count number of replies in the topic 394 $result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error(' Impossible de retrouver le total de messages pour la discussion', __FILE__, __LINE__, $db->error());730 $result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch post count for topic', __FILE__, __LINE__, $db->error()); 395 731 $num_replies = $db->result($result, 0) - 1; 396 732 … … 400 736 // If there is a $second_last_id there is more than 1 reply to the topic 401 737 if (!empty($second_last_id)) 402 $db->query('UPDATE '.$db->prefix.'topics SET last_post='.$second_posted.', last_post_id='.$second_last_id.', last_poster=\''.$db->escape($second_poster).'\', num_replies='.$num_replies.' WHERE id='.$topic_id) or error(' Impossible de mettre à jour la discussion', __FILE__, __LINE__, $db->error());738 $db->query('UPDATE '.$db->prefix.'topics SET last_post='.$second_posted.', last_post_id='.$second_last_id.', last_poster=\''.$db->escape($second_poster).'\', num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Unable to update topic', __FILE__, __LINE__, $db->error()); 403 739 else 404 740 // We deleted the only reply, so now last_post/last_post_id/last_poster is posted/id/poster from the topic itself 405 $db->query('UPDATE '.$db->prefix.'topics SET last_post=posted, last_post_id=id, last_poster=poster, num_replies='.$num_replies.' WHERE id='.$topic_id) or error(' Impossible de mettre à jour la discussion', __FILE__, __LINE__, $db->error());741 $db->query('UPDATE '.$db->prefix.'topics SET last_post=posted, last_post_id=id, last_poster=poster, num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Unable to update topic', __FILE__, __LINE__, $db->error()); 406 742 } 407 743 else 408 744 // Otherwise we just decrement the reply counter 409 $db->query('UPDATE '.$db->prefix.'topics SET num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Impossible de mettre à jour la discussion', __FILE__, __LINE__, $db->error()); 745 $db->query('UPDATE '.$db->prefix.'topics SET num_replies='.$num_replies.' WHERE id='.$topic_id) or error('Unable to update topic', __FILE__, __LINE__, $db->error()); 746 } 747 748 749 // 750 // Delete every .php file in the forum's cache directory 751 // 752 function forum_clear_cache() 753 { 754 $d = dir(FORUM_CACHE_DIR); 755 while (($entry = $d->read()) !== false) 756 { 757 if (substr($entry, -4) == '.php') 758 @unlink(FORUM_CACHE_DIR.$entry); 759 } 760 $d->close(); 410 761 } 411 762 … … 422 773 if (!isset($search_for)) 423 774 { 424 $result = $db->query('SELECT search_for, replace_with FROM '.$db->prefix.'censoring') or error('Impossible de retrouver la liste des mots à censurer', __FILE__, __LINE__, $db->error()); 425 $num_words = $db->num_rows($result); 426 427 $search_for = array(); 428 for ($i = 0; $i < $num_words; ++$i) 429 { 430 list($search_for[$i], $replace_with[$i]) = $db->fetch_row($result); 431 $search_for[$i] = '/\b('.str_replace('\*', '\w*?', preg_quote($search_for[$i], '/')).')\b/i'; 775 if (file_exists(FORUM_CACHE_DIR.'cache_censoring.php')) 776 include FORUM_CACHE_DIR.'cache_censoring.php'; 777 778 if (!defined('PUN_CENSOR_LOADED')) 779 { 780 if (!defined('FORUM_CACHE_FUNCTIONS_LOADED')) 781 require PUN_ROOT.'include/cache.php'; 782 783 generate_censoring_cache(); 784 require FORUM_CACHE_DIR.'cache_censoring.php'; 432 785 } 433 786 } 434 787 435 788 if (!empty($search_for)) 436 $text = substr( preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1);789 $text = substr(ucp_preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1); 437 790 438 791 return $text; … … 459 812 460 813 // If not already loaded in a previous call, load the cached ranks 461 if ($pun_config['o_ranks'] == '1' && empty($pun_ranks)) 462 { 463 @include PUN_ROOT.'cache/cache_ranks.php'; 814 if ($pun_config['o_ranks'] == '1' && !defined('PUN_RANKS_LOADED')) 815 { 816 if (file_exists(FORUM_CACHE_DIR.'cache_ranks.php')) 817 include FORUM_CACHE_DIR.'cache_ranks.php'; 818 464 819 if (!defined('PUN_RANKS_LOADED')) 465 820 { 466 require_once PUN_ROOT.'include/cache.php'; 821 if (!defined('FORUM_CACHE_FUNCTIONS_LOADED')) 822 require PUN_ROOT.'include/cache.php'; 823 467 824 generate_ranks_cache(); 468 require PUN_ROOT.'cache/cache_ranks.php';825 require FORUM_CACHE_DIR.'cache_ranks.php'; 469 826 } 470 827 } … … 487 844 if ($pun_config['o_ranks'] == '1' && !empty($pun_ranks)) 488 845 { 489 @reset($pun_ranks); 490 while (list(, $cur_rank) = @each($pun_ranks)) 846 foreach ($pun_ranks as $cur_rank) 491 847 { 492 if ( intval($user['num_posts'])>= $cur_rank['min_posts'])848 if ($user['num_posts'] >= $cur_rank['min_posts']) 493 849 $user_title = pun_htmlspecialchars($cur_rank['rank']); 494 850 } … … 507 863 // Generate a string with numbered links (for multipage scripts) 508 864 // 509 function paginate($num_pages, $cur_page, $link_to) 510 { 865 function paginate($num_pages, $cur_page, $link) 866 { 867 global $lang_common; 868 511 869 $pages = array(); 512 870 $link_to_all = false; … … 520 878 521 879 if ($num_pages <= 1) 522 $pages = array('<strong >1</strong>');880 $pages = array('<strong class="item1">1</strong>'); 523 881 else 524 882 { 883 // Add a previous page link 884 if ($num_pages > 1 && $cur_page > 1) 885 $pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.($cur_page - 1).'">'.$lang_common['Previous'].'</a>'; 886 525 887 if ($cur_page > 3) 526 888 { 527 $pages[] = '<a href="'.$link_to.'&p=1">1</a>';528 529 if ($cur_page != 4)530 $pages[] = ' …';889 $pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p=1">1</a>'; 890 891 if ($cur_page > 5) 892 $pages[] = '<span class="spacer">'.$lang_common['Spacer'].'</span>'; 531 893 } 532 894 533 895 // Don't ask me how the following works. It just does, OK? :-) 534 for ($current = $cur_page - 2, $stop =$cur_page + 3; $current < $stop; ++$current)896 for ($current = ($cur_page == 5) ? $cur_page - 3 : $cur_page - 2, $stop = ($cur_page + 4 == $num_pages) ? $cur_page + 4 : $cur_page + 3; $current < $stop; ++$current) 535 897 { 536 898 if ($current < 1 || $current > $num_pages) 537 899 continue; 538 900 else if ($current != $cur_page || $link_to_all) 539 $pages[] = '<a href="'.$link_to.'&p='.$current.'">'.$current.'</a>';901 $pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.$current.'">'.forum_number_format($current).'</a>'; 540 902 else 541 $pages[] = '<strong >'.$current.'</strong>';903 $pages[] = '<strong'.(empty($pages) ? ' class="item1"' : '').'>'.forum_number_format($current).'</strong>'; 542 904 } 543 905 544 906 if ($cur_page <= ($num_pages-3)) 545 907 { 546 if ($cur_page != ($num_pages-3)) 547 $pages[] = '…'; 548 549 $pages[] = '<a href="'.$link_to.'&p='.$num_pages.'">'.$num_pages.'</a>'; 550 } 551 } 552 553 return implode(' ', $pages); 908 if ($cur_page != ($num_pages-3) && $cur_page != ($num_pages-4)) 909 $pages[] = '<span class="spacer">'.$lang_common['Spacer'].'</span>'; 910 911 $pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.$num_pages.'">'.forum_number_format($num_pages).'</a>'; 912 } 913 914 // Add a next page link 915 if ($num_pages > 1 && !$link_to_all && $cur_page < $num_pages) 916 $pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.($cur_page +1).'">'.$lang_common['Next'].'</a>'; 917 } 918 919 return implode(' ', $pages); 554 920 } 555 921 … … 560 926 function message($message, $no_back_link = false) 561 927 { 562 563 global $db, $lang_common, $pun_config, $pun_start, $tpl_main, $env; 928 global $db, $lang_common, $pun_config, $pun_start, $tpl_main, $pun_user; 564 929 565 930 if (!defined('PUN_HEADER')) 566 931 { 567 global $pun_user; 568 569 $page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Info']; 932 $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Info']); 933 define('PUN_ACTIVE_PAGE', 'index'); 570 934 require PUN_ROOT.'header.php'; 571 935 } … … 577 941 <div class="box"> 578 942 <div class="inbox"> 579 <p><?php echo $message ?></p>580 <?php if (!$no_back_link): ?> <p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>943 <p><?php echo $message ?></p> 944 <?php if (!$no_back_link): ?> <p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p> 581 945 <?php endif; ?> </div> 582 946 </div> … … 589 953 590 954 // 591 // Format a time string according to $time_format and time zones592 // 593 function format_time($timestamp, $date_only = false )594 { 595 global $pun_config, $lang_common, $pun_user ;955 // Format a time string according to $time_format and time zones 956 // 957 function format_time($timestamp, $date_only = false, $date_format = null, $time_format = null, $time_only = false, $no_text = false) 958 { 959 global $pun_config, $lang_common, $pun_user, $forum_date_formats, $forum_time_formats; 596 960 597 961 if ($timestamp == '') 598 962 return $lang_common['Never']; 599 963 600 $diff = ($pun_user['timezone'] - $pun_config['o_server_timezone']) * 3600;964 $diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600; 601 965 $timestamp += $diff; 602 966 $now = time(); 603 967 604 $date = date($pun_config['o_date_format'], $timestamp); 605 $today = date($pun_config['o_date_format'], $now+$diff); 606 $yesterday = date($pun_config['o_date_format'], $now+$diff-86400); 607 608 if ($date == $today) 609 $date = $lang_common['Today']; 610 else if ($date == $yesterday) 611 $date = $lang_common['Yesterday']; 612 613 if (!$date_only) 614 return $date.' '.date($pun_config['o_time_format'], $timestamp); 968 if($date_format == null) 969 $date_format = $forum_date_formats[$pun_user['date_format']]; 970 971 if($time_format == null) 972 $time_format = $forum_time_formats[$pun_user['time_format']]; 973 974 $date = gmdate($date_format, $timestamp); 975 $today = gmdate($date_format, $now+$diff); 976 $yesterday = gmdate($date_format, $now+$diff-86400); 977 978 if(!$no_text) 979 { 980 if ($date == $today) 981 $date = $lang_common['Today']; 982 else if ($date == $yesterday) 983 $date = $lang_common['Yesterday']; 984 } 985 986 if ($date_only) 987 return $date; 988 else if ($time_only) 989 return gmdate($time_format, $timestamp); 615 990 else 616 return $date; 617 } 618 619 620 // 621 // If we are running pre PHP 4.3.0, we add our own implementation of file_get_contents 622 // 623 if (!function_exists('file_get_contents')) 624 { 625 function file_get_contents($filename, $use_include_path = 0) 626 { 627 $data = ''; 628 629 if ($fh = fopen($filename, 'rb', $use_include_path)) 630 { 631 $data = fread($fh, filesize($filename)); 632 fclose($fh); 633 } 634 635 return $data; 636 } 637 } 638 639 640 // 641 // Make sure that HTTP_REFERER matches $pun_config['o_base_url']/$script 642 // 643 function confirm_referrer($script) 991 return $date.' '.gmdate($time_format, $timestamp); 992 } 993 994 995 // 996 // A wrapper for PHP's number_format function 997 // 998 function forum_number_format($number, $decimals = 0) 999 { 1000 global $lang_common; 1001 1002 return is_numeric($number) ? number_format($number, $decimals, $lang_common['lang_decimal_point'], $lang_common['lang_thousands_sep']) : $number; 1003 } 1004 1005 1006 // 1007 // Generate a random key of length $len 1008 // 1009 function random_key($len, $readable = false, $hash = false) 1010 { 1011 $key = ''; 1012 1013 if ($hash) 1014 $key = substr(pun_hash(uniqid(rand(), true)), 0, $len); 1015 else if ($readable) 1016 { 1017 $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 1018 1019 for ($i = 0; $i < $len; ++$i) 1020 $key .= substr($chars, (mt_rand() % strlen($chars)), 1); 1021 } 1022 else 1023 { 1024 for ($i = 0; $i < $len; ++$i) 1025 $key .= chr(mt_rand(33, 126)); 1026 } 1027 1028 return $key; 1029 } 1030 1031 1032 // 1033 // Make sure that HTTP_REFERER matches base_url/script 1034 // 1035 function confirm_referrer($script, $error_msg = false) 644 1036 { 645 1037 global $pun_config, $lang_common; 646 1038 647 if (!preg_match('#^'.preg_quote(str_replace('www.', '', $pun_config['o_base_url']).'/'.$script, '#').'#i', str_replace('www.', '', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')))) 648 message($lang_common['Bad referrer']); 1039 // There is no referrer 1040 if (empty($_SERVER['HTTP_REFERER'])) 1041 message($error_msg ? $error_msg : $lang_common['Bad referrer']); 1042 1043 $referrer = parse_url(strtolower($_SERVER['HTTP_REFERER'])); 1044 // Remove www subdomain if it exists 1045 if (strpos($referrer['host'], 'www.') === 0) 1046 $referrer['host'] = substr($referrer['host'], 4); 1047 1048 $valid = parse_url(strtolower(get_base_url().'/'.$script)); 1049 // Remove www subdomain if it exists 1050 if (strpos($valid['host'], 'www.') === 0) 1051 $valid['host'] = substr($valid['host'], 4); 1052 1053 // Check the host and path match. Ignore the scheme, port, etc. 1054 if ($referrer['host'] != $valid['host'] || $referrer['path'] != $valid['path']) 1055 message($error_msg ? $error_msg : $lang_common['Bad referrer']); 649 1056 } 650 1057 … … 652 1059 // 653 1060 // Generate a random password of length $len 1061 // Compatibility wrapper for random_key 654 1062 // 655 1063 function random_pass($len) 656 1064 { 657 $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 658 659 $password = ''; 660 for ($i = 0; $i < $len; ++$i) 661 $password .= substr($chars, (mt_rand() % strlen($chars)), 1); 662 663 return $password; 1065 return random_key($len, true); 664 1066 } 665 1067 … … 667 1069 // 668 1070 // Compute a hash of $str 669 // Uses sha1() if available. If not, SHA1 through mhash() if available. If not, fall back on md5().670 1071 // 671 1072 function pun_hash($str) 672 1073 { 673 if (function_exists('sha1')) // Only in PHP 4.3.0+ 674 return sha1($str); 675 else if (function_exists('mhash')) // Only if Mhash library is loaded 676 return bin2hex(mhash(MHASH_SHA1, $str)); 677 else 678 return md5($str); 1074 return sha1($str); 679 1075 } 680 1076 … … 685 1081 function get_remote_address() 686 1082 { 687 return $_SERVER['REMOTE_ADDR']; 688 } 689 690 691 // 692 // Equivalent to htmlspecialchars(), but allows &#[0-9]+ (for unicode) 1083 $remote_addr = $_SERVER['REMOTE_ADDR']; 1084 1085 // If we are behind a reverse proxy try to find the real users IP 1086 if (defined('FORUM_BEHIND_REVERSE_PROXY')) 1087 { 1088 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) 1089 { 1090 // The general format of the field is: 1091 // X-Forwarded-For: client1, proxy1, proxy2 1092 // where the value is a comma+space separated list of IP addresses, the left-most being the farthest downstream client, 1093 // and each successive proxy that passed the request adding the IP address where it received the request from. 1094 $forwarded_for = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); 1095 $forwarded_for = trim($forwarded_for[0]); 1096 1097 if (@preg_match('%^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$%', $forwarded_for) || @preg_match('%^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$%', $forwarded_for)) 1098 $remote_addr = $forwarded_for; 1099 } 1100 } 1101 1102 return $remote_addr; 1103 } 1104 1105 1106 // 1107 // Calls htmlspecialchars with a few options already set 693 1108 // 694 1109 function pun_htmlspecialchars($str) 695 1110 { 696 $str = preg_replace('/&(?!#[0-9]+;)/s', '&', $str); 697 $str = str_replace(array('<', '>', '"'), array('<', '>', '"'), $str); 698 699 return $str; 700 } 701 702 703 // 704 // Equivalent to strlen(), but counts &#[0-9]+ as one character (for unicode) 1111 return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); 1112 } 1113 1114 1115 // 1116 // Calls htmlspecialchars_decode with a few options already set 1117 // 1118 function pun_htmlspecialchars_decode($str) 1119 { 1120 if (function_exists('htmlspecialchars_decode')) 1121 return htmlspecialchars_decode($str, ENT_QUOTES); 1122 1123 static $translations; 1124 if (!isset($translations)) 1125 { 1126 $translations = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES); 1127 $translations['''] = '\''; // get_html_translation_table doesn't include ' which is what htmlspecialchars translates ' to, but apparently that is okay?! http://bugs.php.net/bug.php?id=25927 1128 $translations = array_flip($translations); 1129 } 1130 1131 return strtr($str, $translations); 1132 } 1133 1134 1135 // 1136 // A wrapper for utf8_strlen for compatibility 705 1137 // 706 1138 function pun_strlen($str) 707 1139 { 708 return strlen(preg_replace('/&#([0-9]+);/', '!', $str));1140 return utf8_strlen($str); 709 1141 } 710 1142 … … 720 1152 721 1153 // 722 // A more aggressive version of trim() 723 // 724 function pun_trim($str) 725 { 726 global $lang_common; 727 728 if (strpos($lang_common['lang_encoding'], '8859') !== false) 729 { 730 $fishy_chars = array(chr(0x81), chr(0x8D), chr(0x8F), chr(0x90), chr(0x9D), chr(0xA0)); 731 return trim(str_replace($fishy_chars, ' ', $str)); 732 } 733 else 734 return trim($str); 1154 // A wrapper for utf8_trim for compatibility 1155 // 1156 function pun_trim($str, $charlist = false) 1157 { 1158 return utf8_trim($str, $charlist); 1159 } 1160 1161 // 1162 // Checks if a string is in all uppercase 1163 // 1164 function is_all_uppercase($string) 1165 { 1166 return utf8_strtoupper($string) == $string && utf8_strtolower($string) != $string; 1167 } 1168 1169 1170 // 1171 // Inserts $element into $input at $offset 1172 // $offset can be either a numerical offset to insert at (eg: 0 inserts at the beginning of the array) 1173 // or a string, which is the key that the new element should be inserted before 1174 // $key is optional: it's used when inserting a new key/value pair into an associative array 1175 // 1176 function array_insert(&$input, $offset, $element, $key = null) 1177 { 1178 if ($key == null) 1179 $key = $offset; 1180 1181 // Determine the proper offset if we're using a string 1182 if (!is_int($offset)) 1183 $offset = array_search($offset, array_keys($input), true); 1184 1185 // Out of bounds checks 1186 if ($offset > count($input)) 1187 $offset = count($input); 1188 else if ($offset < 0) 1189 $offset = 0; 1190 1191 $input = array_merge(array_slice($input, 0, $offset), array($key => $element), array_slice($input, $offset)); 735 1192 } 736 1193 … … 742 1199 { 743 1200 global $db, $pun_config, $lang_common, $pun_user; 1201 1202 // Send no-cache headers 1203 header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :) 1204 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); 1205 header('Cache-Control: post-check=0, pre-check=0', false); 1206 header('Pragma: no-cache'); // For HTTP/1.0 compatibility 1207 1208 // Send the Content-type header in case the web server is setup to send something else 1209 header('Content-type: text/html; charset=utf-8'); 744 1210 745 1211 // Deal with newlines, tabs and multiple spaces … … 748 1214 $message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']); 749 1215 750 751 // Load the maintenance template 752 $tpl_maint = trim(file_get_contents(PUN_ROOT.'include/template/maintenance.tpl')); 1216 if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl')) 1217 { 1218 $tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl'; 1219 $tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/'; 1220 } 1221 else 1222 { 1223 $tpl_file = PUN_ROOT.'include/template/maintenance.tpl'; 1224 $tpl_inc_dir = PUN_ROOT.'include/user/'; 1225 } 1226 1227 $tpl_maint = file_get_contents($tpl_file); 1228 1229 // START SUBST - <pun_include "*"> 1230 preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_maint, $pun_includes, PREG_SET_ORDER); 1231 1232 foreach ($pun_includes as $cur_include) 1233 { 1234 ob_start(); 1235 1236 // Allow for overriding user includes, too. 1237 if (file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2])) 1238 require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]; 1239 else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2])) 1240 require PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]; 1241 else 1242 error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file))); 1243 1244 $tpl_temp = ob_get_contents(); 1245 $tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint); 1246 ob_end_clean(); 1247 } 1248 // END SUBST - <pun_include "*"> 1249 1250 1251 // START SUBST - <pun_language> 1252 $tpl_maint = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_maint); 1253 // END SUBST - <pun_language> 753 1254 754 1255 … … 758 1259 759 1260 760 // START SUBST - <pun_char_encoding>761 $tpl_maint = str_replace('<pun_char_encoding>', $lang_common['lang_encoding'], $tpl_maint);762 // END SUBST - <pun_char_encoding>763 764 765 1261 // START SUBST - <pun_head> 766 1262 ob_start(); 767 1263 1264 $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Maintenance']); 1265 768 1266 ?> 769 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Maintenance']?></title>1267 <title><?php echo generate_page_title($page_title) ?></title> 770 1268 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" /> 771 1269 <?php … … 777 1275 778 1276 779 // START SUBST - <pun_maint_heading> 780 $tpl_maint = str_replace('<pun_maint_heading>', $lang_common['Maintenance'], $tpl_maint); 781 // END SUBST - <pun_maint_heading> 782 783 784 // START SUBST - <pun_maint_message> 785 $tpl_maint = str_replace('<pun_maint_message>', $message, $tpl_maint); 786 // END SUBST - <pun_maint_message> 1277 // START SUBST - <pun_maint_main> 1278 ob_start(); 1279 1280 ?> 1281 <div class="block"> 1282 <h2><?php echo $lang_common['Maintenance'] ?></h2> 1283 <div class="box"> 1284 <div class="inbox"> 1285 <p><?php echo $message ?></p> 1286 </div> 1287 </div> 1288 </div> 1289 <?php 1290 1291 $tpl_temp = trim(ob_get_contents()); 1292 $tpl_maint = str_replace('<pun_maint_main>', $tpl_temp, $tpl_maint); 1293 ob_end_clean(); 1294 // END SUBST - <pun_maint_main> 787 1295 788 1296 … … 791 1299 792 1300 793 // START SUBST - <pun_include "*">794 while (preg_match('#<pun_include "([^/\\\\]*?)">#', $tpl_maint, $cur_include))795 {796 if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))797 error('Impossible de procéder à l\'inclusion utilisateur <pun_include "'.htmlspecialchars($cur_include[1]).'"> depuis le template main.tpl. Il n\'y a pas de fichier dans le répertoire /include/user/');798 799 ob_start();800 include PUN_ROOT.'include/user/'.$cur_include[1];801 $tpl_temp = ob_get_contents();802 $tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);803 ob_end_clean();804 }805 // END SUBST - <pun_include "*">806 807 808 1301 // Close the db connection (and free up any result data) 809 1302 $db->close(); … … 820 1313 global $db, $pun_config, $lang_common, $pun_user; 821 1314 822 if ($destination_url == '') 823 $destination_url = 'index.php'; 1315 // Prefix with base_url (unless there's already a valid URI) 1316 if (strpos($destination_url, 'http://') !== 0 && strpos($destination_url, 'https://') !== 0 && strpos($destination_url, '/') !== 0) 1317 $destination_url = get_base_url(true).'/'.$destination_url; 1318 1319 // Do a little spring cleaning 1320 $destination_url = preg_replace('%([\r\n])|(\%0[ad])|(;\s*data\s*:)%i', '', $destination_url); 824 1321 825 1322 // If the delay is 0 seconds, we might as well skip the redirect all together … … 827 1324 header('Location: '.str_replace('&', '&', $destination_url)); 828 1325 829 830 // Load the redirect template 831 $tpl_redir = trim(file_get_contents(PUN_ROOT.'include/template/redirect.tpl')); 1326 // Send no-cache headers 1327 header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :) 1328 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); 1329 header('Cache-Control: post-check=0, pre-check=0', false); 1330 header('Pragma: no-cache'); // For HTTP/1.0 compatibility 1331 1332 // Send the Content-type header in case the web server is setup to send something else 1333 header('Content-type: text/html; charset=utf-8'); 1334 1335 if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl')) 1336 { 1337 $tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl'; 1338 $tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/'; 1339 } 1340 else 1341 { 1342 $tpl_file = PUN_ROOT.'include/template/redirect.tpl'; 1343 $tpl_inc_dir = PUN_ROOT.'include/user/'; 1344 } 1345 1346 $tpl_redir = file_get_contents($tpl_file); 1347 1348 // START SUBST - <pun_include "*"> 1349 preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_redir, $pun_includes, PREG_SET_ORDER); 1350 1351 foreach ($pun_includes as $cur_include) 1352 { 1353 ob_start(); 1354 1355 // Allow for overriding user includes, too. 1356 if (file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2])) 1357 require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]; 1358 else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2])) 1359 require PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]; 1360 else 1361 error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file))); 1362 1363 $tpl_temp = ob_get_contents(); 1364 $tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir); 1365 ob_end_clean(); 1366 } 1367 // END SUBST - <pun_include "*"> 1368 1369 1370 // START SUBST - <pun_language> 1371 $tpl_redir = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_redir); 1372 // END SUBST - <pun_language> 832 1373 833 1374 … … 837 1378 838 1379 839 // START SUBST - <pun_char_encoding>840 $tpl_redir = str_replace('<pun_char_encoding>', $lang_common['lang_encoding'], $tpl_redir);841 // END SUBST - <pun_char_encoding>842 843 844 1380 // START SUBST - <pun_head> 845 1381 ob_start(); 846 1382 1383 $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Redirecting']); 1384 847 1385 ?> 848 1386 <meta http-equiv="refresh" content="<?php echo $pun_config['o_redirect_delay'] ?>;URL=<?php echo str_replace(array('<', '>', '"'), array('<', '>', '"'), $destination_url) ?>" /> 849 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Redirecting']?></title>1387 <title><?php echo generate_page_title($page_title) ?></title> 850 1388 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" /> 851 1389 <?php … … 857 1395 858 1396 859 // START SUBST - <pun_redir_heading> 860 $tpl_redir = str_replace('<pun_redir_heading>', $lang_common['Redirecting'], $tpl_redir); 861 // END SUBST - <pun_redir_heading> 862 863 864 // START SUBST - <pun_redir_text> 865 $tpl_temp = $message.'<br /><br />'.'<a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>'; 866 $tpl_redir = str_replace('<pun_redir_text>', $tpl_temp, $tpl_redir); 867 // END SUBST - <pun_redir_text> 1397 // START SUBST - <pun_redir_main> 1398 ob_start(); 1399 1400 ?> 1401 <div class="block"> 1402 <h2><?php echo $lang_common['Redirecting'] ?></h2> 1403 <div class="box"> 1404 <div class="inbox"> 1405 <p><?php echo $message.'<br /><br /><a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>' ?></p> 1406 </div> 1407 </div> 1408 </div> 1409 <?php 1410 1411 $tpl_temp = trim(ob_get_contents()); 1412 $tpl_redir = str_replace('<pun_redir_main>', $tpl_temp, $tpl_redir); 1413 ob_end_clean(); 1414 // END SUBST - <pun_redir_main> 868 1415 869 1416 … … 884 1431 885 1432 886 // START SUBST - <pun_include "*">887 while (preg_match('<pun_include "(.*?)">', $tpl_redir, $cur_include))888 {889 ob_start();890 include PUN_ROOT.$cur_include[1];891 $tpl_temp = ob_get_contents();892 $tpl_redir = str_replace('<'.$cur_include[0].'>', $tpl_temp, $tpl_redir);893 ob_end_clean();894 }895 // END SUBST - <pun_include "*">896 897 898 1433 // Close the db connection (and free up any result data) 899 1434 $db->close(); … … 906 1441 // Display a simple error message 907 1442 // 908 function error($message, $file , $line, $db_error = false)909 { 910 global $pun_config ;911 912 // Set a default titleif the script failed before $pun_config could be populated1443 function error($message, $file = null, $line = null, $db_error = false) 1444 { 1445 global $pun_config, $lang_common; 1446 1447 // Set some default settings if the script failed before $pun_config could be populated 913 1448 if (empty($pun_config)) 914 $pun_config['o_board_title'] = 'PunBB'; 915 916 // Empty output buffer and stop buffering 917 @ob_end_clean(); 1449 { 1450 $pun_config = array( 1451 'o_board_title' => 'FluxBB', 1452 'o_gzip' => '0' 1453 ); 1454 } 1455 1456 // Set some default translations if the script failed before $lang_common could be populated 1457 if (empty($lang_common)) 1458 { 1459 $lang_common = array( 1460 'Title separator' => ' / ', 1461 'Page' => 'Page %s' 1462 ); 1463 } 1464 1465 // Empty all output buffers and stop buffering 1466 while (@ob_end_clean()); 918 1467 919 1468 // "Restart" output buffering if we are using ob_gzhandler (since the gzip header is already sent) 920 if ( !empty($pun_config['o_gzip']) && extension_loaded('zlib') && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== false))1469 if ($pun_config['o_gzip'] && extension_loaded('zlib')) 921 1470 ob_start('ob_gzhandler'); 1471 1472 // Send no-cache headers 1473 header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :) 1474 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); 1475 header('Cache-Control: post-check=0, pre-check=0', false); 1476 header('Pragma: no-cache'); // For HTTP/1.0 compatibility 1477 1478 // Send the Content-type header in case the web server is setup to send something else 1479 header('Content-type: text/html; charset=utf-8'); 922 1480 923 1481 ?> 924 1482 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 925 <html dir="ltr">1483 <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr"> 926 1484 <head> 927 <meta http-equiv="Content-Type" content="text/html; charset=<?php echo $lang_common["lang_encoding"] ?>" /> 928 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?> / Error</title> 1485 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 1486 <?php $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), 'Error') ?> 1487 <title><?php echo generate_page_title($page_title) ?></title> 929 1488 <style type="text/css"> 930 1489 <!-- … … 939 1498 940 1499 <div id="errorbox"> 941 <h2> Une erreur s'est produite</h2>1500 <h2>An error was encountered</h2> 942 1501 <div> 943 1502 <?php 944 1503 945 if (defined('PUN_DEBUG') )946 { 947 echo "\t\t".'<strong>Fi chier :</strong> '.$file.'<br />'."\n\t\t".'<strong>Ligne :</strong> '.$line.'<br /><br />'."\n\t\t".'<strong>PunBB a rapporté :</strong>'.$message."\n";1504 if (defined('PUN_DEBUG') && $file !== null && $line !== null) 1505 { 1506 echo "\t\t".'<strong>File:</strong> '.$file.'<br />'."\n\t\t".'<strong>Line:</strong> '.$line.'<br /><br />'."\n\t\t".'<strong>FluxBB reported</strong>: '.$message."\n"; 948 1507 949 1508 if ($db_error) 950 1509 { 951 echo "\t\t".'<br /><br /><strong> La base de données a rapporté:</strong> '.pun_htmlspecialchars($db_error['error_msg']).(($db_error['error_no']) ? ' (Errno: '.$db_error['error_no'].')' : '')."\n";1510 echo "\t\t".'<br /><br /><strong>Database reported:</strong> '.pun_htmlspecialchars($db_error['error_msg']).(($db_error['error_no']) ? ' (Errno: '.$db_error['error_no'].')' : '')."\n"; 952 1511 953 1512 if ($db_error['error_sql'] != '') 954 echo "\t\t".'<br /><br /><strong> Requête échouée:</strong> '.pun_htmlspecialchars($db_error['error_sql'])."\n";1513 echo "\t\t".'<br /><br /><strong>Failed query:</strong> '.pun_htmlspecialchars($db_error['error_sql'])."\n"; 955 1514 } 956 1515 } 957 1516 else 958 echo "\t\t".'Err eur: <strong>'.$message.'.</strong>'."\n";1517 echo "\t\t".'Error: <strong>'.$message.'.</strong>'."\n"; 959 1518 960 1519 ?> … … 971 1530 972 1531 exit; 1532 } 1533 1534 1535 // 1536 // Unset any variables instantiated as a result of register_globals being enabled 1537 // 1538 function forum_unregister_globals() 1539 { 1540 $register_globals = ini_get('register_globals'); 1541 if ($register_globals === '' || $register_globals === '0' || strtolower($register_globals) === 'off') 1542 return; 1543 1544 // Prevent script.php?GLOBALS[foo]=bar 1545 if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) 1546 exit('I\'ll have a steak sandwich and... a steak sandwich.'); 1547 1548 // Variables that shouldn't be unset 1549 $no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'); 1550 1551 // Remove elements in $GLOBALS that are present in any of the superglobals 1552 $input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array()); 1553 foreach ($input as $k => $v) 1554 { 1555 if (!in_array($k, $no_unset) && isset($GLOBALS[$k])) 1556 { 1557 unset($GLOBALS[$k]); 1558 unset($GLOBALS[$k]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4 1559 } 1560 } 1561 } 1562 1563 1564 // 1565 // Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from user input 1566 // 1567 function forum_remove_bad_characters() 1568 { 1569 $_GET = remove_bad_characters($_GET); 1570 $_POST = remove_bad_characters($_POST); 1571 $_COOKIE = remove_bad_characters($_COOKIE); 1572 $_REQUEST = remove_bad_characters($_REQUEST); 1573 } 1574 1575 // 1576 // Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from the given string 1577 // See: http://kb.mozillazine.org/Network.IDN.blacklist_chars 1578 // 1579 function remove_bad_characters($array) 1580 { 1581 static $bad_utf8_chars; 1582 1583 if (!isset($bad_utf8_chars)) 1584 { 1585 $bad_utf8_chars = array( 1586 "\xcc\xb7" => '', // COMBINING SHORT SOLIDUS OVERLAY 0337 * 1587 "\xcc\xb8" => '', // COMBINING LONG SOLIDUS OVERLAY 0338 * 1588 "\xe1\x85\x9F" => '', // HANGUL CHOSEONG FILLER 115F * 1589 "\xe1\x85\xA0" => '', // HANGUL JUNGSEONG FILLER 1160 * 1590 "\xe2\x80\x8b" => '', // ZERO WIDTH SPACE 200B * 1591 "\xe2\x80\x8c" => '', // ZERO WIDTH NON-JOINER 200C 1592 "\xe2\x80\x8d" => '', // ZERO WIDTH JOINER 200D 1593 "\xe2\x80\x8e" => '', // LEFT-TO-RIGHT MARK 200E 1594 "\xe2\x80\x8f" => '', // RIGHT-TO-LEFT MARK 200F 1595 "\xe2\x80\xaa" => '', // LEFT-TO-RIGHT EMBEDDING 202A 1596 "\xe2\x80\xab" => '', // RIGHT-TO-LEFT EMBEDDING 202B 1597 "\xe2\x80\xac" => '', // POP DIRECTIONAL FORMATTING 202C 1598 "\xe2\x80\xad" => '', // LEFT-TO-RIGHT OVERRIDE 202D 1599 "\xe2\x80\xae" => '', // RIGHT-TO-LEFT OVERRIDE 202E 1600 "\xe2\x80\xaf" => '', // NARROW NO-BREAK SPACE 202F * 1601 "\xe2\x81\x9f" => '', // MEDIUM MATHEMATICAL SPACE 205F * 1602 "\xe2\x81\xa0" => '', // WORD JOINER 2060 1603 "\xe3\x85\xa4" => '', // HANGUL FILLER 3164 * 1604 "\xef\xbb\xbf" => '', // ZERO WIDTH NO-BREAK SPACE FEFF 1605 "\xef\xbe\xa0" => '', // HALFWIDTH HANGUL FILLER FFA0 * 1606 "\xef\xbf\xb9" => '', // INTERLINEAR ANNOTATION ANCHOR FFF9 * 1607 "\xef\xbf\xba" => '', // INTERLINEAR ANNOTATION SEPARATOR FFFA * 1608 "\xef\xbf\xbb" => '', // INTERLINEAR ANNOTATION TERMINATOR FFFB * 1609 "\xef\xbf\xbc" => '', // OBJECT REPLACEMENT CHARACTER FFFC * 1610 "\xef\xbf\xbd" => '', // REPLACEMENT CHARACTER FFFD * 1611 "\xe2\x80\x80" => ' ', // EN QUAD 2000 * 1612 "\xe2\x80\x81" => ' ', // EM QUAD 2001 * 1613 "\xe2\x80\x82" => ' ', // EN SPACE 2002 * 1614 "\xe2\x80\x83" => ' ', // EM SPACE 2003 * 1615 "\xe2\x80\x84" => ' ', // THREE-PER-EM SPACE 2004 * 1616 "\xe2\x80\x85" => ' ', // FOUR-PER-EM SPACE 2005 * 1617 "\xe2\x80\x86" => ' ', // SIX-PER-EM SPACE 2006 * 1618 "\xe2\x80\x87" => ' ', // FIGURE SPACE 2007 * 1619 "\xe2\x80\x88" => ' ', // PUNCTUATION SPACE 2008 * 1620 "\xe2\x80\x89" => ' ', // THIN SPACE 2009 * 1621 "\xe2\x80\x8a" => ' ', // HAIR SPACE 200A * 1622 "\xE3\x80\x80" => ' ', // IDEOGRAPHIC SPACE 3000 * 1623 ); 1624 } 1625 1626 if (is_array($array)) 1627 return array_map('remove_bad_characters', $array); 1628 1629 // Strip out any invalid characters 1630 $array = utf8_bad_strip($array); 1631 1632 // Remove control characters 1633 $array = preg_replace('%[\x{00}-\x{08}\x{0b}-\x{0c}\x{0e}-\x{1f}]%', '', $array); 1634 1635 // Replace some "bad" characters 1636 $array = str_replace(array_keys($bad_utf8_chars), array_values($bad_utf8_chars), $array); 1637 1638 return $array; 1639 } 1640 1641 1642 // 1643 // Converts the file size in bytes to a human readable file size 1644 // 1645 function file_size($size) 1646 { 1647 global $lang_common; 1648 1649 $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'); 1650 1651 for ($i = 0; $size > 1024; $i++) 1652 $size /= 1024; 1653 1654 return sprintf($lang_common['Size unit '.$units[$i]], round($size, 2));; 1655 } 1656 1657 1658 // 1659 // Fetch a list of available styles 1660 // 1661 function forum_list_styles() 1662 { 1663 $styles = array(); 1664 1665 $d = dir(PUN_ROOT.'style'); 1666 while (($entry = $d->read()) !== false) 1667 { 1668 if ($entry{0} == '.') 1669 continue; 1670 1671 if (substr($entry, -4) == '.css') 1672 $styles[] = substr($entry, 0, -4); 1673 } 1674 $d->close(); 1675 1676 natcasesort($styles); 1677 1678 return $styles; 1679 } 1680 1681 1682 // 1683 // Fetch a list of available language packs 1684 // 1685 function forum_list_langs() 1686 { 1687 $languages = array(); 1688 1689 $d = dir(PUN_ROOT.'lang'); 1690 while (($entry = $d->read()) !== false) 1691 { 1692 if ($entry{0} == '.') 1693 continue; 1694 1695 if (is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php')) 1696 $languages[] = $entry; 1697 } 1698 $d->close(); 1699 1700 natcasesort($languages); 1701 1702 return $languages; 1703 } 1704 1705 1706 // 1707 // Generate a cache ID based on the last modification time for all stopwords files 1708 // 1709 function generate_stopwords_cache_id() 1710 { 1711 $files = glob(PUN_ROOT.'lang/*/stopwords.txt'); 1712 if ($files === false) 1713 return 'cache_id_error'; 1714 1715 $hash = array(); 1716 1717 foreach ($files as $file) 1718 { 1719 $hash[] = $file; 1720 $hash[] = filemtime($file); 1721 } 1722 1723 return sha1(implode('|', $hash)); 1724 } 1725 1726 1727 // 1728 // Fetch a list of available admin plugins 1729 // 1730 function forum_list_plugins($is_admin) 1731 { 1732 $plugins = array(); 1733 1734 $d = dir(PUN_ROOT.'plugins'); 1735 while (($entry = $d->read()) !== false) 1736 { 1737 if ($entry{0} == '.') 1738 continue; 1739 1740 $prefix = substr($entry, 0, strpos($entry, '_')); 1741 $suffix = substr($entry, strlen($entry) - 4); 1742 1743 if ($suffix == '.php' && ((!$is_admin && $prefix == 'AMP') || ($is_admin && ($prefix == 'AP' || $prefix == 'AMP')))) 1744 $plugins[$entry] = substr($entry, strpos($entry, '_') + 1, -4); 1745 } 1746 $d->close(); 1747 1748 natcasesort($plugins); 1749 1750 return $plugins; 1751 } 1752 1753 1754 // 1755 // Split text into chunks ($inside contains all text inside $start and $end, and $outside contains all text outside) 1756 // 1757 function split_text($text, $start, $end, &$errors, $retab = true) 1758 { 1759 global $pun_config, $lang_common; 1760 1761 $result = array(0 => array(), 1 => array()); // 0 = inside, 1 = outside 1762 1763 // split the text into parts 1764 $parts = preg_split('%'.preg_quote($start, '%').'(.*)'.preg_quote($end, '%').'%Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE); 1765 $num_parts = count($parts); 1766 1767 // preg_split results in outside parts having even indices, inside parts having odd 1768 for ($i = 0;$i < $num_parts;$i++) 1769 $result[1 - ($i % 2)][] = $parts[$i]; 1770 1771 if ($pun_config['o_indent_num_spaces'] != 8 && $retab) 1772 { 1773 $spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']); 1774 $result[1] = str_replace("\t", $spaces, $result[1]); 1775 } 1776 1777 return $result; 1778 } 1779 1780 1781 // 1782 // Extract blocks from a text with a starting and ending string 1783 // This function always matches the most outer block so nesting is possible 1784 // 1785 function extract_blocks($text, $start, $end, &$errors = array(), $retab = true) 1786 { 1787 global $pun_config; 1788 1789 $code = array(); 1790 $start_len = strlen($start); 1791 $end_len = strlen($end); 1792 $regex = '%(?:'.preg_quote($start, '%').'|'.preg_quote($end, '%').')%'; 1793 $matches = array(); 1794 1795 if (preg_match_all($regex, $text, $matches)) 1796 { 1797 $counter = $offset = 0; 1798 $start_pos = $end_pos = false; 1799 1800 foreach ($matches[0] as $match) 1801 { 1802 if ($match == $start) 1803 { 1804 if ($counter == 0) 1805 $start_pos = strpos($text, $start); 1806 $counter++; 1807 } 1808 elseif ($match == $end) 1809 { 1810 $counter--; 1811 if ($counter == 0) 1812 $end_pos = strpos($text, $end, $offset + 1); 1813 $offset = strpos($text, $end, $offset + 1); 1814 } 1815 1816 if ($start_pos !== false && $end_pos !== false) 1817 { 1818 $code[] = substr($text, $start_pos + $start_len, 1819 $end_pos - $start_pos - $start_len); 1820 $text = substr_replace($text, "\1", $start_pos, 1821 $end_pos - $start_pos + $end_len); 1822 $start_pos = $end_pos = false; 1823 $offset = 0; 1824 } 1825 } 1826 } 1827 1828 if ($pun_config['o_indent_num_spaces'] != 8 && $retab) 1829 { 1830 $spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']); 1831 $text = str_replace("\t", $spaces, $text); 1832 } 1833 1834 return array($code, $text); 1835 } 1836 1837 1838 // 1839 // function url_valid($url) { 1840 // 1841 // Return associative array of valid URI components, or FALSE if $url is not 1842 // RFC-3986 compliant. If the passed URL begins with: "www." or "ftp.", then 1843 // "http://" or "ftp://" is prepended and the corrected full-url is stored in 1844 // the return array with a key name "url". This value should be used by the caller. 1845 // 1846 // Return value: FALSE if $url is not valid, otherwise array of URI components: 1847 // e.g. 1848 // Given: "http://www.jmrware.com:80/articles?height=10&width=75#fragone" 1849 // Array( 1850 // [scheme] => http 1851 // [authority] => www.jmrware.com:80 1852 // [userinfo] => 1853 // [host] => www.jmrware.com 1854 // [IP_literal] => 1855 // [IPV6address] => 1856 // [ls32] => 1857 // [IPvFuture] => 1858 // [IPv4address] => 1859 // [regname] => www.jmrware.com 1860 // [port] => 80 1861 // [path_abempty] => /articles 1862 // [query] => height=10&width=75 1863 // [fragment] => fragone 1864 // [url] => http://www.jmrware.com:80/articles?height=10&width=75#fragone 1865 // ) 1866 function url_valid($url) 1867 { 1868 if (strpos($url, 'www.') === 0) $url = 'http://'. $url; 1869 if (strpos($url, 'ftp.') === 0) $url = 'ftp://'. $url; 1870 if (!preg_match('/# Valid absolute URI having a non-empty, valid DNS host. 1871 ^ 1872 (?P<scheme>[A-Za-z][A-Za-z0-9+\-.]*):\/\/ 1873 (?P<authority> 1874 (?:(?P<userinfo>(?:[A-Za-z0-9\-._~!$&\'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)? 1875 (?P<host> 1876 (?P<IP_literal> 1877 \[ 1878 (?: 1879 (?P<IPV6address> 1880 (?: (?:[0-9A-Fa-f]{1,4}:){6} 1881 | ::(?:[0-9A-Fa-f]{1,4}:){5} 1882 | (?: [0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4} 1883 | (?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3} 1884 | (?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2} 1885 | (?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}: 1886 | (?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?:: 1887 ) 1888 (?P<ls32>[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4} 1889 | (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3} 1890 (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) 1891 ) 1892 | (?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4} 1893 | (?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?:: 1894 ) 1895 | (?P<IPvFuture>[Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&\'()*+,;=:]+) 1896 ) 1897 \] 1898 ) 1899 | (?P<IPv4address>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3} 1900 (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)) 1901 | (?P<regname>(?:[A-Za-z0-9\-._~!$&\'()*+,;=]|%[0-9A-Fa-f]{2})+) 1902 ) 1903 (?::(?P<port>[0-9]*))? 1904 ) 1905 (?P<path_abempty>(?:\/(?:[A-Za-z0-9\-._~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*) 1906 (?:\?(?P<query> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))? 1907 (?:\#(?P<fragment> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))? 1908 $ 1909 /mx', $url, $m)) return FALSE; 1910 switch ($m['scheme']) 1911 { 1912 case 'https': 1913 case 'http': 1914 if ($m['userinfo']) return FALSE; // HTTP scheme does not allow userinfo. 1915 break; 1916 case 'ftps': 1917 case 'ftp': 1918 break; 1919 default: 1920 return FALSE; // Unrecognised URI scheme. Default to FALSE. 1921 } 1922 // Validate host name conforms to DNS "dot-separated-parts". 1923 if ($m{'regname'}) // If host regname specified, check for DNS conformance. 1924 { 1925 if (!preg_match('/# HTTP DNS host name. 1926 ^ # Anchor to beginning of string. 1927 (?!.{256}) # Overall host length is less than 256 chars. 1928 (?: # Group dot separated host part alternatives. 1929 [0-9A-Za-z]\. # Either a single alphanum followed by dot 1930 | # or... part has more than one char (63 chars max). 1931 [0-9A-Za-z] # Part first char is alphanum (no dash). 1932 [\-0-9A-Za-z]{0,61} # Internal chars are alphanum plus dash. 1933 [0-9A-Za-z] # Part last char is alphanum (no dash). 1934 \. # Each part followed by literal dot. 1935 )* # One or more parts before top level domain. 1936 (?: # Explicitly specify top level domains. 1937 com|edu|gov|int|mil|net|org|biz| 1938 info|name|pro|aero|coop|museum| 1939 asia|cat|jobs|mobi|tel|travel| 1940 [A-Za-z]{2}) # Country codes are exqactly two alpha chars. 1941 $ # Anchor to end of string. 1942 /ix', $m['host'])) return FALSE; 1943 } 1944 $m['url'] = $url; 1945 for ($i = 0; isset($m[$i]); ++$i) unset($m[$i]); 1946 return $m; // return TRUE == array of useful named $matches plus the valid $url. 1947 } 1948 1949 // 1950 // Replace string matching regular expression 1951 // 1952 // This function takes care of possibly disabled unicode properties in PCRE builds 1953 // 1954 function ucp_preg_replace($pattern, $replace, $subject) 1955 { 1956 $replaced = preg_replace($pattern, $replace, $subject); 1957 1958 // If preg_replace() returns false, this probably means unicode support is not built-in, so we need to modify the pattern a little 1959 if ($replaced === false) 1960 { 1961 if (is_array($pattern)) 1962 { 1963 foreach ($pattern as $cur_key => $cur_pattern) 1964 $pattern[$cur_key] = str_replace('\p{L}\p{N}', '\w', $cur_pattern); 1965 1966 $replaced = preg_replace($pattern, $replace, $subject); 1967 } 1968 else 1969 $replaced = preg_replace(str_replace('\p{L}\p{N}', '\w', $pattern), $replace, $subject); 1970 } 1971 1972 return $replaced; 973 1973 } 974 1974 … … 994 1994 <thead> 995 1995 <tr> 996 <th class="tcl" scope="col"> Temps (s)</th>997 <th class="tcr" scope="col"> Requête</th>1996 <th class="tcl" scope="col"><?php echo $lang_common['Query times'] ?></th> 1997 <th class="tcr" scope="col"><?php echo $lang_common['Query'] ?></th> 998 1998 </tr> 999 1999 </thead> … … 1002 2002 1003 2003 $query_time_total = 0.0; 1004 while (list(, $cur_query) = @each($saved_queries))2004 foreach ($saved_queries as $cur_query) 1005 2005 { 1006 2006 $query_time_total += $cur_query[1]; … … 1017 2017 ?> 1018 2018 <tr> 1019 <td class="tcl" colspan="2"> Temps total requête : <?php echo $query_time_total ?> s</td>2019 <td class="tcl" colspan="2"><?php printf($lang_common['Total query time'], $query_time_total.' s') ?></td> 1020 2020 </tr> 1021 2021 </tbody> … … 1030 2030 1031 2031 // 1032 // Unset any variables instantiated as a result of register_globals being enabled1033 //1034 function unregister_globals()1035 {1036 // Prevent script.php?GLOBALS[foo]=bar1037 if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))1038 exit('I\'ll have a steak sandwich and... a steak sandwich.');1039 1040 // Variables that shouldn't be unset1041 $no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');1042 1043 // Remove elements in $GLOBALS that are present in any of the superglobals1044 $input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());1045 foreach ($input as $k => $v)1046 {1047 if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))1048 unset($GLOBALS[$k]);1049 }1050 }1051 1052 1053 //1054 2032 // Dump contents of variable(s) 1055 2033 //
Note: See TracChangeset
for help on using the changeset viewer.