Le site des utilisateurs francophones de FluxBB.
Vous n'êtes pas identifié(e).
D'autre part, j'ai trouvé le pourquoi de l'affichage multiple, et là c'est de ma faute, j'ai oublié un WHERE dans ma requête dans le plugin.
Donc dans AP_Forums_last_images.php, il faut remplacer la ligne :
$result = $db->query('SELECT f.id, f.forum_name, f.last_img, f.last_img_dsp FROM '.$db->prefix.'forums AS f INNER JOIN '.$db->prefix.'categories AS c ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());par :
$result = $db->query('SELECT f.id, f.forum_name, f.last_img, f.last_img_dsp FROM '.$db->prefix.'forums AS f INNER JOIN '.$db->prefix.'categories AS c WHERE f.cat_id=c.id ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());Hors ligne
Bonjour,
Bon, déjà, puisque dans l'étape 7 du readme.txt tu dois avoir une erreur quelque part, et puisque j'ai refait le readme.txt pour l'adapter avec FluxRewrite, dans ton functions.php reprends tes lignes :$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.', num_replies='.$num_replies.', last_topic_id='.$last_topic_id.', last_poster=\''.$db->escape($last_poster).'\', last_topic=\''.$db->escape($last_topic).'\', last_img='.(is_null($last_img) ? 'NULL' : '\''.$db->escape($last_img).'\'').' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_img', __FILE__, __LINE__, $db->error()); } else // There are no topics $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, last_topic=NULL, last_topic_id=NULL, num_replies=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_topic', __FILE__, __LINE__, $db->error());et remplace par :
$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', num_replies='.$num_replies.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\', last_img='.(is_null($last_img) ? 'NULL' : '\''.$db->escape($last_img).'\''), last_topic=\''.$db->escape($last_topic).'\', last_topic_id='.$last_topic_id.' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); } else // There are no topics $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, last_img=NULL, last_topic=NULL, last_topic_id=NULL, num_replies=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_img/last_topic', __FILE__, __LINE__, $db->error());Dis-moi déjà avec ça si tu n'as plus d'erreur "Unable to update".
Bah du coup j'ai une nouvelle erreur
La ligne en question : (l'une des lignes que tu ma dit de changer)
$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', num_replies='.$num_replies.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\', last_img='.(is_null($last_img) ? 'NULL' : '\''.$db->escape($last_img).'\''), last_topic=\''.$db->escape($last_topic).'\', last_topic_id='.$last_topic_id.' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());Je cherche l'erreur en question en m'aidant des autre topic sur ce forum. Si vous savez je suis preneur. 
Du coup pour l'affichage multiple je n'ai pas pu verifier vu que j'ai cette erreur ! 
Dernière modification par a-snowboard (20-03-2012 19:04:14)
Hors ligne
Essaye de mettre en mode "Show Queries" pour afficher les requêtes qui sont effectuées sur ta BDD pendant l'exécution.
Pour cela, à la fin de ton config.php, rajoute :
define('PUN_SHOW_QUERIES', 1);Ensuite tu vas jusqu'au moment où l'erreur se produit et tu nous montre la liste des requêtes.
Hors ligne
En fait l'erreur se fait d'entré de jeux sur l'index. et je suis dans l'impossibilité d'aller nulle part...
je regarde comment je fait pour trouver la liste des requêtes. Et oui patience je ne connais pas tout ! 
Hors ligne
je crois savoir comment afficher la liste de requête. mais pas pour une page précise.
Mais pour le coup je suis pas sur.
Hors ligne
Bonjour,
Tant pour les champs des tables de BDD que pour les variables PHP, NULL ne répond correctement à aucune condition, sauf :
IS NULL ou IS NOT NULL pour les champs des tables
is_null(...) Indique si une variable vaut NULL pour les variables PHP
isset(...) Détermine si une variable PHP est définie et est différente de NULL
Tout autre condition de test sur NULL engendre un résultat indéterminé
Il y a une seule valeur de type null, et c'est la constante insensible à la casse NULL. Ce qui veut dire que 'NULL' (Constante NULL entre quote) est considéré comme une chaîne dont le contenu est la suite de caractères N U L L.La valeur spéciale NULL représente une variable sans valeur. NULL est la seule valeur possible du type NULL.
Une variable est considérée comme null si :
elle s'est vue assigner la constante NULL.
elle n'a pas encore reçu de valeur.
elle a été effacée avec la fonction unset().
Bonjour Otomatic.
En décriptant le code de parser.php j'ai trouvé ça (ligne 85) :
if ($temp === null)Et encore pire (ligne 678) :
if ($alt == null)Cela ne correspond pas à tes préconisations. Qu'en penses-tu ?
Dernière modification par Wan (21-03-2012 18:36:09)
Hors ligne
Bonjour,
Je vais faire un rapport de bug.
La comparaison avec l'opérateur de comparaison "===" est bonne. Ce type de comparaison permet de vérifier l'égalité ET le type. (http://www.php.net/manual/fr/language.o … arison.php)
C'est l'opérateur à utiliser pour vérifier, par exemple, que le résultat d'une fonction est bien false et non pas une valeur similaire à false, comme 0 (zéro).
Ce n'est pas parce que l'erreur se propage qu'elle devient vérité. Gandhi
Sont différents : ça et sa - est et ait - à et a - ce et se - mes et mais ou met - été et était - c'est et ces - ce-si et ceci
La vie sans musique est tout simplement une erreur, une fatigue, un exil. Friedrich Nietzsche
Hors ligne
Bon, du coup et pour résumer, les deux seuls tests valables d'une variable $variable à NULL (ou non) sont donc :
soit :
if (is_null($variable)) (ou if (!is_null($variable)))
soit :
if ($variable === NULL) (ou if ($variable !== NULL))
Du coup, tu vas pouvoir "gonfler" ton rapport de bug sur le code source de FluxBB 1.4.8 :
- dans functions.php :
ligne 968: if($date_format == null)
ligne 971: if($time_format == null)
ligne 1178: if ($key == null)
- dans moderate.php :
ligne 878: if ($cur_topic['moved_to'] == null)
- dans viewforum.php :
ligne 172: if ($cur_topic['moved_to'] == null)
ligne 201: if (!$pun_user['is_guest'] (...) && $cur_topic['moved_to'] == null)
ligne 248: <td class="tc2"><?php echo ($cur_topic['moved_to'] == null) ? (...)
ligne 249: <?php if ($pun_config['o_topic_views'] == '1'): ?> (...) <?php echo ($cur_topic['moved_to'] == null) ? (...)
- dans include/parser.php (déjà cité) :
ligne 678: if ($alt == null)
- dans include/dblayer/mysql.php :
ligne 324: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
ligne 338: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
- dans include/dblayer/mysqli.php :
ligne 331: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
ligne 345: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
- dans include/dblayer/mysql_innodb.php :
ligne 338: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
ligne 352: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
- dans include/dblayer/mysqli_innodb.php :
ligne 344: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
ligne 358: return $this->query('ALTER TABLE ' (...) ($after_field != null ? ' AFTER '.$after_field (...)
Voilà, j'espère ne rien avoir oublié... 
[EDIT] J'ai finalement "gonflé" moi-même dans le ticket #642 du .org partie development/core : https://fluxbb.org/development/core/tickets/642/
Dernière modification par Wan (22-03-2012 00:06:43)
Hors ligne
heu...
je suis un peut perdu avec mon show query là... si vous avez un lien
qui m'explique comment extraire les requêtes...
car je suis completzment paumé la.
mais apres ce n'est pas une fonction prioritaire.
c'sst surtout l'affichage en baniere qui me sera beaucoup plus utile.
bon apres j'ai pas tout suivit ce probleme de bug... desole je suis a la deche ! 
Hors ligne
Bonjour,
Dans le fichier config.php, tu ajoutes (Ou décommente) la ligne :
define('PUN_SHOW_QUERIES', 1);À partir de là, toutes les requêtes seront affichées en bas des pages du forum, avec leur durée d'exécution et le contenu complet de chaque requête.
Ne pas oublier de commenter la ligne après utilisation
Ce n'est pas parce que l'erreur se propage qu'elle devient vérité. Gandhi
Sont différents : ça et sa - est et ait - à et a - ce et se - mes et mais ou met - été et était - c'est et ces - ce-si et ceci
La vie sans musique est tout simplement une erreur, une fatigue, un exil. Friedrich Nietzsche
Hors ligne
heu...
je suis un peut perdu avec mon show query là... si vous avez un lien
qui m'explique comment extraire les requêtes...
car je suis completzment paumé la.
Quand tu ajoutes à la fin de ton config.php :
define('PUN_SHOW_QUERIES', 1);cela permet d'afficher les requêtes effectuées au bas de chaque page, dans un block titré "Informations de débogage".
Evidemment, si la page d'erreur s'affiche immédiatement, ces informations ne s'affichent pas.
Mais on peut peut-être avoir quand même des informations utiles en mode "Debug".
Pour cela, à la fin de ton config.php ajoute :
define('PUN_DEBUG', 1);Va ensuite sur ton index qui pose problème et rapporte-nous le message qui s'affiche.
mais apres ce n'est pas une fonction prioritaire.
c'sst surtout l'affichage en baniere qui me sera beaucoup plus utile.
Pour cela tu peux essayer ceci :
Editer index.php et trouver :
require PUN_ROOT.'header.php';Ajouter après :
// Display last posted images
$nb_img = 7;
$result = $db->query('SELECT p.id, p.message FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id WHERE t.moved_to IS NULL AND f.last_img_dsp=1 ORDER BY p.posted DESC') or error('Unable to fetch message from posts', __FILE__, __LINE__, $db->error());
?>
<div id="lpi" class="blocktable">
<h2><span><?php echo 'Dernières images postées' ?></span></h2>
<div class="box">
<div class="inbox">
<table cellspacing="0">
<tr>
<?php
$i = 0;
while ($tracked_post = $db->fetch_assoc($result))
{
$list_img = detect_image($tracked_post['message']);
if ($list_img[0] > 0)
{
for ($j = $list_img[0] ; $j > 0; $j--)
{
$i += 1;
?>
<th style="text-align:center"><a href="viewtopic.php?pid=<?php echo $tracked_post['id'].'#p'.$tracked_post['id'] ?>"><img src="<?php echo $list_img[$j] ?>" height="100" alt="" /></a></th>
<?php
if ($i == $nb_img)
break 2;
}
}
}
?>
</tr>
</table>
</div>
</div>
</div>
<?phpEnvoyer sur le serveur.
bon apres j'ai pas tout suivit ce probleme de bug... desole je suis a la deche !
Désolé pour ce hors-sujet. Il s'agissait de rectifier quelques erreurs dans le code de FluxBB concernant les tests de variables avec la valeur NULL dont le type est particulier.
Dernière modification par Wan (22-03-2012 12:32:44)
Hors ligne
je fait tout ca dans la journee ou soiree.
pas de souci pour le hs ! a moins que ce soit un coup monte pour me perdre
? 
Hors ligne
... Il s'agissait de rectifier quelques erreurs dans le code de FluxBB concernant les tests de variables avec la valeur NULL dont le type est particulier.
Bonjour,
Et oui, une digression, mais profitable à tous. De plus : « bug » fixé : Setting all null-checks to use is_null().
Ce n'est pas parce que l'erreur se propage qu'elle devient vérité. Gandhi
Sont différents : ça et sa - est et ait - à et a - ce et se - mes et mais ou met - été et était - c'est et ces - ce-si et ceci
La vie sans musique est tout simplement une erreur, une fatigue, un exil. Friedrich Nietzsche
Hors ligne
bon manière d'avoir un peut l'impression d'avancer j'ai mis le code pour l'index. ça marche sans problème. 
J'ai juste une modification a faire pour que ce soit compatible avec fluxrewite. car le bête copiage de code ne marche pas
(ça aurais été trop beau !)
Pour mon erreur initiale je fait ça dès que je peux ! 
Bon après vu qu'il y a conflit avec une mod existante je ne sais pas si ça vaut le coup de batailler. Je vais quand même essayer ! 
Dernière modification par a-snowboard (22-03-2012 17:36:25)
Hors ligne
Bonjour,
Bon, déjà, puisque dans l'étape 7 du readme.txt tu dois avoir une erreur quelque part, et puisque j'ai refait le readme.txt pour l'adapter avec FluxRewrite, dans ton functions.php reprends tes lignes :$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.', num_replies='.$num_replies.', last_topic_id='.$last_topic_id.', last_poster=\''.$db->escape($last_poster).'\', last_topic=\''.$db->escape($last_topic).'\', last_img='.(is_null($last_img) ? 'NULL' : '\''.$db->escape($last_img).'\'').' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_img', __FILE__, __LINE__, $db->error()); } else // There are no topics $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, last_topic=NULL, last_topic_id=NULL, num_replies=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_topic', __FILE__, __LINE__, $db->error());et remplace par :
$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', num_replies='.$num_replies.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\', last_img='.(is_null($last_img) ? 'NULL' : '\''.$db->escape($last_img).'\''), last_topic=\''.$db->escape($last_topic).'\', last_topic_id='.$last_topic_id.' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error()); } else // There are no topics $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, last_img=NULL, last_topic=NULL, last_topic_id=NULL, num_replies=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_img/last_topic', __FILE__, __LINE__, $db->error());Dis-moi déjà avec ça si tu n'as plus d'erreur "Unable to update".
Bon j'ai suivit les instructions en ce qui concerne les requêtes.
Donc pour récapituler avec le nouveau code proposé par wan (voir ci dessus) :
J'ai un plantage dès l'index. impossibilité d’accéder nulle par. Je n'ai pu avoir aucune indication en ce qui concerne les requêtes. Mod débug ou pas.
Du coup j'ai remis le code initial (donc avant modification proposé par wan)
Voila ce qu'il en sort :
File: C:\xampp\htdocs\www\include\functions.php
Line: 743FluxBB reported: Unable to update last_post/last_post_id/last_poster/last_img
Database reported: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' last_topic_id=, last_poster='A-snowboard', last_topic='9', last_img='http://12' at line 1 (Errno: 1064)
Failed query: UPDATE forums SET num_topics=1, num_posts=10, last_post=1332431128, last_post_id=41, num_replies=, last_topic_id=, last_poster='A-snowboard', last_topic='9', last_img='http://127.0.0.1/www/img/members/2/22032012-1645_DSC00010.JPG' WHERE id=4
Je précise que cette erreur m'oblige a faire précédent. Mais elle après rafraichissement de la page le post avec la photo est bien publié. Mais n'est pas affiché sur l'index devant la rubrique ou elle a été posté.
Dernière modification par a-snowboard (22-03-2012 17:50:29)
Hors ligne
Failed query: UPDATE forums SET num_topics=1, num_posts=10, last_post=1332431128, last_post_id=41, num_replies=, last_topic_id=, last_poster='A-snowboard', last_topic='9', last_img='http://127.0.0.1/www/img/members/2/22032012-1645_DSC00010.JPG' WHERE id=4
Bonjour,
num_replies=rien du tout, last_topic_id=rien_du_tout. Si les deux colonnes n'acceptent pas les NULL, il y a erreur.
Ce n'est pas parce que l'erreur se propage qu'elle devient vérité. Gandhi
Sont différents : ça et sa - est et ait - à et a - ce et se - mes et mais ou met - été et était - c'est et ces - ce-si et ceci
La vie sans musique est tout simplement une erreur, une fatigue, un exil. Friedrich Nietzsche
Hors ligne
Bonsoir
Bon je sais que je deviens petit à petit l'homme à abattre sur ce sujet. Mais a force de faire des essais (vive le ctrl+z) et que ce n'est pas concluant je me tourne vers vous
En fait sur l'image suivante le problème est visible :
la phrase "Dernières images postées par les membres" est au même niveau que les images.
En fait le top serait d'avoir "Dernières images postées par les membres" de la même configuration que "derniers message"
et que les images s'affichent sur un fond blanc juste en dessous (sans l’icône carré bien entendu !)
Pour le moment a part ajouter </ br></ br> je n'ai rien trouvé de mieux, et c'est moche au possible ! 
Merci d'avance
Ps : désolé j'ai oublié d'enlever firebug sur l'image.
Hors ligne
Je précise que cette erreur m'oblige a faire précédent. Mais elle après rafraichissement de la page le post avec la photo est bien publié. Mais n'est pas affiché sur l'index devant la rubrique ou elle a été posté.
Peux-tu éditer ici le code de ton fichier include/functions.php ?
Hors ligne
Bon au vu des différents problèmes j'ai fait deux fichiers functions.php
En effet c'était le meilleur moyen pour ne pas trop avoir d'interférence entre les deux problèmes.
Fichier 1 : Concerne le problème d'affichage de la bannière d'image que j'ai illustré précédemment :
<?php
/**
* Copyright (C) 2008-2011 FluxBB
* based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
*/
//
// Return current timestamp (with microseconds) as a float
//
function get_microtime()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
//
// Cookie stuff!
//
function check_cookie(&$pun_user)
{
global $db, $db_type, $pun_config, $cookie_name, $cookie_seed;
$now = time();
// If the cookie is set and it matches the correct pattern, then read the values from it
if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
{
$cookie = array(
'user_id' => intval($matches[1]),
'password_hash' => $matches[2],
'expiration_time' => intval($matches[3]),
'cookie_hash' => $matches[4],
);
}
// If it has a non-guest user, and hasn't expired
if (isset($cookie) && $cookie['user_id'] > 1 && $cookie['expiration_time'] > $now)
{
// If the cookie has been tampered with
if (forum_hmac($cookie['user_id'].'|'.$cookie['expiration_time'], $cookie_seed.'_cookie_hash') != $cookie['cookie_hash'])
{
$expire = $now + 31536000; // The cookie expires after a year
pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
set_default_user();
return;
}
// Check if there's a user with the user ID and password hash from the cookie
$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());
$pun_user = $db->fetch_assoc($result);
// If user authorisation failed
if (!isset($pun_user['id']) || forum_hmac($pun_user['password'], $cookie_seed.'_password_hash') !== $cookie['password_hash'])
{
$expire = $now + 31536000; // The cookie expires after a year
pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
set_default_user();
return;
}
// Send a new, updated cookie with a new expiration timestamp
$expire = ($cookie['expiration_time'] > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit'];
pun_setcookie($pun_user['id'], $pun_user['password'], $expire);
// Set a default language if the user selected language no longer exists
if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
$pun_user['language'] = $pun_config['o_default_lang'];
// Set a default style if the user selected style no longer exists
if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
$pun_user['style'] = $pun_config['o_default_style'];
if (!$pun_user['disp_topics'])
$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
if (!$pun_user['disp_posts'])
$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
// Define this if you want this visit to affect the online list and the users last visit data
if (!defined('PUN_QUIET_VISIT'))
{
// Update the online list
if (!$pun_user['logged'])
{
$pun_user['logged'] = $now;
// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
switch ($db_type)
{
case 'mysql':
case 'mysqli':
case 'mysql_innodb':
case 'mysqli_innodb':
case 'sqlite':
$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());
break;
default:
$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());
break;
}
// Reset tracked topics
set_tracked_topics(null);
}
else
{
// Special case: We've timed out, but no other user has browsed the forums since we timed out
if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
{
$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());
$pun_user['last_visit'] = $pun_user['logged'];
}
$idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : '';
$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());
// Update tracked topics with the current expire time
if (isset($_COOKIE[$cookie_name.'_track']))
forum_setcookie($cookie_name.'_track', $_COOKIE[$cookie_name.'_track'], $now + $pun_config['o_timeout_visit']);
}
}
else
{
if (!$pun_user['logged'])
$pun_user['logged'] = $pun_user['last_visit'];
}
$pun_user['is_guest'] = false;
$pun_user['is_admmod'] = $pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1';
}
else
set_default_user();
}
//
// Converts the CDATA end sequence ]]> into ]]>
//
function escape_cdata($str)
{
return str_replace(']]>', ']]>', $str);
}
//
// Authenticates the provided username and password against the user database
// $user can be either a user ID (integer) or a username (string)
// $password can be either a plaintext password or a password hash including salt ($password_is_hash must be set accordingly)
//
function authenticate_user($user, $password, $password_is_hash = false)
{
global $db, $pun_user;
// Check if there's a user matching $user and $password
$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());
$pun_user = $db->fetch_assoc($result);
if (!isset($pun_user['id']) ||
($password_is_hash && $password != $pun_user['password']) ||
(!$password_is_hash && pun_hash($password) != $pun_user['password']))
set_default_user();
else
$pun_user['is_guest'] = false;
}
//
// Try to determine the current URL
//
function get_current_url($max_length = 0)
{
$protocol = get_current_protocol();
$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'] : '';
$url = urldecode($protocol.'://'.$_SERVER['HTTP_HOST'].$port.$_SERVER['REQUEST_URI']);
if (strlen($url) <= $max_length || $max_length == 0)
return $url;
// We can't find a short enough url
return null;
}
//
// Fetch the current protocol in use - http or https
//
function get_current_protocol()
{
$protocol = 'http';
// Check if the server is claiming to using HTTPS
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off')
$protocol = 'https';
// If we are behind a reverse proxy try to decide which protocol it is using
if (defined('FORUM_BEHIND_REVERSE_PROXY'))
{
// Check if we are behind a Microsoft based reverse proxy
if (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) != 'off')
$protocol = 'https';
// Check if we're behind a "proper" reverse proxy, and what protocol it's using
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']))
$protocol = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
}
return $protocol;
}
//
// Fetch the base_url, optionally support HTTPS and HTTP
//
function get_base_url($support_https = false)
{
global $pun_config;
static $base_url;
if (!$support_https)
return $pun_config['o_base_url'];
if (!isset($base_url))
{
// Make sure we are using the correct protocol
$base_url = str_replace(array('http://', 'https://'), get_current_protocol().'://', $pun_config['o_base_url']);
}
return $base_url;
}
//
// Fill $pun_user with default values (for guests)
//
function set_default_user()
{
global $db, $db_type, $pun_user, $pun_config;
$remote_addr = get_remote_address();
// Fetch guest user
$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());
if (!$db->num_rows($result))
exit('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
$pun_user = $db->fetch_assoc($result);
// Update online list
if (!$pun_user['logged'])
{
$pun_user['logged'] = time();
// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
switch ($db_type)
{
case 'mysql':
case 'mysqli':
case 'mysql_innodb':
case 'mysqli_innodb':
case 'sqlite':
$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());
break;
default:
$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());
break;
}
}
else
$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());
$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
$pun_user['timezone'] = $pun_config['o_default_timezone'];
$pun_user['dst'] = $pun_config['o_default_dst'];
$pun_user['language'] = $pun_config['o_default_lang'];
$pun_user['style'] = $pun_config['o_default_style'];
$pun_user['is_guest'] = true;
$pun_user['is_admmod'] = false;
}
//
// SHA1 HMAC with PHP 4 fallback
//
function forum_hmac($data, $key, $raw_output = false)
{
if (function_exists('hash_hmac'))
return hash_hmac('sha1', $data, $key, $raw_output);
// If key size more than blocksize then we hash it once
if (strlen($key) > 64)
$key = pack('H*', sha1($key)); // we have to use raw output here to match the standard
// Ensure we're padded to exactly one block boundary
$key = str_pad($key, 64, chr(0x00));
$hmac_opad = str_repeat(chr(0x5C), 64);
$hmac_ipad = str_repeat(chr(0x36), 64);
// Do inner and outer padding
for ($i = 0;$i < 64;$i++) {
$hmac_opad[$i] = $hmac_opad[$i] ^ $key[$i];
$hmac_ipad[$i] = $hmac_ipad[$i] ^ $key[$i];
}
// Finally, calculate the HMAC
$hash = sha1($hmac_opad.pack('H*', sha1($hmac_ipad.$data)));
// If we want raw output then we need to pack the final result
if ($raw_output)
$hash = pack('H*', $hash);
return $hash;
}
//
// Set a cookie, FluxBB style!
// Wrapper for forum_setcookie
//
function pun_setcookie($user_id, $password_hash, $expire)
{
global $cookie_name, $cookie_seed;
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);
}
//
// Set a cookie, FluxBB style!
//
function forum_setcookie($name, $value, $expire)
{
global $cookie_path, $cookie_domain, $cookie_secure;
// Enable sending of a P3P header
header('P3P: CP="CUR ADM"');
if (version_compare(PHP_VERSION, '5.2.0', '>='))
setcookie($name, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, true);
else
setcookie($name, $value, $expire, $cookie_path.'; HttpOnly', $cookie_domain, $cookie_secure);
}
//
// Check whether the connecting user is banned (and delete any expired bans while we're at it)
//
function check_bans()
{
global $db, $pun_config, $lang_common, $pun_user, $pun_bans;
// Admins and moderators aren't affected
if ($pun_user['is_admmod'] || !$pun_bans)
return;
// Add a dot or a colon (depending on IPv4/IPv6) at the end of the IP address to prevent banned address
// 192.168.0.5 from matching e.g. 192.168.0.50
$user_ip = get_remote_address();
$user_ip .= (strpos($user_ip, '.') !== false) ? '.' : ':';
$bans_altered = false;
$is_banned = false;
foreach ($pun_bans as $cur_ban)
{
// Has this ban expired?
if ($cur_ban['expire'] != '' && $cur_ban['expire'] <= time())
{
$db->query('DELETE FROM '.$db->prefix.'bans WHERE id='.$cur_ban['id']) or error('Unable to delete expired ban', __FILE__, __LINE__, $db->error());
$bans_altered = true;
continue;
}
if ($cur_ban['username'] != '' && utf8_strtolower($pun_user['username']) == utf8_strtolower($cur_ban['username']))
$is_banned = true;
if ($cur_ban['ip'] != '')
{
$cur_ban_ips = explode(' ', $cur_ban['ip']);
$num_ips = count($cur_ban_ips);
for ($i = 0; $i < $num_ips; ++$i)
{
// Add the proper ending to the ban
if (strpos($user_ip, '.') !== false)
$cur_ban_ips[$i] = $cur_ban_ips[$i].'.';
else
$cur_ban_ips[$i] = $cur_ban_ips[$i].':';
if (substr($user_ip, 0, strlen($cur_ban_ips[$i])) == $cur_ban_ips[$i])
{
$is_banned = true;
break;
}
}
}
if ($is_banned)
{
$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());
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);
}
}
// If we removed any expired bans during our run-through, we need to regenerate the bans cache
if ($bans_altered)
{
if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
require PUN_ROOT.'include/cache.php';
generate_bans_cache();
}
}
//
// Check username
//
function check_username($username, $exclude_id = null)
{
global $db, $pun_config, $errors, $lang_prof_reg, $lang_register, $lang_common, $pun_bans;
// Convert multiple whitespace characters into one (to prevent people from registering with indistinguishable usernames)
$username = preg_replace('%\s+%s', ' ', $username);
// Validate username
if (pun_strlen($username) < 2)
$errors[] = $lang_prof_reg['Username too short'];
else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters
$errors[] = $lang_prof_reg['Username too long'];
else if (!strcasecmp($username, 'Guest') || !strcasecmp($username, $lang_common['Guest']))
$errors[] = $lang_prof_reg['Username guest'];
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))
$errors[] = $lang_prof_reg['Username IP'];
else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
$errors[] = $lang_prof_reg['Username reserved chars'];
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))
$errors[] = $lang_prof_reg['Username BBCode'];
/* FluxToolBar */
if (file_exists(FORUM_CACHE_DIR.'cache_fluxtoolbar_tag_check.php'))
include FORUM_CACHE_DIR.'cache_fluxtoolbar_tag_check.php';
else
{
require_once PUN_ROOT.'include/cache_fluxtoolbar.php';
generate_ftb_cache('tags');
require FORUM_CACHE_DIR.'cache_fluxtoolbar_tag_check.php';
}
// Check username for any censored words
if ($pun_config['o_censoring'] == '1' && censor_words($username) != $username)
$errors[] = $lang_register['Username censor'];
// Check that the username (or a too similar username) is not already registered
$query = ($exclude_id) ? ' AND id!='.$exclude_id : '';
$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());
if ($db->num_rows($result))
{
$busy = $db->result($result);
$errors[] = $lang_register['Username dupe 1'].' '.pun_htmlspecialchars($busy).'. '.$lang_register['Username dupe 2'];
}
// Check username for any banned usernames
foreach ($pun_bans as $cur_ban)
{
if ($cur_ban['username'] != '' && utf8_strtolower($username) == utf8_strtolower($cur_ban['username']))
{
$errors[] = $lang_prof_reg['Banned username'];
break;
}
}
}
//
// Update "Users online"
//
function update_users_online()
{
global $db, $pun_config;
$now = time();
// Fetch all online list entries that are older than "o_timeout_online"
$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());
while ($cur_user = $db->fetch_assoc($result))
{
// If the entry is a guest, delete it
if ($cur_user['user_id'] == '1')
$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());
else
{
// If the entry is older than "o_timeout_visit", update last_visit for the user in question, then delete him/her from the online list
if ($cur_user['logged'] < ($now-$pun_config['o_timeout_visit']))
{
$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());
$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());
}
else if ($cur_user['idle'] == '0')
$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());
}
}
}
//
// Display the profile navigation menu
//
function generate_profile_menu($page = '')
{
global $lang_profile, $pun_config, $pun_user, $id;
?>
<div id="profile" class="block2col">
<div class="blockmenu">
<h2><span><?php echo $lang_profile['Profile menu'] ?></span></h2>
<div class="box">
<div class="inbox">
<ul>
<li<?php if ($page == 'essentials') echo ' class="isactive"'; ?>><a href="profile.php?section=essentials&id=<?php echo $id ?>"><?php echo $lang_profile['Section essentials'] ?></a></li>
<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>
<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>
<?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>
<?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>
<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>
<?php if ($pun_user['id'] == $id): ?> <li<?php if ($page == 'loginza') echo ' class="isactive"'; ?>><a href="reglog.php">Loginza</a></li>
<?php endif; ?>
<?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>
<?php endif; ?>
<?php
// See if there are any plugiles
$plugiles = array();
$d = dir(PUN_ROOT.'plugiles');
while (($entry = $d->read()) !== false)
{
$prefix = substr($entry, 0, strpos($entry, '_'));
$suffix = substr($entry, strlen($entry) - 4);
// UP <=> User Plugile (visible par tous) - UPP <=> User Private Plugile (visible par le membre et les administrateurs)
if ($suffix == '.php' && ($prefix == 'UP' || $prefix == 'UPP'))
$plugiles[] = array(substr(substr($entry, strpos($entry, '_') + 1), 0, -4), $entry);
}
$d->close();
// Did we find any plugiles?
if (!empty($plugiles))
{
if($pun_config['o_plugile_menu'] == '1')
{
?>
</ul>
</div>
</div>
<h2><span><?php echo $pun_config['o_plugile_menu_name'] ?></span></h2>
<div class="box">
<div class="inbox">
<ul>
<?php
}
while (list(, $cur_plugile) = @each($plugiles))
echo "\t\t\t\t\t".'<li'.(($page == $cur_plugile[1]) ? ' class="isactive"' : '').'><a href="profile.php?plugin='.$cur_plugile[1].'&id='.$id.'">'.str_replace('_', ' ', $cur_plugile[0]).'</a></li>'."\n";
?>
</ul>
</div>
</div>
</div>
<?php
}
}
//
// Outputs markup to display a user's avatar
//
function generate_avatar_markup($user_id)
{
global $pun_config;
$filetypes = array('jpg', 'gif', 'png');
$avatar_markup = '';
foreach ($filetypes as $cur_type)
{
$path = $pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type;
if (file_exists(PUN_ROOT.$path) && $img_size = getimagesize(PUN_ROOT.$path))
{
$avatar_markup = '<img src="'.pun_htmlspecialchars(get_base_url(true).'/'.$path.'?m='.filemtime(PUN_ROOT.$path)).'" '.$img_size[3].' alt="" />';
break;
}
}
return $avatar_markup;
}
//
// Generate browser's title
//
function generate_page_title($page_title, $p = null)
{
global $pun_config, $lang_common;
$page_title = array_reverse($page_title);
if ($p != null)
$page_title[0] .= ' ('.sprintf($lang_common['Page'], forum_number_format($p)).')';
$crumbs = implode($lang_common['Title separator'], $page_title);
return $crumbs;
}
//
// Save array of tracked topics in cookie
//
function set_tracked_topics($tracked_topics)
{
global $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $pun_config;
$cookie_data = '';
if (!empty($tracked_topics))
{
// Sort the arrays (latest read first)
arsort($tracked_topics['topics'], SORT_NUMERIC);
arsort($tracked_topics['forums'], SORT_NUMERIC);
// Homebrew serialization (to avoid having to run unserialize() on cookie data)
foreach ($tracked_topics['topics'] as $id => $timestamp)
$cookie_data .= 't'.$id.'='.$timestamp.';';
foreach ($tracked_topics['forums'] as $id => $timestamp)
$cookie_data .= 'f'.$id.'='.$timestamp.';';
// Enforce a byte size limit (4096 minus some space for the cookie name - defaults to 4048)
if (strlen($cookie_data) > FORUM_MAX_COOKIE_SIZE)
{
$cookie_data = substr($cookie_data, 0, FORUM_MAX_COOKIE_SIZE);
$cookie_data = substr($cookie_data, 0, strrpos($cookie_data, ';')).';';
}
}
forum_setcookie($cookie_name.'_track', $cookie_data, time() + $pun_config['o_timeout_visit']);
$_COOKIE[$cookie_name.'_track'] = $cookie_data; // Set it directly in $_COOKIE as well
}
//
// Extract array of tracked topics from cookie
//
function get_tracked_topics()
{
global $cookie_name;
$cookie_data = isset($_COOKIE[$cookie_name.'_track']) ? $_COOKIE[$cookie_name.'_track'] : false;
if (!$cookie_data)
return array('topics' => array(), 'forums' => array());
if (strlen($cookie_data) > 4048)
return array('topics' => array(), 'forums' => array());
// Unserialize data from cookie
$tracked_topics = array('topics' => array(), 'forums' => array());
$temp = explode(';', $cookie_data);
foreach ($temp as $t)
{
$type = substr($t, 0, 1) == 'f' ? 'forums' : 'topics';
$id = intval(substr($t, 1));
$timestamp = intval(substr($t, strpos($t, '=') + 1));
if ($id > 0 && $timestamp > 0)
$tracked_topics[$type][$id] = $timestamp;
}
return $tracked_topics;
}
//
// Detect all images in a message (return an array with the number of images and all their url's)
//
function detect_image($message)
{
$list_img [0] = 0;
$list_img_tmp = array();
preg_match_all('%\[img\]((ht|)tps?://[^\s<"]*?)\[/img\]%e', $message, $list_img_tmp, PREG_SET_ORDER);
if (sizeof($list_img_tmp) > 0)
foreach($list_img_tmp as $img)
{
$list_img [0] += 1;
$list_img [] = $img[1];
}
return $list_img;
}
//
// Update posts, topics, last_post, last_post_id and last_poster for a forum
//
function update_forum($forum_id)
{
global $db;
$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());
list($num_topics, $num_posts) = $db->fetch_row($result);
$num_posts = $num_posts + $num_topics; // $num_posts is only the sum of all replies (we have to add the topic posts)
$result = $db->query('SELECT last_post, last_post_id, last_poster, subject, id, num_replies 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());
if ($db->num_rows($result)) // There are topics in the forum
{
list($last_post, $last_post_id, $last_poster, $last_topic, $last_topic_id, $num_replies) = $db->fetch_row($result);
$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', num_replies='.$num_replies.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\', last_topic=\''.$db->escape($last_topic).'\', last_topic_id='.$last_topic_id.' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
}
else // There are no topics
$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, last_topic=NULL, last_topic_id=NULL, num_replies=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_topic', __FILE__, __LINE__, $db->error());
}
//
// Deletes any avatars owned by the specified user ID
//
function delete_avatar($user_id)
{
global $pun_config;
$filetypes = array('jpg', 'gif', 'png');
// Delete user avatar
foreach ($filetypes as $cur_type)
{
if (file_exists(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type))
@unlink(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type);
}
}
//
// Delete a topic and all of it's posts
//
function delete_topic($topic_id)
{
global $db;
// Delete the topic and any redirect topics
$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());
// Create a list of the post IDs in this topic
$post_ids = '';
$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
while ($row = $db->fetch_row($result))
$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
// Make sure we have a list of post IDs
if ($post_ids != '')
{
strip_search_index($post_ids);
// Delete posts in topic
$db->query('DELETE FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to delete posts', __FILE__, __LINE__, $db->error());
}
// Delete any subscriptions for this topic
$db->query('DELETE FROM '.$db->prefix.'topic_subscriptions WHERE topic_id='.$topic_id) or error('Unable to delete subscriptions', __FILE__, __LINE__, $db->error());
}
//
// Delete a single post
//
function delete_post($post_id, $topic_id)
{
global $db;
$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());
list($last_id, ,) = $db->fetch_row($result);
list($second_last_id, $second_poster, $second_posted) = $db->fetch_row($result);
// Delete the post
$db->query('DELETE FROM '.$db->prefix.'posts WHERE id='.$post_id) or error('Unable to delete post', __FILE__, __LINE__, $db->error());
strip_search_index($post_id);
// Count number of replies in the topic
$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());
$num_replies = $db->result($result, 0) - 1;
// If the message we deleted is the most recent in the topic (at the end of the topic)
if ($last_id == $post_id)
{
// If there is a $second_last_id there is more than 1 reply to the topic
if (!empty($second_last_id))
$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());
else
// We deleted the only reply, so now last_post/last_post_id/last_poster is posted/id/poster from the topic itself
$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());
}
else
// Otherwise we just decrement the reply counter
$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());
}
//
// Delete every .php file in the forum's cache directory
//
function forum_clear_cache()
{
$d = dir(FORUM_CACHE_DIR);
while (($entry = $d->read()) !== false)
{
if (substr($entry, -4) == '.php')
@unlink(FORUM_CACHE_DIR.$entry);
}
$d->close();
}
//
// Replace censored words in $text
//
function censor_words($text)
{
global $db;
static $search_for, $replace_with;
// If not already built in a previous call, build an array of censor words and their replacement text
if (!isset($search_for))
{
if (file_exists(FORUM_CACHE_DIR.'cache_censoring.php'))
include FORUM_CACHE_DIR.'cache_censoring.php';
if (!defined('PUN_CENSOR_LOADED'))
{
if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
require PUN_ROOT.'include/cache.php';
generate_censoring_cache();
require FORUM_CACHE_DIR.'cache_censoring.php';
}
}
if (!empty($search_for))
$text = substr(ucp_preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1);
return $text;
}
//
// Determines the correct title for $user
// $user must contain the elements 'username', 'title', 'posts', 'g_id' and 'g_user_title'
//
function get_title($user)
{
global $db, $pun_config, $pun_bans, $lang_common;
static $ban_list, $pun_ranks;
// If not already built in a previous call, build an array of lowercase banned usernames
if (empty($ban_list))
{
$ban_list = array();
foreach ($pun_bans as $cur_ban)
$ban_list[] = strtolower($cur_ban['username']);
}
// If not already loaded in a previous call, load the cached ranks
if ($pun_config['o_ranks'] == '1' && !defined('PUN_RANKS_LOADED'))
{
if (file_exists(FORUM_CACHE_DIR.'cache_ranks.php'))
include FORUM_CACHE_DIR.'cache_ranks.php';
if (!defined('PUN_RANKS_LOADED'))
{
if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
require PUN_ROOT.'include/cache.php';
generate_ranks_cache();
require FORUM_CACHE_DIR.'cache_ranks.php';
}
}
// If the user has a custom title
if ($user['title'] != '')
$user_title = pun_htmlspecialchars($user['title']);
// If the user is banned
else if (in_array(strtolower($user['username']), $ban_list))
$user_title = $lang_common['Banned'];
// If the user group has a default user title
else if ($user['g_user_title'] != '')
$user_title = pun_htmlspecialchars($user['g_user_title']);
// If the user is a guest
else if ($user['g_id'] == PUN_GUEST)
$user_title = $lang_common['Guest'];
else
{
// Are there any ranks?
if ($pun_config['o_ranks'] == '1' && !empty($pun_ranks))
{
foreach ($pun_ranks as $cur_rank)
{
if ($user['num_posts'] >= $cur_rank['min_posts'])
$user_title = pun_htmlspecialchars($cur_rank['rank']);
}
}
// If the user didn't "reach" any rank (or if ranks are disabled), we assign the default
if (!isset($user_title))
$user_title = $lang_common['Member'];
}
return $user_title;
}
//
// Generate a string with numbered links (for multipage scripts)
//
function paginate($num_pages, $cur_page, $link)
{
global $lang_common;
$pages = array();
$link_to_all = false;
// If $cur_page == -1, we link to all pages (used in viewforum.php)
if ($cur_page == -1)
{
$cur_page = 1;
$link_to_all = true;
}
if ($num_pages <= 1)
$pages = array('<strong class="item1">1</strong>');
else
{
// Add a previous page link
if ($num_pages > 1 && $cur_page > 1)
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.($cur_page - 1).'">'.$lang_common['Previous'].'</a>';
if ($cur_page > 3)
{
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p=1">1</a>';
if ($cur_page > 5)
$pages[] = '<span class="spacer">'.$lang_common['Spacer'].'</span>';
}
// Don't ask me how the following works. It just does, OK? :-)
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)
{
if ($current < 1 || $current > $num_pages)
continue;
else if ($current != $cur_page || $link_to_all)
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.$current.'">'.forum_number_format($current).'</a>';
else
$pages[] = '<strong'.(empty($pages) ? ' class="item1"' : '').'>'.forum_number_format($current).'</strong>';
}
if ($cur_page <= ($num_pages-3))
{
if ($cur_page != ($num_pages-3) && $cur_page != ($num_pages-4))
$pages[] = '<span class="spacer">'.$lang_common['Spacer'].'</span>';
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.$num_pages.'">'.forum_number_format($num_pages).'</a>';
}
// Add a next page link
if ($num_pages > 1 && !$link_to_all && $cur_page < $num_pages)
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.($cur_page +1).'">'.$lang_common['Next'].'</a>';
}
return implode(' ', $pages);
}
//
// Display a message
//
function message($message, $no_back_link = false)
{
global $db, $lang_common, $pun_config, $pun_start, $tpl_main, $pun_user;
if (!defined('PUN_HEADER'))
{
$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Info']);
define('PUN_ACTIVE_PAGE', 'index');
require PUN_ROOT.'header.php';
}
?>
<div id="msg" class="block">
<h2><span><?php echo $lang_common['Info'] ?></span></h2>
<div class="box">
<div class="inbox">
<p><?php echo $message ?></p>
<?php if (!$no_back_link): ?> <p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
<?php endif; ?> </div>
</div>
</div>
<?php
require PUN_ROOT.'footer.php';
}
//
// Format a time string according to $time_format and time zones
//
function format_time($timestamp, $date_only = false, $date_format = null, $time_format = null, $time_only = false, $no_text = false)
{
global $pun_config, $lang_common, $pun_user, $forum_date_formats, $forum_time_formats;
if ($timestamp == '')
return $lang_common['Never'];
$diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
$timestamp += $diff;
$now = time();
if($date_format == null)
$date_format = $forum_date_formats[$pun_user['date_format']];
if($time_format == null)
$time_format = $forum_time_formats[$pun_user['time_format']];
$date = gmdate($date_format, $timestamp);
$today = gmdate($date_format, $now+$diff);
$yesterday = gmdate($date_format, $now+$diff-86400);
if(!$no_text)
{
if ($date == $today)
$date = $lang_common['Today'];
else if ($date == $yesterday)
$date = $lang_common['Yesterday'];
}
if ($date_only)
return $date;
else if ($time_only)
return gmdate($time_format, $timestamp);
else
return $date.' '.gmdate($time_format, $timestamp);
}
//
// A wrapper for PHP's number_format function
//
function forum_number_format($number, $decimals = 0)
{
global $lang_common;
return is_numeric($number) ? number_format($number, $decimals, $lang_common['lang_decimal_point'], $lang_common['lang_thousands_sep']) : $number;
}
//
// Generate a random key of length $len
//
function random_key($len, $readable = false, $hash = false)
{
$key = '';
if ($hash)
$key = substr(pun_hash(uniqid(rand(), true)), 0, $len);
else if ($readable)
{
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for ($i = 0; $i < $len; ++$i)
$key .= substr($chars, (mt_rand() % strlen($chars)), 1);
}
else
{
for ($i = 0; $i < $len; ++$i)
$key .= chr(mt_rand(33, 126));
}
return $key;
}
//
// Make sure that HTTP_REFERER matches base_url/script
//
function confirm_referrer($script, $error_msg = false)
{
global $pun_config, $lang_common;
static $rewrites = array('viewtopic.php' => 'topic-', 'viewforum.php' => 'forum-', 'post.php' => 'message-');
// There is no referrer
if (empty($_SERVER['HTTP_REFERER']))
message($error_msg ? $error_msg : $lang_common['Bad referrer']);
$referrer = parse_url(strtolower($_SERVER['HTTP_REFERER']));
// Remove www subdomain if it exists
if (strpos($referrer['host'], 'www.') === 0)
$referrer['host'] = substr($referrer['host'], 4);
$valid = parse_url(strtolower(get_base_url().'/'.$script));
// Remove www subdomain if it exists
if (strpos($valid['host'], 'www.') === 0)
$valid['host'] = substr($valid['host'], 4);
// Check the host and path match. Ignore the scheme, port, etc.
if ($referrer['host'] != $valid['host'] || $referrer['path'] != $valid['path'])
{
if (array_key_exists($script, $rewrites))
{
if (!preg_match('#^'.get_base_url().'/'.$rewrites[$script].'[0-9]+-[0-9|a-b|\-|\.]*(.?)#i', strtolower($_SERVER['HTTP_REFERER'])))
message($lang_common['Bad referrer']);
}
else
message($lang_common['Bad referrer']);
}
}
//
// Generate a random password of length $len
// Compatibility wrapper for random_key
//
function random_pass($len)
{
return random_key($len, true);
}
//
// Compute a hash of $str
//
function pun_hash($str)
{
return sha1($str);
}
//
// Try to determine the correct remote IP-address
//
function get_remote_address()
{
$remote_addr = $_SERVER['REMOTE_ADDR'];
// If we are behind a reverse proxy try to find the real users IP
if (defined('FORUM_BEHIND_REVERSE_PROXY'))
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
// The general format of the field is:
// X-Forwarded-For: client1, proxy1, proxy2
// where the value is a comma+space separated list of IP addresses, the left-most being the farthest downstream client,
// and each successive proxy that passed the request adding the IP address where it received the request from.
$forwarded_for = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$forwarded_for = trim($forwarded_for[0]);
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))
$remote_addr = $forwarded_for;
}
}
return $remote_addr;
}
//
// Calls htmlspecialchars with a few options already set
//
function pun_htmlspecialchars($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
//
// Calls htmlspecialchars_decode with a few options already set
//
function pun_htmlspecialchars_decode($str)
{
if (function_exists('htmlspecialchars_decode'))
return htmlspecialchars_decode($str, ENT_QUOTES);
static $translations;
if (!isset($translations))
{
$translations = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);
$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
$translations = array_flip($translations);
}
return strtr($str, $translations);
}
//
// A wrapper for utf8_strlen for compatibility
//
function pun_strlen($str)
{
return utf8_strlen($str);
}
//
// Convert \r\n and \r to \n
//
function pun_linebreaks($str)
{
return str_replace("\r", "\n", str_replace("\r\n", "\n", $str));
}
//
// A wrapper for utf8_trim for compatibility
//
function pun_trim($str, $charlist = false)
{
return utf8_trim($str, $charlist);
}
//
// Checks if a string is in all uppercase
//
function is_all_uppercase($string)
{
return utf8_strtoupper($string) == $string && utf8_strtolower($string) != $string;
}
//
// Inserts $element into $input at $offset
// $offset can be either a numerical offset to insert at (eg: 0 inserts at the beginning of the array)
// or a string, which is the key that the new element should be inserted before
// $key is optional: it's used when inserting a new key/value pair into an associative array
//
function array_insert(&$input, $offset, $element, $key = null)
{
if ($key == null)
$key = $offset;
// Determine the proper offset if we're using a string
if (!is_int($offset))
$offset = array_search($offset, array_keys($input), true);
// Out of bounds checks
if ($offset > count($input))
$offset = count($input);
else if ($offset < 0)
$offset = 0;
$input = array_merge(array_slice($input, 0, $offset), array($key => $element), array_slice($input, $offset));
}
//
// Display a message when board is in maintenance mode
//
function maintenance_message()
{
global $db, $pun_config, $lang_common, $pun_user;
// Send no-cache headers
header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache'); // For HTTP/1.0 compatibility
// Send the Content-type header in case the web server is setup to send something else
header('Content-type: text/html; charset=utf-8');
// Deal with newlines, tabs and multiple spaces
$pattern = array("\t", ' ', ' ');
$replace = array('    ', '  ', '  ');
$message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl'))
{
$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl';
$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
}
else
{
$tpl_file = PUN_ROOT.'include/template/maintenance.tpl';
$tpl_inc_dir = PUN_ROOT.'include/user/';
}
$tpl_maint = file_get_contents($tpl_file);
// START SUBST - <pun_include "*">
preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_maint, $pun_includes, PREG_SET_ORDER);
foreach ($pun_includes as $cur_include)
{
ob_start();
// Allow for overriding user includes, too.
if (file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
require PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
else
error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file)));
$tpl_temp = ob_get_contents();
$tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint);
ob_end_clean();
}
// END SUBST - <pun_include "*">
// START SUBST - <pun_language>
$tpl_maint = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_maint);
// END SUBST - <pun_language>
// START SUBST - <pun_content_direction>
$tpl_maint = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_maint);
// END SUBST - <pun_content_direction>
// START SUBST - <pun_head>
ob_start();
$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Maintenance']);
?>
<title><?php echo generate_page_title($page_title) ?></title>
<link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_maint = str_replace('<pun_head>', $tpl_temp, $tpl_maint);
ob_end_clean();
// END SUBST - <pun_head>
// START SUBST - <pun_maint_main>
ob_start();
?>
<div class="block">
<h2><?php echo $lang_common['Maintenance'] ?></h2>
<div class="box">
<div class="inbox">
<p><?php echo $message ?></p>
</div>
</div>
</div>
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_maint = str_replace('<pun_maint_main>', $tpl_temp, $tpl_maint);
ob_end_clean();
// END SUBST - <pun_maint_main>
// End the transaction
$db->end_transaction();
// Close the db connection (and free up any result data)
$db->close();
exit($tpl_maint);
}
//
// Display $message and redirect user to $destination_url
//
function redirect($destination_url, $message)
{
global $db, $pun_config, $lang_common, $pun_user;
// Prefix with base_url (unless there's already a valid URI)
if (strpos($destination_url, 'http://') !== 0 && strpos($destination_url, 'https://') !== 0 && strpos($destination_url, '/') !== 0)
$destination_url = get_base_url(true).'/'.$destination_url;
// Do a little spring cleaning
$destination_url = preg_replace('%([\r\n])|(\%0[ad])|(;\s*data\s*:)%i', '', $destination_url);
// If the delay is 0 seconds, we might as well skip the redirect all together
if ($pun_config['o_redirect_delay'] == '0')
header('Location: '.str_replace('&', '&', $destination_url));
// Send no-cache headers
header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache'); // For HTTP/1.0 compatibility
// Send the Content-type header in case the web server is setup to send something else
header('Content-type: text/html; charset=utf-8');
if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl'))
{
$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl';
$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
}
else
{
$tpl_file = PUN_ROOT.'include/template/redirect.tpl';
$tpl_inc_dir = PUN_ROOT.'include/user/';
}
$tpl_redir = file_get_contents($tpl_file);
// START SUBST - <pun_include "*">
preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_redir, $pun_includes, PREG_SET_ORDER);
foreach ($pun_includes as $cur_include)
{
ob_start();
// Allow for overriding user includes, too.
if (file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
require PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
else
error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file)));
$tpl_temp = ob_get_contents();
$tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);
ob_end_clean();
}
// END SUBST - <pun_include "*">
// START SUBST - <pun_language>
$tpl_redir = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_redir);
// END SUBST - <pun_language>
// START SUBST - <pun_content_direction>
$tpl_redir = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_redir);
// END SUBST - <pun_content_direction>
// START SUBST - <pun_head>
ob_start();
$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Redirecting']);
?>
<meta http-equiv="refresh" content="<?php echo $pun_config['o_redirect_delay'] ?>;URL=<?php echo str_replace(array('<', '>', '"'), array('<', '>', '"'), $destination_url) ?>" />
<title><?php echo generate_page_title($page_title) ?></title>
<link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_redir = str_replace('<pun_head>', $tpl_temp, $tpl_redir);
ob_end_clean();
// END SUBST - <pun_head>
// START SUBST - <pun_redir_main>
ob_start();
?>
<div class="block">
<h2><?php echo $lang_common['Redirecting'] ?></h2>
<div class="box">
<div class="inbox">
<p><?php echo $message.'<br /><br /><a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>' ?></p>
</div>
</div>
</div>
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_redir = str_replace('<pun_redir_main>', $tpl_temp, $tpl_redir);
ob_end_clean();
// END SUBST - <pun_redir_main>
// START SUBST - <pun_footer>
ob_start();
// End the transaction
$db->end_transaction();
// Display executed queries (if enabled)
if (defined('PUN_SHOW_QUERIES'))
display_saved_queries();
$tpl_temp = trim(ob_get_contents());
$tpl_redir = str_replace('<pun_footer>', $tpl_temp, $tpl_redir);
ob_end_clean();
// END SUBST - <pun_footer>
// Close the db connection (and free up any result data)
$db->close();
exit($tpl_redir);
}
//
// Display a simple error message
//
function error($message, $file = null, $line = null, $db_error = false)
{
global $pun_config, $lang_common;
// Set some default settings if the script failed before $pun_config could be populated
if (empty($pun_config))
{
$pun_config = array(
'o_board_title' => 'FluxBB',
'o_gzip' => '0'
);
}
// Set some default translations if the script failed before $lang_common could be populated
if (empty($lang_common))
{
$lang_common = array(
'Title separator' => ' / ',
'Page' => 'Page %s'
);
}
// Empty all output buffers and stop buffering
while (@ob_end_clean());
// "Restart" output buffering if we are using ob_gzhandler (since the gzip header is already sent)
if ($pun_config['o_gzip'] && extension_loaded('zlib'))
ob_start('ob_gzhandler');
// Send no-cache headers
header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache'); // For HTTP/1.0 compatibility
// Send the Content-type header in case the web server is setup to send something else
header('Content-type: text/html; charset=utf-8');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), 'Error') ?>
<title><?php echo generate_page_title($page_title) ?></title>
<style type="text/css">
<!--
BODY {MARGIN: 10% 20% auto 20%; font: 10px Verdana, Arial, Helvetica, sans-serif}
#errorbox {BORDER: 1px solid #B84623}
H2 {MARGIN: 0; COLOR: #FFFFFF; BACKGROUND-COLOR: #B84623; FONT-SIZE: 1.1em; PADDING: 5px 4px}
#errorbox DIV {PADDING: 6px 5px; BACKGROUND-COLOR: #F1F1F1}
-->
</style>
</head>
<body>
<div id="errorbox">
<h2>An error was encountered</h2>
<div>
<?php
if (defined('PUN_DEBUG') && $file !== null && $line !== null)
{
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";
if ($db_error)
{
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";
if ($db_error['error_sql'] != '')
echo "\t\t".'<br /><br /><strong>Failed query:</strong> '.pun_htmlspecialchars($db_error['error_sql'])."\n";
}
}
else
echo "\t\t".'Error: <strong>'.$message.'.</strong>'."\n";
?>
</div>
</div>
</body>
</html>
<?php
// If a database connection was established (before this error) we close it
if ($db_error)
$GLOBALS['db']->close();
exit;
}
//
// Unset any variables instantiated as a result of register_globals being enabled
//
function forum_unregister_globals()
{
$register_globals = ini_get('register_globals');
if ($register_globals === '' || $register_globals === '0' || strtolower($register_globals) === 'off')
return;
// Prevent script.php?GLOBALS[foo]=bar
if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))
exit('I\'ll have a steak sandwich and... a steak sandwich.');
// Variables that shouldn't be unset
$no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
// Remove elements in $GLOBALS that are present in any of the superglobals
$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
foreach ($input as $k => $v)
{
if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))
{
unset($GLOBALS[$k]);
unset($GLOBALS[$k]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
}
}
}
//
// Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from user input
//
function forum_remove_bad_characters()
{
$_GET = remove_bad_characters($_GET);
$_POST = remove_bad_characters($_POST);
$_COOKIE = remove_bad_characters($_COOKIE);
$_REQUEST = remove_bad_characters($_REQUEST);
}
//
// Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from the given string
// See: http://kb.mozillazine.org/Network.IDN.blacklist_chars
//
function remove_bad_characters($array)
{
static $bad_utf8_chars;
if (!isset($bad_utf8_chars))
{
$bad_utf8_chars = array(
"\xcc\xb7" => '', // COMBINING SHORT SOLIDUS OVERLAY 0337 *
"\xcc\xb8" => '', // COMBINING LONG SOLIDUS OVERLAY 0338 *
"\xe1\x85\x9F" => '', // HANGUL CHOSEONG FILLER 115F *
"\xe1\x85\xA0" => '', // HANGUL JUNGSEONG FILLER 1160 *
"\xe2\x80\x8b" => '', // ZERO WIDTH SPACE 200B *
"\xe2\x80\x8c" => '', // ZERO WIDTH NON-JOINER 200C
"\xe2\x80\x8d" => '', // ZERO WIDTH JOINER 200D
"\xe2\x80\x8e" => '', // LEFT-TO-RIGHT MARK 200E
"\xe2\x80\x8f" => '', // RIGHT-TO-LEFT MARK 200F
"\xe2\x80\xaa" => '', // LEFT-TO-RIGHT EMBEDDING 202A
"\xe2\x80\xab" => '', // RIGHT-TO-LEFT EMBEDDING 202B
"\xe2\x80\xac" => '', // POP DIRECTIONAL FORMATTING 202C
"\xe2\x80\xad" => '', // LEFT-TO-RIGHT OVERRIDE 202D
"\xe2\x80\xae" => '', // RIGHT-TO-LEFT OVERRIDE 202E
"\xe2\x80\xaf" => '', // NARROW NO-BREAK SPACE 202F *
"\xe2\x81\x9f" => '', // MEDIUM MATHEMATICAL SPACE 205F *
"\xe2\x81\xa0" => '', // WORD JOINER 2060
"\xe3\x85\xa4" => '', // HANGUL FILLER 3164 *
"\xef\xbb\xbf" => '', // ZERO WIDTH NO-BREAK SPACE FEFF
"\xef\xbe\xa0" => '', // HALFWIDTH HANGUL FILLER FFA0 *
"\xef\xbf\xb9" => '', // INTERLINEAR ANNOTATION ANCHOR FFF9 *
"\xef\xbf\xba" => '', // INTERLINEAR ANNOTATION SEPARATOR FFFA *
"\xef\xbf\xbb" => '', // INTERLINEAR ANNOTATION TERMINATOR FFFB *
"\xef\xbf\xbc" => '', // OBJECT REPLACEMENT CHARACTER FFFC *
"\xef\xbf\xbd" => '', // REPLACEMENT CHARACTER FFFD *
"\xe2\x80\x80" => ' ', // EN QUAD 2000 *
"\xe2\x80\x81" => ' ', // EM QUAD 2001 *
"\xe2\x80\x82" => ' ', // EN SPACE 2002 *
"\xe2\x80\x83" => ' ', // EM SPACE 2003 *
"\xe2\x80\x84" => ' ', // THREE-PER-EM SPACE 2004 *
"\xe2\x80\x85" => ' ', // FOUR-PER-EM SPACE 2005 *
"\xe2\x80\x86" => ' ', // SIX-PER-EM SPACE 2006 *
"\xe2\x80\x87" => ' ', // FIGURE SPACE 2007 *
"\xe2\x80\x88" => ' ', // PUNCTUATION SPACE 2008 *
"\xe2\x80\x89" => ' ', // THIN SPACE 2009 *
"\xe2\x80\x8a" => ' ', // HAIR SPACE 200A *
"\xE3\x80\x80" => ' ', // IDEOGRAPHIC SPACE 3000 *
);
}
if (is_array($array))
return array_map('remove_bad_characters', $array);
// Strip out any invalid characters
$array = utf8_bad_strip($array);
// Remove control characters
$array = preg_replace('%[\x{00}-\x{08}\x{0b}-\x{0c}\x{0e}-\x{1f}]%', '', $array);
// Replace some "bad" characters
$array = str_replace(array_keys($bad_utf8_chars), array_values($bad_utf8_chars), $array);
return $array;
}
//
// Converts the file size in bytes to a human readable file size
//
function file_size($size)
{
global $lang_common;
$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB');
for ($i = 0; $size > 1024; $i++)
$size /= 1024;
return sprintf($lang_common['Size unit '.$units[$i]], round($size, 2));;
}
//
// Fetch a list of available styles
//
function forum_list_styles()
{
$styles = array();
$d = dir(PUN_ROOT.'style');
while (($entry = $d->read()) !== false)
{
if ($entry{0} == '.')
continue;
if (substr($entry, -4) == '.css')
$styles[] = substr($entry, 0, -4);
}
$d->close();
natcasesort($styles);
return $styles;
}
//
// Fetch a list of available language packs
//
function forum_list_langs()
{
$languages = array();
$d = dir(PUN_ROOT.'lang');
while (($entry = $d->read()) !== false)
{
if ($entry{0} == '.')
continue;
if (is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php'))
$languages[] = $entry;
}
$d->close();
natcasesort($languages);
return $languages;
}
//
// Generate a cache ID based on the last modification time for all stopwords files
//
function generate_stopwords_cache_id()
{
$files = glob(PUN_ROOT.'lang/*/stopwords.txt');
if ($files === false)
return 'cache_id_error';
$hash = array();
foreach ($files as $file)
{
$hash[] = $file;
$hash[] = filemtime($file);
}
return sha1(implode('|', $hash));
}
//
// Fetch a list of available admin plugins
//
function forum_list_plugins($is_admin)
{
$plugins = array();
$d = dir(PUN_ROOT.'plugins');
while (($entry = $d->read()) !== false)
{
if ($entry{0} == '.')
continue;
$prefix = substr($entry, 0, strpos($entry, '_'));
$suffix = substr($entry, strlen($entry) - 4);
if ($suffix == '.php' && ((!$is_admin && $prefix == 'AMP') || ($is_admin && ($prefix == 'AP' || $prefix == 'AMP'))))
$plugins[$entry] = substr($entry, strpos($entry, '_') + 1, -4);
}
$d->close();
natcasesort($plugins);
return $plugins;
}
//
// Split text into chunks ($inside contains all text inside $start and $end, and $outside contains all text outside)
//
function split_text($text, $start, $end, &$errors, $retab = true)
{
global $pun_config, $lang_common;
$result = array(0 => array(), 1 => array()); // 0 = inside, 1 = outside
// split the text into parts
$parts = preg_split('%'.preg_quote($start, '%').'(.*)'.preg_quote($end, '%').'%Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$num_parts = count($parts);
// preg_split results in outside parts having even indices, inside parts having odd
for ($i = 0;$i < $num_parts;$i++)
$result[1 - ($i % 2)][] = $parts[$i];
if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
{
$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
$result[1] = str_replace("\t", $spaces, $result[1]);
}
return $result;
}
//
// Extract blocks from a text with a starting and ending string
// This function always matches the most outer block so nesting is possible
//
function extract_blocks($text, $start, $end, &$errors = array(), $retab = true)
{
global $pun_config;
$code = array();
$start_len = strlen($start);
$end_len = strlen($end);
$regex = '%(?:'.preg_quote($start, '%').'|'.preg_quote($end, '%').')%';
$matches = array();
if (preg_match_all($regex, $text, $matches))
{
$counter = $offset = 0;
$start_pos = $end_pos = false;
foreach ($matches[0] as $match)
{
if ($match == $start)
{
if ($counter == 0)
$start_pos = strpos($text, $start);
$counter++;
}
elseif ($match == $end)
{
$counter--;
if ($counter == 0)
$end_pos = strpos($text, $end, $offset + 1);
$offset = strpos($text, $end, $offset + 1);
}
if ($start_pos !== false && $end_pos !== false)
{
$code[] = substr($text, $start_pos + $start_len,
$end_pos - $start_pos - $start_len);
$text = substr_replace($text, "\1", $start_pos,
$end_pos - $start_pos + $end_len);
$start_pos = $end_pos = false;
$offset = 0;
}
}
}
if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
{
$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
$text = str_replace("\t", $spaces, $text);
}
return array($code, $text);
}
//
// function url_valid($url) {
//
// Return associative array of valid URI components, or FALSE if $url is not
// RFC-3986 compliant. If the passed URL begins with: "www." or "ftp.", then
// "http://" or "ftp://" is prepended and the corrected full-url is stored in
// the return array with a key name "url". This value should be used by the caller.
//
// Return value: FALSE if $url is not valid, otherwise array of URI components:
// e.g.
// Given: "http://www.jmrware.com:80/articles?height=10&width=75#fragone"
// Array(
// [scheme] => http
// [authority] => www.jmrware.com:80
// [userinfo] =>
// [host] => www.jmrware.com
// [IP_literal] =>
// [IPV6address] =>
// [ls32] =>
// [IPvFuture] =>
// [IPv4address] =>
// [regname] => www.jmrware.com
// [port] => 80
// [path_abempty] => /articles
// [query] => height=10&width=75
// [fragment] => fragone
// [url] => http://www.jmrware.com:80/articles?height=10&width=75#fragone
// )
function url_valid($url)
{
if (strpos($url, 'www.') === 0) $url = 'http://'. $url;
if (strpos($url, 'ftp.') === 0) $url = 'ftp://'. $url;
if (!preg_match('/# Valid absolute URI having a non-empty, valid DNS host.
^
(?P<scheme>[A-Za-z][A-Za-z0-9+\-.]*):\/\/
(?P<authority>
(?:(?P<userinfo>(?:[A-Za-z0-9\-._~!$&\'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?
(?P<host>
(?P<IP_literal>
\[
(?:
(?P<IPV6address>
(?: (?:[0-9A-Fa-f]{1,4}:){6}
| ::(?:[0-9A-Fa-f]{1,4}:){5}
| (?: [0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}:
| (?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::
)
(?P<ls32>[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}
| (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
)
| (?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::
)
| (?P<IPvFuture>[Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&\'()*+,;=:]+)
)
\]
)
| (?P<IPv4address>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))
| (?P<regname>(?:[A-Za-z0-9\-._~!$&\'()*+,;=]|%[0-9A-Fa-f]{2})+)
)
(?::(?P<port>[0-9]*))?
)
(?P<path_abempty>(?:\/(?:[A-Za-z0-9\-._~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)
(?:\?(?P<query> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
(?:\#(?P<fragment> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
$
/mx', $url, $m)) return FALSE;
switch ($m['scheme'])
{
case 'https':
case 'http':
if ($m['userinfo']) return FALSE; // HTTP scheme does not allow userinfo.
break;
case 'ftps':
case 'ftp':
break;
default:
return FALSE; // Unrecognised URI scheme. Default to FALSE.
}
// Validate host name conforms to DNS "dot-separated-parts".
if ($m{'regname'}) // If host regname specified, check for DNS conformance.
{
if (!preg_match('/# HTTP DNS host name.
^ # Anchor to beginning of string.
(?!.{256}) # Overall host length is less than 256 chars.
(?: # Group dot separated host part alternatives.
[0-9A-Za-z]\. # Either a single alphanum followed by dot
| # or... part has more than one char (63 chars max).
[0-9A-Za-z] # Part first char is alphanum (no dash).
[\-0-9A-Za-z]{0,61} # Internal chars are alphanum plus dash.
[0-9A-Za-z] # Part last char is alphanum (no dash).
\. # Each part followed by literal dot.
)* # One or more parts before top level domain.
(?: # Explicitly specify top level domains.
com|edu|gov|int|mil|net|org|biz|
info|name|pro|aero|coop|museum|
asia|cat|jobs|mobi|tel|travel|
[A-Za-z]{2}) # Country codes are exqactly two alpha chars.
$ # Anchor to end of string.
/ix', $m['host'])) return FALSE;
}
$m['url'] = $url;
for ($i = 0; isset($m[$i]); ++$i) unset($m[$i]);
return $m; // return TRUE == array of useful named $matches plus the valid $url.
}
//
// Replace string matching regular expression
//
// This function takes care of possibly disabled unicode properties in PCRE builds
//
function ucp_preg_replace($pattern, $replace, $subject)
{
$replaced = preg_replace($pattern, $replace, $subject);
// If preg_replace() returns false, this probably means unicode support is not built-in, so we need to modify the pattern a little
if ($replaced === false)
{
if (is_array($pattern))
{
foreach ($pattern as $cur_key => $cur_pattern)
$pattern[$cur_key] = str_replace('\p{L}\p{N}', '\w', $cur_pattern);
$replaced = preg_replace($pattern, $replace, $subject);
}
else
$replaced = preg_replace(str_replace('\p{L}\p{N}', '\w', $pattern), $replace, $subject);
}
return $replaced;
}
// DEBUG FUNCTIONS BELOW
//
// Display executed queries (if enabled)
//
function display_saved_queries()
{
global $db, $lang_common;
// Get the queries so that we can print them out
$saved_queries = $db->get_saved_queries();
?>
<div id="debug" class="blocktable">
<h2><span><?php echo $lang_common['Debug table'] ?></span></h2>
<div class="box">
<div class="inbox">
<table cellspacing="0">
<thead>
<tr>
<th class="tcl" scope="col"><?php echo $lang_common['Query times'] ?></th>
<th class="tcr" scope="col"><?php echo $lang_common['Query'] ?></th>
</tr>
</thead>
<tbody>
<?php
$query_time_total = 0.0;
foreach ($saved_queries as $cur_query)
{
$query_time_total += $cur_query[1];
?>
<tr>
<td class="tcl"><?php echo ($cur_query[1] != 0) ? $cur_query[1] : ' ' ?></td>
<td class="tcr"><?php echo pun_htmlspecialchars($cur_query[0]) ?></td>
</tr>
<?php
}
?>
<tr>
<td class="tcl" colspan="2"><?php printf($lang_common['Total query time'], $query_time_total.' s') ?></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?php
}
//
// Dump contents of variable(s)
//
function dump()
{
echo '<pre>';
$num_args = func_num_args();
for ($i = 0; $i < $num_args; ++$i)
{
print_r(func_get_arg($i));
echo "\n\n";
}
echo '</pre>';
exit;
}fichier 2 : Concerne le problème d'affichage des images devant chaque forum sur l'index. en clair le mod qu'a fait wan et que j'ai adapté en fonction de mon code. Au risque de me répéter ce problème là est vraiment secondaire pour moi car j'ai plus une préférence pour l'affichage en bannière que devant chaque forum.
Mais si ça peut servir à d'autres...
<?php
/**
* Copyright (C) 2008-2011 FluxBB
* based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
*/
//
// Return current timestamp (with microseconds) as a float
//
function get_microtime()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
//
// Cookie stuff!
//
function check_cookie(&$pun_user)
{
global $db, $db_type, $pun_config, $cookie_name, $cookie_seed;
$now = time();
// If the cookie is set and it matches the correct pattern, then read the values from it
if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
{
$cookie = array(
'user_id' => intval($matches[1]),
'password_hash' => $matches[2],
'expiration_time' => intval($matches[3]),
'cookie_hash' => $matches[4],
);
}
// If it has a non-guest user, and hasn't expired
if (isset($cookie) && $cookie['user_id'] > 1 && $cookie['expiration_time'] > $now)
{
// If the cookie has been tampered with
if (forum_hmac($cookie['user_id'].'|'.$cookie['expiration_time'], $cookie_seed.'_cookie_hash') != $cookie['cookie_hash'])
{
$expire = $now + 31536000; // The cookie expires after a year
pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
set_default_user();
return;
}
// Check if there's a user with the user ID and password hash from the cookie
$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());
$pun_user = $db->fetch_assoc($result);
// If user authorisation failed
if (!isset($pun_user['id']) || forum_hmac($pun_user['password'], $cookie_seed.'_password_hash') !== $cookie['password_hash'])
{
$expire = $now + 31536000; // The cookie expires after a year
pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
set_default_user();
return;
}
// Send a new, updated cookie with a new expiration timestamp
$expire = ($cookie['expiration_time'] > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit'];
pun_setcookie($pun_user['id'], $pun_user['password'], $expire);
// Set a default language if the user selected language no longer exists
if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
$pun_user['language'] = $pun_config['o_default_lang'];
// Set a default style if the user selected style no longer exists
if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
$pun_user['style'] = $pun_config['o_default_style'];
if (!$pun_user['disp_topics'])
$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
if (!$pun_user['disp_posts'])
$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
// Define this if you want this visit to affect the online list and the users last visit data
if (!defined('PUN_QUIET_VISIT'))
{
// Update the online list
if (!$pun_user['logged'])
{
$pun_user['logged'] = $now;
// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
switch ($db_type)
{
case 'mysql':
case 'mysqli':
case 'mysql_innodb':
case 'mysqli_innodb':
case 'sqlite':
$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());
break;
default:
$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());
break;
}
// Reset tracked topics
set_tracked_topics(null);
}
else
{
// Special case: We've timed out, but no other user has browsed the forums since we timed out
if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
{
$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());
$pun_user['last_visit'] = $pun_user['logged'];
}
$idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : '';
$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());
// Update tracked topics with the current expire time
if (isset($_COOKIE[$cookie_name.'_track']))
forum_setcookie($cookie_name.'_track', $_COOKIE[$cookie_name.'_track'], $now + $pun_config['o_timeout_visit']);
}
}
else
{
if (!$pun_user['logged'])
$pun_user['logged'] = $pun_user['last_visit'];
}
$pun_user['is_guest'] = false;
$pun_user['is_admmod'] = $pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1';
}
else
set_default_user();
}
//
// Converts the CDATA end sequence ]]> into ]]>
//
function escape_cdata($str)
{
return str_replace(']]>', ']]>', $str);
}
//
// Authenticates the provided username and password against the user database
// $user can be either a user ID (integer) or a username (string)
// $password can be either a plaintext password or a password hash including salt ($password_is_hash must be set accordingly)
//
function authenticate_user($user, $password, $password_is_hash = false)
{
global $db, $pun_user;
// Check if there's a user matching $user and $password
$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());
$pun_user = $db->fetch_assoc($result);
if (!isset($pun_user['id']) ||
($password_is_hash && $password != $pun_user['password']) ||
(!$password_is_hash && pun_hash($password) != $pun_user['password']))
set_default_user();
else
$pun_user['is_guest'] = false;
}
//
// Try to determine the current URL
//
function get_current_url($max_length = 0)
{
$protocol = get_current_protocol();
$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'] : '';
$url = urldecode($protocol.'://'.$_SERVER['HTTP_HOST'].$port.$_SERVER['REQUEST_URI']);
if (strlen($url) <= $max_length || $max_length == 0)
return $url;
// We can't find a short enough url
return null;
}
//
// Fetch the current protocol in use - http or https
//
function get_current_protocol()
{
$protocol = 'http';
// Check if the server is claiming to using HTTPS
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off')
$protocol = 'https';
// If we are behind a reverse proxy try to decide which protocol it is using
if (defined('FORUM_BEHIND_REVERSE_PROXY'))
{
// Check if we are behind a Microsoft based reverse proxy
if (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) != 'off')
$protocol = 'https';
// Check if we're behind a "proper" reverse proxy, and what protocol it's using
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']))
$protocol = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
}
return $protocol;
}
//
// Fetch the base_url, optionally support HTTPS and HTTP
//
function get_base_url($support_https = false)
{
global $pun_config;
static $base_url;
if (!$support_https)
return $pun_config['o_base_url'];
if (!isset($base_url))
{
// Make sure we are using the correct protocol
$base_url = str_replace(array('http://', 'https://'), get_current_protocol().'://', $pun_config['o_base_url']);
}
return $base_url;
}
//
// Fill $pun_user with default values (for guests)
//
function set_default_user()
{
global $db, $db_type, $pun_user, $pun_config;
$remote_addr = get_remote_address();
// Fetch guest user
$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());
if (!$db->num_rows($result))
exit('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
$pun_user = $db->fetch_assoc($result);
// Update online list
if (!$pun_user['logged'])
{
$pun_user['logged'] = time();
// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
switch ($db_type)
{
case 'mysql':
case 'mysqli':
case 'mysql_innodb':
case 'mysqli_innodb':
case 'sqlite':
$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());
break;
default:
$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());
break;
}
}
else
$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());
$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
$pun_user['timezone'] = $pun_config['o_default_timezone'];
$pun_user['dst'] = $pun_config['o_default_dst'];
$pun_user['language'] = $pun_config['o_default_lang'];
$pun_user['style'] = $pun_config['o_default_style'];
$pun_user['is_guest'] = true;
$pun_user['is_admmod'] = false;
}
//
// SHA1 HMAC with PHP 4 fallback
//
function forum_hmac($data, $key, $raw_output = false)
{
if (function_exists('hash_hmac'))
return hash_hmac('sha1', $data, $key, $raw_output);
// If key size more than blocksize then we hash it once
if (strlen($key) > 64)
$key = pack('H*', sha1($key)); // we have to use raw output here to match the standard
// Ensure we're padded to exactly one block boundary
$key = str_pad($key, 64, chr(0x00));
$hmac_opad = str_repeat(chr(0x5C), 64);
$hmac_ipad = str_repeat(chr(0x36), 64);
// Do inner and outer padding
for ($i = 0;$i < 64;$i++) {
$hmac_opad[$i] = $hmac_opad[$i] ^ $key[$i];
$hmac_ipad[$i] = $hmac_ipad[$i] ^ $key[$i];
}
// Finally, calculate the HMAC
$hash = sha1($hmac_opad.pack('H*', sha1($hmac_ipad.$data)));
// If we want raw output then we need to pack the final result
if ($raw_output)
$hash = pack('H*', $hash);
return $hash;
}
//
// Set a cookie, FluxBB style!
// Wrapper for forum_setcookie
//
function pun_setcookie($user_id, $password_hash, $expire)
{
global $cookie_name, $cookie_seed;
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);
}
//
// Set a cookie, FluxBB style!
//
function forum_setcookie($name, $value, $expire)
{
global $cookie_path, $cookie_domain, $cookie_secure;
// Enable sending of a P3P header
header('P3P: CP="CUR ADM"');
if (version_compare(PHP_VERSION, '5.2.0', '>='))
setcookie($name, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, true);
else
setcookie($name, $value, $expire, $cookie_path.'; HttpOnly', $cookie_domain, $cookie_secure);
}
//
// Check whether the connecting user is banned (and delete any expired bans while we're at it)
//
function check_bans()
{
global $db, $pun_config, $lang_common, $pun_user, $pun_bans;
// Admins and moderators aren't affected
if ($pun_user['is_admmod'] || !$pun_bans)
return;
// Add a dot or a colon (depending on IPv4/IPv6) at the end of the IP address to prevent banned address
// 192.168.0.5 from matching e.g. 192.168.0.50
$user_ip = get_remote_address();
$user_ip .= (strpos($user_ip, '.') !== false) ? '.' : ':';
$bans_altered = false;
$is_banned = false;
foreach ($pun_bans as $cur_ban)
{
// Has this ban expired?
if ($cur_ban['expire'] != '' && $cur_ban['expire'] <= time())
{
$db->query('DELETE FROM '.$db->prefix.'bans WHERE id='.$cur_ban['id']) or error('Unable to delete expired ban', __FILE__, __LINE__, $db->error());
$bans_altered = true;
continue;
}
if ($cur_ban['username'] != '' && utf8_strtolower($pun_user['username']) == utf8_strtolower($cur_ban['username']))
$is_banned = true;
if ($cur_ban['ip'] != '')
{
$cur_ban_ips = explode(' ', $cur_ban['ip']);
$num_ips = count($cur_ban_ips);
for ($i = 0; $i < $num_ips; ++$i)
{
// Add the proper ending to the ban
if (strpos($user_ip, '.') !== false)
$cur_ban_ips[$i] = $cur_ban_ips[$i].'.';
else
$cur_ban_ips[$i] = $cur_ban_ips[$i].':';
if (substr($user_ip, 0, strlen($cur_ban_ips[$i])) == $cur_ban_ips[$i])
{
$is_banned = true;
break;
}
}
}
if ($is_banned)
{
$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());
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);
}
}
// If we removed any expired bans during our run-through, we need to regenerate the bans cache
if ($bans_altered)
{
if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
require PUN_ROOT.'include/cache.php';
generate_bans_cache();
}
}
//
// Check username
//
function check_username($username, $exclude_id = null)
{
global $db, $pun_config, $errors, $lang_prof_reg, $lang_register, $lang_common, $pun_bans;
// Convert multiple whitespace characters into one (to prevent people from registering with indistinguishable usernames)
$username = preg_replace('%\s+%s', ' ', $username);
// Validate username
if (pun_strlen($username) < 2)
$errors[] = $lang_prof_reg['Username too short'];
else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters
$errors[] = $lang_prof_reg['Username too long'];
else if (!strcasecmp($username, 'Guest') || !strcasecmp($username, $lang_common['Guest']))
$errors[] = $lang_prof_reg['Username guest'];
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))
$errors[] = $lang_prof_reg['Username IP'];
else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
$errors[] = $lang_prof_reg['Username reserved chars'];
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))
$errors[] = $lang_prof_reg['Username BBCode'];
/* FluxToolBar */
if (file_exists(FORUM_CACHE_DIR.'cache_fluxtoolbar_tag_check.php'))
include FORUM_CACHE_DIR.'cache_fluxtoolbar_tag_check.php';
else
{
require_once PUN_ROOT.'include/cache_fluxtoolbar.php';
generate_ftb_cache('tags');
require FORUM_CACHE_DIR.'cache_fluxtoolbar_tag_check.php';
}
// Check username for any censored words
if ($pun_config['o_censoring'] == '1' && censor_words($username) != $username)
$errors[] = $lang_register['Username censor'];
// Check that the username (or a too similar username) is not already registered
$query = ($exclude_id) ? ' AND id!='.$exclude_id : '';
$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());
if ($db->num_rows($result))
{
$busy = $db->result($result);
$errors[] = $lang_register['Username dupe 1'].' '.pun_htmlspecialchars($busy).'. '.$lang_register['Username dupe 2'];
}
// Check username for any banned usernames
foreach ($pun_bans as $cur_ban)
{
if ($cur_ban['username'] != '' && utf8_strtolower($username) == utf8_strtolower($cur_ban['username']))
{
$errors[] = $lang_prof_reg['Banned username'];
break;
}
}
}
//
// Update "Users online"
//
function update_users_online()
{
global $db, $pun_config;
$now = time();
// Fetch all online list entries that are older than "o_timeout_online"
$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());
while ($cur_user = $db->fetch_assoc($result))
{
// If the entry is a guest, delete it
if ($cur_user['user_id'] == '1')
$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());
else
{
// If the entry is older than "o_timeout_visit", update last_visit for the user in question, then delete him/her from the online list
if ($cur_user['logged'] < ($now-$pun_config['o_timeout_visit']))
{
$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());
$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());
}
else if ($cur_user['idle'] == '0')
$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());
}
}
}
//
// Display the profile navigation menu
//
function generate_profile_menu($page = '')
{
global $lang_profile, $pun_config, $pun_user, $id;
?>
<div id="profile" class="block2col">
<div class="blockmenu">
<h2><span><?php echo $lang_profile['Profile menu'] ?></span></h2>
<div class="box">
<div class="inbox">
<ul>
<li<?php if ($page == 'essentials') echo ' class="isactive"'; ?>><a href="profile.php?section=essentials&id=<?php echo $id ?>"><?php echo $lang_profile['Section essentials'] ?></a></li>
<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>
<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>
<?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>
<?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>
<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>
<?php if ($pun_user['id'] == $id): ?> <li<?php if ($page == 'loginza') echo ' class="isactive"'; ?>><a href="reglog.php">Loginza</a></li>
<?php endif; ?>
<?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>
<?php endif; ?>
<?php
// See if there are any plugiles
$plugiles = array();
$d = dir(PUN_ROOT.'plugiles');
while (($entry = $d->read()) !== false)
{
$prefix = substr($entry, 0, strpos($entry, '_'));
$suffix = substr($entry, strlen($entry) - 4);
// UP <=> User Plugile (visible par tous) - UPP <=> User Private Plugile (visible par le membre et les administrateurs)
if ($suffix == '.php' && ($prefix == 'UP' || $prefix == 'UPP'))
$plugiles[] = array(substr(substr($entry, strpos($entry, '_') + 1), 0, -4), $entry);
}
$d->close();
// Did we find any plugiles?
if (!empty($plugiles))
{
if($pun_config['o_plugile_menu'] == '1')
{
?>
</ul>
</div>
</div>
<h2><span><?php echo $pun_config['o_plugile_menu_name'] ?></span></h2>
<div class="box">
<div class="inbox">
<ul>
<?php
}
while (list(, $cur_plugile) = @each($plugiles))
echo "\t\t\t\t\t".'<li'.(($page == $cur_plugile[1]) ? ' class="isactive"' : '').'><a href="profile.php?plugin='.$cur_plugile[1].'&id='.$id.'">'.str_replace('_', ' ', $cur_plugile[0]).'</a></li>'."\n";
?>
</ul>
</div>
</div>
</div>
<?php
}
}
//
// Outputs markup to display a user's avatar
//
function generate_avatar_markup($user_id)
{
global $pun_config;
$filetypes = array('jpg', 'gif', 'png');
$avatar_markup = '';
foreach ($filetypes as $cur_type)
{
$path = $pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type;
if (file_exists(PUN_ROOT.$path) && $img_size = getimagesize(PUN_ROOT.$path))
{
$avatar_markup = '<img src="'.pun_htmlspecialchars(get_base_url(true).'/'.$path.'?m='.filemtime(PUN_ROOT.$path)).'" '.$img_size[3].' alt="" />';
break;
}
}
return $avatar_markup;
}
//
// Generate browser's title
//
function generate_page_title($page_title, $p = null)
{
global $pun_config, $lang_common;
$page_title = array_reverse($page_title);
if ($p != null)
$page_title[0] .= ' ('.sprintf($lang_common['Page'], forum_number_format($p)).')';
$crumbs = implode($lang_common['Title separator'], $page_title);
return $crumbs;
}
//
// Save array of tracked topics in cookie
//
function set_tracked_topics($tracked_topics)
{
global $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $pun_config;
$cookie_data = '';
if (!empty($tracked_topics))
{
// Sort the arrays (latest read first)
arsort($tracked_topics['topics'], SORT_NUMERIC);
arsort($tracked_topics['forums'], SORT_NUMERIC);
// Homebrew serialization (to avoid having to run unserialize() on cookie data)
foreach ($tracked_topics['topics'] as $id => $timestamp)
$cookie_data .= 't'.$id.'='.$timestamp.';';
foreach ($tracked_topics['forums'] as $id => $timestamp)
$cookie_data .= 'f'.$id.'='.$timestamp.';';
// Enforce a byte size limit (4096 minus some space for the cookie name - defaults to 4048)
if (strlen($cookie_data) > FORUM_MAX_COOKIE_SIZE)
{
$cookie_data = substr($cookie_data, 0, FORUM_MAX_COOKIE_SIZE);
$cookie_data = substr($cookie_data, 0, strrpos($cookie_data, ';')).';';
}
}
forum_setcookie($cookie_name.'_track', $cookie_data, time() + $pun_config['o_timeout_visit']);
$_COOKIE[$cookie_name.'_track'] = $cookie_data; // Set it directly in $_COOKIE as well
}
//
// Extract array of tracked topics from cookie
//
function get_tracked_topics()
{
global $cookie_name;
$cookie_data = isset($_COOKIE[$cookie_name.'_track']) ? $_COOKIE[$cookie_name.'_track'] : false;
if (!$cookie_data)
return array('topics' => array(), 'forums' => array());
if (strlen($cookie_data) > 4048)
return array('topics' => array(), 'forums' => array());
// Unserialize data from cookie
$tracked_topics = array('topics' => array(), 'forums' => array());
$temp = explode(';', $cookie_data);
foreach ($temp as $t)
{
$type = substr($t, 0, 1) == 'f' ? 'forums' : 'topics';
$id = intval(substr($t, 1));
$timestamp = intval(substr($t, strpos($t, '=') + 1));
if ($id > 0 && $timestamp > 0)
$tracked_topics[$type][$id] = $timestamp;
}
return $tracked_topics;
}
//
// Detect all images in a message (return an array with the number of images and all their url's)
//
function detect_image($message)
{
$list_img [0] = 0;
$list_img_tmp = array();
preg_match_all('%\[img\]((ht|)tps?://[^\s<"]*?)\[/img\]%e', $message, $list_img_tmp, PREG_SET_ORDER);
if (sizeof($list_img_tmp) > 0)
foreach($list_img_tmp as $img)
{
$list_img [0] += 1;
$list_img [] = $img[1];
}
return $list_img;
}
//
// Update posts, topics, last_post, last_post_id and last_poster for a forum
//
function update_forum($forum_id)
{
global $db;
$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());
list($num_topics, $num_posts) = $db->fetch_row($result);
$num_posts = $num_posts + $num_topics; // $num_posts is only the sum of all replies (we have to add the topic posts)
$result = $db->query('SELECT last_post, last_post_id, last_poster, subject, id, num_replies 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());
if ($db->num_rows($result)) // There are topics in the forum
{
list($last_post, $last_post_id, $last_poster, $last_msg, $last_img, $last_topic, $last_topic_id, $num_replies) = $db->fetch_row($result);
// Is there an image in the message of the last post ?...
$list_img = detect_image($last_msg);
if ($list_img[0] > 0) $last_img = $list_img[$list_img[0]];
// if not, have to find the last image posted in all the messages of all topics of the forum (if there is...)
elseif (!is_null($last_img))
{
$last_img = NULL;
$result = $db->query('SELECT p.message FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE t.forum_id='.$forum_id.' ORDER BY p.posted DESC') or error('Unable to fetch posts info', __FILE__, __LINE__, $db->error());
while ($tracked_post = $db->fetch_assoc($result))
{
$list_img = detect_image($tracked_post['message']);
if ($list_img[0] > 0)
{
$last_img = $list_img[$list_img[0]];
break;
}
}
}
$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.', num_replies='.$num_replies.', last_topic_id='.$last_topic_id.', last_poster=\''.$db->escape($last_poster).'\', last_topic=\''.$db->escape($last_topic).'\', last_img='.(is_null($last_img) ? 'NULL' : '\''.$db->escape($last_img).'\'').' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_img', __FILE__, __LINE__, $db->error());
}
else // There are no topics
$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, last_topic=NULL, last_topic_id=NULL, num_replies=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster/last_topic', __FILE__, __LINE__, $db->error());
}
//
// Deletes any avatars owned by the specified user ID
//
function delete_avatar($user_id)
{
global $pun_config;
$filetypes = array('jpg', 'gif', 'png');
// Delete user avatar
foreach ($filetypes as $cur_type)
{
if (file_exists(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type))
@unlink(PUN_ROOT.$pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type);
}
}
//
// Delete a topic and all of it's posts
//
function delete_topic($topic_id)
{
global $db;
// Delete the topic and any redirect topics
$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());
// Create a list of the post IDs in this topic
$post_ids = '';
$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
while ($row = $db->fetch_row($result))
$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
// Make sure we have a list of post IDs
if ($post_ids != '')
{
strip_search_index($post_ids);
// Delete posts in topic
$db->query('DELETE FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to delete posts', __FILE__, __LINE__, $db->error());
}
// Delete any subscriptions for this topic
$db->query('DELETE FROM '.$db->prefix.'topic_subscriptions WHERE topic_id='.$topic_id) or error('Unable to delete subscriptions', __FILE__, __LINE__, $db->error());
}
//
// Delete a single post
//
function delete_post($post_id, $topic_id)
{
global $db;
$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());
list($last_id, ,) = $db->fetch_row($result);
list($second_last_id, $second_poster, $second_posted) = $db->fetch_row($result);
// Delete the post
$db->query('DELETE FROM '.$db->prefix.'posts WHERE id='.$post_id) or error('Unable to delete post', __FILE__, __LINE__, $db->error());
strip_search_index($post_id);
// Count number of replies in the topic
$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());
$num_replies = $db->result($result, 0) - 1;
// If the message we deleted is the most recent in the topic (at the end of the topic)
if ($last_id == $post_id)
{
// If there is a $second_last_id there is more than 1 reply to the topic
if (!empty($second_last_id))
$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());
else
// We deleted the only reply, so now last_post/last_post_id/last_poster is posted/id/poster from the topic itself
$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());
}
else
// Otherwise we just decrement the reply counter
$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());
}
//
// Delete every .php file in the forum's cache directory
//
function forum_clear_cache()
{
$d = dir(FORUM_CACHE_DIR);
while (($entry = $d->read()) !== false)
{
if (substr($entry, -4) == '.php')
@unlink(FORUM_CACHE_DIR.$entry);
}
$d->close();
}
//
// Replace censored words in $text
//
function censor_words($text)
{
global $db;
static $search_for, $replace_with;
// If not already built in a previous call, build an array of censor words and their replacement text
if (!isset($search_for))
{
if (file_exists(FORUM_CACHE_DIR.'cache_censoring.php'))
include FORUM_CACHE_DIR.'cache_censoring.php';
if (!defined('PUN_CENSOR_LOADED'))
{
if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
require PUN_ROOT.'include/cache.php';
generate_censoring_cache();
require FORUM_CACHE_DIR.'cache_censoring.php';
}
}
if (!empty($search_for))
$text = substr(ucp_preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1);
return $text;
}
//
// Determines the correct title for $user
// $user must contain the elements 'username', 'title', 'posts', 'g_id' and 'g_user_title'
//
function get_title($user)
{
global $db, $pun_config, $pun_bans, $lang_common;
static $ban_list, $pun_ranks;
// If not already built in a previous call, build an array of lowercase banned usernames
if (empty($ban_list))
{
$ban_list = array();
foreach ($pun_bans as $cur_ban)
$ban_list[] = strtolower($cur_ban['username']);
}
// If not already loaded in a previous call, load the cached ranks
if ($pun_config['o_ranks'] == '1' && !defined('PUN_RANKS_LOADED'))
{
if (file_exists(FORUM_CACHE_DIR.'cache_ranks.php'))
include FORUM_CACHE_DIR.'cache_ranks.php';
if (!defined('PUN_RANKS_LOADED'))
{
if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
require PUN_ROOT.'include/cache.php';
generate_ranks_cache();
require FORUM_CACHE_DIR.'cache_ranks.php';
}
}
// If the user has a custom title
if ($user['title'] != '')
$user_title = pun_htmlspecialchars($user['title']);
// If the user is banned
else if (in_array(strtolower($user['username']), $ban_list))
$user_title = $lang_common['Banned'];
// If the user group has a default user title
else if ($user['g_user_title'] != '')
$user_title = pun_htmlspecialchars($user['g_user_title']);
// If the user is a guest
else if ($user['g_id'] == PUN_GUEST)
$user_title = $lang_common['Guest'];
else
{
// Are there any ranks?
if ($pun_config['o_ranks'] == '1' && !empty($pun_ranks))
{
foreach ($pun_ranks as $cur_rank)
{
if ($user['num_posts'] >= $cur_rank['min_posts'])
$user_title = pun_htmlspecialchars($cur_rank['rank']);
}
}
// If the user didn't "reach" any rank (or if ranks are disabled), we assign the default
if (!isset($user_title))
$user_title = $lang_common['Member'];
}
return $user_title;
}
//
// Generate a string with numbered links (for multipage scripts)
//
function paginate($num_pages, $cur_page, $link)
{
global $lang_common;
$pages = array();
$link_to_all = false;
// If $cur_page == -1, we link to all pages (used in viewforum.php)
if ($cur_page == -1)
{
$cur_page = 1;
$link_to_all = true;
}
if ($num_pages <= 1)
$pages = array('<strong class="item1">1</strong>');
else
{
// Add a previous page link
if ($num_pages > 1 && $cur_page > 1)
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.($cur_page - 1).'">'.$lang_common['Previous'].'</a>';
if ($cur_page > 3)
{
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p=1">1</a>';
if ($cur_page > 5)
$pages[] = '<span class="spacer">'.$lang_common['Spacer'].'</span>';
}
// Don't ask me how the following works. It just does, OK? :-)
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)
{
if ($current < 1 || $current > $num_pages)
continue;
else if ($current != $cur_page || $link_to_all)
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.$current.'">'.forum_number_format($current).'</a>';
else
$pages[] = '<strong'.(empty($pages) ? ' class="item1"' : '').'>'.forum_number_format($current).'</strong>';
}
if ($cur_page <= ($num_pages-3))
{
if ($cur_page != ($num_pages-3) && $cur_page != ($num_pages-4))
$pages[] = '<span class="spacer">'.$lang_common['Spacer'].'</span>';
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.$num_pages.'">'.forum_number_format($num_pages).'</a>';
}
// Add a next page link
if ($num_pages > 1 && !$link_to_all && $cur_page < $num_pages)
$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&p='.($cur_page +1).'">'.$lang_common['Next'].'</a>';
}
return implode(' ', $pages);
}
//
// Display a message
//
function message($message, $no_back_link = false)
{
global $db, $lang_common, $pun_config, $pun_start, $tpl_main, $pun_user;
if (!defined('PUN_HEADER'))
{
$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Info']);
define('PUN_ACTIVE_PAGE', 'index');
require PUN_ROOT.'header.php';
}
?>
<div id="msg" class="block">
<h2><span><?php echo $lang_common['Info'] ?></span></h2>
<div class="box">
<div class="inbox">
<p><?php echo $message ?></p>
<?php if (!$no_back_link): ?> <p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
<?php endif; ?> </div>
</div>
</div>
<?php
require PUN_ROOT.'footer.php';
}
//
// Format a time string according to $time_format and time zones
//
function format_time($timestamp, $date_only = false, $date_format = null, $time_format = null, $time_only = false, $no_text = false)
{
global $pun_config, $lang_common, $pun_user, $forum_date_formats, $forum_time_formats;
if ($timestamp == '')
return $lang_common['Never'];
$diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
$timestamp += $diff;
$now = time();
if($date_format == null)
$date_format = $forum_date_formats[$pun_user['date_format']];
if($time_format == null)
$time_format = $forum_time_formats[$pun_user['time_format']];
$date = gmdate($date_format, $timestamp);
$today = gmdate($date_format, $now+$diff);
$yesterday = gmdate($date_format, $now+$diff-86400);
if(!$no_text)
{
if ($date == $today)
$date = $lang_common['Today'];
else if ($date == $yesterday)
$date = $lang_common['Yesterday'];
}
if ($date_only)
return $date;
else if ($time_only)
return gmdate($time_format, $timestamp);
else
return $date.' '.gmdate($time_format, $timestamp);
}
//
// A wrapper for PHP's number_format function
//
function forum_number_format($number, $decimals = 0)
{
global $lang_common;
return is_numeric($number) ? number_format($number, $decimals, $lang_common['lang_decimal_point'], $lang_common['lang_thousands_sep']) : $number;
}
//
// Generate a random key of length $len
//
function random_key($len, $readable = false, $hash = false)
{
$key = '';
if ($hash)
$key = substr(pun_hash(uniqid(rand(), true)), 0, $len);
else if ($readable)
{
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for ($i = 0; $i < $len; ++$i)
$key .= substr($chars, (mt_rand() % strlen($chars)), 1);
}
else
{
for ($i = 0; $i < $len; ++$i)
$key .= chr(mt_rand(33, 126));
}
return $key;
}
//
// Make sure that HTTP_REFERER matches base_url/script
//
function confirm_referrer($script, $error_msg = false)
{
global $pun_config, $lang_common;
static $rewrites = array('viewtopic.php' => 'topic-', 'viewforum.php' => 'forum-', 'post.php' => 'message-');
// There is no referrer
if (empty($_SERVER['HTTP_REFERER']))
message($error_msg ? $error_msg : $lang_common['Bad referrer']);
$referrer = parse_url(strtolower($_SERVER['HTTP_REFERER']));
// Remove www subdomain if it exists
if (strpos($referrer['host'], 'www.') === 0)
$referrer['host'] = substr($referrer['host'], 4);
$valid = parse_url(strtolower(get_base_url().'/'.$script));
// Remove www subdomain if it exists
if (strpos($valid['host'], 'www.') === 0)
$valid['host'] = substr($valid['host'], 4);
// Check the host and path match. Ignore the scheme, port, etc.
if ($referrer['host'] != $valid['host'] || $referrer['path'] != $valid['path'])
{
if (array_key_exists($script, $rewrites))
{
if (!preg_match('#^'.get_base_url().'/'.$rewrites[$script].'[0-9]+-[0-9|a-b|\-|\.]*(.?)#i', strtolower($_SERVER['HTTP_REFERER'])))
message($lang_common['Bad referrer']);
}
else
message($lang_common['Bad referrer']);
}
}
//
// Generate a random password of length $len
// Compatibility wrapper for random_key
//
function random_pass($len)
{
return random_key($len, true);
}
//
// Compute a hash of $str
//
function pun_hash($str)
{
return sha1($str);
}
//
// Try to determine the correct remote IP-address
//
function get_remote_address()
{
$remote_addr = $_SERVER['REMOTE_ADDR'];
// If we are behind a reverse proxy try to find the real users IP
if (defined('FORUM_BEHIND_REVERSE_PROXY'))
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
// The general format of the field is:
// X-Forwarded-For: client1, proxy1, proxy2
// where the value is a comma+space separated list of IP addresses, the left-most being the farthest downstream client,
// and each successive proxy that passed the request adding the IP address where it received the request from.
$forwarded_for = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$forwarded_for = trim($forwarded_for[0]);
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))
$remote_addr = $forwarded_for;
}
}
return $remote_addr;
}
//
// Calls htmlspecialchars with a few options already set
//
function pun_htmlspecialchars($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
//
// Calls htmlspecialchars_decode with a few options already set
//
function pun_htmlspecialchars_decode($str)
{
if (function_exists('htmlspecialchars_decode'))
return htmlspecialchars_decode($str, ENT_QUOTES);
static $translations;
if (!isset($translations))
{
$translations = get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES);
$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
$translations = array_flip($translations);
}
return strtr($str, $translations);
}
//
// A wrapper for utf8_strlen for compatibility
//
function pun_strlen($str)
{
return utf8_strlen($str);
}
//
// Convert \r\n and \r to \n
//
function pun_linebreaks($str)
{
return str_replace("\r", "\n", str_replace("\r\n", "\n", $str));
}
//
// A wrapper for utf8_trim for compatibility
//
function pun_trim($str, $charlist = false)
{
return utf8_trim($str, $charlist);
}
//
// Checks if a string is in all uppercase
//
function is_all_uppercase($string)
{
return utf8_strtoupper($string) == $string && utf8_strtolower($string) != $string;
}
//
// Inserts $element into $input at $offset
// $offset can be either a numerical offset to insert at (eg: 0 inserts at the beginning of the array)
// or a string, which is the key that the new element should be inserted before
// $key is optional: it's used when inserting a new key/value pair into an associative array
//
function array_insert(&$input, $offset, $element, $key = null)
{
if ($key == null)
$key = $offset;
// Determine the proper offset if we're using a string
if (!is_int($offset))
$offset = array_search($offset, array_keys($input), true);
// Out of bounds checks
if ($offset > count($input))
$offset = count($input);
else if ($offset < 0)
$offset = 0;
$input = array_merge(array_slice($input, 0, $offset), array($key => $element), array_slice($input, $offset));
}
//
// Display a message when board is in maintenance mode
//
function maintenance_message()
{
global $db, $pun_config, $lang_common, $pun_user;
// Send no-cache headers
header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache'); // For HTTP/1.0 compatibility
// Send the Content-type header in case the web server is setup to send something else
header('Content-type: text/html; charset=utf-8');
// Deal with newlines, tabs and multiple spaces
$pattern = array("\t", ' ', ' ');
$replace = array('    ', '  ', '  ');
$message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl'))
{
$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl';
$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
}
else
{
$tpl_file = PUN_ROOT.'include/template/maintenance.tpl';
$tpl_inc_dir = PUN_ROOT.'include/user/';
}
$tpl_maint = file_get_contents($tpl_file);
// START SUBST - <pun_include "*">
preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_maint, $pun_includes, PREG_SET_ORDER);
foreach ($pun_includes as $cur_include)
{
ob_start();
// Allow for overriding user includes, too.
if (file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
require PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
else
error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file)));
$tpl_temp = ob_get_contents();
$tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint);
ob_end_clean();
}
// END SUBST - <pun_include "*">
// START SUBST - <pun_language>
$tpl_maint = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_maint);
// END SUBST - <pun_language>
// START SUBST - <pun_content_direction>
$tpl_maint = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_maint);
// END SUBST - <pun_content_direction>
// START SUBST - <pun_head>
ob_start();
$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Maintenance']);
?>
<title><?php echo generate_page_title($page_title) ?></title>
<link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_maint = str_replace('<pun_head>', $tpl_temp, $tpl_maint);
ob_end_clean();
// END SUBST - <pun_head>
// START SUBST - <pun_maint_main>
ob_start();
?>
<div class="block">
<h2><?php echo $lang_common['Maintenance'] ?></h2>
<div class="box">
<div class="inbox">
<p><?php echo $message ?></p>
</div>
</div>
</div>
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_maint = str_replace('<pun_maint_main>', $tpl_temp, $tpl_maint);
ob_end_clean();
// END SUBST - <pun_maint_main>
// End the transaction
$db->end_transaction();
// Close the db connection (and free up any result data)
$db->close();
exit($tpl_maint);
}
//
// Display $message and redirect user to $destination_url
//
function redirect($destination_url, $message)
{
global $db, $pun_config, $lang_common, $pun_user;
// Prefix with base_url (unless there's already a valid URI)
if (strpos($destination_url, 'http://') !== 0 && strpos($destination_url, 'https://') !== 0 && strpos($destination_url, '/') !== 0)
$destination_url = get_base_url(true).'/'.$destination_url;
// Do a little spring cleaning
$destination_url = preg_replace('%([\r\n])|(\%0[ad])|(;\s*data\s*:)%i', '', $destination_url);
// If the delay is 0 seconds, we might as well skip the redirect all together
if ($pun_config['o_redirect_delay'] == '0')
header('Location: '.str_replace('&', '&', $destination_url));
// Send no-cache headers
header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache'); // For HTTP/1.0 compatibility
// Send the Content-type header in case the web server is setup to send something else
header('Content-type: text/html; charset=utf-8');
if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl'))
{
$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl';
$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
}
else
{
$tpl_file = PUN_ROOT.'include/template/redirect.tpl';
$tpl_inc_dir = PUN_ROOT.'include/user/';
}
$tpl_redir = file_get_contents($tpl_file);
// START SUBST - <pun_include "*">
preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_redir, $pun_includes, PREG_SET_ORDER);
foreach ($pun_includes as $cur_include)
{
ob_start();
// Allow for overriding user includes, too.
if (file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
require PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
else
error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file)));
$tpl_temp = ob_get_contents();
$tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);
ob_end_clean();
}
// END SUBST - <pun_include "*">
// START SUBST - <pun_language>
$tpl_redir = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_redir);
// END SUBST - <pun_language>
// START SUBST - <pun_content_direction>
$tpl_redir = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_redir);
// END SUBST - <pun_content_direction>
// START SUBST - <pun_head>
ob_start();
$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Redirecting']);
?>
<meta http-equiv="refresh" content="<?php echo $pun_config['o_redirect_delay'] ?>;URL=<?php echo str_replace(array('<', '>', '"'), array('<', '>', '"'), $destination_url) ?>" />
<title><?php echo generate_page_title($page_title) ?></title>
<link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_redir = str_replace('<pun_head>', $tpl_temp, $tpl_redir);
ob_end_clean();
// END SUBST - <pun_head>
// START SUBST - <pun_redir_main>
ob_start();
?>
<div class="block">
<h2><?php echo $lang_common['Redirecting'] ?></h2>
<div class="box">
<div class="inbox">
<p><?php echo $message.'<br /><br /><a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>' ?></p>
</div>
</div>
</div>
<?php
$tpl_temp = trim(ob_get_contents());
$tpl_redir = str_replace('<pun_redir_main>', $tpl_temp, $tpl_redir);
ob_end_clean();
// END SUBST - <pun_redir_main>
// START SUBST - <pun_footer>
ob_start();
// End the transaction
$db->end_transaction();
// Display executed queries (if enabled)
if (defined('PUN_SHOW_QUERIES'))
display_saved_queries();
$tpl_temp = trim(ob_get_contents());
$tpl_redir = str_replace('<pun_footer>', $tpl_temp, $tpl_redir);
ob_end_clean();
// END SUBST - <pun_footer>
// Close the db connection (and free up any result data)
$db->close();
exit($tpl_redir);
}
//
// Display a simple error message
//
function error($message, $file = null, $line = null, $db_error = false)
{
global $pun_config, $lang_common;
// Set some default settings if the script failed before $pun_config could be populated
if (empty($pun_config))
{
$pun_config = array(
'o_board_title' => 'FluxBB',
'o_gzip' => '0'
);
}
// Set some default translations if the script failed before $lang_common could be populated
if (empty($lang_common))
{
$lang_common = array(
'Title separator' => ' / ',
'Page' => 'Page %s'
);
}
// Empty all output buffers and stop buffering
while (@ob_end_clean());
// "Restart" output buffering if we are using ob_gzhandler (since the gzip header is already sent)
if ($pun_config['o_gzip'] && extension_loaded('zlib'))
ob_start('ob_gzhandler');
// Send no-cache headers
header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache'); // For HTTP/1.0 compatibility
// Send the Content-type header in case the web server is setup to send something else
header('Content-type: text/html; charset=utf-8');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), 'Error') ?>
<title><?php echo generate_page_title($page_title) ?></title>
<style type="text/css">
<!--
BODY {MARGIN: 10% 20% auto 20%; font: 10px Verdana, Arial, Helvetica, sans-serif}
#errorbox {BORDER: 1px solid #B84623}
H2 {MARGIN: 0; COLOR: #FFFFFF; BACKGROUND-COLOR: #B84623; FONT-SIZE: 1.1em; PADDING: 5px 4px}
#errorbox DIV {PADDING: 6px 5px; BACKGROUND-COLOR: #F1F1F1}
-->
</style>
</head>
<body>
<div id="errorbox">
<h2>An error was encountered</h2>
<div>
<?php
if (defined('PUN_DEBUG') && $file !== null && $line !== null)
{
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";
if ($db_error)
{
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";
if ($db_error['error_sql'] != '')
echo "\t\t".'<br /><br /><strong>Failed query:</strong> '.pun_htmlspecialchars($db_error['error_sql'])."\n";
}
}
else
echo "\t\t".'Error: <strong>'.$message.'.</strong>'."\n";
?>
</div>
</div>
</body>
</html>
<?php
// If a database connection was established (before this error) we close it
if ($db_error)
$GLOBALS['db']->close();
exit;
}
//
// Unset any variables instantiated as a result of register_globals being enabled
//
function forum_unregister_globals()
{
$register_globals = ini_get('register_globals');
if ($register_globals === '' || $register_globals === '0' || strtolower($register_globals) === 'off')
return;
// Prevent script.php?GLOBALS[foo]=bar
if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))
exit('I\'ll have a steak sandwich and... a steak sandwich.');
// Variables that shouldn't be unset
$no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
// Remove elements in $GLOBALS that are present in any of the superglobals
$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
foreach ($input as $k => $v)
{
if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))
{
unset($GLOBALS[$k]);
unset($GLOBALS[$k]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
}
}
}
//
// Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from user input
//
function forum_remove_bad_characters()
{
$_GET = remove_bad_characters($_GET);
$_POST = remove_bad_characters($_POST);
$_COOKIE = remove_bad_characters($_COOKIE);
$_REQUEST = remove_bad_characters($_REQUEST);
}
//
// Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from the given string
// See: http://kb.mozillazine.org/Network.IDN.blacklist_chars
//
function remove_bad_characters($array)
{
static $bad_utf8_chars;
if (!isset($bad_utf8_chars))
{
$bad_utf8_chars = array(
"\xcc\xb7" => '', // COMBINING SHORT SOLIDUS OVERLAY 0337 *
"\xcc\xb8" => '', // COMBINING LONG SOLIDUS OVERLAY 0338 *
"\xe1\x85\x9F" => '', // HANGUL CHOSEONG FILLER 115F *
"\xe1\x85\xA0" => '', // HANGUL JUNGSEONG FILLER 1160 *
"\xe2\x80\x8b" => '', // ZERO WIDTH SPACE 200B *
"\xe2\x80\x8c" => '', // ZERO WIDTH NON-JOINER 200C
"\xe2\x80\x8d" => '', // ZERO WIDTH JOINER 200D
"\xe2\x80\x8e" => '', // LEFT-TO-RIGHT MARK 200E
"\xe2\x80\x8f" => '', // RIGHT-TO-LEFT MARK 200F
"\xe2\x80\xaa" => '', // LEFT-TO-RIGHT EMBEDDING 202A
"\xe2\x80\xab" => '', // RIGHT-TO-LEFT EMBEDDING 202B
"\xe2\x80\xac" => '', // POP DIRECTIONAL FORMATTING 202C
"\xe2\x80\xad" => '', // LEFT-TO-RIGHT OVERRIDE 202D
"\xe2\x80\xae" => '', // RIGHT-TO-LEFT OVERRIDE 202E
"\xe2\x80\xaf" => '', // NARROW NO-BREAK SPACE 202F *
"\xe2\x81\x9f" => '', // MEDIUM MATHEMATICAL SPACE 205F *
"\xe2\x81\xa0" => '', // WORD JOINER 2060
"\xe3\x85\xa4" => '', // HANGUL FILLER 3164 *
"\xef\xbb\xbf" => '', // ZERO WIDTH NO-BREAK SPACE FEFF
"\xef\xbe\xa0" => '', // HALFWIDTH HANGUL FILLER FFA0 *
"\xef\xbf\xb9" => '', // INTERLINEAR ANNOTATION ANCHOR FFF9 *
"\xef\xbf\xba" => '', // INTERLINEAR ANNOTATION SEPARATOR FFFA *
"\xef\xbf\xbb" => '', // INTERLINEAR ANNOTATION TERMINATOR FFFB *
"\xef\xbf\xbc" => '', // OBJECT REPLACEMENT CHARACTER FFFC *
"\xef\xbf\xbd" => '', // REPLACEMENT CHARACTER FFFD *
"\xe2\x80\x80" => ' ', // EN QUAD 2000 *
"\xe2\x80\x81" => ' ', // EM QUAD 2001 *
"\xe2\x80\x82" => ' ', // EN SPACE 2002 *
"\xe2\x80\x83" => ' ', // EM SPACE 2003 *
"\xe2\x80\x84" => ' ', // THREE-PER-EM SPACE 2004 *
"\xe2\x80\x85" => ' ', // FOUR-PER-EM SPACE 2005 *
"\xe2\x80\x86" => ' ', // SIX-PER-EM SPACE 2006 *
"\xe2\x80\x87" => ' ', // FIGURE SPACE 2007 *
"\xe2\x80\x88" => ' ', // PUNCTUATION SPACE 2008 *
"\xe2\x80\x89" => ' ', // THIN SPACE 2009 *
"\xe2\x80\x8a" => ' ', // HAIR SPACE 200A *
"\xE3\x80\x80" => ' ', // IDEOGRAPHIC SPACE 3000 *
);
}
if (is_array($array))
return array_map('remove_bad_characters', $array);
// Strip out any invalid characters
$array = utf8_bad_strip($array);
// Remove control characters
$array = preg_replace('%[\x{00}-\x{08}\x{0b}-\x{0c}\x{0e}-\x{1f}]%', '', $array);
// Replace some "bad" characters
$array = str_replace(array_keys($bad_utf8_chars), array_values($bad_utf8_chars), $array);
return $array;
}
//
// Converts the file size in bytes to a human readable file size
//
function file_size($size)
{
global $lang_common;
$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB');
for ($i = 0; $size > 1024; $i++)
$size /= 1024;
return sprintf($lang_common['Size unit '.$units[$i]], round($size, 2));;
}
//
// Fetch a list of available styles
//
function forum_list_styles()
{
$styles = array();
$d = dir(PUN_ROOT.'style');
while (($entry = $d->read()) !== false)
{
if ($entry{0} == '.')
continue;
if (substr($entry, -4) == '.css')
$styles[] = substr($entry, 0, -4);
}
$d->close();
natcasesort($styles);
return $styles;
}
//
// Fetch a list of available language packs
//
function forum_list_langs()
{
$languages = array();
$d = dir(PUN_ROOT.'lang');
while (($entry = $d->read()) !== false)
{
if ($entry{0} == '.')
continue;
if (is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php'))
$languages[] = $entry;
}
$d->close();
natcasesort($languages);
return $languages;
}
//
// Generate a cache ID based on the last modification time for all stopwords files
//
function generate_stopwords_cache_id()
{
$files = glob(PUN_ROOT.'lang/*/stopwords.txt');
if ($files === false)
return 'cache_id_error';
$hash = array();
foreach ($files as $file)
{
$hash[] = $file;
$hash[] = filemtime($file);
}
return sha1(implode('|', $hash));
}
//
// Fetch a list of available admin plugins
//
function forum_list_plugins($is_admin)
{
$plugins = array();
$d = dir(PUN_ROOT.'plugins');
while (($entry = $d->read()) !== false)
{
if ($entry{0} == '.')
continue;
$prefix = substr($entry, 0, strpos($entry, '_'));
$suffix = substr($entry, strlen($entry) - 4);
if ($suffix == '.php' && ((!$is_admin && $prefix == 'AMP') || ($is_admin && ($prefix == 'AP' || $prefix == 'AMP'))))
$plugins[$entry] = substr($entry, strpos($entry, '_') + 1, -4);
}
$d->close();
natcasesort($plugins);
return $plugins;
}
//
// Split text into chunks ($inside contains all text inside $start and $end, and $outside contains all text outside)
//
function split_text($text, $start, $end, &$errors, $retab = true)
{
global $pun_config, $lang_common;
$result = array(0 => array(), 1 => array()); // 0 = inside, 1 = outside
// split the text into parts
$parts = preg_split('%'.preg_quote($start, '%').'(.*)'.preg_quote($end, '%').'%Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$num_parts = count($parts);
// preg_split results in outside parts having even indices, inside parts having odd
for ($i = 0;$i < $num_parts;$i++)
$result[1 - ($i % 2)][] = $parts[$i];
if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
{
$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
$result[1] = str_replace("\t", $spaces, $result[1]);
}
return $result;
}
//
// Extract blocks from a text with a starting and ending string
// This function always matches the most outer block so nesting is possible
//
function extract_blocks($text, $start, $end, &$errors = array(), $retab = true)
{
global $pun_config;
$code = array();
$start_len = strlen($start);
$end_len = strlen($end);
$regex = '%(?:'.preg_quote($start, '%').'|'.preg_quote($end, '%').')%';
$matches = array();
if (preg_match_all($regex, $text, $matches))
{
$counter = $offset = 0;
$start_pos = $end_pos = false;
foreach ($matches[0] as $match)
{
if ($match == $start)
{
if ($counter == 0)
$start_pos = strpos($text, $start);
$counter++;
}
elseif ($match == $end)
{
$counter--;
if ($counter == 0)
$end_pos = strpos($text, $end, $offset + 1);
$offset = strpos($text, $end, $offset + 1);
}
if ($start_pos !== false && $end_pos !== false)
{
$code[] = substr($text, $start_pos + $start_len,
$end_pos - $start_pos - $start_len);
$text = substr_replace($text, "\1", $start_pos,
$end_pos - $start_pos + $end_len);
$start_pos = $end_pos = false;
$offset = 0;
}
}
}
if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
{
$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
$text = str_replace("\t", $spaces, $text);
}
return array($code, $text);
}
//
// function url_valid($url) {
//
// Return associative array of valid URI components, or FALSE if $url is not
// RFC-3986 compliant. If the passed URL begins with: "www." or "ftp.", then
// "http://" or "ftp://" is prepended and the corrected full-url is stored in
// the return array with a key name "url". This value should be used by the caller.
//
// Return value: FALSE if $url is not valid, otherwise array of URI components:
// e.g.
// Given: "http://www.jmrware.com:80/articles?height=10&width=75#fragone"
// Array(
// [scheme] => http
// [authority] => www.jmrware.com:80
// [userinfo] =>
// [host] => www.jmrware.com
// [IP_literal] =>
// [IPV6address] =>
// [ls32] =>
// [IPvFuture] =>
// [IPv4address] =>
// [regname] => www.jmrware.com
// [port] => 80
// [path_abempty] => /articles
// [query] => height=10&width=75
// [fragment] => fragone
// [url] => http://www.jmrware.com:80/articles?height=10&width=75#fragone
// )
function url_valid($url)
{
if (strpos($url, 'www.') === 0) $url = 'http://'. $url;
if (strpos($url, 'ftp.') === 0) $url = 'ftp://'. $url;
if (!preg_match('/# Valid absolute URI having a non-empty, valid DNS host.
^
(?P<scheme>[A-Za-z][A-Za-z0-9+\-.]*):\/\/
(?P<authority>
(?:(?P<userinfo>(?:[A-Za-z0-9\-._~!$&\'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?
(?P<host>
(?P<IP_literal>
\[
(?:
(?P<IPV6address>
(?: (?:[0-9A-Fa-f]{1,4}:){6}
| ::(?:[0-9A-Fa-f]{1,4}:){5}
| (?: [0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}:
| (?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::
)
(?P<ls32>[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}
| (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
)
| (?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?:: [0-9A-Fa-f]{1,4}
| (?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::
)
| (?P<IPvFuture>[Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&\'()*+,;=:]+)
)
\]
)
| (?P<IPv4address>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))
| (?P<regname>(?:[A-Za-z0-9\-._~!$&\'()*+,;=]|%[0-9A-Fa-f]{2})+)
)
(?::(?P<port>[0-9]*))?
)
(?P<path_abempty>(?:\/(?:[A-Za-z0-9\-._~!$&\'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)
(?:\?(?P<query> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
(?:\#(?P<fragment> (?:[A-Za-z0-9\-._~!$&\'()*+,;=:@\\/?]|%[0-9A-Fa-f]{2})*))?
$
/mx', $url, $m)) return FALSE;
switch ($m['scheme'])
{
case 'https':
case 'http':
if ($m['userinfo']) return FALSE; // HTTP scheme does not allow userinfo.
break;
case 'ftps':
case 'ftp':
break;
default:
return FALSE; // Unrecognised URI scheme. Default to FALSE.
}
// Validate host name conforms to DNS "dot-separated-parts".
if ($m{'regname'}) // If host regname specified, check for DNS conformance.
{
if (!preg_match('/# HTTP DNS host name.
^ # Anchor to beginning of string.
(?!.{256}) # Overall host length is less than 256 chars.
(?: # Group dot separated host part alternatives.
[0-9A-Za-z]\. # Either a single alphanum followed by dot
| # or... part has more than one char (63 chars max).
[0-9A-Za-z] # Part first char is alphanum (no dash).
[\-0-9A-Za-z]{0,61} # Internal chars are alphanum plus dash.
[0-9A-Za-z] # Part last char is alphanum (no dash).
\. # Each part followed by literal dot.
)* # One or more parts before top level domain.
(?: # Explicitly specify top level domains.
com|edu|gov|int|mil|net|org|biz|
info|name|pro|aero|coop|museum|
asia|cat|jobs|mobi|tel|travel|
[A-Za-z]{2}) # Country codes are exqactly two alpha chars.
$ # Anchor to end of string.
/ix', $m['host'])) return FALSE;
}
$m['url'] = $url;
for ($i = 0; isset($m[$i]); ++$i) unset($m[$i]);
return $m; // return TRUE == array of useful named $matches plus the valid $url.
}
//
// Replace string matching regular expression
//
// This function takes care of possibly disabled unicode properties in PCRE builds
//
function ucp_preg_replace($pattern, $replace, $subject)
{
$replaced = preg_replace($pattern, $replace, $subject);
// If preg_replace() returns false, this probably means unicode support is not built-in, so we need to modify the pattern a little
if ($replaced === false)
{
if (is_array($pattern))
{
foreach ($pattern as $cur_key => $cur_pattern)
$pattern[$cur_key] = str_replace('\p{L}\p{N}', '\w', $cur_pattern);
$replaced = preg_replace($pattern, $replace, $subject);
}
else
$replaced = preg_replace(str_replace('\p{L}\p{N}', '\w', $pattern), $replace, $subject);
}
return $replaced;
}
// DEBUG FUNCTIONS BELOW
//
// Display executed queries (if enabled)
//
function display_saved_queries()
{
global $db, $lang_common;
// Get the queries so that we can print them out
$saved_queries = $db->get_saved_queries();
?>
<div id="debug" class="blocktable">
<h2><span><?php echo $lang_common['Debug table'] ?></span></h2>
<div class="box">
<div class="inbox">
<table cellspacing="0">
<thead>
<tr>
<th class="tcl" scope="col"><?php echo $lang_common['Query times'] ?></th>
<th class="tcr" scope="col"><?php echo $lang_common['Query'] ?></th>
</tr>
</thead>
<tbody>
<?php
$query_time_total = 0.0;
foreach ($saved_queries as $cur_query)
{
$query_time_total += $cur_query[1];
?>
<tr>
<td class="tcl"><?php echo ($cur_query[1] != 0) ? $cur_query[1] : ' ' ?></td>
<td class="tcr"><?php echo pun_htmlspecialchars($cur_query[0]) ?></td>
</tr>
<?php
}
?>
<tr>
<td class="tcl" colspan="2"><?php printf($lang_common['Total query time'], $query_time_total.' s') ?></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<?php
}
//
// Dump contents of variable(s)
//
function dump()
{
echo '<pre>';
$num_args = func_num_args();
for ($i = 0; $i < $num_args; ++$i)
{
print_r(func_get_arg($i));
echo "\n\n";
}
echo '</pre>';
exit;
}Hors ligne
Après analyse de tes deux fichiers include/functions.php, il manque des modifs (ou peut-être ont-elles disparues lors de tes manips), d'où les dysfonctionnements.
Bon, procédons par ordre chronologique des modifs proposées, et commençons donc par ton fichier 2 :
Ligne 718, tu as :
$result = $db->query('SELECT last_post, last_post_id, last_poster, subject, id, num_replies 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());et il faut avoir :
$result = $db->query('SELECT t.last_post, t.last_post_id, t.last_poster, t.subject, t.id, t.num_replies, p.message, f.last_img FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'posts AS p ON p.id=t.last_post_id INNER JOIN '.$db->prefix.'forums AS f ON f.id='.$forum_id.' WHERE t.forum_id='.$forum_id.' AND t.moved_to IS NULL ORDER BY t.last_post DESC LIMIT 1') or error('Unable to fetch last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());Concernant ton fichier 1, à la ligne 722, tu as :
list($last_post, $last_post_id, $last_poster, $last_topic, $last_topic_id, $num_replies) = $db->fetch_row($result);et il faut avoir :
list($last_post, $last_post_id, $last_poster, $last_msg, $last_topic, $last_topic_id, $num_replies) = $db->fetch_row($result);Maintenant, si tu veux que ta bannière fonctionne, il faut prendre comme base ton fichier 2 avec la modif de la ligne 718 correctement appliquée. Le fichier 1 est trop incomplet pour espérer quoi que ce soit.
Dernière modification par Wan (23-03-2012 16:22:53)
Hors ligne
bon j'ai fait la modification du fichier 2
du coup quand je valide le post avec une image j'ai ça
File: C:\xampp\htdocs\www\include\functions.php
Line: 743
FluxBB reported: Unable to update last_post/last_post_id/last_poster/last_img
Database reported: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '://127.0.0.1/www/img/members/2/DSC00118.JPG, last_topic_id=SFRSHV, last_poster=' at line 1 (Errno: 1064)
Failed query: UPDATE forums SET num_topics=1, num_posts=14, last_post=1332526339, last_post_id=47, num_replies=http://127.0.0.1/www/img/members/2/DSC00118.JPG, last_topic_id=SFRSHV, last_poster='A-snowboard', last_topic='13', last_img='http://127.0.0.1/www/img/members/2/DSC00059.JPG' WHERE id=4 et quand je valide un post sans images (dans le même topic)
File: C:\xampp\htdocs\www\include\functions.php
Line: 743
FluxBB reported: Unable to update last_post/last_post_id/last_poster/last_img
Database reported: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '://127.0.0.1/www/img/members/2/DSC00118.JPG, last_topic_id=SFRSHV, last_poster=' at line 1 (Errno: 1064)
Failed query: UPDATE forums SET num_topics=1, num_posts=14, last_post=1332526339, last_post_id=47, num_replies=http://127.0.0.1/www/img/members/2/DSC00118.JPG, last_topic_id=SFRSHV, last_poster='A-snowboard', last_topic='13', last_img='http://127.0.0.1/www/img/members/2/DSC00059.JPG' WHERE id=4 et quand je suis sur un autre topic et que je valide mon post (sans images) j'ai ça :
File: C:\xampp\htdocs\www\include\functions.php
Line: 743
FluxBB reported: Unable to update last_post/last_post_id/last_poster/last_img
Database reported: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '://127.0.0.1/www/img/members/2/04032012-1614_DSC08955.JPG, last_topic_id=wfdf, ' at line 1 (Errno: 1064)
Failed query: UPDATE forums SET num_topics=5, num_posts=12, last_post=1332526473, last_post_id=48, num_replies=http://127.0.0.1/www/img/members/2/04032012-1614_DSC08955.JPG, last_topic_id=wfdf, last_poster='A-snowboard', last_topic='2', last_img='http://127.0.0.1/www/img/members/2/DSC00021.JPG' WHERE id=2 Du coup pour le fichier 1, je vais donc attendre de stabiliser mon problème de fichier 2.
Dernière modification par a-snowboard (23-03-2012 20:16:51)
Hors ligne
Bon, il y a un pb là-dessus :
num_replies=http://127.0.0.1/www/img/members/2/DSC00118.JPG, last_topic_id=SFRSHVOn n'est pas loin, il faut que je regarde à nouveau. Je ne pourrai le faire que demain matin. Patience...
[EDIT] : je pense que c'est un simple problème d'ordre dans ton list, mais je préfère attendre demain voir ça au calme pour te confirmer...
Dernière modification par Wan (23-03-2012 20:27:01)
Hors ligne
pas de souci, mis a part que tu met ma patience à rude épreuve ! lol
et j'ai remarqué ce qu"avais remarqué otomatik
last_poster=Dernière modification par a-snowboard (23-03-2012 20:27:38)
Hors ligne
pas de souci, mis a part que tu met ma patience à rude épreuve ! lol
et j'ai remarqué ce qu"avais remarqué otomatik
last_poster=
Non, maintenant, tu as bien :
last_poster='A-snowboard'Hors ligne
pas de souci, mis a part que tu met ma patience à rude épreuve ! lol
Et la mienne ! 
Hors ligne