bug3
[aidenligne_francais_universite.git] / fluxbb / include / parser.php
CommitLineData
c495c100
P
1<?php
2/***********************************************************************
3
4 Copyright (C) 2002-2005 Rickard Andersson (rickard@punbb.org)
5
6 This file is part of PunBB.
7
8 PunBB is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 PunBB is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 MA 02111-1307 USA
22
23************************************************************************/
24
25// Make sure no one attempts to run this script "directly"
26if (!defined('PUN'))
27 exit;
28
29
30// Here you can add additional smilies if you like (please note that you must escape singlequote and backslash)
31$smiley_text = array(':)', '=)', ':|', '=|', ':(', '=(', ':D', '=D', ':o', ':O', ';)', ':/', ':P', ':lol:', ':mad:', ':rolleyes:', ':cool:');
32$smiley_img = array('smile.png', 'smile.png', 'neutral.png', 'neutral.png', 'sad.png', 'sad.png', 'big_smile.png', 'big_smile.png', 'yikes.png', 'yikes.png', 'wink.png', 'hmm.png', 'tongue.png', 'lol.png', 'mad.png', 'roll.png', 'cool.png');
33
34// Uncomment the next row if you add smilies that contain any of the characters &"'<>
35//$smiley_text = array_map('pun_htmlspecialchars', $smiley_text);
36
37
38//
39// Make sure all BBCodes are lower case and do a little cleanup
40//
41function preparse_bbcode($text, &$errors, $is_signature = false)
42{
43 // Change all simple BBCodes to lower case
44 $a = array('[B]', '[I]', '[U]', '[/B]', '[/I]', '[/U]');
45 $b = array('[b]', '[i]', '[u]', '[/b]', '[/i]', '[/u]');
46 $text = str_replace($a, $b, $text);
47
48 // Do the more complex BBCodes (also strip excessive whitespace and useless quotes)
49 $a = array( '#\[url=("|\'|)(.*?)\\1\]\s*#i',
50 '#\[url\]\s*#i',
51 '#\s*\[/url\]#i',
52 '#\[email=("|\'|)(.*?)\\1\]\s*#i',
53 '#\[email\]\s*#i',
54 '#\s*\[/email\]#i',
55 '#\[img\]\s*(.*?)\s*\[/img\]#is',
56 '#\[colou?r=("|\'|)(.*?)\\1\](.*?)\[/colou?r\]#is');
57
58 $b = array( '[url=$2]',
59 '[url]',
60 '[/url]',
61 '[email=$2]',
62 '[email]',
63 '[/email]',
64 '[img]$1[/img]',
65 '[color=$2]$3[/color]');
66
67 if (!$is_signature)
68 {
69 // For non-signatures, we have to do the quote and code tags as well
70 $a[] = '#\[quote=(&quot;|"|\'|)(.*?)\\1\]\s*#i';
71 $a[] = '#\[quote\]\s*#i';
72 $a[] = '#\s*\[/quote\]\s*#i';
73 $a[] = '#\[code\][\r\n]*(.*?)\s*\[/code\]\s*#is';
74
75 $b[] = '[quote=$1$2$1]';
76 $b[] = '[quote]';
77 $b[] = '[/quote]'."\n";
78 $b[] = '[code]$1[/code]'."\n";
79 }
80
81 // Run this baby!
82 $text = preg_replace($a, $b, $text);
83
84 if (!$is_signature)
85 {
86 $overflow = check_tag_order($text, $error);
87
88 if ($error)
89 // A BBCode error was spotted in check_tag_order()
90 $errors[] = $error;
91 else if ($overflow)
92 // The quote depth level was too high, so we strip out the inner most quote(s)
93 $text = substr($text, 0, $overflow[0]).substr($text, $overflow[1], (strlen($text) - $overflow[0]));
94 }
95 else
96 {
97 global $lang_prof_reg;
98
99 if (preg_match('#\[quote=(&quot;|"|\'|)(.*)\\1\]|\[quote\]|\[/quote\]|\[code\]|\[/code\]#i', $text))
100 message($lang_prof_reg['Signature quote/code']);
101 }
102
103 return trim($text);
104}
105
106
107//
108// Parse text and make sure that [code] and [quote] syntax is correct
109//
110function check_tag_order($text, &$error)
111{
112 global $lang_common;
113
114 // The maximum allowed quote depth
115 $max_depth = 3;
116
117 $cur_index = 0;
118 $q_depth = 0;
119
120 while (true)
121 {
122 // Look for regular code and quote tags
123 $c_start = strpos($text, '[code]');
124 $c_end = strpos($text, '[/code]');
125 $q_start = strpos($text, '[quote]');
126 $q_end = strpos($text, '[/quote]');
127
128 // Look for [quote=username] style quote tags
129 if (preg_match('#\[quote=(&quot;|"|\'|)(.*)\\1\]#sU', $text, $matches))
130 $q2_start = strpos($text, $matches[0]);
131 else
132 $q2_start = 65536;
133
134 // Deal with strpos() returning false when the string is not found
135 // (65536 is one byte longer than the maximum post length)
136 if ($c_start === false) $c_start = 65536;
137 if ($c_end === false) $c_end = 65536;
138 if ($q_start === false) $q_start = 65536;
139 if ($q_end === false) $q_end = 65536;
140
141 // If none of the strings were found
142 if (min($c_start, $c_end, $q_start, $q_end, $q2_start) == 65536)
143 break;
144
145 // We are interested in the first quote (regardless of the type of quote)
146 $q3_start = ($q_start < $q2_start) ? $q_start : $q2_start;
147
148 // We found a [quote] or a [quote=username]
149 if ($q3_start < min($q_end, $c_start, $c_end))
150 {
151 $step = ($q_start < $q2_start) ? 7 : strlen($matches[0]);
152
153 $cur_index += $q3_start + $step;
154
155 // Did we reach $max_depth?
156 if ($q_depth == $max_depth)
157 $overflow_begin = $cur_index - $step;
158
159 ++$q_depth;
160 $text = substr($text, $q3_start + $step);
161 }
162
163 // We found a [/quote]
164 else if ($q_end < min($q_start, $c_start, $c_end))
165 {
166 if ($q_depth == 0)
167 {
168 $error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 1'];
169 return;
170 }
171
172 $q_depth--;
173 $cur_index += $q_end+8;
174
175 // Did we reach $max_depth?
176 if ($q_depth == $max_depth)
177 $overflow_end = $cur_index;
178
179 $text = substr($text, $q_end+8);
180 }
181
182 // We found a [code]
183 else if ($c_start < min($c_end, $q_start, $q_end))
184 {
185 // Make sure there's a [/code] and that any new [code] doesn't occur before the end tag
186 $tmp = strpos($text, '[/code]');
187 $tmp2 = strpos(substr($text, $c_start+6), '[code]');
188 if ($tmp2 !== false)
189 $tmp2 += $c_start+6;
190
191 if ($tmp === false || ($tmp2 !== false && $tmp2 < $tmp))
192 {
193 $error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 2'];
194 return;
195 }
196 else
197 $text = substr($text, $tmp+7);
198
199 $cur_index += $tmp+7;
200 }
201
202 // We found a [/code] (this shouldn't happen since we handle both start and end tag in the if clause above)
203 else if ($c_end < min($c_start, $q_start, $q_end))
204 {
205 $error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 3'];
206 return;
207 }
208 }
209
210 // If $q_depth <> 0 something is wrong with the quote syntax
211 if ($q_depth)
212 {
213 $error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 4'];
214 return;
215 }
216 else if ($q_depth < 0)
217 {
218 $error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 5'];
219 return;
220 }
221
222 // If the quote depth level was higher than $max_depth we return the index for the
223 // beginning and end of the part we should strip out
224 if (isset($overflow_begin))
225 return array($overflow_begin, $overflow_end);
226 else
227 return null;
228}
229
230
231//
232// Split text into chunks ($inside contains all text inside $start and $end, and $outside contains all text outside)
233//
234function split_text($text, $start, $end)
235{
236 global $pun_config;
237
238 $tokens = explode($start, $text);
239
240 $outside[] = $tokens[0];
241
242 $num_tokens = count($tokens);
243 for ($i = 1; $i < $num_tokens; ++$i)
244 {
245 $temp = explode($end, $tokens[$i]);
246 $inside[] = $temp[0];
247 $outside[] = $temp[1];
248 }
249
250 if ($pun_config['o_indent_num_spaces'] != 8 && $start == '[code]')
251 {
252 $spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
253 $inside = str_replace("\t", $spaces, $inside);
254 }
255
256 return array($inside, $outside);
257}
258
259
260//
261// Truncate URL if longer than 55 characters (add http:// or ftp:// if missing)
262//
263function handle_url_tag($url, $link = '')
264{
265 global $pun_user;
266
267 $full_url = str_replace(array(' ', '\'', '`', '"'), array('%20', '', '', ''), $url);
268 if (strpos($url, 'www.') === 0) // If it starts with www, we add http://
269 $full_url = 'http://'.$full_url;
270 else if (strpos($url, 'ftp.') === 0) // Else if it starts with ftp, we add ftp://
271 $full_url = 'ftp://'.$full_url;
272 else if (!preg_match('#^([a-z0-9]{3,6})://#', $url, $bah)) // Else if it doesn't start with abcdef://, we add http://
273 $full_url = 'http://'.$full_url;
274
275 // Ok, not very pretty :-)
276 $link = ($link == '' || $link == $url) ? ((strlen($url) > 55) ? substr($url, 0 , 39).' &hellip; '.substr($url, -10) : $url) : stripslashes($link);
277
278 return '<a href="'.$full_url.'">'.$link.'</a>';
279}
280
281
282//
283// Turns an URL from the [img] tag into an <img> tag or a <a href...> tag
284//
285function handle_img_tag($url, $is_signature = false)
286{
287 global $lang_common, $pun_config, $pun_user;
288
289 $img_tag = '<a href="'.$url.'">&lt;'.$lang_common['Image link'].'&gt;</a>';
290
291 if ($is_signature && $pun_user['show_img_sig'] != '0')
292 $img_tag = '<img class="sigimage" src="'.$url.'" alt="'.htmlspecialchars($url).'" />';
293 else if (!$is_signature && $pun_user['show_img'] != '0')
294 $img_tag = '<img class="postimg" src="'.$url.'" alt="'.htmlspecialchars($url).'" />';
295
296 return $img_tag;
297}
298
299
300//
301// Convert BBCodes to their HTML equivalent
302//
303function do_bbcode($text)
304{
305 global $lang_common, $pun_user;
306
307 if (strpos($text, 'quote') !== false)
308 {
309 $text = str_replace('[quote]', '</p><blockquote><div class="incqbox"><p>', $text);
310 $text = preg_replace('#\[quote=(&quot;|"|\'|)(.*)\\1\]#seU', '"</p><blockquote><div class=\"incqbox\"><h4>".str_replace(array(\'[\', \'\\"\'), array(\'&#91;\', \'"\'), \'$2\')." ".$lang_common[\'wrote\'].":</h4><p>"', $text);
311 $text = preg_replace('#\[\/quote\]\s*#', '</p></div></blockquote><p>', $text);
312 }
313
314 $pattern = array('#\[b\](.*?)\[/b\]#s',
315 '#\[i\](.*?)\[/i\]#s',
316 '#\[u\](.*?)\[/u\]#s',
317 '#\[url\]([^\[<]*?)\[/url\]#e',
318 '#\[url=([^\[<]*?)\](.*?)\[/url\]#e',
319 '#\[email\]([^\[<]*?)\[/email\]#',
320 '#\[email=([^\[<]*?)\](.*?)\[/email\]#',
321 '#\[color=([a-zA-Z]*|\#?[0-9a-fA-F]{6})](.*?)\[/color\]#s');
322
323 $replace = array('<strong>$1</strong>',
324 '<em>$1</em>',
325 '<span class="bbu">$1</span>',
326 'handle_url_tag(\'$1\')',
327 'handle_url_tag(\'$1\', \'$2\')',
328 '<a href="mailto:$1">$1</a>',
329 '<a href="mailto:$1">$2</a>',
330 '<span style="color: $1">$2</span>');
331
332 // This thing takes a while! :)
333 $text = preg_replace($pattern, $replace, $text);
334
335 return $text;
336}
337
338
339//
340// Make hyperlinks clickable
341//
342function do_clickable($text)
343{
344 global $pun_user;
345
346 $text = ' '.$text;
347
348 $text = preg_replace('#([\s\(\)])(https?|ftp|news){1}://([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^"\s\(\)<\[]*)?)#ie', '\'$1\'.handle_url_tag(\'$2://$3\')', $text);
349 $text = preg_replace('#([\s\(\)])(www|ftp)\.(([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^"\s\(\)<\[]*)?)#ie', '\'$1\'.handle_url_tag(\'$2.$3\', \'$2.$3\')', $text);
350
351 return substr($text, 1);
352}
353
354
355//
356// Convert a series of smilies to images
357//
358function do_smilies($text)
359{
360 global $smiley_text, $smiley_img;
361
362 $text = ' '.$text.' ';
363
364 $num_smilies = count($smiley_text);
365 for ($i = 0; $i < $num_smilies; ++$i)
366 $text = preg_replace("#(?<=.\W|\W.|^\W)".preg_quote($smiley_text[$i], '#')."(?=.\W|\W.|\W$)#m", '$1<img src="img/smilies/'.$smiley_img[$i].'" width="15" height="15" alt="'.substr($smiley_img[$i], 0, strrpos($smiley_img[$i], '.')).'" />$2', $text);
367
368 return substr($text, 1, -1);
369}
370
371
372//
373// Parse message text
374//
375function parse_message($text, $hide_smilies)
376{
377 global $pun_config, $lang_common, $pun_user;
378
379 if ($pun_config['o_censoring'] == '1')
380 $text = censor_words($text);
381
382 // Convert applicable characters to HTML entities
383 $text = pun_htmlspecialchars($text);
384
385 // If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched)
386 if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
387 {
388 list($inside, $outside) = split_text($text, '[code]', '[/code]');
389 $outside = array_map('ltrim', $outside);
390 $text = implode('<">', $outside);
391 }
392
393 if ($pun_config['o_make_links'] == '1')
394 $text = do_clickable($text);
395
396 if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0')
397 $text = do_smilies($text);
398
399 if ($pun_config['p_message_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
400 {
401 $text = do_bbcode($text);
402
403 if ($pun_config['p_message_img_tag'] == '1')
404 {
405// $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\')', $text);
406 $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\')', $text);
407 }
408 }
409
410 // Deal with newlines, tabs and multiple spaces
411 $pattern = array("\n", "\t", ' ', ' ');
412 $replace = array('<br />', '&nbsp; &nbsp; ', '&nbsp; ', ' &nbsp;');
413 $text = str_replace($pattern, $replace, $text);
414
415 // If we split up the message before we have to concatenate it together again (code tags)
416 if (isset($inside))
417 {
418 $outside = explode('<">', $text);
419 $text = '';
420
421 $num_tokens = count($outside);
422
423 for ($i = 0; $i < $num_tokens; ++$i)
424 {
425 $text .= $outside[$i];
426 if (isset($inside[$i]))
427 {
428 $num_lines = ((substr_count($inside[$i], "\n")) + 3) * 1.5;
429 $height_str = ($num_lines > 35) ? '35em' : $num_lines.'em';
430 $text .= '</p><div class="codebox"><div class="incqbox"><h4>'.$lang_common['Code'].':</h4><div class="scrollbox" style="height: '.$height_str.'"><pre>'.$inside[$i].'</pre></div></div></div><p>';
431 }
432 }
433 }
434
435 // Add paragraph tag around post, but make sure there are no empty paragraphs
436 $text = str_replace('<p></p>', '', '<p>'.$text.'</p>');
437
438 return $text;
439}
440
441
442//
443// Parse signature text
444//
445function parse_signature($text)
446{
447 global $pun_config, $lang_common, $pun_user;
448
449 if ($pun_config['o_censoring'] == '1')
450 $text = censor_words($text);
451
452 $text = pun_htmlspecialchars($text);
453
454 if ($pun_config['o_make_links'] == '1')
455 $text = do_clickable($text);
456
457 if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] != '0')
458 $text = do_smilies($text);
459
460 if ($pun_config['p_sig_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
461 {
462 $text = do_bbcode($text);
463
464 if ($pun_config['p_sig_img_tag'] == '1')
465 {
466// $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\', true)', $text);
467 $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\', true)', $text);
468 }
469 }
470
471 // Deal with newlines, tabs and multiple spaces
472 $pattern = array("\n", "\t", ' ', ' ');
473 $replace = array('<br />', '&nbsp; &nbsp; ', '&nbsp; ', ' &nbsp;');
474 $text = str_replace($pattern, $replace, $text);
475
476 return $text;
477}