source: trunk/web/punbb/include/parser.php @ 7

Last change on this file since 7 was 6, checked in by dj3c1t, 13 years ago

mise a jour du trunk

File size: 28.1 KB
RevLine 
[6]1<?php
2
3/**
4 * Copyright (C) 2008-2011 FluxBB
5 * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
6 * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
7 */
8
9// Make sure no one attempts to run this script "directly"
10if (!defined('PUN'))
11        exit;
12
13// Global variables
14/* regular expression to match nested BBCode LIST tags
15'%
16\[list                # match opening bracket and tag name of outermost LIST tag
17(?:=([1a*]))?+        # optional attribute capture in group 1
18\]                    # closing bracket of outermost opening LIST tag
19(                     # capture contents of LIST tag in group 2
20  (?:                 # non capture group for either contents or whole nested LIST
21        [^\[]*+           # unroll the loop! consume everything up to next [ (normal *)
22        (?:               # (See "Mastering Regular Expressions" chapter 6 for details)
23          (?!             # negative lookahead ensures we are NOT on [LIST*] or [/LIST]
24                \[list        # opening LIST tag
25                (?:=[1a*])?+  # with optional attribute
26                \]            # closing bracket of opening LIST tag
27                |             # or...
28                \[/list\]     # a closing LIST tag
29          )               # end negative lookahead assertion (we are not on a LIST tag)
30          \[              # match the [ which is NOT the start of LIST tag (special)
31          [^\[]*+         # consume everything up to next [ (normal *)
32        )*+               # finish up "unrolling the loop" technique (special (normal*))*
33  |                   # or...
34        (?R)              # recursively match a whole nested LIST element
35  )*                  # as many times as necessary until deepest nested LIST tag grabbed
36)                     # end capturing contents of LIST tag into group 2
37\[/list\]             # match outermost closing LIST tag
38%iex' */
39$re_list = '%\[list(?:=([1a*]))?+\]((?:[^\[]*+(?:(?!\[list(?:=[1a*])?+\]|\[/list\])\[[^\[]*+)*+|(?R))*)\[/list\]%ie';
40
41// Here you can add additional smilies if you like (please note that you must escape single quote and backslash)
42$smilies = array(
43        ':)' => 'smile.png',
44        '=)' => 'smile.png',
45        ':|' => 'neutral.png',
46        '=|' => 'neutral.png',
47        ':(' => 'sad.png',
48        '=(' => 'sad.png',
49        ':D' => 'big_smile.png',
50        '=D' => 'big_smile.png',
51        ':o' => 'yikes.png',
52        ':O' => 'yikes.png',
53        ';)' => 'wink.png',
54        ':/' => 'hmm.png',
55        ':P' => 'tongue.png',
56        ':p' => 'tongue.png',
57        ':lol:' => 'lol.png',
58        ':mad:' => 'mad.png',
59        ':rolleyes:' => 'roll.png',
60        ':cool:' => 'cool.png');
61
62//
63// Make sure all BBCodes are lower case and do a little cleanup
64//
65function preparse_bbcode($text, &$errors, $is_signature = false)
66{
67        global $pun_config, $lang_common, $lang_post, $re_list;
68
69        if ($is_signature)
70        {
71                global $lang_profile;
72
73                if (preg_match('%\[/?(?:quote|code|list|h)\b[^\]]*\]%i', $text))
74                        $errors[] = $lang_profile['Signature quote/code/list/h'];
75        }
76
77        // If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched)
78        if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
79                list($inside, $text) = extract_blocks($text, '[code]', '[/code]', $errors);
80
81        // Tidy up lists
82        $temp = preg_replace($re_list, 'preparse_list_tag(\'$2\', \'$1\', $errors)', $text);
83
84        // If the regex failed
85        if ($temp === null)
86                $errors[] = $lang_common['BBCode list size error'];
87        else
88                $text = str_replace('*'."\0".']', '*]', $temp);
89
90        if ($pun_config['o_make_links'] == '1')
91                $text = do_clickable($text);
92
93        // If we split up the message before we have to concatenate it together again (code tags)
94        if (isset($inside))
95        {
96                $outside = explode("\1", $text);
97                $text = '';
98
99                $num_tokens = count($outside);
100                for ($i = 0; $i < $num_tokens; ++$i)
101                {
102                        $text .= $outside[$i];
103                        if (isset($inside[$i]))
104                                $text .= '[code]'.$inside[$i].'[/code]';
105                }
106
107                unset($inside);
108        }
109
110        $temp_text = false;
111        if (empty($errors))
112                $temp_text = preparse_tags($text, $errors, $is_signature);
113
114        if ($temp_text !== false)
115                $text = $temp_text;
116
117        // Remove empty tags
118        while (($new_text = strip_empty_bbcode($text, $errors)) !== false)
119        {
120                if ($new_text != $text)
121                {
122                        $text = $new_text;
123                        if ($new_text == '')
124                        {
125                                $errors[] = $lang_post['Empty after strip'];
126                                break;
127                        }
128                }
129                else
130                        break;
131        }
132
133        return pun_trim($text);
134}
135
136
137//
138// Strip empty bbcode tags from some text
139//
140function strip_empty_bbcode($text, &$errors)
141{
142        // If the message contains a code tag we have to split it up (empty tags within [code][/code] are fine)
143        if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
144                list($inside, $text) = extract_blocks($text, '[code]', '[/code]', $errors);
145
146        // Remove empty tags
147        while (($new_text = preg_replace('%\[(b|u|s|ins|del|em|i|h|colou?r|quote|img|url|email|list|topic|post|forum|user)(?:\=[^\]]*)?\]\s*\[/\1\]%', '', $text)) !== NULL)
148        {
149                if ($new_text != $text)
150                        $text = $new_text;
151                else
152                        break;
153        }
154
155        // If we split up the message before we have to concatenate it together again (code tags)
156    if (isset($inside)) {
157        $parts = explode("\1", $text);
158        $text = '';
159        foreach ($parts as $i => $part)
160        {
161            $text .= $part;
162            if (isset($inside[$i]))
163                $text .= '[code]'.$inside[$i].'[/code]';
164        }
165    }
166
167        // Remove empty code tags
168        while (($new_text = preg_replace('%\[(code)\]\s*\[/\1\]%', '', $text)) !== NULL)
169        {
170                if ($new_text != $text)
171                        $text = $new_text;
172                else
173                        break;
174        }
175
176        return $text;
177}
178
179
180//
181// Check the structure of bbcode tags and fix simple mistakes where possible
182//
183function preparse_tags($text, &$errors, $is_signature = false)
184{
185        global $lang_common, $pun_config;
186
187        // Start off by making some arrays of bbcode tags and what we need to do with each one
188
189        // List of all the tags
190        $tags = array('quote', 'code', 'b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'img', 'list', '*', 'h', 'topic', 'post', 'forum', 'user');
191        // List of tags that we need to check are open (You could not put b,i,u in here then illegal nesting like [b][i][/b][/i] would be allowed)
192        $tags_opened = $tags;
193        // and tags we need to check are closed (the same as above, added it just in case)
194        $tags_closed = $tags;
195        // Tags we can nest and the depth they can be nested to
196        $tags_nested = array('quote' => $pun_config['o_quote_depth'], 'list' => 5, '*' => 5);
197        // Tags to ignore the contents of completely (just code)
198        $tags_ignore = array('code');
199        // Block tags, block tags can only go within another block tag, they cannot be in a normal tag
200        $tags_block = array('quote', 'code', 'list', 'h', '*');
201        // Inline tags, we do not allow new lines in these
202        $tags_inline = array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'h', 'topic', 'post', 'forum', 'user');
203        // Tags we trim interior space
204        $tags_trim = array('img');
205        // Tags we remove quotes from the argument
206        $tags_quotes = array('url', 'email', 'img', 'topic', 'post', 'forum', 'user');
207        // Tags we limit bbcode in
208        $tags_limit_bbcode = array(
209                '*'     => array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'list', 'img', 'code', 'topic', 'post', 'forum', 'user'),
210                'list'  => array('*'),
211                'url'   => array('img'),
212                'email' => array('img'),
213                'topic' => array('img'),
214                'post'  => array('img'),
215                'forum' => array('img'),
216                'user'  => array('img'),
217                'img'   => array(),
218                'h'             => array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'topic', 'post', 'forum', 'user'),
219        );
220        // Tags we can automatically fix bad nesting
221        $tags_fix = array('quote', 'b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'h', 'topic', 'post', 'forum', 'user');
222
223        $split_text = preg_split('%(\[[\*a-zA-Z0-9-/]*?(?:=.*?)?\])%', $text, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
224
225        $open_tags = array('fluxbb-bbcode');
226        $open_args = array('');
227        $opened_tag = 0;
228        $new_text = '';
229        $current_ignore = '';
230        $current_nest = '';
231        $current_depth = array();
232        $limit_bbcode = $tags;
233        $count_ignored = array();
234
235        foreach ($split_text as $current)
236        {
237                if ($current == '')
238                        continue;
239
240                // Are we dealing with a tag?
241                if (substr($current, 0, 1) != '[' || substr($current, -1, 1) != ']')
242                {
243                        // It's not a bbcode tag so we put it on the end and continue
244                        // If we are nested too deeply don't add to the end
245                        if ($current_nest)
246                                continue;
247
248                        $current = str_replace("\r\n", "\n", $current);
249                        $current = str_replace("\r", "\n", $current);
250                        if (in_array($open_tags[$opened_tag], $tags_inline) && strpos($current, "\n") !== false)
251                        {
252                                // Deal with new lines
253                                $split_current = preg_split('%(\n\n+)%', $current, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
254                                $current = '';
255
256                                if (!pun_trim($split_current[0], "\n")) // The first part is a linebreak so we need to handle any open tags first
257                                        array_unshift($split_current, '');
258
259                                for ($i = 1; $i < count($split_current); $i += 2)
260                                {
261                                        $temp_opened = array();
262                                        $temp_opened_arg = array();
263                                        $temp = $split_current[$i - 1];
264                                        while (!empty($open_tags))
265                                        {
266                                                $temp_tag = array_pop($open_tags);
267                                                $temp_arg = array_pop($open_args);
268
269                                                if (in_array($temp_tag , $tags_inline))
270                                                {
271                                                        array_push($temp_opened, $temp_tag);
272                                                        array_push($temp_opened_arg, $temp_arg);
273                                                        $temp .= '[/'.$temp_tag.']';
274                                                }
275                                                else
276                                                {
277                                                        array_push($open_tags, $temp_tag);
278                                                        array_push($open_args, $temp_arg);
279                                                        break;
280                                                }
281                                        }
282                                        $current .= $temp.$split_current[$i];
283                                        $temp = '';
284                                        while (!empty($temp_opened))
285                                        {
286                                                $temp_tag = array_pop($temp_opened);
287                                                $temp_arg = array_pop($temp_opened_arg);
288                                                if (empty($temp_arg))
289                                                        $temp .= '['.$temp_tag.']';
290                                                else
291                                                        $temp .= '['.$temp_tag.'='.$temp_arg.']';
292                                                array_push($open_tags, $temp_tag);
293                                                array_push($open_args, $temp_arg);
294                                        }
295                                        $current .= $temp;
296                                }
297
298                                if (array_key_exists($i - 1, $split_current))
299                                        $current .= $split_current[$i - 1];
300                        }
301
302                        if (in_array($open_tags[$opened_tag], $tags_trim))
303                                $new_text .= pun_trim($current);
304                        else
305                                $new_text .= $current;
306
307                        continue;
308                }
309
310                // Get the name of the tag
311                $current_arg = '';
312                if (strpos($current, '/') === 1)
313                {
314                        $current_tag = substr($current, 2, -1);
315                }
316                else if (strpos($current, '=') === false)
317                {
318                        $current_tag = substr($current, 1, -1);
319                }
320                else
321                {
322                        $current_tag = substr($current, 1, strpos($current, '=')-1);
323                        $current_arg = substr($current, strpos($current, '=')+1, -1);
324                }
325                $current_tag = strtolower($current_tag);
326
327                // Is the tag defined?
328                if (!in_array($current_tag, $tags))
329                {
330                        // It's not a bbcode tag so we put it on the end and continue
331                        if (!$current_nest)
332                                $new_text .= $current;
333
334                        continue;
335                }
336
337                // We definitely have a bbcode tag
338
339                // Make the tag string lower case
340                if ($equalpos = strpos($current,'='))
341                {
342                        // We have an argument for the tag which we don't want to make lowercase
343                        if (strlen(substr($current, $equalpos)) == 2)
344                        {
345                                // Empty tag argument
346                                $errors[] = sprintf($lang_common['BBCode error empty attribute'], $current_tag);
347                                return false;
348                        }
349                        $current = strtolower(substr($current, 0, $equalpos)).substr($current, $equalpos);
350                }
351                else
352                        $current = strtolower($current);
353
354                // This is if we are currently in a tag which escapes other bbcode such as code
355                // We keep a cound of ignored bbcodes (code tags) so we can nest them, but
356                // only balanced sets of tags can be nested
357                if ($current_ignore)
358                {
359                        // Increase the current ignored tags counter
360                        if ('['.$current_ignore.']' == $current)
361                        {
362                                if (!isset($count_ignored[$current_tag]))
363                                        $count_ignored[$current_tag] = 2;
364                                else
365                                        $count_ignored[$current_tag]++;
366                        }
367
368                        // Decrease the current ignored tags counter
369                        if ('[/'.$current_ignore.']' == $current)
370                                $count_ignored[$current_tag]--;
371
372                        if ('[/'.$current_ignore.']' == $current && $count_ignored[$current_tag] == 0)
373                        {
374                                // We've finished the ignored section
375                                $current = '[/'.$current_tag.']';
376                                $current_ignore = '';
377                                $count_ignored = array();
378                        }
379
380                        $new_text .= $current;
381
382                        continue;
383                }
384
385                if ($current_nest)
386                {
387                        // We are currently too deeply nested so lets see if we are closing the tag or not
388                        if ($current_tag != $current_nest)
389                                continue;
390
391                        if (substr($current, 1, 1) == '/')
392                                $current_depth[$current_nest]--;
393                        else
394                                $current_depth[$current_nest]++;
395
396                        if ($current_depth[$current_nest] <= $tags_nested[$current_nest])
397                                $current_nest = '';
398
399                        continue;
400                }
401
402                // Check the current tag is allowed here
403                if (!in_array($current_tag, $limit_bbcode) && $current_tag != $open_tags[$opened_tag])
404                {
405                        $errors[] = sprintf($lang_common['BBCode error invalid nesting'], $current_tag, $open_tags[$opened_tag]);
406                        return false;
407                }
408
409                if (substr($current, 1, 1) == '/')
410                {
411                        // This is if we are closing a tag
412                        if ($opened_tag == 0 || !in_array($current_tag, $open_tags))
413                        {
414                                // We tried to close a tag which is not open
415                                if (in_array($current_tag, $tags_opened))
416                                {
417                                        $errors[] = sprintf($lang_common['BBCode error no opening tag'], $current_tag);
418                                        return false;
419                                }
420                        }
421                        else
422                        {
423                                // Check nesting
424                                while (true)
425                                {
426                                        // Nesting is ok
427                                        if ($open_tags[$opened_tag] == $current_tag)
428                                        {
429                                                array_pop($open_tags);
430                                                array_pop($open_args);
431                                                $opened_tag--;
432                                                break;
433                                        }
434
435                                        // Nesting isn't ok, try to fix it
436                                        if (in_array($open_tags[$opened_tag], $tags_closed) && in_array($current_tag, $tags_closed))
437                                        {
438                                                if (in_array($current_tag, $open_tags))
439                                                {
440                                                        $temp_opened = array();
441                                                        $temp_opened_arg = array();
442                                                        $temp = '';
443                                                        while (!empty($open_tags))
444                                                        {
445                                                                $temp_tag = array_pop($open_tags);
446                                                                $temp_arg = array_pop($open_args);
447
448                                                                if (!in_array($temp_tag, $tags_fix))
449                                                                {
450                                                                        // We couldn't fix nesting
451                                                                        $errors[] = sprintf($lang_common['BBCode error no closing tag'], array_pop($temp_opened));
452                                                                        return false;
453                                                                }
454                                                                array_push($temp_opened, $temp_tag);
455                                                                array_push($temp_opened_arg, $temp_arg);
456
457                                                                if ($temp_tag == $current_tag)
458                                                                        break;
459                                                                else
460                                                                        $temp .= '[/'.$temp_tag.']';
461                                                        }
462                                                        $current = $temp.$current;
463                                                        $temp = '';
464                                                        array_pop($temp_opened);
465                                                        array_pop($temp_opened_arg);
466
467                                                        while (!empty($temp_opened))
468                                                        {
469                                                                $temp_tag = array_pop($temp_opened);
470                                                                $temp_arg = array_pop($temp_opened_arg);
471                                                                if (empty($temp_arg))
472                                                                        $temp .= '['.$temp_tag.']';
473                                                                else
474                                                                        $temp .= '['.$temp_tag.'='.$temp_arg.']';
475                                                                array_push($open_tags, $temp_tag);
476                                                                array_push($open_args, $temp_arg);
477                                                        }
478                                                        $current .= $temp;
479                                                        $opened_tag--;
480                                                        break;
481                                                }
482                                                else
483                                                {
484                                                        // We couldn't fix nesting
485                                                        $errors[] = sprintf($lang_common['BBCode error no opening tag'], $current_tag);
486                                                        return false;
487                                                }
488                                        }
489                                        else if (in_array($open_tags[$opened_tag], $tags_closed))
490                                                break;
491                                        else
492                                        {
493                                                array_pop($open_tags);
494                                                array_pop($open_args);
495                                                $opened_tag--;
496                                        }
497                                }
498                        }
499
500                        if (in_array($current_tag, array_keys($tags_nested)))
501                        {
502                                if (isset($current_depth[$current_tag]))
503                                        $current_depth[$current_tag]--;
504                        }
505
506                        if (in_array($open_tags[$opened_tag], array_keys($tags_limit_bbcode)))
507                                $limit_bbcode = $tags_limit_bbcode[$open_tags[$opened_tag]];
508                        else
509                                $limit_bbcode = $tags;
510
511                        $new_text .= $current;
512
513                        continue;
514                }
515                else
516                {
517                        // We are opening a tag
518                        if (in_array($current_tag, array_keys($tags_limit_bbcode)))
519                                $limit_bbcode = $tags_limit_bbcode[$current_tag];
520                        else
521                                $limit_bbcode = $tags;
522
523                        if (in_array($current_tag, $tags_block) && !in_array($open_tags[$opened_tag], $tags_block) && $opened_tag != 0)
524                        {
525                                // We tried to open a block tag within a non-block tag
526                                $errors[] = sprintf($lang_common['BBCode error invalid nesting'], $current_tag, $open_tags[$opened_tag]);
527                                return false;
528                        }
529
530                        if (in_array($current_tag, $tags_ignore))
531                        {
532                                // It's an ignore tag so we don't need to worry about what's inside it
533                                $current_ignore = $current_tag;
534                                $new_text .= $current;
535                                continue;
536                        }
537
538                        // Deal with nested tags
539                        if (in_array($current_tag, $open_tags) && !in_array($current_tag, array_keys($tags_nested)))
540                        {
541                                // We nested a tag we shouldn't
542                                $errors[] = sprintf($lang_common['BBCode error invalid self-nesting'], $current_tag);
543                                return false;
544                        }
545                        else if (in_array($current_tag, array_keys($tags_nested)))
546                        {
547                                // We are allowed to nest this tag
548
549                                if (isset($current_depth[$current_tag]))
550                                        $current_depth[$current_tag]++;
551                                else
552                                        $current_depth[$current_tag] = 1;
553
554                                // See if we are nested too deep
555                                if ($current_depth[$current_tag] > $tags_nested[$current_tag])
556                                {
557                                        $current_nest = $current_tag;
558                                        continue;
559                                }
560                        }
561
562                        // Remove quotes from arguments for certain tags
563                        if (strpos($current, '=') !== false && in_array($current_tag, $tags_quotes))
564                        {
565                                $current = preg_replace('%\['.$current_tag.'=("|\'|)(.*?)\\1\]\s*%i', '['.$current_tag.'=$2]', $current);
566                        }
567
568                        if (in_array($current_tag, array_keys($tags_limit_bbcode)))
569                                $limit_bbcode = $tags_limit_bbcode[$current_tag];
570
571                        $open_tags[] = $current_tag;
572                        $open_args[] = $current_arg;
573                        $opened_tag++;
574                        $new_text .= $current;
575                        continue;
576                }
577        }
578
579        // Check we closed all the tags we needed to
580        foreach ($tags_closed as $check)
581        {
582                if (in_array($check, $open_tags))
583                {
584                        // We left an important tag open
585                        $errors[] = sprintf($lang_common['BBCode error no closing tag'], $check);
586                        return false;
587                }
588        }
589
590        if ($current_ignore)
591        {
592                // We left an ignore tag open
593                $errors[] = sprintf($lang_common['BBCode error no closing tag'], $current_ignore);
594                return false;
595        }
596
597        return $new_text;
598}
599
600
601//
602// Preparse the contents of [list] bbcode
603//
604function preparse_list_tag($content, $type = '*', &$errors)
605{
606        global $lang_common, $re_list;
607
608        if (strlen($type) != 1)
609                $type = '*';
610
611        if (strpos($content,'[list') !== false)
612        {
613                $content = preg_replace($re_list, 'preparse_list_tag(\'$2\', \'$1\', $errors)', $content);
614        }
615
616        $items = explode('[*]', str_replace('\"', '"', $content));
617
618        $content = '';
619        foreach ($items as $item)
620        {
621                if (pun_trim($item) != '')
622                        $content .= '[*'."\0".']'.str_replace('[/*]', '', pun_trim($item)).'[/*'."\0".']'."\n";
623        }
624
625        return '[list='.$type.']'."\n".$content.'[/list]';
626}
627
628
629//
630// Truncate URL if longer than 55 characters (add http:// or ftp:// if missing)
631//
632function handle_url_tag($url, $link = '', $bbcode = false)
633{
634        $url = pun_trim($url);
635        $full_url = str_replace(array(' ', '\'', '`', '"'), array('%20', '', '', ''), $url);
636        if (strpos($url, 'www.') === 0) // If it starts with www, we add http://
637                $full_url = 'http://'.$full_url;
638        else if (strpos($url, 'ftp.') === 0) // Else if it starts with ftp, we add ftp://
639                $full_url = 'ftp://'.$full_url;
640        else if (strpos($url, '/') === 0) // Allow for relative URLs that start with a slash
641                $full_url = get_base_url(true).$full_url;
642        else if (!preg_match('#^([a-z0-9]{3,6})://#', $url)) // Else if it doesn't start with abcdef://, we add http://
643                $full_url = 'http://'.$full_url;
644
645        // Ok, not very pretty :-)
646        if ($bbcode)
647        {
648                if ($full_url == $link)
649                        return '[url]'.$link.'[/url]';
650                else
651                        return '[url='.$full_url.']'.$link.'[/url]';
652        }
653        else
654        {
655                if ($link == '' || $link == $url)
656                {
657                        $url = pun_htmlspecialchars_decode($url);
658                        $link = utf8_strlen($url) > 55 ? utf8_substr($url, 0 , 39).' 
 '.utf8_substr($url, -10) : $url;
659                        $link = pun_htmlspecialchars($link);
660                }
661                else
662                        $link = stripslashes($link);
663
664                return '<a href="'.$full_url.'">'.$link.'</a>';
665        }
666}
667
668
669//
670// Turns an URL from the [img] tag into an <img> tag or a <a href...> tag
671//
672function handle_img_tag($url, $is_signature = false, $alt = null)
673{
674        global $lang_common, $pun_user;
675
676        if ($alt == null)
677                $alt = basename($url);
678
679        $img_tag = '<a href="'.$url.'">&lt;'.$lang_common['Image link'].' - '.$alt.'&gt;</a>';
680
681        if ($is_signature && $pun_user['show_img_sig'] != '0')
682                $img_tag = '<img class="sigimage" src="'.$url.'" alt="'.$alt.'" />';
683        else if (!$is_signature && $pun_user['show_img'] != '0')
684                $img_tag = '<span class="postimg"><img src="'.$url.'" alt="'.$alt.'" /></span>';
685
686        return $img_tag;
687}
688
689
690//
691// Parse the contents of [list] bbcode
692//
693function handle_list_tag($content, $type = '*')
694{
695        global $re_list;
696
697        if (strlen($type) != 1)
698                $type = '*';
699
700        if (strpos($content,'[list') !== false)
701        {
702                $content = preg_replace($re_list, 'handle_list_tag(\'$2\', \'$1\')', $content);
703        }
704
705        $content = preg_replace('#\s*\[\*\](.*?)\[/\*\]\s*#s', '<li><p>$1</p></li>', pun_trim($content));
706
707        if ($type == '*')
708                $content = '<ul>'.$content.'</ul>';
709        else
710                if ($type == 'a')
711                        $content = '<ol class="alpha">'.$content.'</ol>';
712                else
713                        $content = '<ol class="decimal">'.$content.'</ol>';
714
715        return '</p>'.$content.'<p>';
716}
717
718
719//
720// Convert BBCodes to their HTML equivalent
721//
722function do_bbcode($text, $is_signature = false)
723{
724        global $lang_common, $pun_user, $pun_config, $re_list;
725
726        if (strpos($text, '[quote') !== false)
727        {
728                $text = preg_replace('%\[quote\]\s*%', '</p><div class="quotebox"><blockquote><div><p>', $text);
729                $text = preg_replace('%\[quote=(&quot;|&\#039;|"|\'|)(.*?)\\1\]%se', '"</p><div class=\"quotebox\"><cite>".str_replace(array(\'[\', \'\\"\'), array(\'&#91;\', \'"\'), \'$2\')." ".$lang_common[\'wrote\']."</cite><blockquote><div><p>"', $text);
730                $text = preg_replace('%\s*\[\/quote\]%S', '</p></div></blockquote></div><p>', $text);
731        }
732
733        if (!$is_signature)
734        {
735                $pattern[] = $re_list;
736                $replace[] = 'handle_list_tag(\'$2\', \'$1\')';
737        }
738
739        $pattern[] = '%\[b\](.*?)\[/b\]%ms';
740        $pattern[] = '%\[i\](.*?)\[/i\]%ms';
741        $pattern[] = '%\[u\](.*?)\[/u\]%ms';
742        $pattern[] = '%\[s\](.*?)\[/s\]%ms';
743        $pattern[] = '%\[del\](.*?)\[/del\]%ms';
744        $pattern[] = '%\[ins\](.*?)\[/ins\]%ms';
745        $pattern[] = '%\[em\](.*?)\[/em\]%ms';
746        $pattern[] = '%\[colou?r=([a-zA-Z]{3,20}|\#[0-9a-fA-F]{6}|\#[0-9a-fA-F]{3})](.*?)\[/colou?r\]%ms';
747        $pattern[] = '%\[h\](.*?)\[/h\]%ms';
748
749        $replace[] = '<strong>$1</strong>';
750        $replace[] = '<em>$1</em>';
751        $replace[] = '<span class="bbu">$1</span>';
752        $replace[] = '<span class="bbs">$1</span>';
753        $replace[] = '<del>$1</del>';
754        $replace[] = '<ins>$1</ins>';
755        $replace[] = '<em>$1</em>';
756        $replace[] = '<span style="color: $1">$2</span>';
757        $replace[] = '</p><h5>$1</h5><p>';
758
759        if (($is_signature && $pun_config['p_sig_img_tag'] == '1') || (!$is_signature && $pun_config['p_message_img_tag'] == '1'))
760        {
761                $pattern[] = '%\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]%e';
762                $pattern[] = '%\[img=([^\[]*?)\]((ht|f)tps?://)([^\s<"]*?)\[/img\]%e';
763                if ($is_signature)
764                {
765                        $replace[] = 'handle_img_tag(\'$1$3\', true)';
766                        $replace[] = 'handle_img_tag(\'$2$4\', true, \'$1\')';
767                }
768                else
769                {
770                        $replace[] = 'handle_img_tag(\'$1$3\', false)';
771                        $replace[] = 'handle_img_tag(\'$2$4\', false, \'$1\')';
772                }
773        }
774
775        $pattern[] = '%\[url\]([^\[]*?)\[/url\]%e';
776        $pattern[] = '%\[url=([^\[]+?)\](.*?)\[/url\]%e';
777        $pattern[] = '%\[email\]([^\[]*?)\[/email\]%';
778        $pattern[] = '%\[email=([^\[]+?)\](.*?)\[/email\]%';
779        $pattern[] = '%\[topic\]([^\[]*?)\[/topic\]%e';
780        $pattern[] = '%\[topic=([^\[]+?)\](.*?)\[/topic\]%e';
781        $pattern[] = '%\[post\]([^\[]*?)\[/post\]%e';
782        $pattern[] = '%\[post=([^\[]+?)\](.*?)\[/post\]%e';
783        $pattern[] = '%\[forum\]([^\[]*?)\[/forum\]%e';
784        $pattern[] = '%\[forum=([^\[]+?)\](.*?)\[/forum\]%e';
785        $pattern[] = '%\[user\]([^\[]*?)\[/user\]%e';
786        $pattern[] = '%\[user=([^\[]+?)\](.*?)\[/user\]%e';
787
788        $replace[] = 'handle_url_tag(\'$1\')';
789        $replace[] = 'handle_url_tag(\'$1\', \'$2\')';
790        $replace[] = '<a href="mailto:$1">$1</a>';
791        $replace[] = '<a href="mailto:$1">$2</a>';
792        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?id=$1\')';
793        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?id=$1\', \'$2\')';
794        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?pid=$1#p$1\')';
795        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?pid=$1#p$1\', \'$2\')';
796        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewforum.php?id=$1\')';
797        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewforum.php?id=$1\', \'$2\')';
798        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/profile.php?id=$1\')';
799        $replace[] = 'handle_url_tag(\''.get_base_url(true).'/profile.php?id=$1\', \'$2\')';
800
801        // This thing takes a while! :)
802        $text = preg_replace($pattern, $replace, $text);
803
804        return $text;
805}
806
807
808//
809// Make hyperlinks clickable
810//
811function do_clickable($text)
812{
813        $text = ' '.$text;
814
815        $text = ucp_preg_replace('%(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(https?|ftp|news){1}://([\p{L}\p{N}\-]+\.([\p{L}\p{N}\-]+\.)*[\p{L}\p{N}]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])%uie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5://$6\', \'$5://$6\', true).stripslashes(\'$4$10$11$12\')', $text);
816        $text = ucp_preg_replace('%(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(www|ftp)\.(([\p{L}\p{N}\-]+\.)*[\p{L}\p{N}]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])%uie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5.$6\', \'$5.$6\', true).stripslashes(\'$4$10$11$12\')', $text);
817
818        return substr($text, 1);
819}
820
821
822//
823// Convert a series of smilies to images
824//
825function do_smilies($text)
826{
827        global $pun_config, $smilies;
828
829        $text = ' '.$text.' ';
830
831        foreach ($smilies as $smiley_text => $smiley_img)
832        {
833                if (strpos($text, $smiley_text) !== false)
834                        $text = ucp_preg_replace('%(?<=[>\s])'.preg_quote($smiley_text, '%').'(?=[^\p{L}\p{N}])%um', '<img src="'.pun_htmlspecialchars(get_base_url(true).'/img/smilies/'.$smiley_img).'" width="15" height="15" alt="'.substr($smiley_img, 0, strrpos($smiley_img, '.')).'" />', $text);
835        }
836
837        return substr($text, 1, -1);
838}
839
840
841//
842// Parse message text
843//
844function parse_message($text, $hide_smilies)
845{
846        global $pun_config, $lang_common, $pun_user;
847
848        if ($pun_config['o_censoring'] == '1')
849                $text = censor_words($text);
850
851        // Convert applicable characters to HTML entities
852        $text = pun_htmlspecialchars($text);
853
854        // If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched)
855        if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
856                list($inside, $text) = extract_blocks($text, '[code]', '[/code]', $errors);
857
858        if ($pun_config['p_message_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
859                $text = do_bbcode($text);
860
861        if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0')
862                $text = do_smilies($text);
863
864        // Deal with newlines, tabs and multiple spaces
865        $pattern = array("\n", "\t", '  ', '  ');
866        $replace = array('<br />', '&#160; &#160; ', '&#160; ', ' &#160;');
867        $text = str_replace($pattern, $replace, $text);
868
869        // If we split up the message before we have to concatenate it together again (code tags)
870    if (isset($inside)) {
871        $parts = explode("\1", $text);
872        $text = '';
873        foreach ($parts as $i => $part)
874        {
875            $text .= $part;
876            if (isset($inside[$i]))
877            {
878                $num_lines = (substr_count($inside[$i], "\n"));
879                $text .= '</p><div class="codebox"><pre'.(($num_lines > 28) ? ' class="vscroll"' : '').'><code>'.pun_trim($inside[$i], "\n\r").'</code></pre></div><p>';
880            }
881        }
882    }
883
884        // Add paragraph tag around post, but make sure there are no empty paragraphs
885        $text = preg_replace('%<br />\s*?<br />((\s*<br />)*)%i', "</p>$1<p>", $text);
886        $text = str_replace('<p><br />', '<p>', $text);
887        $text = str_replace('<p></p>', '', '<p>'.$text.'</p>');
888
889        return $text;
890}
891
892
893//
894// Parse signature text
895//
896function parse_signature($text)
897{
898        global $pun_config, $lang_common, $pun_user;
899
900        if ($pun_config['o_censoring'] == '1')
901                $text = censor_words($text);
902
903        // Convert applicable characters to HTML entities
904        $text = pun_htmlspecialchars($text);
905
906        if ($pun_config['p_sig_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
907                $text = do_bbcode($text, true);
908
909        if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] == '1')
910                $text = do_smilies($text);
911
912
913        // Deal with newlines, tabs and multiple spaces
914        $pattern = array("\n", "\t", '  ', '  ');
915        $replace = array('<br />', '&#160; &#160; ', '&#160; ', ' &#160;');
916        $text = str_replace($pattern, $replace, $text);
917
918        // Add paragraph tag around post, but make sure there are no empty paragraphs
919        $text = preg_replace('%<br />\s*?<br />((\s*<br />)*)%i', "</p>$1<p>", $text);
920        $text = str_replace('<p><br />', '<p>', $text);
921        $text = str_replace('<p></p>', '', '<p>'.$text.'</p>');
922
923        return $text;
924}
Note: See TracBrowser for help on using the repository browser.