Verzeichnisstruktur phpBB-3.0.0
- Veröffentlicht
- 12.12.2007
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
message_parser.php
0001 <?php
0002 /**
0003 *
0004 * @package phpBB3
0005 * @version $Id$
0006 * @copyright (c) 2005 phpBB Group
0007 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
0008 *
0009 */
0010
0011 /**
0012 * @ignore
0013 */
0014 if (!defined('IN_PHPBB'))
0015 {
0016 exit;
0017 }
0018
0019 if (!class_exists('bbcode'))
0020 {
0021 include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
0022 }
0023
0024 /**
0025 * BBCODE FIRSTPASS
0026 * BBCODE first pass class (functions for parsing messages for db storage)
0027 * @package phpBB3
0028 */
0029 class bbcode_firstpass extends bbcode
0030 {
0031 var $message = '';
0032 var $warn_msg = array();
0033 var $parsed_items = array();
0034
0035 /**
0036 * Parse BBCode
0037 */
0038 function parse_bbcode()
0039 {
0040 if (!$this->bbcodes)
0041 {
0042 $this->bbcode_init();
0043 }
0044
0045 global $user;
0046
0047 $this->bbcode_bitfield = '';
0048 $bitfield = new bitfield();
0049
0050 foreach ($this->bbcodes as $bbcode_name => $bbcode_data)
0051 {
0052 if (isset($bbcode_data['disabled']) && $bbcode_data['disabled'])
0053 {
0054 foreach ($bbcode_data['regexp'] as $regexp => $replacement)
0055 {
0056 if (preg_match($regexp, $this->message))
0057 {
0058 $this->warn_msg[] = sprintf($user->lang['UNAUTHORISED_BBCODE'] , '[' . $bbcode_name . ']');
0059 continue;
0060 }
0061 }
0062 }
0063 else
0064 {
0065 foreach ($bbcode_data['regexp'] as $regexp => $replacement)
0066 {
0067 // The pattern gets compiled and cached by the PCRE extension,
0068 // it should not demand recompilation
0069 if (preg_match($regexp, $this->message))
0070 {
0071 $this->message = preg_replace($regexp, $replacement, $this->message);
0072 $bitfield->set($bbcode_data['bbcode_id']);
0073 }
0074 }
0075 }
0076 }
0077
0078 $this->bbcode_bitfield = $bitfield->get_base64();
0079 }
0080
0081 /**
0082 * Prepare some bbcodes for better parsing
0083 */
0084 function prepare_bbcodes()
0085 {
0086 // Ok, seems like users instead want the no-parsing of urls, smilies, etc. after and before and within quote tags being tagged as "not a bug".
0087 // Fine by me ;) Will ease our live... but do not come back and cry at us, we won't hear you.
0088
0089 /* Add newline at the end and in front of each quote block to prevent parsing errors (urls, smilies, etc.)
0090 if (strpos($this->message, '[quote') !== false && strpos($this->message, '[/quote]') !== false)
0091 {
0092 $this->message = str_replace("\r\n", "\n", $this->message);
0093
0094 // We strip newlines and spaces after and before quotes in quotes (trimming) and then add exactly one newline
0095 $this->message = preg_replace('#\[quote(=".*?")?\]\s*(.*?)\s*\[/quote\]#siu', '[quote\1]' . "\n" . '\2' ."\n[/quote]", $this->message);
0096 }
0097 */
0098
0099 // Add other checks which needs to be placed before actually parsing anything (be it bbcodes, smilies, urls...)
0100 }
0101
0102 /**
0103 * Init bbcode data for later parsing
0104 */
0105 function bbcode_init()
0106 {
0107 static $rowset;
0108
0109 // This array holds all bbcode data. BBCodes will be processed in this
0110 // order, so it is important to keep [code] in first position and
0111 // [quote] in second position.
0112 $this->bbcodes = array(
0113 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\$1', '\$2')")),
0114 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\$0')")),
0115 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#ise' => "\$this->bbcode_attachment('\$1', '\$2')")),
0116 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#ise' => "\$this->bbcode_strong('\$1')")),
0117 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#ise' => "\$this->bbcode_italic('\$1')")),
0118 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")),
0119 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#iUe' => "\$this->bbcode_img('\$1')")),
0120 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#ise' => "\$this->bbcode_size('\$1', '\$2')")),
0121 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")),
0122 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#ise' => "\$this->bbcode_underline('\$1')")),
0123 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#ise' => "\$this->bbcode_parse_list('\$0')")),
0124 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")),
0125 'flash' => array('bbcode_id' => 11, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')"))
0126 );
0127
0128 // Zero the parsed items array
0129 $this->parsed_items = array();
0130
0131 foreach ($this->bbcodes as $tag => $bbcode_data)
0132 {
0133 $this->parsed_items[$tag] = 0;
0134 }
0135
0136 if (!is_array($rowset))
0137 {
0138 global $db;
0139 $rowset = array();
0140
0141 $sql = 'SELECT *
0142 FROM ' . BBCODES_TABLE;
0143 $result = $db->sql_query($sql);
0144
0145 while ($row = $db->sql_fetchrow($result))
0146 {
0147 $rowset[] = $row;
0148 }
0149 $db->sql_freeresult($result);
0150 }
0151
0152 foreach ($rowset as $row)
0153 {
0154 $this->bbcodes[$row['bbcode_tag']] = array(
0155 'bbcode_id' => (int) $row['bbcode_id'],
0156 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace']))
0157 );
0158 }
0159 }
0160
0161 /**
0162 * Making some pre-checks for bbcodes as well as increasing the number of parsed items
0163 */
0164 function check_bbcode($bbcode, &$in)
0165 {
0166 // when using the /e modifier, preg_replace slashes double-quotes but does not
0167 // seem to slash anything else
0168 $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in));
0169
0170 // Trimming here to make sure no empty bbcodes are parsed accidently
0171 if (trim($in) == '')
0172 {
0173 return false;
0174 }
0175
0176 $this->parsed_items[$bbcode]++;
0177
0178 return true;
0179 }
0180
0181 /**
0182 * Transform some characters in valid bbcodes
0183 */
0184 function bbcode_specialchars($text)
0185 {
0186 $str_from = array('<', '>', '[', ']', '.', ':');
0187 $str_to = array('<', '>', '[', ']', '.', ':');
0188
0189 return str_replace($str_from, $str_to, $text);
0190 }
0191
0192 /**
0193 * Parse size tag
0194 */
0195 function bbcode_size($stx, $in)
0196 {
0197 global $user, $config;
0198
0199 if (!$this->check_bbcode('size', $in))
0200 {
0201 return '';
0202 }
0203
0204 if ($config['max_' . $this->mode . '_font_size'] && $config['max_' . $this->mode . '_font_size'] < $stx)
0205 {
0206 $this->warn_msg[] = sprintf($user->lang['MAX_FONT_SIZE_EXCEEDED'], $config['max_' . $this->mode . '_font_size']);
0207
0208 return '[size=' . $stx . ']' . $in . '[/size]';
0209 }
0210
0211 // Do not allow size=0
0212 if ($stx <= 0)
0213 {
0214 return '[size=' . $stx . ']' . $in . '[/size]';
0215 }
0216
0217 return '[size=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/size:' . $this->bbcode_uid . ']';
0218 }
0219
0220 /**
0221 * Parse color tag
0222 */
0223 function bbcode_color($stx, $in)
0224 {
0225 if (!$this->check_bbcode('color', $in))
0226 {
0227 return '';
0228 }
0229
0230 return '[color=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/color:' . $this->bbcode_uid . ']';
0231 }
0232
0233 /**
0234 * Parse u tag
0235 */
0236 function bbcode_underline($in)
0237 {
0238 if (!$this->check_bbcode('u', $in))
0239 {
0240 return '';
0241 }
0242
0243 return '[u:' . $this->bbcode_uid . ']' . $in . '[/u:' . $this->bbcode_uid . ']';
0244 }
0245
0246 /**
0247 * Parse b tag
0248 */
0249 function bbcode_strong($in)
0250 {
0251 if (!$this->check_bbcode('b', $in))
0252 {
0253 return '';
0254 }
0255
0256 return '[b:' . $this->bbcode_uid . ']' . $in . '[/b:' . $this->bbcode_uid . ']';
0257 }
0258
0259 /**
0260 * Parse i tag
0261 */
0262 function bbcode_italic($in)
0263 {
0264 if (!$this->check_bbcode('i', $in))
0265 {
0266 return '';
0267 }
0268
0269 return '[i:' . $this->bbcode_uid . ']' . $in . '[/i:' . $this->bbcode_uid . ']';
0270 }
0271
0272 /**
0273 * Parse img tag
0274 */
0275 function bbcode_img($in)
0276 {
0277 global $user, $config;
0278
0279 if (!$this->check_bbcode('img', $in))
0280 {
0281 return '';
0282 }
0283
0284 $in = trim($in);
0285 $error = false;
0286
0287 $in = str_replace(' ', '%20', $in);
0288
0289 // Checking urls
0290 if (!preg_match('#^' . get_preg_expression('url') . '$#i', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#i', $in))
0291 {
0292 return '[img]' . $in . '[/img]';
0293 }
0294
0295 // Try to cope with a common user error... not specifying a protocol but only a subdomain
0296 if (!preg_match('#^[a-z0-9]+://#i', $in))
0297 {
0298 $in = 'http://' . $in;
0299 }
0300
0301 if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width'])
0302 {
0303 $stats = @getimagesize($in);
0304
0305 if ($stats === false)
0306 {
0307 $error = true;
0308 $this->warn_msg[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
0309 }
0310 else
0311 {
0312 if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $stats[1])
0313 {
0314 $error = true;
0315 $this->warn_msg[] = sprintf($user->lang['MAX_IMG_HEIGHT_EXCEEDED'], $config['max_' . $this->mode . '_img_height']);
0316 }
0317
0318 if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $stats[0])
0319 {
0320 $error = true;
0321 $this->warn_msg[] = sprintf($user->lang['MAX_IMG_WIDTH_EXCEEDED'], $config['max_' . $this->mode . '_img_width']);
0322 }
0323 }
0324 }
0325
0326 if ($error || $this->path_in_domain($in))
0327 {
0328 return '[img]' . $in . '[/img]';
0329 }
0330
0331 return '[img:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/img:' . $this->bbcode_uid . ']';
0332 }
0333
0334 /**
0335 * Parse flash tag
0336 */
0337 function bbcode_flash($width, $height, $in)
0338 {
0339 global $user, $config;
0340
0341 if (!$this->check_bbcode('flash', $in))
0342 {
0343 return '';
0344 }
0345
0346 $in = trim($in);
0347 $error = false;
0348
0349 // Apply the same size checks on flash files as on images
0350 if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width'])
0351 {
0352 if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $height)
0353 {
0354 $error = true;
0355 $this->warn_msg[] = sprintf($user->lang['MAX_FLASH_HEIGHT_EXCEEDED'], $config['max_' . $this->mode . '_img_height']);
0356 }
0357
0358 if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $width)
0359 {
0360 $error = true;
0361 $this->warn_msg[] = sprintf($user->lang['MAX_FLASH_WIDTH_EXCEEDED'], $config['max_' . $this->mode . '_img_width']);
0362 }
0363 }
0364
0365 if ($error || $this->path_in_domain($in))
0366 {
0367 return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]';
0368 }
0369
0370 return '[flash=' . $width . ',' . $height . ':' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/flash:' . $this->bbcode_uid . ']';
0371 }
0372
0373 /**
0374 * Parse inline attachments [ia]
0375 */
0376 function bbcode_attachment($stx, $in)
0377 {
0378 if (!$this->check_bbcode('attachment', $in))
0379 {
0380 return '';
0381 }
0382
0383 return '[attachment=' . $stx . ':' . $this->bbcode_uid . ']<!-- ia' . $stx . ' -->' . trim($in) . '<!-- ia' . $stx . ' -->[/attachment:' . $this->bbcode_uid . ']';
0384 }
0385
0386 /**
0387 * Parse code text from code tag
0388 * @private
0389 */
0390 function bbcode_parse_code($stx, &$code)
0391 {
0392 switch (strtolower($stx))
0393 {
0394 case 'php':
0395
0396 $remove_tags = false;
0397 $code = str_replace(array('<', '>'), array('<', '>'), $code);
0398
0399 if (!preg_match('/\<\?.*?\?\>/is', $code))
0400 {
0401 $remove_tags = true;
0402 $code = "<?php $code ?>";
0403 }
0404
0405 $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string');
0406 foreach ($conf as $ini_var)
0407 {
0408 @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var));
0409 }
0410
0411 // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results
0412 $code = htmlspecialchars_decode($code);
0413 $code = highlight_string($code, true);
0414
0415 $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':');
0416 $str_to = array('<span class="', '<span class="syntax', '</span>', '', '', '[', ']', '.', ':');
0417
0418 if ($remove_tags)
0419 {
0420 $str_from[] = '<span class="syntaxdefault"><?php </span>';
0421 $str_to[] = '';
0422 $str_from[] = '<span class="syntaxdefault"><?php ';
0423 $str_to[] = '<span class="syntaxdefault">';
0424 }
0425
0426 $code = str_replace($str_from, $str_to, $code);
0427 $code = preg_replace('#^(<span class="[a-z_]+">)\n?(.*?)\n?(</span>)$#is', '$1$2$3', $code);
0428
0429 if ($remove_tags)
0430 {
0431 $code = preg_replace('#(<span class="[a-z]+">)?\?>(</span>)#', '$1 $2', $code);
0432 }
0433
0434 $code = preg_replace('#^<span class="[a-z]+"><span class="([a-z]+)">(.*)</span></span>#s', '<span class="$1">$2</span>', $code);
0435 $code = preg_replace('#(?:\s++| )*+</span>$#u', '</span>', $code);
0436
0437 // remove newline at the end
0438 if (!empty($code) && substr($code, -1) == "\n")
0439 {
0440 $code = substr($code, 0, -1);
0441 }
0442
0443 return "[code=$stx:" . $this->bbcode_uid . ']' . $code . '[/code:' . $this->bbcode_uid . ']';
0444 break;
0445
0446 default:
0447 return '[code:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($code) . '[/code:' . $this->bbcode_uid . ']';
0448 break;
0449 }
0450 }
0451
0452 /**
0453 * Parse code tag
0454 * Expects the argument to start right after the opening [code] tag and to end with [/code]
0455 */
0456 function bbcode_code($stx, $in)
0457 {
0458 if (!$this->check_bbcode('code', $in))
0459 {
0460 return '';
0461 }
0462
0463 // We remove the hardcoded elements from the code block here because it is not used in code blocks
0464 // Having it here saves us one preg_replace per message containing [code] blocks
0465 // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too...
0466 $htm_match = get_preg_expression('bbcode_htm');
0467 unset($htm_match[4], $htm_match[5]);
0468 $htm_replace = array('\1', '\1', '\2', '\1');
0469
0470 $out = $code_block = '';
0471 $open = 1;
0472
0473 while ($in)
0474 {
0475 // Determine position and tag length of next code block
0476 preg_match('#(.*?)(\[code(?:=([a-z]+))?\])(.+)#is', $in, $buffer);
0477 $pos = (isset($buffer[1])) ? strlen($buffer[1]) : false;
0478 $tag_length = (isset($buffer[2])) ? strlen($buffer[2]) : false;
0479
0480 // Determine position of ending code tag
0481 $pos2 = stripos($in, '[/code]');
0482
0483 // Which is the next block, ending code or code block
0484 if ($pos !== false && $pos < $pos2)
0485 {
0486 // Open new block
0487 if (!$open)
0488 {
0489 $out .= substr($in, 0, $pos);
0490 $in = substr($in, $pos);
0491 $stx = (isset($buffer[3])) ? $buffer[3] : '';
0492 $code_block = '';
0493 }
0494 else
0495 {
0496 // Already opened block, just append to the current block
0497 $code_block .= substr($in, 0, $pos) . ((isset($buffer[2])) ? $buffer[2] : '');
0498 $in = substr($in, $pos);
0499 }
0500
0501 $in = substr($in, $tag_length);
0502 $open++;
0503 }
0504 else
0505 {
0506 // Close the block
0507 if ($open == 1)
0508 {
0509 $code_block .= substr($in, 0, $pos2);
0510 $code_block = preg_replace($htm_match, $htm_replace, $code_block);
0511
0512 // Parse this code block
0513 $out .= $this->bbcode_parse_code($stx, $code_block);
0514 $code_block = '';
0515 $open--;
0516 }
0517 else if ($open)
0518 {
0519 // Close one open tag... add to the current code block
0520 $code_block .= substr($in, 0, $pos2 + 7);
0521 $open--;
0522 }
0523 else
0524 {
0525 // end code without opening code... will be always outside code block
0526 $out .= substr($in, 0, $pos2 + 7);
0527 }
0528
0529 $in = substr($in, $pos2 + 7);
0530 }
0531 }
0532
0533 // if now $code_block has contents we need to parse the remaining code while removing the last closing tag to match up.
0534 if ($code_block)
0535 {
0536 $code_block = substr($code_block, 0, -7);
0537 $code_block = preg_replace($htm_match, $htm_replace, $code_block);
0538
0539 $out .= $this->bbcode_parse_code($stx, $code_block);
0540 }
0541
0542 return $out;
0543 }
0544
0545 /**
0546 * Parse list bbcode
0547 * Expects the argument to start with a tag
0548 */
0549 function bbcode_parse_list($in)
0550 {
0551 if (!$this->check_bbcode('list', $in))
0552 {
0553 return '';
0554 }
0555
0556 // $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
0557 $tok = ']';
0558 $out = '[';
0559
0560 // First character is [
0561 $in = substr($in, 1);
0562 $list_end_tags = $item_end_tags = array();
0563
0564 do
0565 {
0566 $pos = strlen($in);
0567
0568 for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i)
0569 {
0570 $tmp_pos = strpos($in, $tok[$i]);
0571
0572 if ($tmp_pos !== false && $tmp_pos < $pos)
0573 {
0574 $pos = $tmp_pos;
0575 }
0576 }
0577
0578 $buffer = substr($in, 0, $pos);
0579 $tok = $in[$pos];
0580
0581 $in = substr($in, $pos + 1);
0582
0583 if ($tok == ']')
0584 {
0585 // if $tok is ']' the buffer holds a tag
0586 if (strtolower($buffer) == '/list' && sizeof($list_end_tags))
0587 {
0588 // valid [/list] tag, check nesting so that we don't hit false positives
0589 if (sizeof($item_end_tags) && sizeof($item_end_tags) >= sizeof($list_end_tags))
0590 {
0591 // current li tag has not been closed
0592 $out = preg_replace('/\n?\[$/', '[', $out) . array_pop($item_end_tags) . '][';
0593 }
0594
0595 $out .= array_pop($list_end_tags) . ']';
0596 $tok = '[';
0597 }
0598 else if (preg_match('#^list(=[0-9a-z])?$#i', $buffer, $m))
0599 {
0600 // sub-list, add a closing tag
0601 if (empty($m[1]) || preg_match('/^(?:disc|square|circle)$/i', $m[1]))
0602 {
0603 array_push($list_end_tags, '/list:u:' . $this->bbcode_uid);
0604 }
0605 else
0606 {
0607 array_push($list_end_tags, '/list:o:' . $this->bbcode_uid);
0608 }
0609 $out .= 'list' . substr($buffer, 4) . ':' . $this->bbcode_uid . ']';
0610 $tok = '[';
0611 }
0612 else
0613 {
0614 if (($buffer == '*' || substr($buffer, -2) == '[*') && sizeof($list_end_tags))
0615 {
0616 // the buffer holds a bullet tag and we have a [list] tag open
0617 if (sizeof($item_end_tags) >= sizeof($list_end_tags))
0618 {
0619 if (substr($buffer, -2) == '[*')
0620 {
0621 $out .= substr($buffer, 0, -2) . '[';
0622 }
0623 // current li tag has not been closed
0624 if (preg_match('/\n\[$/', $out, $m))
0625 {
0626 $out = preg_replace('/\n\[$/', '[', $out);
0627 $buffer = array_pop($item_end_tags) . "]\n[*:" . $this->bbcode_uid;
0628 }
0629 else
0630 {
0631 $buffer = array_pop($item_end_tags) . '][*:' . $this->bbcode_uid;
0632 }
0633 }
0634 else
0635 {
0636 $buffer = '*:' . $this->bbcode_uid;
0637 }
0638
0639 $item_end_tags[] = '/*:m:' . $this->bbcode_uid;
0640 }
0641 else if ($buffer == '/*')
0642 {
0643 array_pop($item_end_tags);
0644 $buffer = '/*:' . $this->bbcode_uid;
0645 }
0646
0647 $out .= $buffer . $tok;
0648 $tok = '[]';
0649 }
0650 }
0651 else
0652 {
0653 // Not within a tag, just add buffer to the return string
0654 $out .= $buffer . $tok;
0655 $tok = ($tok == '[') ? ']' : '[]';
0656 }
0657 }
0658 while ($in);
0659
0660 // do we have some tags open? close them now
0661 if (sizeof($item_end_tags))
0662 {
0663 $out .= '[' . implode('][', $item_end_tags) . ']';
0664 }
0665 if (sizeof($list_end_tags))
0666 {
0667 $out .= '[' . implode('][', $list_end_tags) . ']';
0668 }
0669
0670 return $out;
0671 }
0672
0673 /**
0674 * Parse quote bbcode
0675 * Expects the argument to start with a tag
0676 */
0677 function bbcode_quote($in)
0678 {
0679 global $config, $user;
0680
0681 /**
0682 * If you change this code, make sure the cases described within the following reports are still working:
0683 * #3572 - [quote="[test]test"]test [ test[/quote] - (correct: parsed)
0684 * #14667 - [quote]test[/quote] test ] and [ test [quote]test[/quote] (correct: parsed)
0685 * #14770 - [quote="["]test[/quote] (correct: parsed)
0686 * [quote="[i]test[/i]"]test[/quote] (correct: parsed)
0687 * [quote="[quote]test[/quote]"]test[/quote] (correct: NOT parsed)
0688 */
0689
0690 $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in)));
0691
0692 if (!$in)
0693 {
0694 return '';
0695 }
0696
0697 // To let the parser not catch tokens within quote_username quotes we encode them before we start this...
0698 $in = preg_replace('#quote="(.*?)"\]#ie', "'quote="' . str_replace(array('[', ']'), array('[', ']'), '\$1') . '"]'", $in);
0699
0700 $tok = ']';
0701 $out = '[';
0702
0703 $in = substr($in, 1);
0704 $close_tags = $error_ary = array();
0705 $buffer = '';
0706
0707 do
0708 {
0709 $pos = strlen($in);
0710 for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i)
0711 {
0712 $tmp_pos = strpos($in, $tok[$i]);
0713 if ($tmp_pos !== false && $tmp_pos < $pos)
0714 {
0715 $pos = $tmp_pos;
0716 }
0717 }
0718
0719 $buffer .= substr($in, 0, $pos);
0720 $tok = $in[$pos];
0721 $in = substr($in, $pos + 1);
0722
0723 if ($tok == ']')
0724 {
0725 if (strtolower($buffer) == '/quote' && sizeof($close_tags) && substr($out, -1, 1) == '[')
0726 {
0727 // we have found a closing tag
0728 $out .= array_pop($close_tags) . ']';
0729 $tok = '[';
0730 $buffer = '';
0731
0732 /* Add space at the end of the closing tag if not happened before to allow following urls/smilies to be parsed correctly
0733 * Do not try to think for the user. :/ Do not parse urls/smilies if there is no space - is the same as with other bbcodes too.
0734 * Also, we won't have any spaces within $in anyway, only adding up spaces -> #10982
0735 if (!$in || $in[0] !== ' ')
0736 {
0737 $out .= ' ';
0738 }*/
0739 }
0740 else if (preg_match('#^quote(?:="(.*?)")?$#is', $buffer, $m))
0741 {
0742 $this->parsed_items['quote']++;
0743
0744 // the buffer holds a valid opening tag
0745 if ($config['max_quote_depth'] && sizeof($close_tags) >= $config['max_quote_depth'])
0746 {
0747 // there are too many nested quotes
0748 $error_ary['quote_depth'] = sprintf($user->lang['QUOTE_DEPTH_EXCEEDED'], $config['max_quote_depth']);
0749
0750 $out .= $buffer . $tok;
0751 $tok = '[]';
0752 $buffer = '';
0753
0754 continue;
0755 }
0756
0757 array_push($close_tags, '/quote:' . $this->bbcode_uid);
0758
0759 if (isset($m[1]) && $m[1])
0760 {
0761 $username = str_replace(array('[', ']'), array('[', ']'), $m[1]);
0762 $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[$1', $username);
0763
0764 $end_tags = array();
0765 $error = false;
0766
0767 preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags);
0768 foreach ($tags[1] as $tag)
0769 {
0770 if ($tag[0] != '/')
0771 {
0772 $end_tags[] = '/' . $tag;
0773 }
0774 else
0775 {
0776 $end_tag = array_pop($end_tags);
0777 $error = ($end_tag != $tag) ? true : false;
0778 }
0779 }
0780
0781 if ($error)
0782 {
0783 $username = $m[1];
0784 }
0785
0786 $out .= 'quote="' . $username . '":' . $this->bbcode_uid . ']';
0787 }
0788 else
0789 {
0790 $out .= 'quote:' . $this->bbcode_uid . ']';
0791 }
0792
0793 $tok = '[';
0794 $buffer = '';
0795 }
0796 else if (preg_match('#^quote="(.*?)#is', $buffer, $m))
0797 {
0798 // the buffer holds an invalid opening tag
0799 $buffer .= ']';
0800 }
0801 else
0802 {
0803 $out .= $buffer . $tok;
0804 $tok = '[]';
0805 $buffer = '';
0806 }
0807 }
0808 else
0809 {
0810 /**
0811 * Old quote code working fine, but having errors listed in bug #3572
0812 *
0813 * $out .= $buffer . $tok;
0814 * $tok = ($tok == '[') ? ']' : '[]';
0815 * $buffer = '';
0816 */
0817
0818 $out .= $buffer . $tok;
0819
0820 if ($tok == '[')
0821 {
0822 // Search the text for the next tok... if an ending quote comes first, then change tok to []
0823 $pos1 = stripos($in, '[/quote');
0824 // If the token ] comes first, we change it to ]
0825 $pos2 = strpos($in, ']');
0826 // If the token [ comes first, we change it to [
0827 $pos3 = strpos($in, '[');
0828
0829 if ($pos1 !== false && ($pos2 === false || $pos1 < $pos2) && ($pos3 === false || $pos1 < $pos3))
0830 {
0831 $tok = '[]';
0832 }
0833 else if ($pos3 !== false && ($pos2 === false || $pos3 < $pos2))
0834 {
0835 $tok = '[';
0836 }
0837 else
0838 {
0839 $tok = ']';
0840 }
0841 }
0842 else
0843 {
0844 $tok = '[]';
0845 }
0846 $buffer = '';
0847 }
0848 }
0849 while ($in);
0850
0851 if (sizeof($close_tags))
0852 {
0853 $out .= '[' . implode('][', $close_tags) . ']';
0854 }
0855
0856 foreach ($error_ary as $error_msg)
0857 {
0858 $this->warn_msg[] = $error_msg;
0859 }
0860
0861 return $out;
0862 }
0863
0864 /**
0865 * Validate email
0866 */
0867 function validate_email($var1, $var2)
0868 {
0869 $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
0870 $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
0871
0872 $txt = $var2;
0873 $email = ($var1) ? $var1 : $var2;
0874
0875 $validated = true;
0876
0877 if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email))
0878 {
0879 $validated = false;
0880 }
0881
0882 if (!$validated)
0883 {
0884 return '[email' . (($var1) ? "=$var1" : '') . ']' . $var2 . '[/email]';
0885 }
0886
0887 $this->parsed_items['email']++;
0888
0889 if ($var1)
0890 {
0891 $retval = '[email=' . $this->bbcode_specialchars($email) . ':' . $this->bbcode_uid . ']' . $txt . '[/email:' . $this->bbcode_uid . ']';
0892 }
0893 else
0894 {
0895 $retval = '[email:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($email) . '[/email:' . $this->bbcode_uid . ']';
0896 }
0897
0898 return $retval;
0899 }
0900
0901 /**
0902 * Validate url
0903 *
0904 * @param string $var1 optional url parameter for url bbcode: [url(=$var1)]$var2[/url]
0905 * @param string $var2 url bbcode content: [url(=$var1)]$var2[/url]
0906 */
0907 function validate_url($var1, $var2)
0908 {
0909 global $config;
0910
0911 $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
0912 $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
0913
0914 $url = ($var1) ? $var1 : $var2;
0915
0916 if (!$url || ($var1 && !$var2))
0917 {
0918 return '';
0919 }
0920
0921 $valid = false;
0922
0923 $url = str_replace(' ', '%20', $url);
0924
0925 // Checking urls
0926 if (preg_match('#^' . get_preg_expression('url') . '$#i', $url) ||
0927 preg_match('#^' . get_preg_expression('www_url') . '$#i', $url) ||
0928 preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#i', $url))
0929 {
0930 $valid = true;
0931 }
0932
0933 if ($valid)
0934 {
0935 $this->parsed_items['url']++;
0936
0937 // if there is no scheme, then add http schema
0938 if (!preg_match('#^[a-z][a-z\d+\-.]*:/{2}#i', $url))
0939 {
0940 $url = 'http://' . $url;
0941 }
0942
0943 // Is this a link to somewhere inside this board? If so then remove the session id from the url
0944 if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false)
0945 {
0946 $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\1', $url);
0947 $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', $url);
0948 $url = append_sid($url);
0949 }
0950
0951 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 . ']';
0952 }
0953
0954 return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]';
0955 }
0956
0957 /**
0958 * Check if url is pointing to this domain/script_path/php-file
0959 *
0960 * @param string $url the url to check
0961 * @return true if the url is pointing to this domain/script_path/php-file, false if not
0962 *
0963 * @access private
0964 */
0965 function path_in_domain($url)
0966 {
0967 global $config, $phpEx, $user;
0968
0969 if ($config['force_server_vars'])
0970 {
0971 $check_path = $config['script_path'];
0972 }
0973 else
0974 {
0975 $check_path = ($user->page['root_script_path'] != '/') ? substr($user->page['root_script_path'], 0, -1) : '/';
0976 }
0977
0978 // Is the user trying to link to a php file in this domain and script path?
0979 if (strpos($url, ".{$phpEx}") !== false && strpos($url, $check_path) !== false)
0980 {
0981 $server_name = (!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME');
0982
0983 // Forcing server vars is the only way to specify/override the protocol
0984 if ($config['force_server_vars'] || !$server_name)
0985 {
0986 $server_name = $config['server_name'];
0987 }
0988
0989 // Check again in correct order...
0990 $pos_ext = strpos($url, ".{$phpEx}");
0991 $pos_path = strpos($url, $check_path);
0992 $pos_domain = strpos($url, $server_name);
0993
0994 if ($pos_domain !== false && $pos_path >= $pos_domain && $pos_ext >= $pos_path)
0995 {
0996 // Ok, actually we allow linking to some files (this may be able to be extended in some way later...)
0997 if (strpos($url, '/' . $check_path . '/download/file.' . $phpEx) !== 0)
0998 {
0999 return false;
1000 }
1001
1002 return true;
1003 }
1004 }
1005
1006 return false;
1007 }
1008 }
1009
1010 /**
1011 * Main message parser for posting, pm, etc. takes raw message
1012 * and parses it for attachments, bbcode and smilies
1013 * @package phpBB3
1014 */
1015 class parse_message extends bbcode_firstpass
1016 {
1017 var $attachment_data = array();
1018 var $filename_data = array();
1019
1020 // Helps ironing out user error
1021 var $message_status = '';
1022
1023 var $allow_img_bbcode = true;
1024 var $allow_flash_bbcode = true;
1025 var $allow_quote_bbcode = true;
1026 var $allow_url_bbcode = true;
1027
1028 var $mode;
1029
1030 /**
1031 * Init - give message here or manually
1032 */
1033 function parse_message($message = '')
1034 {
1035 // Init BBCode UID
1036 $this->bbcode_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN);
1037
1038 if ($message)
1039 {
1040 $this->message = $message;
1041 }
1042 }
1043
1044 /**
1045 * Parse Message
1046 */
1047 function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post')
1048 {
1049 global $config, $db, $user;
1050
1051 $mode = ($mode != 'post') ? 'sig' : 'post';
1052
1053 $this->mode = $mode;
1054
1055 $this->allow_img_bbcode = $allow_img_bbcode;
1056 $this->allow_flash_bbcode = $allow_flash_bbcode;
1057 $this->allow_quote_bbcode = $allow_quote_bbcode;
1058 $this->allow_url_bbcode = $allow_url_bbcode;
1059
1060 // If false, then $this->message won't be altered, the text will be returned instead.
1061 if (!$update_this_message)
1062 {
1063 $tmp_message = $this->message;
1064 $return_message = &$this->message;
1065 }
1066
1067 if ($this->message_status == 'display')
1068 {
1069 $this->decode_message();
1070 }
1071
1072 // Do some general 'cleanup' first before processing message,
1073 // e.g. remove excessive newlines(?), smilies(?)
1074 $match = array('#(script|about|applet|activex|chrome):#i');
1075 $replace = array("\\1:");
1076 $this->message = preg_replace($match, $replace, trim($this->message));
1077
1078 // Message length check. 0 disables this check completely.
1079 if ($config['max_' . $mode . '_chars'] > 0)
1080 {
1081 $msg_len = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message));
1082
1083 if ((!$msg_len && $mode !== 'sig') || $config['max_' . $mode . '_chars'] && $msg_len > $config['max_' . $mode . '_chars'])
1084 {
1085 $this->warn_msg[] = (!$msg_len) ? $user->lang['TOO_FEW_CHARS'] : sprintf($user->lang['TOO_MANY_CHARS_' . strtoupper($mode)], $msg_len, $config['max_' . $mode . '_chars']);
1086 return $this->warn_msg;
1087 }
1088 }
1089
1090 // Check for "empty" message
1091 if ($mode !== 'sig' && !utf8_clean_string($this->message))
1092 {
1093 $this->warn_msg[] = $user->lang['TOO_FEW_CHARS'];
1094 return $this->warn_msg;
1095 }
1096
1097 // Prepare BBcode (just prepares some tags for better parsing)
1098 if ($allow_bbcode && strpos($this->message, '[') !== false)
1099 {
1100 $this->bbcode_init();
1101 $disallow = array('img', 'flash', 'quote', 'url');
1102 foreach ($disallow as $bool)
1103 {
1104 if (!${'allow_' . $bool . '_bbcode'})
1105 {
1106 $this->bbcodes[$bool]['disabled'] = true;
1107 }
1108 }
1109
1110 $this->prepare_bbcodes();
1111 }
1112
1113 // Parse smilies
1114 if ($allow_smilies)
1115 {
1116 $this->smilies($config['max_' . $mode . '_smilies']);
1117 }
1118
1119 $num_urls = 0;
1120
1121 // Parse BBCode
1122 if ($allow_bbcode && strpos($this->message, '[') !== false)
1123 {
1124 $this->parse_bbcode();
1125 $num_urls += $this->parsed_items['url'];
1126 }
1127
1128 // Parse URL's
1129 if ($allow_magic_url)
1130 {
1131 $this->magic_url(generate_board_url());
1132
1133 if ($config['max_' . $mode . '_urls'])
1134 {
1135 $num_urls += preg_match_all('#\<!-- ([lmwe]) --\>.*?\<!-- \1 --\>#', $this->message, $matches);
1136 }
1137 }
1138
1139 // Check number of links
1140 if ($config['max_' . $mode . '_urls'] && $num_urls > $config['max_' . $mode . '_urls'])
1141 {
1142 $this->warn_msg[] = sprintf($user->lang['TOO_MANY_URLS'], $config['max_' . $mode . '_urls']);
1143 return $this->warn_msg;
1144 }
1145
1146 if (!$update_this_message)
1147 {
1148 unset($this->message);
1149 $this->message = $tmp_message;
1150 return $return_message;
1151 }
1152
1153 $this->message_status = 'parsed';
1154 return false;
1155 }
1156
1157 /**
1158 * Formatting text for display
1159 */
1160 function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true)
1161 {
1162 // If false, then the parsed message get returned but internal message not processed.
1163 if (!$update_this_message)
1164 {
1165 $tmp_message = $this->message;
1166 $return_message = &$this->message;
1167 }
1168
1169 if ($this->message_status == 'plain')
1170 {
1171 // Force updating message - of course.
1172 $this->parse($allow_bbcode, $allow_magic_url, $allow_smilies, $this->allow_img_bbcode, $this->allow_flash_bbcode, $this->allow_quote_bbcode, $this->allow_url_bbcode, true);
1173 }
1174
1175 // Replace naughty words such as farty pants
1176 $this->message = censor_text($this->message);
1177
1178 // Parse BBcode
1179 if ($allow_bbcode)
1180 {
1181 $this->bbcode_cache_init();
1182
1183 // We are giving those parameters to be able to use the bbcode class on its own
1184 $this->bbcode_second_pass($this->message, $this->bbcode_uid);
1185 }
1186
1187 $this->message = bbcode_nl2br($this->message);
1188 $this->message = smiley_text($this->message, !$allow_smilies);
1189
1190 if (!$update_this_message)
1191 {
1192 unset($this->message);
1193 $this->message = $tmp_message;
1194 return $return_message;
1195 }
1196
1197 $this->message_status = 'display';
1198 return false;
1199 }
1200
1201 /**
1202 * Decode message to be placed back into form box
1203 */
1204 function decode_message($custom_bbcode_uid = '', $update_this_message = true)
1205 {
1206 // If false, then the parsed message get returned but internal message not processed.
1207 if (!$update_this_message)
1208 {
1209 $tmp_message = $this->message;
1210 $return_message = &$this->message;
1211 }
1212
1213 ($custom_bbcode_uid) ? decode_message($this->message, $custom_bbcode_uid) : decode_message($this->message, $this->bbcode_uid);
1214
1215 if (!$update_this_message)
1216 {
1217 unset($this->message);
1218 $this->message = $tmp_message;
1219 return $return_message;
1220 }
1221
1222 $this->message_status = 'plain';
1223 return false;
1224 }
1225
1226 /**
1227 * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx.
1228 * Cuts down displayed size of link if over 50 chars, turns absolute links
1229 * into relative versions when the server/script path matches the link
1230 */
1231 function magic_url($server_url)
1232 {
1233 // We use the global make_clickable function
1234 $this->message = make_clickable($this->message, $server_url);
1235 }
1236
1237 /**
1238 * Parse Smilies
1239 */
1240 function smilies($max_smilies = 0)
1241 {
1242 global $db, $user;
1243 static $match;
1244 static $replace;
1245
1246 // See if the static arrays have already been filled on an earlier invocation
1247 if (!is_array($match))
1248 {
1249 $match = $replace = array();
1250
1251 // NOTE: obtain_* function? chaching the table contents?
1252
1253 // For now setting the ttl to 10 minutes
1254 switch ($db->sql_layer)
1255 {
1256 case 'mssql':
1257 case 'mssql_odbc':
1258 $sql = 'SELECT *
1259 FROM ' . SMILIES_TABLE . '
1260 ORDER BY LEN(code) DESC';
1261 break;
1262
1263 case 'firebird':
1264 $sql = 'SELECT *
1265 FROM ' . SMILIES_TABLE . '
1266 ORDER BY CHAR_LENGTH(code) DESC';
1267 break;
1268
1269 // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure...
1270 default:
1271 $sql = 'SELECT *
1272 FROM ' . SMILIES_TABLE . '
1273 ORDER BY LENGTH(code) DESC';
1274 break;
1275 }
1276 $result = $db->sql_query($sql, 600);
1277
1278 while ($row = $db->sql_fetchrow($result))
1279 {
1280 if (empty($row['code']))
1281 {
1282 continue;
1283 }
1284
1285 // (assertion)
1286 $match[] = '(?<=^|[\n .])' . preg_quote($row['code'], '#') . '(?![^<>]*>)';
1287 $replace[] = '<!-- s' . $row['code'] . ' --><img src="{SMILIES_PATH}/' . $row['smiley_url'] . '" alt="' . $row['code'] . '" title="' . $row['emotion'] . '" /><!-- s' . $row['code'] . ' -->';
1288 }
1289 $db->sql_freeresult($result);
1290 }
1291
1292 if (sizeof($match))
1293 {
1294 if ($max_smilies)
1295 {
1296 $num_matches = preg_match_all('#' . implode('|', $match) . '#', $this->message, $matches);
1297 unset($matches);
1298
1299 if ($num_matches !== false && $num_matches > $max_smilies)
1300 {
1301 $this->warn_msg[] = sprintf($user->lang['TOO_MANY_SMILIES'], $max_smilies);
1302 return;
1303 }
1304 }
1305
1306 // Make sure the delimiter # is added in front and at the end of every element within $match
1307 $this->message = trim(preg_replace(explode(chr(0), '#' . implode('#' . chr(0) . '#', $match) . '#'), $replace, $this->message));
1308 }
1309 }
1310
1311 /**
1312 * Parse Attachments
1313 */
1314 function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false)
1315 {
1316 global $config, $auth, $user, $phpbb_root_path, $phpEx, $db;
1317
1318 $error = array();
1319
1320 $num_attachments = sizeof($this->attachment_data);
1321 $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true));
1322 $upload_file = (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none' && trim($_FILES[$form_name]['name'])) ? true : false;
1323
1324 $add_file = (isset($_POST['add_file'])) ? true : false;
1325 $delete_file = (isset($_POST['delete_file'])) ? true : false;
1326
1327 // First of all adjust comments if changed
1328 $actual_comment_list = utf8_normalize_nfc(request_var('comment_list', array(''), true));
1329
1330 foreach ($actual_comment_list as $comment_key => $comment)
1331 {
1332 if (!isset($this->attachment_data[$comment_key]))
1333 {
1334 continue;
1335 }
1336
1337 if ($this->attachment_data[$comment_key]['attach_comment'] != $actual_comment_list[$comment_key])
1338 {
1339 $this->attachment_data[$comment_key]['attach_comment'] = $actual_comment_list[$comment_key];
1340 }
1341 }
1342
1343 $cfg = array();
1344 $cfg['max_attachments'] = ($is_message) ? $config['max_attachments_pm'] : $config['max_attachments'];
1345 $forum_id = ($is_message) ? 0 : $forum_id;
1346
1347 if ($submit && in_array($mode, array('post', 'reply', 'quote', 'edit')) && $upload_file)
1348 {
1349 if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id))
1350 {
1351 $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
1352 $error = $filedata['error'];
1353
1354 if ($filedata['post_attach'] && !sizeof($error))
1355 {
1356 $sql_ary = array(
1357 'physical_filename' => $filedata['physical_filename'],
1358 'attach_comment' => $this->filename_data['filecomment'],
1359 'real_filename' => $filedata['real_filename'],
1360 'extension' => $filedata['extension'],
1361 'mimetype' => $filedata['mimetype'],
1362 'filesize' => $filedata['filesize'],
1363 'filetime' => $filedata['filetime'],
1364 'thumbnail' => $filedata['thumbnail'],
1365 'is_orphan' => 1,
1366 'in_message' => ($is_message) ? 1 : 0,
1367 'poster_id' => $user->data['user_id'],
1368 );
1369
1370 $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
1371
1372 $new_entry = array(
1373 'attach_id' => $db->sql_nextid(),
1374 'is_orphan' => 1,
1375 'real_filename' => $filedata['real_filename'],
1376 'attach_comment'=> $this->filename_data['filecomment'],
1377 );
1378
1379 $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
1380 $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
1381
1382 $this->filename_data['filecomment'] = '';
1383
1384 // This Variable is set to false here, because Attachments are entered into the
1385 // Database in two modes, one if the id_list is 0 and the second one if post_attach is true
1386 // Since post_attach is automatically switched to true if an Attachment got added to the filesystem,
1387 // but we are assigning an id of 0 here, we have to reset the post_attach variable to false.
1388 //
1389 // This is very relevant, because it could happen that the post got not submitted, but we do not
1390 // know this circumstance here. We could be at the posting page or we could be redirected to the entered
1391 // post. :)
1392 $filedata['post_attach'] = false;
1393 }
1394 }
1395 else
1396 {
1397 $error[] = sprintf($user->lang['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']);
1398 }
1399 }
1400
1401 if ($preview || $refresh || sizeof($error))
1402 {
1403 // Perform actions on temporary attachments
1404 if ($delete_file)
1405 {
1406 include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1407
1408 $index = array_keys(request_var('delete_file', array(0 => 0)));
1409 $index = (!empty($index)) ? $index[0] : false;
1410
1411 if ($index !== false && !empty($this->attachment_data[$index]))
1412 {
1413 // delete selected attachment
1414 if ($this->attachment_data[$index]['is_orphan'])
1415 {
1416 $sql = 'SELECT attach_id, physical_filename, thumbnail
1417 FROM ' . ATTACHMENTS_TABLE . '
1418 WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id'] . '
1419 AND is_orphan = 1
1420 AND poster_id = ' . $user->data['user_id'];
1421 $result = $db->sql_query($sql);
1422 $row = $db->sql_fetchrow($result);
1423 $db->sql_freeresult($result);
1424
1425 if ($row)
1426 {
1427 phpbb_unlink($row['physical_filename'], 'file');
1428
1429 if ($row['thumbnail'])
1430 {
1431 phpbb_unlink($row['physical_filename'], 'thumbnail');
1432 }
1433
1434 $db->sql_query('DELETE FROM ' . ATTACHMENTS_TABLE . ' WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id']);
1435 }
1436 }
1437 else
1438 {
1439 delete_attachments('attach', array(intval($this->attachment_data[$index]['attach_id'])));
1440 }
1441
1442 unset($this->attachment_data[$index]);
1443 $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "(\\1 == \$index) ? '' : ((\\1 > \$index) ? '[attachment=' . (\\1 - 1) . ']\\2[/attachment]' : '\\0')", $this->message);
1444
1445 // Reindex Array
1446 $this->attachment_data = array_values($this->attachment_data);
1447 }
1448 }
1449 else if (($add_file || $preview) && $upload_file)
1450 {
1451 if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id))
1452 {
1453 $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
1454 $error = array_merge($error, $filedata['error']);
1455
1456 if (!sizeof($error))
1457 {
1458 $sql_ary = array(
1459 'physical_filename' => $filedata['physical_filename'],
1460 'attach_comment' => $this->filename_data['filecomment'],
1461 'real_filename' => $filedata['real_filename'],
1462 'extension' => $filedata['extension'],
1463 'mimetype' => $filedata['mimetype'],
1464 'filesize' => $filedata['filesize'],
1465 'filetime' => $filedata['filetime'],
1466 'thumbnail' => $filedata['thumbnail'],
1467 'is_orphan' => 1,
1468 'in_message' => ($is_message) ? 1 : 0,
1469 'poster_id' => $user->data['user_id'],
1470 );
1471
1472 $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
1473
1474 $new_entry = array(
1475 'attach_id' => $db->sql_nextid(),
1476 'is_orphan' => 1,
1477 'real_filename' => $filedata['real_filename'],
1478 'attach_comment'=> $this->filename_data['filecomment'],
1479 );
1480
1481 $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
1482 $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
1483 $this->filename_data['filecomment'] = '';
1484 }
1485 }
1486 else
1487 {
1488 $error[] = sprintf($user->lang['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']);
1489 }
1490 }
1491 }
1492
1493 foreach ($error as $error_msg)
1494 {
1495 $this->warn_msg[] = $error_msg;
1496 }
1497 }
1498
1499 /**
1500 * Get Attachment Data
1501 */
1502 function get_submitted_attachment_data($check_user_id = false)
1503 {
1504 global $user, $db, $phpbb_root_path, $phpEx, $config;
1505
1506 $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true));
1507 $attachment_data = (isset($_POST['attachment_data'])) ? $_POST['attachment_data'] : array();
1508 $this->attachment_data = array();
1509
1510 $check_user_id = ($check_user_id === false) ? $user->data['user_id'] : $check_user_id;
1511
1512 if (!sizeof($attachment_data))
1513 {
1514 return;
1515 }
1516
1517 $not_orphan = $orphan = array();
1518
1519 foreach ($attachment_data as $pos => $var_ary)
1520 {
1521 if ($var_ary['is_orphan'])
1522 {
1523 $orphan[(int) $var_ary['attach_id']] = $pos;
1524 }
1525 else
1526 {
1527 $not_orphan[(int) $var_ary['attach_id']] = $pos;
1528 }
1529 }
1530
1531 // Regenerate already posted attachments
1532 if (sizeof($not_orphan))
1533 {
1534 // Get the attachment data, based on the poster id...
1535 $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment
1536 FROM ' . ATTACHMENTS_TABLE . '
1537 WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . '
1538 AND poster_id = ' . $check_user_id;
1539 $result = $db->sql_query($sql);
1540
1541 while ($row = $db->sql_fetchrow($result))
1542 {
1543 $pos = $not_orphan[$row['attach_id']];
1544 $this->attachment_data[$pos] = $row;
1545 set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true);
1546
1547 unset($not_orphan[$row['attach_id']]);
1548 }
1549 $db->sql_freeresult($result);
1550 }
1551
1552 if (sizeof($not_orphan))
1553 {
1554 trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR);
1555 }
1556
1557 // Regenerate newly uploaded attachments
1558 if (sizeof($orphan))
1559 {
1560 $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment
1561 FROM ' . ATTACHMENTS_TABLE . '
1562 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . '
1563 AND poster_id = ' . $user->data['user_id'] . '
1564 AND is_orphan = 1';
1565 $result = $db->sql_query($sql);
1566
1567 while ($row = $db->sql_fetchrow($result))
1568 {
1569 $pos = $orphan[$row['attach_id']];
1570 $this->attachment_data[$pos] = $row;
1571 set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true);
1572
1573 unset($orphan[$row['attach_id']]);
1574 }
1575 $db->sql_freeresult($result);
1576 }
1577
1578 if (sizeof($orphan))
1579 {
1580 trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR);
1581 }
1582
1583 ksort($this->attachment_data);
1584 }
1585
1586 /**
1587 * Parse Poll
1588 */
1589 function parse_poll(&$poll)
1590 {
1591 global $auth, $user, $config;
1592
1593 $poll_max_options = $poll['poll_max_options'];
1594
1595 // Parse Poll Option text ;)
1596 $tmp_message = $this->message;
1597 $this->message = $poll['poll_option_text'];
1598 $bbcode_bitfield = $this->bbcode_bitfield;
1599
1600
1601 $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false);
1602
1603 $bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield));
1604 $this->message = $tmp_message;
1605
1606 // Parse Poll Title
1607 $tmp_message = $this->message;
1608 $this->message = $poll['poll_title'];
1609 $this->bbcode_bitfield = $bbcode_bitfield;
1610
1611 $poll['poll_options'] = explode("\n", trim($poll['poll_option_text']));
1612 $poll['poll_options_size'] = sizeof($poll['poll_options']);
1613
1614 if (!$poll['poll_title'] && $poll['poll_options_size'])
1615 {
1616 $this->warn_msg[] = $user->lang['NO_POLL_TITLE'];
1617 }
1618 else
1619 {
1620 if (utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)) > 100)
1621 {
1622 $this->warn_msg[] = $user->lang['POLL_TITLE_TOO_LONG'];
1623 }
1624 $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false);
1625 if (strlen($poll['poll_title']) > 255)
1626 {
1627 $this->warn_msg[] = $user->lang['POLL_TITLE_COMP_TOO_LONG'];
1628 }
1629 }
1630
1631 $this->bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield));
1632 $this->message = $tmp_message;
1633 unset($tmp_message);
1634
1635 if (sizeof($poll['poll_options']) == 1)
1636 {
1637 $this->warn_msg[] = $user->lang['TOO_FEW_POLL_OPTIONS'];
1638 }
1639 else if ($poll['poll_options_size'] > (int) $config['max_poll_options'])
1640 {
1641 $this->warn_msg[] = $user->lang['TOO_MANY_POLL_OPTIONS'];
1642 }
1643 else if ($poll_max_options > $poll['poll_options_size'])
1644 {
1645 $this->warn_msg[] = $user->lang['TOO_MANY_USER_OPTIONS'];
1646 }
1647
1648 $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']);
1649 }
1650 }
1651
1652 ?>