phpBB
Statistics
| Revision:

root / branches / phpBB-3_0_0 / phpBB / includes / bbcode.php

History | View | Annotate | Download (16.3 kB)

1
<?php
2
/**
3
*
4
* @package phpBB3
5
* @version $Id: bbcode.php 11348 2011-08-07 20:30:10Z git-gate $
6
* @copyright (c) 2005 phpBB Group
7
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8
*
9
*/
10
11
/**
12
* @ignore
13
*/
14
if (!defined('IN_PHPBB'))
15
{
16
        exit;
17
}
18
19
/**
20
* BBCode class
21
* @package phpBB3
22
*/
23
class bbcode
24
{
25
        var $bbcode_uid = '';
26
        var $bbcode_bitfield = '';
27
        var $bbcode_cache = array();
28
        var $bbcode_template = array();
29
30
        var $bbcodes = array();
31
32
        var $template_bitfield;
33
        var $template_filename = '';
34
35
        /**
36
        * Constructor
37
        * Init bbcode cache entries if bitfield is specified
38
        */
39
        function bbcode($bitfield = '')
40
        {
41
                if ($bitfield)
42
                {
43
                        $this->bbcode_bitfield = $bitfield;
44
                        $this->bbcode_cache_init();
45
                }
46
        }
47
48
        /**
49
        * Second pass bbcodes
50
        */
51
        function bbcode_second_pass(&$message, $bbcode_uid = '', $bbcode_bitfield = false)
52
        {
53
                if ($bbcode_uid)
54
                {
55
                        $this->bbcode_uid = $bbcode_uid;
56
                }
57
58
                if ($bbcode_bitfield !== false)
59
                {
60
                        $this->bbcode_bitfield = $bbcode_bitfield;
61
62
                        // Init those added with a new bbcode_bitfield (already stored codes will not get parsed again)
63
                        $this->bbcode_cache_init();
64
                }
65
66
                if (!$this->bbcode_bitfield)
67
                {
68
                        // Remove the uid from tags that have not been transformed into HTML
69
                        if ($this->bbcode_uid)
70
                        {
71
                                $message = str_replace(':' . $this->bbcode_uid, '', $message);
72
                        }
73
74
                        return;
75
                }
76
77
                $str = array('search' => array(), 'replace' => array());
78
                $preg = array('search' => array(), 'replace' => array());
79
80
                $bitfield = new bitfield($this->bbcode_bitfield);
81
                $bbcodes_set = $bitfield->get_all_set();
82
83
                $undid_bbcode_specialchars = false;
84
                foreach ($bbcodes_set as $bbcode_id)
85
                {
86
                        if (!empty($this->bbcode_cache[$bbcode_id]))
87
                        {
88
                                foreach ($this->bbcode_cache[$bbcode_id] as $type => $array)
89
                                {
90
                                        foreach ($array as $search => $replace)
91
                                        {
92
                                                ${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search);
93
                                                ${$type}['replace'][] = $replace;
94
                                        }
95
96
                                        if (sizeof($str['search']))
97
                                        {
98
                                                $message = str_replace($str['search'], $str['replace'], $message);
99
                                                $str = array('search' => array(), 'replace' => array());
100
                                        }
101
102
                                        if (sizeof($preg['search']))
103
                                        {
104
                                                // we need to turn the entities back into their original form to allow the
105
                                                // search patterns to work properly
106
                                                if (!$undid_bbcode_specialchars)
107
                                                {
108
                                                        $message = str_replace(array('&#58;', '&#46;'), array(':', '.'), $message);
109
                                                        $undid_bbcode_specialchars = true;
110
                                                }
111
112
                                                $message = preg_replace($preg['search'], $preg['replace'], $message);
113
                                                $preg = array('search' => array(), 'replace' => array());
114
                                        }
115
                                }
116
                        }
117
                }
118
119
                // Remove the uid from tags that have not been transformed into HTML
120
                $message = str_replace(':' . $this->bbcode_uid, '', $message);
121
        }
122
123
        /**
124
        * Init bbcode cache
125
        *
126
        * requires: $this->bbcode_bitfield
127
        * sets: $this->bbcode_cache with bbcode templates needed for bbcode_bitfield
128
        */
129
        function bbcode_cache_init()
130
        {
131
                global $phpbb_root_path, $template, $user;
132
133
                if (empty($this->template_filename))
134
                {
135
                        $this->template_bitfield = new bitfield($user->theme['bbcode_bitfield']);
136
                        $this->template_filename = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template/bbcode.html';
137
138
                        if (!@file_exists($this->template_filename))
139
                        {
140
                                if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'])
141
                                {
142
                                        $this->template_filename = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template/bbcode.html';
143
                                        if (!@file_exists($this->template_filename))
144
                                        {
145
                                                trigger_error('The file ' . $this->template_filename . ' is missing.', E_USER_ERROR);
146
                                        }
147
                                }
148
                                else
149
                                {
150
                                        trigger_error('The file ' . $this->template_filename . ' is missing.', E_USER_ERROR);
151
                                }
152
                        }
153
                }
154
155
                $bbcode_ids = $rowset = $sql = array();
156
157
                $bitfield = new bitfield($this->bbcode_bitfield);
158
                $bbcodes_set = $bitfield->get_all_set();
159
160
                foreach ($bbcodes_set as $bbcode_id)
161
                {
162
                        if (isset($this->bbcode_cache[$bbcode_id]))
163
                        {
164
                                // do not try to re-cache it if it's already in
165
                                continue;
166
                        }
167
                        $bbcode_ids[] = $bbcode_id;
168
169
                        if ($bbcode_id > NUM_CORE_BBCODES)
170
                        {
171
                                $sql[] = $bbcode_id;
172
                        }
173
                }
174
175
                if (sizeof($sql))
176
                {
177
                        global $db;
178
179
                        $sql = 'SELECT *
180
                                FROM ' . BBCODES_TABLE . '
181
                                WHERE ' . $db->sql_in_set('bbcode_id', $sql);
182
                        $result = $db->sql_query($sql, 3600);
183
184
                        while ($row = $db->sql_fetchrow($result))
185
                        {
186
                                // To circumvent replacing newlines with <br /> for the generated html,
187
                                // we use carriage returns here. They are later changed back to newlines
188
                                $row['bbcode_tpl'] = str_replace("\n", "\r", $row['bbcode_tpl']);
189
                                $row['second_pass_replace'] = str_replace("\n", "\r", $row['second_pass_replace']);
190
191
                                $rowset[$row['bbcode_id']] = $row;
192
                        }
193
                        $db->sql_freeresult($result);
194
                }
195
196
                foreach ($bbcode_ids as $bbcode_id)
197
                {
198
                        switch ($bbcode_id)
199
                        {
200
                                case 0:
201
                                        $this->bbcode_cache[$bbcode_id] = array(
202
                                                'str' => array(
203
                                                        '[/quote:$uid]'        => $this->bbcode_tpl('quote_close', $bbcode_id)
204
                                                ),
205
                                                'preg' => array(
206
                                                        '#\[quote(?:=&quot;(.*?)&quot;)?:$uid\]((?!\[quote(?:=&quot;.*?&quot;)?:$uid\]).)?#ise'        => "\$this->bbcode_second_pass_quote('\$1', '\$2')"
207
                                                )
208
                                        );
209
                                break;
210
211
                                case 1:
212
                                        $this->bbcode_cache[$bbcode_id] = array(
213
                                                'str' => array(
214
                                                        '[b:$uid]'        => $this->bbcode_tpl('b_open', $bbcode_id),
215
                                                        '[/b:$uid]'        => $this->bbcode_tpl('b_close', $bbcode_id),
216
                                                )
217
                                        );
218
                                break;
219
220
                                case 2:
221
                                        $this->bbcode_cache[$bbcode_id] = array(
222
                                                'str' => array(
223
                                                        '[i:$uid]'        => $this->bbcode_tpl('i_open', $bbcode_id),
224
                                                        '[/i:$uid]'        => $this->bbcode_tpl('i_close', $bbcode_id),
225
                                                )
226
                                        );
227
                                break;
228
229
                                case 3:
230
                                        $this->bbcode_cache[$bbcode_id] = array(
231
                                                'preg' => array(
232
                                                        '#\[url:$uid\]((.*?))\[/url:$uid\]#s'                        => $this->bbcode_tpl('url', $bbcode_id),
233
                                                        '#\[url=([^\[]+?):$uid\](.*?)\[/url:$uid\]#s'        => $this->bbcode_tpl('url', $bbcode_id),
234
                                                )
235
                                        );
236
                                break;
237
238
                                case 4:
239
                                        if ($user->optionget('viewimg'))
240
                                        {
241
                                                $this->bbcode_cache[$bbcode_id] = array(
242
                                                        'preg' => array(
243
                                                                '#\[img:$uid\](.*?)\[/img:$uid\]#s'                => $this->bbcode_tpl('img', $bbcode_id),
244
                                                        )
245
                                                );
246
                                        }
247
                                        else
248
                                        {
249
                                                $this->bbcode_cache[$bbcode_id] = array(
250
                                                        'preg' => array(
251
                                                                '#\[img:$uid\](.*?)\[/img:$uid\]#s'                => str_replace('$2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id, true)),
252
                                                        )
253
                                                );
254
                                        }
255
                                break;
256
257
                                case 5:
258
                                        $this->bbcode_cache[$bbcode_id] = array(
259
                                                'preg' => array(
260
                                                        '#\[size=([\-\+]?\d+):$uid\](.*?)\[/size:$uid\]#s'        => $this->bbcode_tpl('size', $bbcode_id),
261
                                                )
262
                                        );
263
                                break;
264
265
                                case 6:
266
                                        $this->bbcode_cache[$bbcode_id] = array(
267
                                                'preg' => array(
268
                                                        '!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+):$uid\](.*?)\[/color:$uid\]!is'        => $this->bbcode_tpl('color', $bbcode_id),
269
                                                )
270
                                        );
271
                                break;
272
273
                                case 7:
274
                                        $this->bbcode_cache[$bbcode_id] = array(
275
                                                'str' => array(
276
                                                        '[u:$uid]'        => $this->bbcode_tpl('u_open', $bbcode_id),
277
                                                        '[/u:$uid]'        => $this->bbcode_tpl('u_close', $bbcode_id),
278
                                                )
279
                                        );
280
                                break;
281
282
                                case 8:
283
                                        $this->bbcode_cache[$bbcode_id] = array(
284
                                                'preg' => array(
285
                                                        '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#ise'        => "\$this->bbcode_second_pass_code('\$1', '\$2')",
286
                                                )
287
                                        );
288
                                break;
289
290
                                case 9:
291
                                        $this->bbcode_cache[$bbcode_id] = array(
292
                                                'preg' => array(
293
                                                        '#(\[\/?(list|\*):[mou]?:?$uid\])[\n]{1}#'        => "\$1",
294
                                                        '#(\[list=([^\[]+):$uid\])[\n]{1}#'                        => "\$1",
295
                                                        '#\[list=([^\[]+):$uid\]#e'                                        => "\$this->bbcode_list('\$1')",
296
                                                ),
297
                                                'str' => array(
298
                                                        '[list:$uid]'                => $this->bbcode_tpl('ulist_open_default', $bbcode_id),
299
                                                        '[/list:u:$uid]'        => $this->bbcode_tpl('ulist_close', $bbcode_id),
300
                                                        '[/list:o:$uid]'        => $this->bbcode_tpl('olist_close', $bbcode_id),
301
                                                        '[*:$uid]'                        => $this->bbcode_tpl('listitem', $bbcode_id),
302
                                                        '[/*:$uid]'                        => $this->bbcode_tpl('listitem_close', $bbcode_id),
303
                                                        '[/*:m:$uid]'                => $this->bbcode_tpl('listitem_close', $bbcode_id)
304
                                                ),
305
                                        );
306
                                break;
307
308
                                case 10:
309
                                        $this->bbcode_cache[$bbcode_id] = array(
310
                                                'preg' => array(
311
                                                        '#\[email:$uid\]((.*?))\[/email:$uid\]#is'                        => $this->bbcode_tpl('email', $bbcode_id),
312
                                                        '#\[email=([^\[]+):$uid\](.*?)\[/email:$uid\]#is'        => $this->bbcode_tpl('email', $bbcode_id)
313
                                                )
314
                                        );
315
                                break;
316
317
                                case 11:
318
                                        if ($user->optionget('viewflash'))
319
                                        {
320
                                                $this->bbcode_cache[$bbcode_id] = array(
321
                                                        'preg' => array(
322
                                                                '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#'        => $this->bbcode_tpl('flash', $bbcode_id),
323
                                                        )
324
                                                );
325
                                        }
326
                                        else
327
                                        {
328
                                                $this->bbcode_cache[$bbcode_id] = array(
329
                                                        'preg' => array(
330
                                                                '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#'        => str_replace('$1', '$3', str_replace('$2', '[ flash ]', $this->bbcode_tpl('url', $bbcode_id, true)))
331
                                                        )
332
                                                );
333
                                        }
334
                                break;
335
336
                                case 12:
337
                                        $this->bbcode_cache[$bbcode_id] = array(
338
                                                'str'        => array(
339
                                                        '[/attachment:$uid]'        => $this->bbcode_tpl('inline_attachment_close', $bbcode_id)
340
                                                ),
341
                                                'preg'        => array(
342
                                                        '#\[attachment=([0-9]+):$uid\]#'        => $this->bbcode_tpl('inline_attachment_open', $bbcode_id)
343
                                                )
344
                                        );
345
                                break;
346
347
                                default:
348
                                        if (isset($rowset[$bbcode_id]))
349
                                        {
350
                                                if ($this->template_bitfield->get($bbcode_id))
351
                                                {
352
                                                        // The bbcode requires a custom template to be loaded
353
                                                        if (!$bbcode_tpl = $this->bbcode_tpl($rowset[$bbcode_id]['bbcode_tag'], $bbcode_id))
354
                                                        {
355
                                                                // For some reason, the required template seems not to be available, use the default template
356
                                                                $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl'];
357
                                                        }
358
                                                        else
359
                                                        {
360
                                                                // In order to use templates with custom bbcodes we need
361
                                                                // to replace all {VARS} to corresponding backreferences
362
                                                                // Note that backreferences are numbered from bbcode_match
363
                                                                if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|INTTEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m))
364
                                                                {
365
                                                                        foreach ($m[0] as $i => $tok)
366
                                                                        {
367
                                                                                $bbcode_tpl = str_replace($tok, '$' . ($i + 1), $bbcode_tpl);
368
                                                                        }
369
                                                                }
370
                                                        }
371
                                                }
372
                                                else
373
                                                {
374
                                                        // Default template
375
                                                        $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl'];
376
                                                }
377
378
                                                // Replace {L_*} lang strings
379
                                                $bbcode_tpl = preg_replace('/{L_([A-Z_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $bbcode_tpl);
380
381
                                                if (!empty($rowset[$bbcode_id]['second_pass_replace']))
382
                                                {
383
                                                        // The custom BBCode requires second-pass pattern replacements
384
                                                        $this->bbcode_cache[$bbcode_id] = array(
385
                                                                'preg' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl)
386
                                                        );
387
                                                }
388
                                                else
389
                                                {
390
                                                        $this->bbcode_cache[$bbcode_id] = array(
391
                                                                'str' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl)
392
                                                        );
393
                                                }
394
                                        }
395
                                        else
396
                                        {
397
                                                $this->bbcode_cache[$bbcode_id] = false;
398
                                        }
399
                                break;
400
                        }
401
                }
402
        }
403
404
        /**
405
        * Return bbcode template
406
        */
407
        function bbcode_tpl($tpl_name, $bbcode_id = -1, $skip_bitfield_check = false)
408
        {
409
                static $bbcode_hardtpl = array();
410
                if (empty($bbcode_hardtpl))
411
                {
412
                        global $user;
413
414
                        $bbcode_hardtpl = array(
415
                                'b_open'        => '<span style="font-weight: bold">',
416
                                'b_close'        => '</span>',
417
                                'i_open'        => '<span style="font-style: italic">',
418
                                'i_close'        => '</span>',
419
                                'u_open'        => '<span style="text-decoration: underline">',
420
                                'u_close'        => '</span>',
421
                                'img'                => '<img src="$1" alt="' . $user->lang['IMAGE'] . '" />',
422
                                'size'                => '<span style="font-size: $1%; line-height: normal">$2</span>',
423
                                'color'                => '<span style="color: $1">$2</span>',
424
                                'email'                => '<a href="mailto:$1">$2</a>'
425
                        );
426
                }
427
428
                if ($bbcode_id != -1 && !$skip_bitfield_check && !$this->template_bitfield->get($bbcode_id))
429
                {
430
                        return (isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false;
431
                }
432
433
                if (empty($this->bbcode_template))
434
                {
435
                        if (($tpl = file_get_contents($this->template_filename)) === false)
436
                        {
437
                                trigger_error('Could not load bbcode template', E_USER_ERROR);
438
                        }
439
440
                        // replace \ with \\ and then ' with \'.
441
                        $tpl = str_replace('\\', '\\\\', $tpl);
442
                        $tpl = str_replace("'", "\'", $tpl);
443
444
                        // strip newlines and indent
445
                        $tpl = preg_replace("/\n[\n\r\s\t]*/", '', $tpl);
446
447
                        // Turn template blocks into PHP assignment statements for the values of $bbcode_tpl..
448
                        $this->bbcode_template = array();
449
450
                        $matches = preg_match_all('#<!-- BEGIN (.*?) -->(.*?)<!-- END (?:.*?) -->#', $tpl, $match);
451
452
                        for ($i = 0; $i < $matches; $i++)
453
                        {
454
                                if (empty($match[1][$i]))
455
                                {
456
                                        continue;
457
                                }
458
459
                                $this->bbcode_template[$match[1][$i]] = $this->bbcode_tpl_replace($match[1][$i], $match[2][$i]);
460
                        }
461
                }
462
463
                return (isset($this->bbcode_template[$tpl_name])) ? $this->bbcode_template[$tpl_name] : ((isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false);
464
        }
465
466
        /**
467
        * Return bbcode template replacement
468
        */
469
        function bbcode_tpl_replace($tpl_name, $tpl)
470
        {
471
                global $user;
472
473
                static $replacements = array(
474
                        'quote_username_open'        => array('{USERNAME}'        => '$1'),
475
                        'color'                                        => array('{COLOR}'                => '$1', '{TEXT}'                        => '$2'),
476
                        'size'                                        => array('{SIZE}'                => '$1', '{TEXT}'                        => '$2'),
477
                        'img'                                        => array('{URL}'                => '$1'),
478
                        'flash'                                        => array('{WIDTH}'                => '$1', '{HEIGHT}'                        => '$2', '{URL}'        => '$3'),
479
                        'url'                                        => array('{URL}'                => '$1', '{DESCRIPTION}'        => '$2'),
480
                        'email'                                        => array('{EMAIL}'                => '$1', '{DESCRIPTION}'        => '$2')
481
                );
482
483
                $tpl = preg_replace('/{L_([A-Z_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $tpl);
484
485
                if (!empty($replacements[$tpl_name]))
486
                {
487
                        $tpl = strtr($tpl, $replacements[$tpl_name]);
488
                }
489
490
                return trim($tpl);
491
        }
492
493
        /**
494
        * Second parse list bbcode
495
        */
496
        function bbcode_list($type)
497
        {
498
                if ($type == '')
499
                {
500
                        $tpl = 'ulist_open_default';
501
                        $type = 'default';
502
                }
503
                else if ($type == 'i')
504
                {
505
                        $tpl = 'olist_open';
506
                        $type = 'lower-roman';
507
                }
508
                else if ($type == 'I')
509
                {
510
                        $tpl = 'olist_open';
511
                        $type = 'upper-roman';
512
                }
513
                else if (preg_match('#^(disc|circle|square)$#i', $type))
514
                {
515
                        $tpl = 'ulist_open';
516
                        $type = strtolower($type);
517
                }
518
                else if (preg_match('#^[a-z]$#', $type))
519
                {
520
                        $tpl = 'olist_open';
521
                        $type = 'lower-alpha';
522
                }
523
                else if (preg_match('#[A-Z]#', $type))
524
                {
525
                        $tpl = 'olist_open';
526
                        $type = 'upper-alpha';
527
                }
528
                else if (is_numeric($type))
529
                {
530
                        $tpl = 'olist_open';
531
                        $type = 'decimal';
532
                }
533
                else
534
                {
535
                        $tpl = 'olist_open';
536
                        $type = 'decimal';
537
                }
538
539
                return str_replace('{LIST_TYPE}', $type, $this->bbcode_tpl($tpl));
540
        }
541
542
        /**
543
        * Second parse quote tag
544
        */
545
        function bbcode_second_pass_quote($username, $quote)
546
        {
547
                // when using the /e modifier, preg_replace slashes double-quotes but does not
548
                // seem to slash anything else
549
                $quote = str_replace('\"', '"', $quote);
550
                $username = str_replace('\"', '"', $username);
551
552
                // remove newline at the beginning
553
                if ($quote == "\n")
554
                {
555
                        $quote = '';
556
                }
557
558
                $quote = (($username) ? str_replace('$1', $username, $this->bbcode_tpl('quote_username_open')) : $this->bbcode_tpl('quote_open')) . $quote;
559
560
                return $quote;
561
        }
562
563
        /**
564
        * Second parse code tag
565
        */
566
        function bbcode_second_pass_code($type, $code)
567
        {
568
                // when using the /e modifier, preg_replace slashes double-quotes but does not
569
                // seem to slash anything else
570
                $code = str_replace('\"', '"', $code);
571
572
                switch ($type)
573
                {
574
                        case 'php':
575
                                // Not the english way, but valid because of hardcoded syntax highlighting
576
                                if (strpos($code, '<span class="syntaxdefault"><br /></span>') === 0)
577
                                {
578
                                        $code = substr($code, 41);
579
                                }
580
581
                        // no break;
582
583
                        default:
584
                                $code = str_replace("\t", '&nbsp; &nbsp;', $code);
585
                                $code = str_replace('  ', '&nbsp; ', $code);
586
                                $code = str_replace('  ', ' &nbsp;', $code);
587
                                $code = str_replace("\n ", "\n&nbsp;", $code);
588
589
                                // keep space at the beginning
590
                                if (!empty($code) && $code[0] == ' ')
591
                                {
592
                                        $code = '&nbsp;' . substr($code, 1);
593
                                }
594
595
                                // remove newline at the beginning
596
                                if (!empty($code) && $code[0] == "\n")
597
                                {
598
                                        $code = substr($code, 1);
599
                                }
600
                        break;
601
                }
602
603
                $code = $this->bbcode_tpl('code_open') . $code . $this->bbcode_tpl('code_close');
604
605
                return $code;
606
        }
607
}
608
609
?>