Пример #1
0
 static function error_check($text, &$errors)
 {
     global $futurebb_user, $futurebb_config;
     static $filter_data, $filter_domains;
     if (!$futurebb_user['g_post_links'] && preg_match('%\\[url.*?\\]%', $text)) {
         $errors[] = translate('nolinks');
     }
     if (!$futurebb_user['g_post_images'] && preg_match('%\\[img.*?\\]%', $text)) {
         $errors[] = translate('noimgs');
     }
     if (!isset($filter_data)) {
         $filter_data = explode('|', $futurebb_config['imghostrestriction']);
     }
     if (!$futurebb_user['g_mod_privs'] && !$futurebb_user['g_admin_privs'] && $filter_data[0] != 'none') {
         if (!isset($filter_domains)) {
             $filter_domains = explode("\n", $filter_data[1]);
         }
         preg_match_all('%\\[img\\](.*?)\\[/img\\]%', $text, $matches);
         foreach ($matches[1] as $url) {
             if (!preg_match('%^(ht|f)tps?://%', $url)) {
                 $url = 'http://' . $url;
             }
             $parse = parse_url($url);
             $host = $parse['host'];
             if ($filter_data[0] == 'blacklist') {
                 foreach ($filter_domains as $domain) {
                     if (preg_match('%' . preg_quote($domain) . '$%', $host)) {
                         $errors[] = translate('imgblacklisterror', $url, implode(', ', $filter_domains));
                         break;
                     }
                 }
             } else {
                 if ($filter_data[0] == 'whitelist') {
                     $ok = false;
                     foreach ($filter_domains as $domain) {
                         if (preg_match('%' . preg_quote($domain) . '$%', $host)) {
                             $ok = true;
                         }
                     }
                     if (!$ok) {
                         $errors[] = translate('imgwhitelisterror', $url, implode(', ', $filter_domains));
                     }
                 }
             }
         }
     }
     if (empty(self::$tags)) {
         self::$tags = array('b', 'i', 'u', 's', 'color', 'colour', 'url', 'img', 'quote', 'code', 'list', '\\*', 'table', 'tr', 'td', 'th');
     }
     if (preg_match_all('%\\[(' . implode('|', self::$tags) . ')=(.*?)(\\[|\\])\\]%', $text, $matches)) {
         $errors[] = translate('bracketparam', $matches[1][0]);
         return;
     }
     //parsing rules
     $no_nest_tags = array('img');
     $block_tags = array('quote', 'code', 'list', 'table', 'tr');
     $inline_tags = array('b', 'i', 'u', 's', 'color', 'colour', 'url', 'img', '\\*', 'th', 'td');
     $nest_only = array('table' => array('tr'), 'tr' => array('td', 'th'), 'list' => array('*'));
     //tags that can only have a specific set of subtags
     $nest_forbid = array('td' => array('td', 'th'), 'th' => array('td', 'th'));
     $no_body = array('table', 'tr', 'list');
     //tags that can't have text inside them
     $bbcode_parts = preg_split('%(\\[[\\*a-zA-Z0-9-/]*?(?:=.*?)?\\])%', $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
     //this regular expression was copied from FluxBB. However, everything used to parse it is completely original
     //split the message into tags and check syntax
     $open_tags = array();
     $last_key = 0;
     $quotes = 0;
     foreach ($bbcode_parts as $key => $val) {
         if (preg_match('%^\\[/(' . implode('|', self::$tags) . ')\\]$%', $val, $matches)) {
             //closing tag of some sort
             if ($last_key == 0) {
                 $errors[] = translate('closenoopen', $matches[1]);
                 $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                 return;
             }
             if ($open_tags[$last_key - 1] != 'code' && $matches[1] != $open_tags[$last_key - 1]) {
                 //if it's not a [code] tag, ignore it
                 $errors[] = translate('expectedfound', $open_tags[$last_key - 1], $matches[1]);
                 $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                 return;
             }
             if (!($open_tags[$last_key - 1] == 'code' && $matches[1] != $open_tags[$last_key - 1])) {
                 //close the tag in the tag stack if it's not a mismatch inside a [code] tag (like [code][/tr][/code])
                 if ($open_tags[$last_key - 1] == 'quote') {
                     $quotes--;
                 }
                 unset($open_tags[$last_key - 1]);
                 $last_key--;
             }
         } else {
             if (!($last_key > 0 && $open_tags[$last_key - 1] == 'code') && preg_match('%^\\[(' . implode('|', self::$tags) . ')(=.*?)?\\]$%', $val, $matches)) {
                 //opening tag of some sort
                 $open_tags[$last_key] = $matches[1];
                 //check if there are any block tags inside inline tags
                 if ($last_key > 0 && in_array($open_tags[$last_key - 1], $inline_tags) && in_array($matches[1], $block_tags)) {
                     $errors[] = translate('blockininline', $matches[1], $open_tags[$last_key - 1]);
                     $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                 }
                 //check for the tags that only allow specific tags directly inside them
                 if ($last_key > 0 && array_key_exists($open_tags[$last_key - 1], $nest_only) && !in_array($open_tags[$last_key], $nest_only[$open_tags[$last_key - 1]])) {
                     $errors[] = translate('specificnestingerror', $matches[1], $open_tags[$last_key - 1]);
                     $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                 }
                 if ($last_key > 0 && array_key_exists($open_tags[$last_key - 1], $nest_forbid) && in_array($open_tags[$last_key], $nest_forbid[$open_tags[$last_key - 1]])) {
                     $errors[] = translate('specificnestingerror', $matches[1], $open_tags[$last_key - 1]);
                     $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                 }
                 //check if there is any bbcode inside a tag which can't nest
                 if ($last_key > 0 && in_array($open_tags[$last_key - 1], $no_nest_tags)) {
                     $errors[] = translate('nonesting', $open_tags[$last_key - 1]);
                     $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                 }
                 if ($open_tags[$last_key] == 'quote') {
                     $quotes++;
                     if ($quotes > $futurebb_config['max_quote_depth']) {
                         $errors[] = translate('toomanynestedquotes', $futurebb_config['max_quote_depth']);
                         $errors[] = self::highlight_error($text, $matches[0], $bbcode_parts, $key);
                     }
                 }
                 $last_key++;
             } else {
                 if ($last_key > 0) {
                     //no tag, just text
                     if (!preg_match('%^\\s+$%ms', $val) && in_array($open_tags[$last_key - 1], $no_body)) {
                         $errors[] = translate('notextinsidetag', $open_tags[$last_key - 1]);
                         $errors[] = self::highlight_error($text, $val, $bbcode_parts, $key);
                     }
                 }
             }
         }
     }
     if (sizeof($open_tags) > 0) {
         $location_notices = array();
         foreach ($open_tags as &$val) {
             //find the last occurrence of this tag
             $reverse_parts = array_reverse($bbcode_parts);
             foreach ($reverse_parts as $partkey => $part) {
                 if (strpos($part, '[' . $val) === 0) {
                     $location_notices[] = self::highlight_error($text, $part, $bbcode_parts, sizeof($bbcode_parts) - $partkey - 1, 'tagwasopened', $val);
                     break;
                 }
             }
             //bold this so it goes on the error list
             $val = '<b>[' . $val . ']</b>';
         }
         $errors[] = translate('tagsnotclosed', implode(', ', $open_tags));
         $errors = array_merge($errors, $location_notices);
     }
 }