6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
14 if (!defined('IN_PHPBB'))
19 if (!class_exists('bbcode'))
21 include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
26 * BBCODE first pass class (functions for parsing messages for db storage)
29 class bbcode_firstpass
extends bbcode
32 var $warn_msg = array();
33 var $parsed_items = array();
38 function parse_bbcode()
46 $this->bbcode_bitfield
= 0;
48 $size = strlen($this->message
);
49 foreach ($this->bbcodes
as $bbcode_name => $bbcode_data)
51 if (isset($bbcode_data['disabled']) && $bbcode_data['disabled'])
53 foreach ($bbcode_data['regexp'] as $regexp => $replacement)
55 if (preg_match($regexp, $this->message
))
57 $this->warn_msg
[] = $user->lang
['UNAUTHORISED_BBCODE'] . '[' . $bbcode_name . ']';
64 foreach ($bbcode_data['regexp'] as $regexp => $replacement)
66 $this->message
= preg_replace($regexp, $replacement, $this->message
);
70 // Because we add bbcode_uid to all tags, the message length
71 // will increase whenever a tag is found
72 $new_size = strlen($this->message
);
73 if ($size != $new_size)
75 $this->bbcode_bitfield |
= (1 << $bbcode_data['bbcode_id']);
82 * Prepare some bbcodes for better parsing
84 function prepare_bbcodes()
86 // Add newline at the end and in front of each quote block to prevent parsing errors (urls, smilies, etc.)
87 if (strpos($this->message
, '[quote') !== false)
89 $in = str_replace("\r\n", "\n", $this->message
);
91 $this->message
= preg_replace(array('#\[quote(=".*?")?\]([^\n])#is', '#([^\n])\[\/quote\]#is'), array("[quote\\1]\n\\2", "\\1\n[/quote]"), $this->message
);
92 $this->message
= preg_replace(array('#\[quote(=".*?")?\]([^\n])#is', '#([^\n])\[\/quote\]#is'), array("[quote\\1]\n\\2", "\\1\n[/quote]"), $this->message
);
95 // Add other checks which needs to be placed before actually parsing anything (be it bbcodes, smilies, urls...)
99 * Init bbcode data for later parsing
101 function bbcode_init()
105 // This array holds all bbcode data. BBCodes will be processed in this
106 // order, so it is important to keep [code] in first position and
107 // [quote] in second position.
108 $this->bbcodes
= array(
109 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\$1', '\$2')")),
110 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\$0')")),
111 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#ise' => "\$this->bbcode_attachment('\$1', '\$2')")),
112 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#ise' => "\$this->bbcode_strong('\$1')")),
113 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#ise' => "\$this->bbcode_italic('\$1')")),
114 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")),
115 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](https?://)([a-z0-9\-\.,\?!%\*_:;~\\&$@/=\+]+)\[/img\]#ie' => "\$this->bbcode_img('\$1\$2')")),
116 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?[1-2]?[0-9])\](.*?)\[/size\]#ise' => "\$this->bbcode_size('\$1', '\$2')")),
117 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9A-Fa-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")),
118 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#ise' => "\$this->bbcode_underline('\$1')")),
119 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(=[a-z|0-9|(?:disc|circle|square))]+)?\].*\[/list\]#ise' => "\$this->bbcode_parse_list('\$0')")),
120 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")),
121 'flash' => array('bbcode_id' => 11, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')"))
124 // Zero the parsed items array
125 $this->parsed_items
= array();
127 foreach ($this->bbcodes
as $tag => $bbcode_data)
129 $this->parsed_items
[$tag] = 0;
132 if (!is_array($rowset))
138 FROM ' . BBCODES_TABLE
;
139 $result = $db->sql_query($sql);
141 while ($row = $db->sql_fetchrow($result))
145 $db->sql_freeresult($result);
148 foreach ($rowset as $row)
150 $this->bbcodes
[$row['bbcode_tag']] = array(
151 'bbcode_id' => (int) $row['bbcode_id'],
152 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid
, $row['first_pass_replace']))
158 * Making some pre-checks for bbcodes as well as increasing the number of parsed items
160 function check_bbcode($bbcode, &$in)
162 // when using the /e modifier, preg_replace slashes double-quotes but does not
163 // seem to slash anything else
164 $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in));
166 // Trimming here to make sure no empty bbcodes are parsed accidently
172 $this->parsed_items
[$bbcode]++
;
178 * Transform some characters in valid bbcodes
180 function bbcode_specialchars($text)
182 $str_from = array('<', '>', '[', ']', '.', ':');
183 $str_to = array('<', '>', '[', ']', '.', ':');
185 return str_replace($str_from, $str_to, $text);
191 function bbcode_size($stx, $in)
193 global $user, $config;
195 if (!$this->check_bbcode('size', $in))
200 if ($config['max_' . $this->mode
. '_font_size'] && $config['max_' . $this->mode
. '_font_size'] < $stx)
202 $this->warn_msg
[] = sprintf($user->lang
['MAX_FONT_SIZE_EXCEEDED'], $config['max_' . $this->mode
. '_font_size']);
205 return '[size=' . $stx . ':' . $this->bbcode_uid
. ']' . $in . '[/size:' . $this->bbcode_uid
. ']';
211 function bbcode_color($stx, $in)
213 if (!$this->check_bbcode('color', $in))
218 return '[color=' . $stx . ':' . $this->bbcode_uid
. ']' . $in . '[/color:' . $this->bbcode_uid
. ']';
224 function bbcode_underline($in)
226 if (!$this->check_bbcode('u', $in))
231 return '[u:' . $this->bbcode_uid
. ']' . $in . '[/u:' . $this->bbcode_uid
. ']';
237 function bbcode_strong($in)
239 if (!$this->check_bbcode('b', $in))
244 return '[b:' . $this->bbcode_uid
. ']' . $in . '[/b:' . $this->bbcode_uid
. ']';
250 function bbcode_italic($in)
252 if (!$this->check_bbcode('i', $in))
257 return '[i:' . $this->bbcode_uid
. ']' . $in . '[/i:' . $this->bbcode_uid
. ']';
263 function bbcode_img($in)
265 global $user, $config, $phpEx;
267 if (!$this->check_bbcode('img', $in))
274 if ($config['max_' . $this->mode
. '_img_height'] ||
$config['max_' . $this->mode
. '_img_width'])
276 $stats = @getimagesize
($in);
278 if ($stats === false)
280 $this->warn_msg
[] = $user->lang
['UNABLE_GET_IMAGE_SIZE'];
284 if ($config['max_' . $this->mode
. '_img_height'] && $config['max_' . $this->mode
. '_img_height'] < $stats[1])
286 $this->warn_msg
[] = sprintf($user->lang
['MAX_IMG_HEIGHT_EXCEEDED'], $config['max_' . $this->mode
. '_img_height']);
289 if ($config['max_' . $this->mode
. '_img_width'] && $config['max_' . $this->mode
. '_img_width'] < $stats[0])
291 $this->warn_msg
[] = sprintf($user->lang
['MAX_IMG_WIDTH_EXCEEDED'], $config['max_' . $this->mode
. '_img_width']);
296 if ($this->path_in_domain($in))
298 return '[img]' . $in . '[/img]';
301 return '[img:' . $this->bbcode_uid
. ']' . $this->bbcode_specialchars($in) . '[/img:' . $this->bbcode_uid
. ']';
307 function bbcode_flash($width, $height, $in)
309 global $user, $config, $phpEx;
311 if (!$this->check_bbcode('flash', $in))
318 // Apply the same size checks on flash files as on images
319 if ($config['max_' . $this->mode
. '_img_height'] ||
$config['max_' . $this->mode
. '_img_width'])
321 if ($config['max_' . $this->mode
. '_img_height'] && $config['max_' . $this->mode
. '_img_height'] < $height)
323 $this->warn_msg
[] = sprintf($user->lang
['MAX_FLASH_HEIGHT_EXCEEDED'], $config['max_' . $this->mode
. '_img_height']);
326 if ($config['max_' . $this->mode
. '_img_width'] && $config['max_' . $this->mode
. '_img_width'] < $width)
328 $this->warn_msg
[] = sprintf($user->lang
['MAX_FLASH_WIDTH_EXCEEDED'], $config['max_' . $this->mode
. '_img_width']);
332 if ($this->path_in_domain($in))
334 return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]';
337 return '[flash=' . $width . ',' . $height . ':' . $this->bbcode_uid
. ']' . $this->bbcode_specialchars($in) . '[/flash:' . $this->bbcode_uid
. ']';
341 * Parse inline attachments [ia]
343 function bbcode_attachment($stx, $in)
345 if (!$this->check_bbcode('attachment', $in))
350 return '[attachment=' . $stx . ':' . $this->bbcode_uid
. ']<!-- ia' . $stx . ' -->' . trim($in) . '<!-- ia' . $stx . ' -->[/attachment:' . $this->bbcode_uid
. ']';
355 * Expects the argument to start right after the opening [code] tag and to end with [/code]
357 function bbcode_code($stx, $in)
359 if (!$this->check_bbcode('code', $in))
364 // We remove the hardcoded elements from the code block here because it is not used in code blocks
365 // Having it here saves us one preg_replace per message containing [code] blocks
366 // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too...
368 '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
369 '#<!\-\- m \-\-><a href="(.*?)" target="_blank">.*?</a><!\-\- m \-\->#',
370 '#<!\-\- w \-\-><a href="http:\/\/(.*?)" target="_blank">.*?</a><!\-\- w \-\->#',
371 '#<!\-\- l \-\-><a href="(.*?)">.*?</a><!\-\- l \-\->#',
372 '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
375 $htm_replace = array('\1', '\1', '\1', '\1', '\1', '&#\1;');
381 $pos = stripos($in, '[/code]') +
7;
382 $code = substr($in, 0, $pos);
383 $in = substr($in, $pos);
385 // $code contains everything that was between code tags (including the ending tag) but we're trying to grab as much extra text as possible, as long as it does not contain open [code] tags
388 $pos = stripos($in, '[/code]') +
7;
389 $buffer = substr($in, 0, $pos);
391 if (preg_match('#\[code(?:=([a-z]+))?\]#i', $buffer))
397 $in = substr($in, $pos);
402 $code = substr($code, 0, -7);
403 // $code = preg_replace('#^[\r\n]*(.*?)[\n\r\s\t]*$#s', '$1', $code);
404 $code = preg_replace($htm_match, $htm_replace, $code);
406 switch (strtolower($stx))
411 $remove_tags = false;
412 $code = str_replace(array('<', '>'), array('<', '>'), $code);
414 if (!preg_match('/^\<\?.*?\?\>/is', $code))
417 $code = "<?php $code ?>";
420 $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string');
421 foreach ($conf as $ini_var)
423 ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var));
426 // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results
427 $code = html_entity_decode($code);
428 $code = highlight_string($code, true);
430 $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':');
431 $str_to = array('<span class="', '<span class="syntax', '</span>', '', '', '[', ']', '.', ':');
435 $str_from[] = '<span class="syntaxdefault"><?php </span>';
437 $str_from[] = '<span class="syntaxdefault"><?php ';
438 $str_to[] = '<span class="syntaxdefault">';
441 $code = str_replace($str_from, $str_to, $code);
442 $code = preg_replace('#^(<span class="[a-z_]+">)\n?(.*?)\n?(</span>)$#is', '$1$2$3', $code);
446 $code = preg_replace('#(<span class="[a-z]+">)?\?></span>#', '', $code);
449 $code = preg_replace('#^<span class="[a-z]+"><span class="([a-z]+)">(.*)</span></span>#s', '<span class="$1">$2</span>', $code);
450 $code = preg_replace('#(?:[\n\r\s\t]| )*</span>$#', '</span>', $code);
452 $out .= "[code=$stx:" . $this->bbcode_uid
. ']' . $code . '[/code:' . $this->bbcode_uid
. ']';
456 $out .= '[code:' . $this->bbcode_uid
. ']' . $this->bbcode_specialchars($code) . '[/code:' . $this->bbcode_uid
. ']';
460 if (preg_match('#(.*?)\[code(?:=([a-z]+))?\](.+)#is', $in, $m))
474 * Expects the argument to start with a tag
476 function bbcode_parse_list($in)
478 if (!$this->check_bbcode('list', $in))
485 // Grab item_start with no item_end
486 $in = preg_replace('#\[\*\](.*?)(\[\/list\]|\[list(=?(?:[0-9]|[a-z]|))\]|\[\*\])#is', '[*:' . $this->bbcode_uid
. ']\1[/*:m:' . $this->bbcode_uid
. ']\2', $in);
488 // Grab them again as backreference
489 $in = preg_replace('#\[\*\](.*?)(\[\/list\]|\[list(=?(?:[0-9]|[a-z]|))\]|\[\*\])(^\[\/*\])#is', '[*:' . $this->bbcode_uid
. ']\1[/*:m:' . $this->bbcode_uid
. ']\2', $in);
491 // Grab end tag following start tag
492 $in = preg_replace('#\[\/\*:m:' . $this->bbcode_uid
. '\](\n|)\[\*\]#is', '[/*:m:' . $this->bbcode_uid
. '][*:' . $this->bbcode_uid
. ']', $in);
495 $in = preg_replace('#\[\/\*\]#i', '[/*:' . $this->bbcode_uid
. ']', $in);
497 // $tok holds characters to stop at. Since the string starts with a '[' we'll get everything up to the first ']' which should be the opening [list] tag
501 $in = substr($in, 1);
502 $list_end_tags = array();
507 for ($i = 0; $i < strlen($tok); ++
$i)
509 $tmp_pos = strpos($in, $tok{$i});
511 if ($tmp_pos !== false && $tmp_pos < $pos)
517 $buffer = substr($in, 0, $pos);
520 $in = substr($in, $pos +
1);
524 // if $tok is ']' the buffer holds a tag
525 if ($buffer == '/list' && sizeof($list_end_tags))
527 $out .= array_pop($list_end_tags) . ']';
530 else if (preg_match('#list(=?(?:[0-9]|[a-z]|))#i', $buffer, $m))
532 // sub-list, add a closing tag
533 if (!$m[1] ||
preg_match('/^(disc|square|circle)$/i', $m[1]))
535 array_push($list_end_tags, '/list:u:' . $this->bbcode_uid
);
539 array_push($list_end_tags, '/list:o:' . $this->bbcode_uid
);
541 $out .= $buffer . ':' . $this->bbcode_uid
. ']';
546 $out .= $buffer . $tok;
552 // Not within a tag, just add buffer to the return string
553 $out .= $buffer . $tok;
554 $tok = ($tok == '[') ?
']' : '[]';
559 if (sizeof($list_end_tags))
561 $out .= '[' . implode('][', $list_end_tags) . ']';
569 * Expects the argument to start with a tag
571 function bbcode_quote($in)
573 global $config, $user;
575 $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in)));
585 $in = substr($in, 1);
586 $close_tags = $error_ary = array();
592 for ($i = 0; $i < strlen($tok); ++
$i)
594 $tmp_pos = strpos($in, $tok{$i});
595 if ($tmp_pos !== false && $tmp_pos < $pos)
601 $buffer .= substr($in, 0, $pos);
603 $in = substr($in, $pos +
1);
607 if ($buffer == '/quote' && sizeof($close_tags))
609 // we have found a closing tag
610 // Add space at the end of the closing tag to allow following urls/smilies to be parsed correctly
611 $out .= array_pop($close_tags) . '] ';
615 else if (preg_match('#^quote(?:="(.*?)")?$#is', $buffer, $m))
617 $this->parsed_items
['quote']++
;
619 // the buffer holds a valid opening tag
620 if ($config['max_quote_depth'] && sizeof($close_tags) >= $config['max_quote_depth'])
622 // there are too many nested quotes
623 $error_ary['quote_depth'] = sprintf($user->lang
['QUOTE_DEPTH_EXCEEDED'], $config['max_quote_depth']);
625 $out .= $buffer . $tok;
632 array_push($close_tags, '/quote:' . $this->bbcode_uid
);
634 if (isset($m[1]) && $m[1])
636 $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[$1', $m[1]);
640 preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags);
641 foreach ($tags[1] as $tag)
645 $end_tags[] = '/' . $tag;
649 $end_tag = array_pop($end_tags);
650 if ($end_tag != $tag)
663 $username = str_replace('[', '[', str_replace(']', ']', $m[1]));
666 $out .= 'quote="' . $username . '":' . $this->bbcode_uid
. ']';
670 $out .= 'quote:' . $this->bbcode_uid
. ']';
676 else if (preg_match('#^quote="(.*?)#is', $buffer, $m))
678 // the buffer holds an invalid opening tag
683 $out .= $buffer . $tok;
690 $out .= $buffer . $tok;
691 $tok = ($tok == '[') ?
']' : '[]';
697 if (sizeof($close_tags))
699 $out .= '[' . implode('][', $close_tags) . ']';
702 foreach ($error_ary as $error_msg)
704 $this->warn_msg
[] = $error_msg;
713 function validate_email($var1, $var2)
715 $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
716 $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
719 $email = ($var1) ?
$var1 : $var2;
723 if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email))
730 return '[email' . (($var1) ?
"=$var1" : '') . ']' . $var2 . '[/email]';
733 $this->parsed_items
['email']++
;
737 $retval = '[email=' . $this->bbcode_specialchars($email) . ':' . $this->bbcode_uid
. ']' . $txt . '[/email:' . $this->bbcode_uid
. ']';
741 $retval = '[email:' . $this->bbcode_uid
. ']' . $this->bbcode_specialchars($email) . '[/email:' . $this->bbcode_uid
. ']';
750 function validate_url($var1, $var2)
754 $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
755 $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
757 $url = ($var1) ?
$var1 : $var2;
760 if (!$url ||
($var1 && !$var2))
766 if (preg_match('#' . preg_quote(generate_board_url(), '#') . '/([^ \t\n\r<"\']+)#i', $url) ||
767 preg_match('#([\w]+?://.*?[^ \t\n\r<"\']*)#i', $url) ||
768 preg_match('#(www\.[\w\-]+\.[\w\-.\~]+(?:/[^ \t\n\r<"\']*)?)#i', $url))
775 $this->parsed_items
['url']++
;
777 if (!preg_match('#^[\w]+?://.*?#i', $url))
779 $url = 'http://' . $url;
782 // We take our test url and stick on the first bit of text we get to check if we are really at the domain. If so, lets go!
783 if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false)
785 $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}/', '\1', $url);
788 return ($var1) ?
'[url=' . $this->bbcode_specialchars($url) . ':' . $this->bbcode_uid
. ']' . $var2 . '[/url:' . $this->bbcode_uid
. ']' : '[url:' . $this->bbcode_uid
. ']' . $this->bbcode_specialchars($url) . '[/url:' . $this->bbcode_uid
. ']';
791 return '[url' . (($var1) ?
'=' . $var1 : '') . ']' . $var2 . '[/url]';
795 * Check if url is pointing to this domain/script_path/php-file
797 * @param string $url the url to check
798 * @return true if the url is pointing to this domain/script_path/php-file, false if not
802 function path_in_domain($url)
804 global $config, $phpEx, $user;
806 $check_path = ($user->page
['root_script_path'] != '/') ?
substr($user->page
['root_script_path'], 0, -1) : '/';
808 // Is the user trying to link to a php file in this domain and script path?
809 if (strpos($url, ".{$phpEx}") !== false && strpos($url, $check_path) !== false)
811 $server_name = (!empty($_SERVER['SERVER_NAME'])) ?
$_SERVER['SERVER_NAME'] : getenv('SERVER_NAME');
813 // Forcing server vars is the only way to specify/override the protocol
814 if ($config['force_server_vars'] ||
!$server_name)
816 $server_name = $config['server_name'];
819 // Check again in correct order...
820 $pos_ext = strpos($url, ".{$phpEx}");
821 $pos_path = strpos($url, $check_path);
822 $pos_domain = strpos($url, $server_name);
824 if ($pos_domain !== false && $pos_path >= $pos_domain && $pos_ext >= $pos_path)
835 * Main message parser for posting, pm, etc. takes raw message
836 * and parses it for attachments, bbcode and smilies
839 class parse_message
extends bbcode_firstpass
841 var $attachment_data = array();
842 var $filename_data = array();
844 // Helps ironing out user error
845 var $message_status = '';
847 var $allow_img_bbcode = true;
848 var $allow_flash_bbcode = true;
849 var $allow_quote_bbcode = true;
854 * Init - give message here or manually
856 function parse_message($message = '')
859 $this->bbcode_uid
= substr(md5(time()), 0, BBCODE_UID_LEN
);
863 $this->message
= $message;
870 function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $update_this_message = true, $mode = 'post')
872 global $config, $db, $user;
874 $mode = ($mode != 'post') ?
'sig' : 'post';
878 $this->allow_img_bbcode
= $allow_img_bbcode;
879 $this->allow_flash_bbcode
= $allow_flash_bbcode;
880 $this->allow_quote_bbcode
= $allow_quote_bbcode;
882 // If false, then $this->message won't be altered, the text will be returned instead.
883 if (!$update_this_message)
885 $tmp_message = $this->message
;
886 $return_message = &$this->message
;
889 if ($this->message_status
== 'display')
891 $this->decode_message();
894 // Do some general 'cleanup' first before processing message,
895 // e.g. remove excessive newlines(?), smilies(?)
896 // Transform \r\n and \r into \n
897 $match = array('#\r\n?#', "#([\n][\s]+){3,}#", '#(script|about|applet|activex|chrome):#i');
898 $replace = array("\n", "\n\n", "\\1:");
899 $this->message
= preg_replace($match, $replace, trim($this->message
));
901 // Message length check. -1 disables this check completely.
902 if ($config['max_' . $mode . '_chars'] != -1)
904 $msg_len = ($mode == 'post') ?
strlen($this->message
) : strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#is', ' ', $this->message
));
906 if ((!$msg_len && $mode !== 'sig') ||
$config['max_' . $mode . '_chars'] && $msg_len > $config['max_' . $mode . '_chars'])
908 $this->warn_msg
[] = (!$msg_len) ?
$user->lang
['TOO_FEW_CHARS'] : $user->lang
['TOO_MANY_CHARS'];
909 return $this->warn_msg
;
913 // Prepare BBcode (just prepares some tags for better parsing)
914 if ($allow_bbcode && strpos($this->message
, '[') !== false)
916 $this->bbcode_init();
917 $disallow = array('img', 'flash', 'quote');
918 foreach ($disallow as $bool)
920 if (!$
{'allow_' . $bool . '_bbcode'})
922 $this->bbcodes
[$bool]['disabled'] = true;
926 $this->prepare_bbcodes();
932 $this->smilies($config['max_' . $mode . '_smilies']);
938 if ($allow_bbcode && strpos($this->message
, '[') !== false)
940 $this->parse_bbcode();
941 $num_urls +
= $this->parsed_items
['url'];
945 if ($allow_magic_url)
947 $this->magic_url(generate_board_url());
949 if ($config['max_' . $mode . '_urls'])
951 $num_urls +
= preg_match_all('#\<!-- (l|m|w|e) --\>.*?\<!-- \1 --\>#', $this->message
, $matches);
955 // Check number of links
956 if ($config['max_' . $mode . '_urls'] && $num_urls > $config['max_' . $mode . '_urls'])
958 $this->warn_msg
[] = sprintf($user->lang
['TOO_MANY_URLS'], $config['max_' . $mode . '_urls']);
959 return $this->warn_msg
;
962 if (!$update_this_message)
964 unset($this->message
);
965 $this->message
= $tmp_message;
966 return $return_message;
969 $this->message_status
= 'parsed';
974 * Formatting text for display
976 function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true)
978 // If false, then the parsed message get returned but internal message not processed.
979 if (!$update_this_message)
981 $tmp_message = $this->message
;
982 $return_message = &$this->message
;
985 if ($this->message_status
== 'plain')
987 // Force updating message - of course.
988 $this->parse($allow_bbcode, $allow_magic_url, $allow_smilies, $this->allow_img_bbcode
, $this->allow_flash_bbcode
, $this->allow_quote_bbcode
, true);
994 $this->bbcode_cache_init();
996 // We are giving those parameters to be able to use the bbcode class on its own
997 $this->bbcode_second_pass($this->message
, $this->bbcode_uid
);
1000 $this->message
= smiley_text($this->message
, !$allow_smilies);
1002 // Replace naughty words such as farty pants
1003 $this->message
= str_replace("\n", '<br />', censor_text($this->message
));
1005 if (!$update_this_message)
1007 unset($this->message
);
1008 $this->message
= $tmp_message;
1009 return $return_message;
1012 $this->message_status
= 'display';
1017 * Decode message to be placed back into form box
1019 function decode_message($custom_bbcode_uid = '', $update_this_message = true)
1021 // If false, then the parsed message get returned but internal message not processed.
1022 if (!$update_this_message)
1024 $tmp_message = $this->message
;
1025 $return_message = &$this->message
;
1028 ($custom_bbcode_uid) ?
decode_message($this->message
, $custom_bbcode_uid) : decode_message($this->message
, $this->bbcode_uid
);
1030 if (!$update_this_message)
1032 unset($this->message
);
1033 $this->message
= $tmp_message;
1034 return $return_message;
1037 $this->message_status
= 'plain';
1042 * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx.
1043 * Cuts down displayed size of link if over 50 chars, turns absolute links
1044 * into relative versions when the server/script path matches the link
1046 function magic_url($server_url)
1048 // We use the global make_clickable function
1049 $this->message
= make_clickable($this->message
, $server_url);
1055 function smilies($max_smilies = 0)
1057 global $db, $user, $phpbb_root_path;
1061 // See if the static arrays have already been filled on an earlier invocation
1062 if (!is_array($match))
1064 $match = $replace = array();
1066 // NOTE: obtain_* function? chaching the table contents?
1068 // For now setting the ttl to 10 minutes
1074 FROM ' . SMILIES_TABLE
. '
1075 ORDER BY LEN(code) DESC';
1080 FROM ' . SMILIES_TABLE
. '
1081 ORDER BY STRLEN(code) DESC';
1084 // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure...
1087 FROM ' . SMILIES_TABLE
. '
1088 ORDER BY LENGTH(code) DESC';
1091 $result = $db->sql_query($sql, 600);
1093 while ($row = $db->sql_fetchrow($result))
1096 $match[] = '#(?<=^|[\n ]|\.)' . preg_quote($row['code'], '#') . '#';
1097 $replace[] = '<!-- s' . $row['code'] . ' --><img src="{SMILIES_PATH}/' . $row['smiley_url'] . '" border="0" alt="' . $row['emotion'] . '" title="' . $row['emotion'] . '" /><!-- s' . $row['code'] . ' -->';
1099 $db->sql_freeresult($result);
1106 $num_matches = preg_match_all('#' . str_replace('#', '', implode('|', $match)) . '#', $this->message
, $matches);
1109 if ($num_matches !== false && $num_matches > $max_smilies)
1111 $this->warn_msg
[] = sprintf($user->lang
['TOO_MANY_SMILIES'], $max_smilies);
1115 $this->message
= trim(preg_replace($match, $replace, $this->message
));
1122 function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false)
1124 global $config, $auth, $user, $phpbb_root_path, $phpEx;
1128 $num_attachments = sizeof($this->attachment_data
);
1129 $this->filename_data
['filecomment'] = request_var('filecomment', '', true);
1130 $upload_file = (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none' && trim($_FILES[$form_name]['name'])) ?
true : false;
1132 $add_file = (isset($_POST['add_file'])) ?
true : false;
1133 $delete_file = (isset($_POST['delete_file'])) ?
true : false;
1134 $edit_comment = (isset($_POST['edit_comment'])) ?
true : false;
1137 $cfg['max_attachments'] = ($is_message) ?
$config['max_attachments_pm'] : $config['max_attachments'];
1138 $forum_id = ($is_message) ?
0 : $forum_id;
1140 if ($submit && in_array($mode, array('post', 'reply', 'quote', 'edit')) && $upload_file)
1142 if ($num_attachments < $cfg['max_attachments'] ||
$auth->acl_get('a_') ||
$auth->acl_get('m_', $forum_id))
1144 $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
1145 $error = $filedata['error'];
1147 if ($filedata['post_attach'] && !sizeof($error))
1150 'physical_filename' => $filedata['physical_filename'],
1151 'comment' => $this->filename_data
['filecomment'],
1152 'real_filename' => $filedata['real_filename'],
1153 'extension' => $filedata['extension'],
1154 'mimetype' => $filedata['mimetype'],
1155 'filesize' => $filedata['filesize'],
1156 'filetime' => $filedata['filetime'],
1158 'thumbnail' => $filedata['thumbnail']
1161 $this->attachment_data
= array_merge(array(0 => $new_entry), $this->attachment_data
);
1162 $this->message
= preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message
);
1164 $this->filename_data
['filecomment'] = '';
1166 // This Variable is set to false here, because Attachments are entered into the
1167 // Database in two modes, one if the id_list is 0 and the second one if post_attach is true
1168 // Since post_attach is automatically switched to true if an Attachment got added to the filesystem,
1169 // but we are assigning an id of 0 here, we have to reset the post_attach variable to false.
1171 // This is very relevant, because it could happen that the post got not submitted, but we do not
1172 // know this circumstance here. We could be at the posting page or we could be redirected to the entered
1174 $filedata['post_attach'] = false;
1179 $error[] = sprintf($user->lang
['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']);
1183 if ($preview ||
$refresh ||
sizeof($error))
1185 // Perform actions on temporary attachments
1188 include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1190 $index = (int) key($_POST['delete_file']);
1192 // delete selected attachment
1193 if (!$this->attachment_data
[$index]['attach_id'])
1195 phpbb_unlink($this->attachment_data
[$index]['physical_filename'], 'file');
1197 if ($this->attachment_data
[$index]['thumbnail'])
1199 phpbb_unlink($this->attachment_data
[$index]['physical_filename'], 'thumbnail');
1204 delete_attachments('attach', array(intval($this->attachment_data
[$index]['attach_id'])));
1207 unset($this->attachment_data
[$index]);
1208 $this->message
= preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "(\\1 == \$index) ? '' : ((\\1 > \$index) ? '[attachment=' . (\\1 - 1) . ']\\2[/attachment]' : '\\0')", $this->message
);
1211 $this->attachment_data
= array_values($this->attachment_data
);
1213 else if ($edit_comment ||
$add_file ||
$preview)
1217 $actual_comment_list = request_var('comment_list', array(''), true);
1219 $edit_comment = request_var('edit_comment', array(0 => ''));
1220 $edit_comment = key($edit_comment);
1221 $this->attachment_data
[$edit_comment]['comment'] = $actual_comment_list[$edit_comment];
1224 if (($add_file ||
$preview) && $upload_file)
1226 if ($num_attachments < $cfg['max_attachments'] ||
$auth->acl_gets('m_', 'a_'))
1228 $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
1229 $error = array_merge($error, $filedata['error']);
1231 if (!sizeof($error))
1234 'physical_filename' => $filedata['physical_filename'],
1235 'comment' => $this->filename_data
['filecomment'],
1236 'real_filename' => $filedata['real_filename'],
1237 'extension' => $filedata['extension'],
1238 'mimetype' => $filedata['mimetype'],
1239 'filesize' => $filedata['filesize'],
1240 'filetime' => $filedata['filetime'],
1242 'thumbnail' => $filedata['thumbnail']
1245 $this->attachment_data
= array_merge(array(0 => $new_entry), $this->attachment_data
);
1246 $this->message
= preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message
);
1247 $this->filename_data
['filecomment'] = '';
1252 $error[] = sprintf($user->lang
['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']);
1258 foreach ($error as $error_msg)
1260 $this->warn_msg
[] = $error_msg;
1265 * Get Attachment Data
1267 function get_submitted_attachment_data($check_user_id = false)
1269 global $user, $db, $phpbb_root_path, $phpEx, $config;
1271 $this->filename_data
['filecomment'] = request_var('filecomment', '', true);
1272 $this->attachment_data
= (isset($_POST['attachment_data'])) ?
$_POST['attachment_data'] : array();
1274 $check_user_id = ($check_user_id === false) ?
$user->data
['user_id'] : $check_user_id;
1276 // Regenerate data array...
1277 $attach_ids = $filenames = array();
1279 foreach ($this->attachment_data
as $pos => $var_ary)
1281 if ($var_ary['attach_id'])
1283 $attach_ids[(int) $this->attachment_data
[$pos]['attach_id']] = $pos;
1287 $filenames[$pos] = '';
1288 set_var($filenames[$pos], $this->attachment_data
[$pos]['physical_filename'], 'string');
1289 $filenames[$pos] = basename($filenames[$pos]);
1293 $this->attachment_data
= array();
1295 // Regenerate already posted attachments...
1296 if (sizeof($attach_ids))
1298 // Get the data from the attachments
1299 $sql = 'SELECT attach_id, physical_filename, real_filename, extension, mimetype, filesize, filetime, thumbnail
1300 FROM ' . ATTACHMENTS_TABLE
. '
1301 WHERE attach_id IN (' . implode(', ', array_keys($attach_ids)) . ')
1302 AND poster_id = ' . $check_user_id;
1303 $result = $db->sql_query($sql);
1305 while ($row = $db->sql_fetchrow($result))
1307 if (isset($attach_ids[$row['attach_id']]))
1309 $pos = $attach_ids[$row['attach_id']];
1310 $this->attachment_data
[$pos] = $row;
1311 set_var($this->attachment_data
[$pos]['comment'], $_POST['attachment_data'][$pos]['comment'], 'string', true);
1313 unset($attach_ids[$row['attach_id']]);
1316 $db->sql_freeresult($result);
1318 if (sizeof($attach_ids))
1320 trigger_error($user->lang
['NO_ACCESS_ATTACHMENT'], E_USER_ERROR
);
1324 // Regenerate newly uploaded attachments
1325 if (sizeof($filenames))
1327 include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
1329 $sql = 'SELECT attach_id
1330 FROM ' . ATTACHMENTS_TABLE
. "
1331 WHERE LOWER(physical_filename) IN ('" . implode("', '", array_map('strtolower', $filenames)) . "')";
1332 $result = $db->sql_query_limit($sql, 1);
1333 $row = $db->sql_fetchrow($result);
1334 $db->sql_freeresult($result);
1338 trigger_error($user->lang
['NO_ACCESS_ATTACHMENT'], E_USER_ERROR
);
1341 foreach ($filenames as $pos => $physical_filename)
1343 $this->attachment_data
[$pos] = array(
1344 'physical_filename' => $physical_filename,
1345 'extension' => strtolower(filespec
::get_extension($phpbb_root_path . $config['upload_path'] . '/' . $physical_filename)),
1346 'filesize' => filespec
::get_filesize($phpbb_root_path . $config['upload_path'] . '/' . $physical_filename),
1348 'thumbnail' => (file_exists($phpbb_root_path . $config['upload_path'] . '/thumb_' . $physical_filename)) ?
1 : 0,
1351 set_var($this->attachment_data
[$pos]['comment'], $_POST['attachment_data'][$pos]['comment'], 'string', true);
1352 set_var($this->attachment_data
[$pos]['real_filename'], $_POST['attachment_data'][$pos]['real_filename'], 'string', true);
1353 set_var($this->attachment_data
[$pos]['filetime'], $_POST['attachment_data'][$pos]['filetime'], 'int');
1355 if (strpos($_POST['attachment_data'][$pos]['mimetype'], 'image/') !== false)
1357 set_var($this->attachment_data
[$pos]['mimetype'], $_POST['attachment_data'][$pos]['mimetype'], 'string');
1361 $this->attachment_data
[$pos]['mimetype'] = filespec
::get_mimetype($phpbb_root_path . $config['upload_path'] . '/' . $physical_filename);
1370 function parse_poll(&$poll)
1372 global $auth, $user, $config;
1374 $poll_max_options = $poll['poll_max_options'];
1376 // Parse Poll Option text ;)
1377 $tmp_message = $this->message
;
1378 $this->message
= $poll['poll_option_text'];
1379 $bbcode_bitfield = $this->bbcode_bitfield
;
1381 $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], $poll['enable_urls'], $poll['enable_smilies'], $poll['img_status'], false, false, false);
1383 $this->bbcode_bitfield |
= $bbcode_bitfield;
1384 $this->message
= $tmp_message;
1387 $tmp_message = $this->message
;
1388 $this->message
= $poll['poll_title'];
1389 $bbcode_bitfield = $this->bbcode_bitfield
;
1391 $poll['poll_title'] = $this->parse($poll['enable_bbcode'], $poll['enable_urls'], $poll['enable_smilies'], $poll['img_status'], false, false, false);
1393 $this->bbcode_bitfield |
= $bbcode_bitfield;
1394 $this->message
= $tmp_message;
1396 unset($tmp_message);
1398 $poll['poll_options'] = explode("\n", trim($poll['poll_option_text']));
1399 $poll['poll_options_size'] = sizeof($poll['poll_options']);
1401 if (sizeof($poll['poll_options']) == 1)
1403 $this->warn_msg
[] = $user->lang
['TOO_FEW_POLL_OPTIONS'];
1405 else if ($poll['poll_options_size'] > (int) $config['max_poll_options'])
1407 $this->warn_msg
[] = $user->lang
['TOO_MANY_POLL_OPTIONS'];
1409 else if ($poll_max_options > $poll['poll_options_size'])
1411 $this->warn_msg
[] = $user->lang
['TOO_MANY_USER_OPTIONS'];
1414 if (!$poll['poll_title'] && $poll['poll_options_size'])
1416 $this->warn_msg
[] = $user->lang
['NO_POLL_TITLE'];
1419 $poll['poll_max_options'] = ($poll['poll_max_options'] < 1) ?
1 : (($poll['poll_max_options'] > $config['max_poll_options']) ?
$config['max_poll_options'] : $poll['poll_max_options']);