Yoshi2889 /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file contains those functions specific to the editing box and is |
||
| 5 | * generally used for WYSIWYG type functionality. |
||
| 6 | * |
||
| 7 | * Simple Machines Forum (SMF) |
||
| 8 | * |
||
| 9 | * @package SMF |
||
| 10 | * @author Simple Machines http://www.simplemachines.org |
||
| 11 | * @copyright 2017 Simple Machines and individual contributors |
||
| 12 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 13 | * |
||
| 14 | * @version 2.1 Beta 4 |
||
| 15 | */ |
||
| 16 | |||
| 17 | if (!defined('SMF')) |
||
| 18 | die('No direct access...'); |
||
| 19 | |||
| 20 | /** |
||
| 21 | * !!!Compatibility!!! |
||
| 22 | * Since we changed the editor we don't need it any more, but let's keep it if any mod wants to use it |
||
| 23 | * Convert only the BBC that can be edited in HTML mode for the editor. |
||
| 24 | * |
||
| 25 | * @param string $text The text with bbcode in it |
||
| 26 | * @param boolean $compat_mode Whether to actually convert the text |
||
| 27 | * @return string The text |
||
| 28 | */ |
||
| 29 | function bbc_to_html($text, $compat_mode = false) |
||
| 30 | { |
||
| 31 | global $modSettings; |
||
| 32 | |||
| 33 | if (!$compat_mode) |
||
| 34 | return $text; |
||
| 35 | |||
| 36 | // Turn line breaks back into br's. |
||
| 37 | $text = strtr($text, array("\r" => '', "\n" => '<br>')); |
||
| 38 | |||
| 39 | // Prevent conversion of all bbcode inside these bbcodes. |
||
| 40 | // @todo Tie in with bbc permissions ? |
||
| 41 | foreach (array('code', 'php', 'nobbc') as $code) |
||
| 42 | { |
||
| 43 | if (strpos($text, '[' . $code) !== false) |
||
| 44 | { |
||
| 45 | $parts = preg_split('~(\[/' . $code . '\]|\[' . $code . '(?:=[^\]]+)?\])~i', $text, -1, PREG_SPLIT_DELIM_CAPTURE); |
||
| 46 | |||
| 47 | // Only mess with stuff inside tags. |
||
| 48 | for ($i = 0, $n = count($parts); $i < $n; $i++) |
||
| 49 | { |
||
| 50 | // Value of 2 means we're inside the tag. |
||
| 51 | if ($i % 4 == 2) |
||
| 52 | $parts[$i] = strtr($parts[$i], array('[' => '[', ']' => ']', "'" => "'")); |
||
| 53 | } |
||
| 54 | // Put our humpty dumpty message back together again. |
||
| 55 | $text = implode('', $parts); |
||
| 56 | } |
||
| 57 | } |
||
| 58 | |||
| 59 | // What tags do we allow? |
||
| 60 | $allowed_tags = array('b', 'u', 'i', 's', 'hr', 'list', 'li', 'font', 'size', 'color', 'img', 'left', 'center', 'right', 'url', 'email', 'ftp', 'sub', 'sup'); |
||
| 61 | |||
| 62 | $text = parse_bbc($text, true, '', $allowed_tags); |
||
| 63 | |||
| 64 | // Fix for having a line break then a thingy. |
||
| 65 | $text = strtr($text, array('<br><div' => '<div', "\n" => '', "\r" => '')); |
||
| 66 | |||
| 67 | // Note that IE doesn't understand spans really - make them something "legacy" |
||
| 68 | $working_html = array( |
||
| 69 | '~<del>(.+?)</del>~i' => '<strike>$1</strike>', |
||
| 70 | '~<span\sclass="bbc_u">(.+?)</span>~i' => '<u>$1</u>', |
||
| 71 | '~<span\sstyle="color:\s*([#\d\w]+);" class="bbc_color">(.+?)</span>~i' => '<font color="$1">$2</font>', |
||
| 72 | '~<span\sstyle="font-family:\s*([#\d\w\s]+);" class="bbc_font">(.+?)</span>~i' => '<font face="$1">$2</font>', |
||
| 73 | '~<div\sstyle="text-align:\s*(left|right);">(.+?)</div>~i' => '<p align="$1">$2</p>', |
||
| 74 | ); |
||
| 75 | $text = preg_replace(array_keys($working_html), array_values($working_html), $text); |
||
| 76 | |||
| 77 | // Parse unique ID's and disable javascript into the smileys - using the double space. |
||
| 78 | $i = 1; |
||
| 79 | $text = preg_replace_callback('~(?:\s| )?<(img\ssrc="' . preg_quote($modSettings['smileys_url'], '~') . '/[^<>]+?/([^<>]+?)"\s*)[^<>]*?class="smiley">~', |
||
| 80 | function($m) use (&$i) |
||
| 81 | { |
||
| 82 | return '<' . stripslashes($m[1]) . 'alt="" title="" onresizestart="return false;" id="smiley_' . $i++ . '_' . $m[2] . '" style="padding: 0 3px 0 3px;">'; |
||
| 83 | }, $text); |
||
| 84 | |||
| 85 | return $text; |
||
| 86 | } |
||
| 87 | |||
| 88 | /** |
||
| 89 | * !!!Compatibility!!! |
||
| 90 | * This is no more needed, but to avoid break mods let's keep it |
||
| 91 | * Run it it shouldn't even hurt either, so let's not bother remove it |
||
| 92 | * |
||
| 93 | * The harder one - wysiwyg to BBC! |
||
| 94 | * |
||
| 95 | * @param string $text Text containing HTML |
||
| 96 | * @return string The text with html converted to bbc |
||
| 97 | */ |
||
| 98 | function html_to_bbc($text) |
||
| 99 | { |
||
| 100 | global $modSettings, $smcFunc, $scripturl, $context; |
||
| 101 | |||
| 102 | // Replace newlines with spaces, as that's how browsers usually interpret them. |
||
| 103 | $text = preg_replace("~\s*[\r\n]+\s*~", ' ', $text); |
||
| 104 | |||
| 105 | // Though some of us love paragraphs, the parser will do better with breaks. |
||
| 106 | $text = preg_replace('~</p>\s*?<p~i', '</p><br><p', $text); |
||
| 107 | $text = preg_replace('~</p>\s*(?!<)~i', '</p><br>', $text); |
||
| 108 | |||
| 109 | // Safari/webkit wraps lines in Wysiwyg in <div>'s. |
||
| 110 | if (isBrowser('webkit')) |
||
| 111 | $text = preg_replace(array('~<div(?:\s(?:[^<>]*?))?' . '>~i', '</div>'), array('<br>', ''), $text); |
||
| 112 | |||
| 113 | // If there's a trailing break get rid of it - Firefox tends to add one. |
||
| 114 | $text = preg_replace('~<br\s?/?' . '>$~i', '', $text); |
||
| 115 | |||
| 116 | // Remove any formatting within code tags. |
||
| 117 | if (strpos($text, '[code') !== false) |
||
| 118 | { |
||
| 119 | $text = preg_replace('~<br\s?/?' . '>~i', '#smf_br_spec_grudge_cool!#', $text); |
||
| 120 | $parts = preg_split('~(\[/code\]|\[code(?:=[^\]]+)?\])~i', $text, -1, PREG_SPLIT_DELIM_CAPTURE); |
||
| 121 | |||
| 122 | // Only mess with stuff outside [code] tags. |
||
| 123 | for ($i = 0, $n = count($parts); $i < $n; $i++) |
||
| 124 | { |
||
| 125 | // Value of 2 means we're inside the tag. |
||
| 126 | if ($i % 4 == 2) |
||
| 127 | $parts[$i] = strip_tags($parts[$i]); |
||
| 128 | } |
||
| 129 | |||
| 130 | $text = strtr(implode('', $parts), array('#smf_br_spec_grudge_cool!#' => '<br>')); |
||
| 131 | } |
||
| 132 | |||
| 133 | // Remove scripts, style and comment blocks. |
||
| 134 | $text = preg_replace('~<script[^>]*[^/]?' . '>.*?</script>~i', '', $text); |
||
| 135 | $text = preg_replace('~<style[^>]*[^/]?' . '>.*?</style>~i', '', $text); |
||
| 136 | $text = preg_replace('~\\<\\!--.*?-->~i', '', $text); |
||
| 137 | $text = preg_replace('~\\<\\!\\[CDATA\\[.*?\\]\\]\\>~i', '', $text); |
||
| 138 | |||
| 139 | // Do the smileys ultra first! |
||
| 140 | preg_match_all('~<img\s+[^<>]*?id="*smiley_\d+_([^<>]+?)[\s"/>]\s*[^<>]*?/*>(?:\s)?~i', $text, $matches); |
||
| 141 | if (!empty($matches[0])) |
||
| 142 | { |
||
| 143 | // Easy if it's not custom. |
||
| 144 | if (empty($modSettings['smiley_enable'])) |
||
| 145 | { |
||
| 146 | $smileysfrom = array('>:D', ':D', '::)', '>:(', ':)', ';)', ';D', ':(', ':o', '8)', ':P', '???', ':-[', ':-X', ':-*', ':\'(', ':-\\', '^-^', 'O0', 'C:-)', '0:)'); |
||
| 147 | $smileysto = array('evil.gif', 'cheesy.gif', 'rolleyes.gif', 'angry.gif', 'smiley.gif', 'wink.gif', 'grin.gif', 'sad.gif', 'shocked.gif', 'cool.gif', 'tongue.gif', 'huh.gif', 'embarrassed.gif', 'lipsrsealed.gif', 'kiss.gif', 'cry.gif', 'undecided.gif', 'azn.gif', 'afro.gif', 'police.gif', 'angel.gif'); |
||
| 148 | |||
| 149 | foreach ($matches[1] as $k => $file) |
||
| 150 | { |
||
| 151 | $found = array_search($file, $smileysto); |
||
| 152 | // Note the weirdness here is to stop double spaces between smileys. |
||
| 153 | if ($found) |
||
|
0 ignored issues
–
show
|
|||
| 154 | $matches[1][$k] = '-[]-smf_smily_start#|#' . $smcFunc['htmlspecialchars']($smileysfrom[$found]) . '-[]-smf_smily_end#|#'; |
||
| 155 | else |
||
| 156 | $matches[1][$k] = ''; |
||
| 157 | } |
||
| 158 | } |
||
| 159 | else |
||
| 160 | { |
||
| 161 | // Load all the smileys. |
||
| 162 | $names = array(); |
||
| 163 | foreach ($matches[1] as $file) |
||
| 164 | $names[] = $file; |
||
| 165 | $names = array_unique($names); |
||
| 166 | |||
| 167 | if (!empty($names)) |
||
| 168 | { |
||
| 169 | $request = $smcFunc['db_query']('', ' |
||
| 170 | SELECT code, filename |
||
| 171 | FROM {db_prefix}smileys |
||
| 172 | WHERE filename IN ({array_string:smiley_filenames})', |
||
| 173 | array( |
||
| 174 | 'smiley_filenames' => $names, |
||
| 175 | ) |
||
| 176 | ); |
||
| 177 | $mappings = array(); |
||
| 178 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 179 | $mappings[$row['filename']] = $smcFunc['htmlspecialchars']($row['code']); |
||
| 180 | $smcFunc['db_free_result']($request); |
||
| 181 | |||
| 182 | foreach ($matches[1] as $k => $file) |
||
| 183 | if (isset($mappings[$file])) |
||
| 184 | $matches[1][$k] = '-[]-smf_smily_start#|#' . $mappings[$file] . '-[]-smf_smily_end#|#'; |
||
| 185 | } |
||
| 186 | } |
||
| 187 | |||
| 188 | // Replace the tags! |
||
| 189 | $text = str_replace($matches[0], $matches[1], $text); |
||
| 190 | |||
| 191 | // Now sort out spaces |
||
| 192 | $text = str_replace(array('-[]-smf_smily_end#|#-[]-smf_smily_start#|#', '-[]-smf_smily_end#|#', '-[]-smf_smily_start#|#'), ' ', $text); |
||
| 193 | } |
||
| 194 | |||
| 195 | // Only try to buy more time if the client didn't quit. |
||
| 196 | if (connection_aborted() && $context['server']['is_apache']) |
||
| 197 | @apache_reset_timeout(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 198 | |||
| 199 | $parts = preg_split('~(<[A-Za-z]+\s*[^<>]*?style="?[^<>"]+"?[^<>]*?(?:/?)>|</[A-Za-z]+>)~', $text, -1, PREG_SPLIT_DELIM_CAPTURE); |
||
| 200 | $replacement = ''; |
||
| 201 | $stack = array(); |
||
| 202 | |||
| 203 | foreach ($parts as $part) |
||
| 204 | { |
||
| 205 | if (preg_match('~(<([A-Za-z]+)\s*[^<>]*?)style="?([^<>"]+)"?([^<>]*?(/?)>)~', $part, $matches) === 1) |
||
| 206 | { |
||
| 207 | // If it's being closed instantly, we can't deal with it...yet. |
||
| 208 | if ($matches[5] === '/') |
||
| 209 | continue; |
||
| 210 | else |
||
| 211 | { |
||
| 212 | // Get an array of styles that apply to this element. (The strtr is there to combat HTML generated by Word.) |
||
| 213 | $styles = explode(';', strtr($matches[3], array('"' => ''))); |
||
| 214 | $curElement = $matches[2]; |
||
| 215 | $precedingStyle = $matches[1]; |
||
| 216 | $afterStyle = $matches[4]; |
||
| 217 | $curCloseTags = ''; |
||
| 218 | $extra_attr = ''; |
||
| 219 | |||
| 220 | foreach ($styles as $type_value_pair) |
||
| 221 | { |
||
| 222 | // Remove spaces and convert uppercase letters. |
||
| 223 | $clean_type_value_pair = strtolower(strtr(trim($type_value_pair), '=', ':')); |
||
| 224 | |||
| 225 | // Something like 'font-weight: bold' is expected here. |
||
| 226 | if (strpos($clean_type_value_pair, ':') === false) |
||
| 227 | continue; |
||
| 228 | |||
| 229 | // Capture the elements of a single style item (e.g. 'font-weight' and 'bold'). |
||
| 230 | list ($style_type, $style_value) = explode(':', $type_value_pair); |
||
| 231 | |||
| 232 | $style_value = trim($style_value); |
||
| 233 | |||
| 234 | switch (trim($style_type)) |
||
| 235 | { |
||
| 236 | case 'font-weight': |
||
| 237 | if ($style_value === 'bold') |
||
| 238 | { |
||
| 239 | $curCloseTags .= '[/b]'; |
||
| 240 | $replacement .= '[b]'; |
||
| 241 | } |
||
| 242 | break; |
||
| 243 | |||
| 244 | case 'text-decoration': |
||
| 245 | if ($style_value == 'underline') |
||
| 246 | { |
||
| 247 | $curCloseTags .= '[/u]'; |
||
| 248 | $replacement .= '[u]'; |
||
| 249 | } |
||
| 250 | elseif ($style_value == 'line-through') |
||
| 251 | { |
||
| 252 | $curCloseTags .= '[/s]'; |
||
| 253 | $replacement .= '[s]'; |
||
| 254 | } |
||
| 255 | break; |
||
| 256 | |||
| 257 | case 'text-align': |
||
| 258 | if ($style_value == 'left') |
||
| 259 | { |
||
| 260 | $curCloseTags .= '[/left]'; |
||
| 261 | $replacement .= '[left]'; |
||
| 262 | } |
||
| 263 | elseif ($style_value == 'center') |
||
| 264 | { |
||
| 265 | $curCloseTags .= '[/center]'; |
||
| 266 | $replacement .= '[center]'; |
||
| 267 | } |
||
| 268 | elseif ($style_value == 'right') |
||
| 269 | { |
||
| 270 | $curCloseTags .= '[/right]'; |
||
| 271 | $replacement .= '[right]'; |
||
| 272 | } |
||
| 273 | break; |
||
| 274 | |||
| 275 | case 'font-style': |
||
| 276 | if ($style_value == 'italic') |
||
| 277 | { |
||
| 278 | $curCloseTags .= '[/i]'; |
||
| 279 | $replacement .= '[i]'; |
||
| 280 | } |
||
| 281 | break; |
||
| 282 | |||
| 283 | case 'color': |
||
| 284 | $curCloseTags .= '[/color]'; |
||
| 285 | $replacement .= '[color=' . $style_value . ']'; |
||
| 286 | break; |
||
| 287 | |||
| 288 | case 'font-size': |
||
| 289 | // Sometimes people put decimals where decimals should not be. |
||
| 290 | if (preg_match('~(\d)+\.\d+(p[xt])~i', $style_value, $dec_matches) === 1) |
||
| 291 | $style_value = $dec_matches[1] . $dec_matches[2]; |
||
| 292 | |||
| 293 | $curCloseTags .= '[/size]'; |
||
| 294 | $replacement .= '[size=' . $style_value . ']'; |
||
| 295 | break; |
||
| 296 | |||
| 297 | case 'font-family': |
||
| 298 | // Only get the first freaking font if there's a list! |
||
| 299 | if (strpos($style_value, ',') !== false) |
||
| 300 | $style_value = substr($style_value, 0, strpos($style_value, ',')); |
||
| 301 | |||
| 302 | $curCloseTags .= '[/font]'; |
||
| 303 | $replacement .= '[font=' . strtr($style_value, array("'" => '')) . ']'; |
||
| 304 | break; |
||
| 305 | |||
| 306 | // This is a hack for images with dimensions embedded. |
||
| 307 | case 'width': |
||
| 308 | case 'height': |
||
| 309 | if (preg_match('~[1-9]\d*~i', $style_value, $dimension) === 1) |
||
| 310 | $extra_attr .= ' ' . $style_type . '="' . $dimension[0] . '"'; |
||
| 311 | break; |
||
| 312 | |||
| 313 | case 'list-style-type': |
||
| 314 | if (preg_match('~none|disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman|lower-alpha|upper-alpha|lower-greek|lower-latin|upper-latin|hebrew|armenian|georgian|cjk-ideographic|hiragana|katakana|hiragana-iroha|katakana-iroha~i', $style_value, $listType) === 1) |
||
| 315 | $extra_attr .= ' listtype="' . $listType[0] . '"'; |
||
| 316 | break; |
||
| 317 | } |
||
| 318 | } |
||
| 319 | |||
| 320 | // Preserve some tags stripping the styling. |
||
| 321 | if (in_array($matches[2], array('a', 'font', 'td'))) |
||
| 322 | { |
||
| 323 | $replacement .= $precedingStyle . $afterStyle; |
||
| 324 | $curCloseTags = '</' . $matches[2] . '>' . $curCloseTags; |
||
| 325 | } |
||
| 326 | |||
| 327 | // If there's something that still needs closing, push it to the stack. |
||
| 328 | if (!empty($curCloseTags)) |
||
| 329 | array_push($stack, array( |
||
| 330 | 'element' => strtolower($curElement), |
||
| 331 | 'closeTags' => $curCloseTags |
||
| 332 | ) |
||
| 333 | ); |
||
| 334 | elseif (!empty($extra_attr)) |
||
| 335 | $replacement .= $precedingStyle . $extra_attr . $afterStyle; |
||
| 336 | } |
||
| 337 | } |
||
| 338 | |||
| 339 | elseif (preg_match('~</([A-Za-z]+)>~', $part, $matches) === 1) |
||
| 340 | { |
||
| 341 | // Is this the element that we've been waiting for to be closed? |
||
| 342 | if (!empty($stack) && strtolower($matches[1]) === $stack[count($stack) - 1]['element']) |
||
| 343 | { |
||
| 344 | $byebyeTag = array_pop($stack); |
||
| 345 | $replacement .= $byebyeTag['closeTags']; |
||
| 346 | } |
||
| 347 | |||
| 348 | // Must've been something else. |
||
| 349 | else |
||
| 350 | $replacement .= $part; |
||
| 351 | } |
||
| 352 | // In all other cases, just add the part to the replacement. |
||
| 353 | else |
||
| 354 | $replacement .= $part; |
||
| 355 | } |
||
| 356 | |||
| 357 | // Now put back the replacement in the text. |
||
| 358 | $text = $replacement; |
||
| 359 | |||
| 360 | // We are not finished yet, request more time. |
||
| 361 | if (connection_aborted() && $context['server']['is_apache']) |
||
| 362 | @apache_reset_timeout(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 363 | |||
| 364 | // Let's pull out any legacy alignments. |
||
| 365 | while (preg_match('~<([A-Za-z]+)\s+[^<>]*?(align="*(left|center|right)"*)[^<>]*?(/?)>~i', $text, $matches) === 1) |
||
| 366 | { |
||
| 367 | // Find the position in the text of this tag over again. |
||
| 368 | $start_pos = strpos($text, $matches[0]); |
||
| 369 | if ($start_pos === false) |
||
| 370 | break; |
||
| 371 | |||
| 372 | // End tag? |
||
| 373 | if ($matches[4] != '/' && strpos($text, '</' . $matches[1] . '>', $start_pos) !== false) |
||
| 374 | { |
||
| 375 | $end_pos = strpos($text, '</' . $matches[1] . '>', $start_pos); |
||
| 376 | |||
| 377 | // Remove the align from that tag so it's never checked again. |
||
| 378 | $tag = substr($text, $start_pos, strlen($matches[0])); |
||
| 379 | $content = substr($text, $start_pos + strlen($matches[0]), $end_pos - $start_pos - strlen($matches[0])); |
||
| 380 | $tag = str_replace($matches[2], '', $tag); |
||
| 381 | |||
| 382 | // Put the tags back into the body. |
||
| 383 | $text = substr($text, 0, $start_pos) . $tag . '[' . $matches[3] . ']' . $content . '[/' . $matches[3] . ']' . substr($text, $end_pos); |
||
| 384 | } |
||
| 385 | else |
||
| 386 | { |
||
| 387 | // Just get rid of this evil tag. |
||
| 388 | $text = substr($text, 0, $start_pos) . substr($text, $start_pos + strlen($matches[0])); |
||
| 389 | } |
||
| 390 | } |
||
| 391 | |||
| 392 | // Let's do some special stuff for fonts - cause we all love fonts. |
||
| 393 | while (preg_match('~<font\s+([^<>]*)>~i', $text, $matches) === 1) |
||
| 394 | { |
||
| 395 | // Find the position of this again. |
||
| 396 | $start_pos = strpos($text, $matches[0]); |
||
| 397 | $end_pos = false; |
||
| 398 | if ($start_pos === false) |
||
| 399 | break; |
||
| 400 | |||
| 401 | // This must have an end tag - and we must find the right one. |
||
| 402 | $lower_text = strtolower($text); |
||
| 403 | |||
| 404 | $start_pos_test = $start_pos + 4; |
||
| 405 | // How many starting tags must we find closing ones for first? |
||
| 406 | $start_font_tag_stack = 0; |
||
| 407 | while ($start_pos_test < strlen($text)) |
||
| 408 | { |
||
| 409 | // Where is the next starting font? |
||
| 410 | $next_start_pos = strpos($lower_text, '<font', $start_pos_test); |
||
| 411 | $next_end_pos = strpos($lower_text, '</font>', $start_pos_test); |
||
| 412 | |||
| 413 | // Did we past another starting tag before an end one? |
||
| 414 | if ($next_start_pos !== false && $next_start_pos < $next_end_pos) |
||
| 415 | { |
||
| 416 | $start_font_tag_stack++; |
||
| 417 | $start_pos_test = $next_start_pos + 4; |
||
| 418 | } |
||
| 419 | // Otherwise we have an end tag but not the right one? |
||
| 420 | elseif ($start_font_tag_stack) |
||
| 421 | { |
||
| 422 | $start_font_tag_stack--; |
||
| 423 | $start_pos_test = $next_end_pos + 4; |
||
| 424 | } |
||
| 425 | // Otherwise we're there! |
||
| 426 | else |
||
| 427 | { |
||
| 428 | $end_pos = $next_end_pos; |
||
| 429 | break; |
||
| 430 | } |
||
| 431 | } |
||
| 432 | if ($end_pos === false) |
||
| 433 | break; |
||
| 434 | |||
| 435 | // Now work out what the attributes are. |
||
| 436 | $attribs = fetchTagAttributes($matches[1]); |
||
| 437 | $tags = array(); |
||
| 438 | $sizes_equivalence = array(1 => '8pt', '10pt', '12pt', '14pt', '18pt', '24pt', '36pt'); |
||
| 439 | foreach ($attribs as $s => $v) |
||
| 440 | { |
||
| 441 | if ($s == 'size') |
||
| 442 | { |
||
| 443 | // Cast before empty chech because casting a string results in a 0 and we don't have zeros in the array! ;) |
||
| 444 | $v = (int) trim($v); |
||
| 445 | $v = empty($v) ? 1 : $v; |
||
| 446 | $tags[] = array('[size=' . $sizes_equivalence[$v] . ']', '[/size]'); |
||
| 447 | } |
||
| 448 | View Code Duplication | elseif ($s == 'face') |
|
| 449 | $tags[] = array('[font=' . trim(strtolower($v)) . ']', '[/font]'); |
||
| 450 | View Code Duplication | elseif ($s == 'color') |
|
| 451 | $tags[] = array('[color=' . trim(strtolower($v)) . ']', '[/color]'); |
||
| 452 | } |
||
| 453 | |||
| 454 | // As before add in our tags. |
||
| 455 | $before = $after = ''; |
||
| 456 | foreach ($tags as $tag) |
||
| 457 | { |
||
| 458 | $before .= $tag[0]; |
||
| 459 | if (isset($tag[1])) |
||
| 460 | $after = $tag[1] . $after; |
||
| 461 | } |
||
| 462 | |||
| 463 | // Remove the tag so it's never checked again. |
||
| 464 | $content = substr($text, $start_pos + strlen($matches[0]), $end_pos - $start_pos - strlen($matches[0])); |
||
| 465 | |||
| 466 | // Put the tags back into the body. |
||
| 467 | $text = substr($text, 0, $start_pos) . $before . $content . $after . substr($text, $end_pos + 7); |
||
| 468 | } |
||
| 469 | |||
| 470 | // Almost there, just a little more time. |
||
| 471 | if (connection_aborted() && $context['server']['is_apache']) |
||
| 472 | @apache_reset_timeout(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 473 | |||
| 474 | if (count($parts = preg_split('~<(/?)(li|ol|ul)([^>]*)>~i', $text, null, PREG_SPLIT_DELIM_CAPTURE)) > 1) |
||
| 475 | { |
||
| 476 | // A toggle that dermines whether we're directly under a <ol> or <ul>. |
||
| 477 | $inList = false; |
||
| 478 | |||
| 479 | // Keep track of the number of nested list levels. |
||
| 480 | $listDepth = 0; |
||
| 481 | |||
| 482 | // Map what we can expect from the HTML to what is supported by SMF. |
||
| 483 | $listTypeMapping = array( |
||
| 484 | '1' => 'decimal', |
||
| 485 | 'A' => 'upper-alpha', |
||
| 486 | 'a' => 'lower-alpha', |
||
| 487 | 'I' => 'upper-roman', |
||
| 488 | 'i' => 'lower-roman', |
||
| 489 | 'disc' => 'disc', |
||
| 490 | 'square' => 'square', |
||
| 491 | 'circle' => 'circle', |
||
| 492 | ); |
||
| 493 | |||
| 494 | // $i: text, $i + 1: '/', $i + 2: tag, $i + 3: tail. |
||
| 495 | for ($i = 0, $numParts = count($parts) - 1; $i < $numParts; $i += 4) |
||
| 496 | { |
||
| 497 | $tag = strtolower($parts[$i + 2]); |
||
| 498 | $isOpeningTag = $parts[$i + 1] === ''; |
||
| 499 | |||
| 500 | if ($isOpeningTag) |
||
| 501 | { |
||
| 502 | switch ($tag) |
||
| 503 | { |
||
| 504 | case 'ol': |
||
| 505 | case 'ul': |
||
| 506 | |||
| 507 | // We have a problem, we're already in a list. |
||
| 508 | if ($inList) |
||
| 509 | { |
||
| 510 | // Inject a list opener, we'll deal with the ol/ul next loop. |
||
| 511 | array_splice($parts, $i, 0, array( |
||
| 512 | '', |
||
| 513 | '', |
||
| 514 | str_repeat("\t", $listDepth) . '[li]', |
||
| 515 | '', |
||
| 516 | )); |
||
| 517 | $numParts = count($parts) - 1; |
||
| 518 | |||
| 519 | // The inlist status changes a bit. |
||
| 520 | $inList = false; |
||
| 521 | } |
||
| 522 | |||
| 523 | // Just starting a new list. |
||
| 524 | else |
||
| 525 | { |
||
| 526 | $inList = true; |
||
| 527 | |||
| 528 | if ($tag === 'ol') |
||
| 529 | $listType = 'decimal'; |
||
| 530 | elseif (preg_match('~type="?(' . implode('|', array_keys($listTypeMapping)) . ')"?~', $parts[$i + 3], $match) === 1) |
||
| 531 | $listType = $listTypeMapping[$match[1]]; |
||
| 532 | else |
||
| 533 | $listType = null; |
||
| 534 | |||
| 535 | $listDepth++; |
||
| 536 | |||
| 537 | $parts[$i + 2] = '[list' . ($listType === null ? '' : ' type=' . $listType) . ']' . "\n"; |
||
| 538 | $parts[$i + 3] = ''; |
||
| 539 | } |
||
| 540 | break; |
||
| 541 | |||
| 542 | case 'li': |
||
| 543 | |||
| 544 | // This is how it should be: a list item inside the list. |
||
| 545 | if ($inList) |
||
| 546 | { |
||
| 547 | $parts[$i + 2] = str_repeat("\t", $listDepth) . '[li]'; |
||
| 548 | $parts[$i + 3] = ''; |
||
| 549 | |||
| 550 | // Within a list item, it's almost as if you're outside. |
||
| 551 | $inList = false; |
||
| 552 | } |
||
| 553 | |||
| 554 | // The li is no direct child of a list. |
||
| 555 | else |
||
| 556 | { |
||
| 557 | // We are apparently in a list item. |
||
| 558 | if ($listDepth > 0) |
||
| 559 | { |
||
| 560 | $parts[$i + 2] = '[/li]' . "\n" . str_repeat("\t", $listDepth) . '[li]'; |
||
| 561 | $parts[$i + 3] = ''; |
||
| 562 | } |
||
| 563 | |||
| 564 | // We're not even near a list. |
||
| 565 | else |
||
| 566 | { |
||
| 567 | // Quickly create a list with an item. |
||
| 568 | $listDepth++; |
||
| 569 | |||
| 570 | $parts[$i + 2] = '[list]' . "\n\t" . '[li]'; |
||
| 571 | $parts[$i + 3] = ''; |
||
| 572 | } |
||
| 573 | } |
||
| 574 | |||
| 575 | break; |
||
| 576 | } |
||
| 577 | } |
||
| 578 | |||
| 579 | // Handle all the closing tags. |
||
| 580 | else |
||
| 581 | { |
||
| 582 | switch ($tag) |
||
| 583 | { |
||
| 584 | case 'ol': |
||
| 585 | case 'ul': |
||
| 586 | |||
| 587 | // As we expected it, closing the list while we're in it. |
||
| 588 | if ($inList) |
||
| 589 | { |
||
| 590 | $inList = false; |
||
| 591 | |||
| 592 | $listDepth--; |
||
| 593 | |||
| 594 | $parts[$i + 1] = ''; |
||
| 595 | $parts[$i + 2] = str_repeat("\t", $listDepth) . '[/list]'; |
||
| 596 | $parts[$i + 3] = ''; |
||
| 597 | } |
||
| 598 | |||
| 599 | else |
||
| 600 | { |
||
| 601 | // We're in a list item. |
||
| 602 | if ($listDepth > 0) |
||
| 603 | { |
||
| 604 | // Inject closure for this list item first. |
||
| 605 | // The content of $parts[$i] is left as is! |
||
| 606 | array_splice($parts, $i + 1, 0, array( |
||
| 607 | '', // $i + 1 |
||
| 608 | '[/li]' . "\n", // $i + 2 |
||
| 609 | '', // $i + 3 |
||
| 610 | '', // $i + 4 |
||
| 611 | )); |
||
| 612 | $numParts = count($parts) - 1; |
||
| 613 | |||
| 614 | // Now that we've closed the li, we're in list space. |
||
| 615 | $inList = true; |
||
| 616 | } |
||
| 617 | |||
| 618 | // We're not even in a list, ignore |
||
| 619 | View Code Duplication | else |
|
| 620 | { |
||
| 621 | $parts[$i + 1] = ''; |
||
| 622 | $parts[$i + 2] = ''; |
||
| 623 | $parts[$i + 3] = ''; |
||
| 624 | } |
||
| 625 | } |
||
| 626 | break; |
||
| 627 | |||
| 628 | case 'li': |
||
| 629 | |||
| 630 | if ($inList) |
||
| 631 | { |
||
| 632 | // There's no use for a </li> after <ol> or <ul>, ignore. |
||
| 633 | $parts[$i + 1] = ''; |
||
| 634 | $parts[$i + 2] = ''; |
||
| 635 | $parts[$i + 3] = ''; |
||
| 636 | } |
||
| 637 | |||
| 638 | else |
||
| 639 | { |
||
| 640 | // Remove the trailing breaks from the list item. |
||
| 641 | $parts[$i] = preg_replace('~\s*<br\s*' . '/?' . '>\s*$~', '', $parts[$i]); |
||
| 642 | $parts[$i + 1] = ''; |
||
| 643 | $parts[$i + 2] = '[/li]' . "\n"; |
||
| 644 | $parts[$i + 3] = ''; |
||
| 645 | |||
| 646 | // And we're back in the [list] space. |
||
| 647 | $inList = true; |
||
| 648 | } |
||
| 649 | |||
| 650 | break; |
||
| 651 | } |
||
| 652 | } |
||
| 653 | |||
| 654 | // If we're in the [list] space, no content is allowed. |
||
| 655 | if ($inList && trim(preg_replace('~\s*<br\s*' . '/?' . '>\s*~', '', $parts[$i + 4])) !== '') |
||
| 656 | { |
||
| 657 | // Fix it by injecting an extra list item. |
||
| 658 | array_splice($parts, $i + 4, 0, array( |
||
| 659 | '', // No content. |
||
| 660 | '', // Opening tag. |
||
| 661 | 'li', // It's a <li>. |
||
| 662 | '', // No tail. |
||
| 663 | )); |
||
| 664 | $numParts = count($parts) - 1; |
||
| 665 | } |
||
| 666 | } |
||
| 667 | |||
| 668 | $text = implode('', $parts); |
||
| 669 | |||
| 670 | if ($inList) |
||
| 671 | { |
||
| 672 | $listDepth--; |
||
| 673 | $text .= str_repeat("\t", $listDepth) . '[/list]'; |
||
| 674 | } |
||
| 675 | |||
| 676 | for ($i = $listDepth; $i > 0; $i--) |
||
| 677 | $text .= '[/li]' . "\n" . str_repeat("\t", $i - 1) . '[/list]'; |
||
| 678 | |||
| 679 | } |
||
| 680 | |||
| 681 | // I love my own image... |
||
| 682 | while (preg_match('~<img\s+([^<>]*)/*>~i', $text, $matches) === 1) |
||
| 683 | { |
||
| 684 | // Find the position of the image. |
||
| 685 | $start_pos = strpos($text, $matches[0]); |
||
| 686 | if ($start_pos === false) |
||
| 687 | break; |
||
| 688 | $end_pos = $start_pos + strlen($matches[0]); |
||
| 689 | |||
| 690 | $params = ''; |
||
| 691 | $src = ''; |
||
| 692 | |||
| 693 | $attrs = fetchTagAttributes($matches[1]); |
||
| 694 | foreach ($attrs as $attrib => $value) |
||
| 695 | { |
||
| 696 | if (in_array($attrib, array('width', 'height'))) |
||
| 697 | $params .= ' ' . $attrib . '=' . (int) $value; |
||
| 698 | elseif ($attrib == 'alt' && trim($value) != '') |
||
| 699 | $params .= ' alt=' . trim($value); |
||
| 700 | elseif ($attrib == 'src') |
||
| 701 | $src = trim($value); |
||
| 702 | } |
||
| 703 | |||
| 704 | $tag = ''; |
||
| 705 | if (!empty($src)) |
||
| 706 | { |
||
| 707 | // Attempt to fix the path in case it's not present. |
||
| 708 | View Code Duplication | if (preg_match('~^https?://~i', $src) === 0 && is_array($parsedURL = parse_url($scripturl)) && isset($parsedURL['host'])) |
|
| 709 | { |
||
| 710 | $baseURL = (isset($parsedURL['scheme']) ? $parsedURL['scheme'] : 'http') . '://' . $parsedURL['host'] . (empty($parsedURL['port']) ? '' : ':' . $parsedURL['port']); |
||
| 711 | |||
| 712 | if (substr($src, 0, 1) === '/') |
||
| 713 | $src = $baseURL . $src; |
||
| 714 | else |
||
| 715 | $src = $baseURL . (empty($parsedURL['path']) ? '/' : preg_replace('~/(?:index\\.php)?$~', '', $parsedURL['path'])) . '/' . $src; |
||
| 716 | } |
||
| 717 | |||
| 718 | $tag = '[img' . $params . ']' . $src . '[/img]'; |
||
| 719 | } |
||
| 720 | |||
| 721 | // Replace the tag |
||
| 722 | $text = substr($text, 0, $start_pos) . $tag . substr($text, $end_pos); |
||
| 723 | } |
||
| 724 | |||
| 725 | // The final bits are the easy ones - tags which map to tags which map to tags - etc etc. |
||
| 726 | $tags = array( |
||
| 727 | '~<b(\s(.)*?)*?' . '>~i' => function() |
||
| 728 | { |
||
| 729 | return '[b]'; |
||
| 730 | }, |
||
| 731 | '~</b>~i' => function() |
||
| 732 | { |
||
| 733 | return '[/b]'; |
||
| 734 | }, |
||
| 735 | '~<i(\s(.)*?)*?' . '>~i' => function() |
||
| 736 | { |
||
| 737 | return '[i]'; |
||
| 738 | }, |
||
| 739 | '~</i>~i' => function() |
||
| 740 | { |
||
| 741 | return '[/i]'; |
||
| 742 | }, |
||
| 743 | '~<u(\s(.)*?)*?' . '>~i' => function() |
||
| 744 | { |
||
| 745 | return '[u]'; |
||
| 746 | }, |
||
| 747 | '~</u>~i' => function() |
||
| 748 | { |
||
| 749 | return '[/u]'; |
||
| 750 | }, |
||
| 751 | '~<strong(\s(.)*?)*?' . '>~i' => function() |
||
| 752 | { |
||
| 753 | return '[b]'; |
||
| 754 | }, |
||
| 755 | '~</strong>~i' => function() |
||
| 756 | { |
||
| 757 | return '[/b]'; |
||
| 758 | }, |
||
| 759 | '~<em(\s(.)*?)*?' . '>~i' => function() |
||
| 760 | { |
||
| 761 | return '[i]'; |
||
| 762 | }, |
||
| 763 | '~</em>~i' => function() |
||
| 764 | { |
||
| 765 | return '[i]'; |
||
| 766 | }, |
||
| 767 | '~<s(\s(.)*?)*?' . '>~i' => function() |
||
| 768 | { |
||
| 769 | return "[s]"; |
||
| 770 | }, |
||
| 771 | '~</s>~i' => function() |
||
| 772 | { |
||
| 773 | return "[/s]"; |
||
| 774 | }, |
||
| 775 | '~<strike(\s(.)*?)*?' . '>~i' => function() |
||
| 776 | { |
||
| 777 | return '[s]'; |
||
| 778 | }, |
||
| 779 | '~</strike>~i' => function() |
||
| 780 | { |
||
| 781 | return '[/s]'; |
||
| 782 | }, |
||
| 783 | '~<del(\s(.)*?)*?' . '>~i' => function() |
||
| 784 | { |
||
| 785 | return '[s]'; |
||
| 786 | }, |
||
| 787 | '~</del>~i' => function() |
||
| 788 | { |
||
| 789 | return '[/s]'; |
||
| 790 | }, |
||
| 791 | '~<center(\s(.)*?)*?' . '>~i' => function() |
||
| 792 | { |
||
| 793 | return '[center]'; |
||
| 794 | }, |
||
| 795 | '~</center>~i' => function() |
||
| 796 | { |
||
| 797 | return '[/center]'; |
||
| 798 | }, |
||
| 799 | '~<pre(\s(.)*?)*?' . '>~i' => function() |
||
| 800 | { |
||
| 801 | return '[pre]'; |
||
| 802 | }, |
||
| 803 | '~</pre>~i' => function() |
||
| 804 | { |
||
| 805 | return '[/pre]'; |
||
| 806 | }, |
||
| 807 | '~<sub(\s(.)*?)*?' . '>~i' => function() |
||
| 808 | { |
||
| 809 | return '[sub]'; |
||
| 810 | }, |
||
| 811 | '~</sub>~i' => function() |
||
| 812 | { |
||
| 813 | return '[/sub]'; |
||
| 814 | }, |
||
| 815 | '~<sup(\s(.)*?)*?' . '>~i' => function() |
||
| 816 | { |
||
| 817 | return '[sup]'; |
||
| 818 | }, |
||
| 819 | '~</sup>~i' => function() |
||
| 820 | { |
||
| 821 | return '[/sup]'; |
||
| 822 | }, |
||
| 823 | '~<tt(\s(.)*?)*?' . '>~i' => function() |
||
| 824 | { |
||
| 825 | return '[tt]'; |
||
| 826 | }, |
||
| 827 | '~</tt>~i' => function() |
||
| 828 | { |
||
| 829 | return '[/tt]'; |
||
| 830 | }, |
||
| 831 | '~<table(\s(.)*?)*?' . '>~i' => function() |
||
| 832 | { |
||
| 833 | return '[table]'; |
||
| 834 | }, |
||
| 835 | '~</table>~i' => function() |
||
| 836 | { |
||
| 837 | return '[/table]'; |
||
| 838 | }, |
||
| 839 | '~<tr(\s(.)*?)*?' . '>~i' => function() |
||
| 840 | { |
||
| 841 | return '[tr]'; |
||
| 842 | }, |
||
| 843 | '~</tr>~i' => function() |
||
| 844 | { |
||
| 845 | return '[/tr]'; |
||
| 846 | }, |
||
| 847 | '~<(td|th)\s[^<>]*?colspan="?(\d{1,2})"?.*?' . '>~i' => function($matches) |
||
| 848 | { |
||
| 849 | return str_repeat('[td][/td]', $matches[2] - 1) . '[td]'; |
||
| 850 | }, |
||
| 851 | '~<(td|th)(\s(.)*?)*?' . '>~i' => function() |
||
| 852 | { |
||
| 853 | return '[td]'; |
||
| 854 | }, |
||
| 855 | '~</(td|th)>~i' => function() |
||
| 856 | { |
||
| 857 | return '[/td]'; |
||
| 858 | }, |
||
| 859 | '~<br(?:\s[^<>]*?)?' . '>~i' => function() |
||
| 860 | { |
||
| 861 | return "\n"; |
||
| 862 | }, |
||
| 863 | '~<hr[^<>]*>(\n)?~i' => function($matches) |
||
| 864 | { |
||
| 865 | return "[hr]\n" . $matches[0]; |
||
| 866 | }, |
||
| 867 | '~(\n)?\\[hr\\]~i' => function() |
||
| 868 | { |
||
| 869 | return "\n[hr]"; |
||
| 870 | }, |
||
| 871 | '~^\n\\[hr\\]~i' => function() |
||
| 872 | { |
||
| 873 | return "[hr]"; |
||
| 874 | }, |
||
| 875 | '~<blockquote(\s(.)*?)*?' . '>~i' => function() |
||
| 876 | { |
||
| 877 | return "<blockquote>"; |
||
| 878 | }, |
||
| 879 | '~</blockquote>~i' => function() |
||
| 880 | { |
||
| 881 | return "</blockquote>"; |
||
| 882 | }, |
||
| 883 | '~<ins(\s(.)*?)*?' . '>~i' => function() |
||
| 884 | { |
||
| 885 | return "<ins>"; |
||
| 886 | }, |
||
| 887 | '~</ins>~i' => function() |
||
| 888 | { |
||
| 889 | return "</ins>"; |
||
| 890 | }, |
||
| 891 | ); |
||
| 892 | |||
| 893 | foreach ($tags as $tag => $replace) |
||
| 894 | $text = preg_replace_callback($tag, $replace, $text); |
||
| 895 | |||
| 896 | // Please give us just a little more time. |
||
| 897 | if (connection_aborted() && $context['server']['is_apache']) |
||
| 898 | @apache_reset_timeout(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 899 | |||
| 900 | // What about URL's - the pain in the ass of the tag world. |
||
| 901 | while (preg_match('~<a\s+([^<>]*)>([^<>]*)</a>~i', $text, $matches) === 1) |
||
| 902 | { |
||
| 903 | // Find the position of the URL. |
||
| 904 | $start_pos = strpos($text, $matches[0]); |
||
| 905 | if ($start_pos === false) |
||
| 906 | break; |
||
| 907 | $end_pos = $start_pos + strlen($matches[0]); |
||
| 908 | |||
| 909 | $tag_type = 'url'; |
||
| 910 | $href = ''; |
||
| 911 | |||
| 912 | $attrs = fetchTagAttributes($matches[1]); |
||
| 913 | foreach ($attrs as $attrib => $value) |
||
| 914 | { |
||
| 915 | if ($attrib == 'href') |
||
| 916 | { |
||
| 917 | $href = trim($value); |
||
| 918 | |||
| 919 | // Are we dealing with an FTP link? |
||
| 920 | if (preg_match('~^ftps?://~', $href) === 1) |
||
| 921 | $tag_type = 'ftp'; |
||
| 922 | |||
| 923 | // Or is this a link to an email address? |
||
| 924 | elseif (substr($href, 0, 7) == 'mailto:') |
||
| 925 | { |
||
| 926 | $tag_type = 'email'; |
||
| 927 | $href = substr($href, 7); |
||
| 928 | } |
||
| 929 | |||
| 930 | // No http(s), so attempt to fix this potential relative URL. |
||
| 931 | View Code Duplication | elseif (preg_match('~^https?://~i', $href) === 0 && is_array($parsedURL = parse_url($scripturl)) && isset($parsedURL['host'])) |
|
| 932 | { |
||
| 933 | $baseURL = (isset($parsedURL['scheme']) ? $parsedURL['scheme'] : 'http') . '://' . $parsedURL['host'] . (empty($parsedURL['port']) ? '' : ':' . $parsedURL['port']); |
||
| 934 | |||
| 935 | if (substr($href, 0, 1) === '/') |
||
| 936 | $href = $baseURL . $href; |
||
| 937 | else |
||
| 938 | $href = $baseURL . (empty($parsedURL['path']) ? '/' : preg_replace('~/(?:index\\.php)?$~', '', $parsedURL['path'])) . '/' . $href; |
||
| 939 | } |
||
| 940 | } |
||
| 941 | |||
| 942 | // External URL? |
||
| 943 | if ($attrib == 'target' && $tag_type == 'url') |
||
| 944 | { |
||
| 945 | if (trim($value) == '_blank') |
||
| 946 | $tag_type == 'iurl'; |
||
| 947 | } |
||
| 948 | } |
||
| 949 | |||
| 950 | $tag = ''; |
||
| 951 | if ($href != '') |
||
| 952 | { |
||
| 953 | if ($matches[2] == $href) |
||
| 954 | $tag = '[' . $tag_type . ']' . $href . '[/' . $tag_type . ']'; |
||
| 955 | else |
||
| 956 | $tag = '[' . $tag_type . '=' . $href . ']' . $matches[2] . '[/' . $tag_type . ']'; |
||
| 957 | } |
||
| 958 | |||
| 959 | // Replace the tag |
||
| 960 | $text = substr($text, 0, $start_pos) . $tag . substr($text, $end_pos); |
||
| 961 | } |
||
| 962 | |||
| 963 | $text = strip_tags($text); |
||
| 964 | |||
| 965 | // Some tags often end up as just dummy tags - remove those. |
||
| 966 | $text = preg_replace('~\[[bisu]\]\s*\[/[bisu]\]~', '', $text); |
||
| 967 | |||
| 968 | // Fix up entities. |
||
| 969 | $text = preg_replace('~&~i', '&#38;', $text); |
||
| 970 | |||
| 971 | $text = legalise_bbc($text); |
||
| 972 | |||
| 973 | return $text; |
||
| 974 | } |
||
| 975 | |||
| 976 | /** |
||
| 977 | * !!!Compatibility!!! |
||
| 978 | * This is no more needed, but to avoid break mods let's keep it |
||
| 979 | * |
||
| 980 | * Returns an array of attributes associated with a tag. |
||
| 981 | * |
||
| 982 | * @param string $text A tag |
||
| 983 | * @return array An array of attributes |
||
| 984 | */ |
||
| 985 | function fetchTagAttributes($text) |
||
| 986 | { |
||
| 987 | $attribs = array(); |
||
| 988 | $key = $value = ''; |
||
| 989 | $tag_state = 0; // 0 = key, 1 = attribute with no string, 2 = attribute with string |
||
| 990 | for ($i = 0; $i < strlen($text); $i++) |
||
| 991 | { |
||
| 992 | // We're either moving from the key to the attribute or we're in a string and this is fine. |
||
| 993 | if ($text[$i] == '=') |
||
| 994 | { |
||
| 995 | if ($tag_state == 0) |
||
| 996 | $tag_state = 1; |
||
| 997 | elseif ($tag_state == 2) |
||
| 998 | $value .= '='; |
||
| 999 | } |
||
| 1000 | // A space is either moving from an attribute back to a potential key or in a string is fine. |
||
| 1001 | elseif ($text[$i] == ' ') |
||
| 1002 | { |
||
| 1003 | if ($tag_state == 2) |
||
| 1004 | $value .= ' '; |
||
| 1005 | elseif ($tag_state == 1) |
||
| 1006 | { |
||
| 1007 | $attribs[$key] = $value; |
||
| 1008 | $key = $value = ''; |
||
| 1009 | $tag_state = 0; |
||
| 1010 | } |
||
| 1011 | } |
||
| 1012 | // A quote? |
||
| 1013 | elseif ($text[$i] == '"') |
||
| 1014 | { |
||
| 1015 | // Must be either going into or out of a string. |
||
| 1016 | if ($tag_state == 1) |
||
| 1017 | $tag_state = 2; |
||
| 1018 | else |
||
| 1019 | $tag_state = 1; |
||
| 1020 | } |
||
| 1021 | // Otherwise it's fine. |
||
| 1022 | else |
||
| 1023 | { |
||
| 1024 | if ($tag_state == 0) |
||
| 1025 | $key .= $text[$i]; |
||
| 1026 | else |
||
| 1027 | $value .= $text[$i]; |
||
| 1028 | } |
||
| 1029 | } |
||
| 1030 | |||
| 1031 | // Anything left? |
||
| 1032 | if ($key != '' && $value != '') |
||
| 1033 | $attribs[$key] = $value; |
||
| 1034 | |||
| 1035 | return $attribs; |
||
| 1036 | } |
||
| 1037 | |||
| 1038 | /** |
||
| 1039 | * !!!Compatibility!!! |
||
| 1040 | * Attempt to clean up illegal BBC caused by browsers like Opera which don't obey the rules |
||
| 1041 | * @param string $text Text |
||
| 1042 | * @return string Cleaned up text |
||
| 1043 | */ |
||
| 1044 | function legalise_bbc($text) |
||
| 1045 | { |
||
| 1046 | global $modSettings; |
||
| 1047 | |||
| 1048 | // Don't care about the texts that are too short. |
||
| 1049 | if (strlen($text) < 3) |
||
| 1050 | return $text; |
||
| 1051 | |||
| 1052 | // A list of tags that's disabled by the admin. |
||
| 1053 | $disabled = empty($modSettings['disabledBBC']) ? array() : array_flip(explode(',', strtolower($modSettings['disabledBBC']))); |
||
| 1054 | |||
| 1055 | // Add flash if it's disabled as embedded tag. |
||
| 1056 | if (empty($modSettings['enableEmbeddedFlash'])) |
||
| 1057 | $disabled['flash'] = true; |
||
| 1058 | |||
| 1059 | // Get a list of all the tags that are not disabled. |
||
| 1060 | $all_tags = parse_bbc(false); |
||
| 1061 | $valid_tags = array(); |
||
| 1062 | $self_closing_tags = array(); |
||
| 1063 | foreach ($all_tags as $tag) |
||
|
0 ignored issues
–
show
|
|||
| 1064 | { |
||
| 1065 | if (!isset($disabled[$tag['tag']])) |
||
| 1066 | $valid_tags[$tag['tag']] = !empty($tag['block_level']); |
||
| 1067 | if (isset($tag['type']) && $tag['type'] == 'closed') |
||
| 1068 | $self_closing_tags[] = $tag['tag']; |
||
| 1069 | } |
||
| 1070 | |||
| 1071 | // Right - we're going to start by going through the whole lot to make sure we don't have align stuff crossed as this happens load and is stupid! |
||
| 1072 | $align_tags = array('left', 'center', 'right', 'pre'); |
||
| 1073 | |||
| 1074 | // Remove those align tags that are not valid. |
||
| 1075 | $align_tags = array_intersect($align_tags, array_keys($valid_tags)); |
||
| 1076 | |||
| 1077 | // These keep track of where we are! |
||
| 1078 | if (!empty($align_tags) && count($matches = preg_split('~(\\[/?(?:' . implode('|', $align_tags) . ')\\])~', $text, -1, PREG_SPLIT_DELIM_CAPTURE)) > 1) |
||
| 1079 | { |
||
| 1080 | // The first one is never a tag. |
||
| 1081 | $isTag = false; |
||
| 1082 | |||
| 1083 | // By default we're not inside a tag too. |
||
| 1084 | $insideTag = null; |
||
| 1085 | |||
| 1086 | foreach ($matches as $i => $match) |
||
| 1087 | { |
||
| 1088 | // We're only interested in tags, not text. |
||
| 1089 | if ($isTag) |
||
| 1090 | { |
||
| 1091 | $isClosingTag = substr($match, 1, 1) === '/'; |
||
| 1092 | $tagName = substr($match, $isClosingTag ? 2 : 1, -1); |
||
| 1093 | |||
| 1094 | // We're closing the exact same tag that we opened. |
||
| 1095 | if ($isClosingTag && $insideTag === $tagName) |
||
| 1096 | $insideTag = null; |
||
| 1097 | |||
| 1098 | // We're opening a tag and we're not yet inside one either |
||
| 1099 | elseif (!$isClosingTag && $insideTag === null) |
||
| 1100 | $insideTag = $tagName; |
||
| 1101 | |||
| 1102 | // In all other cases, this tag must be invalid |
||
| 1103 | else |
||
| 1104 | unset($matches[$i]); |
||
| 1105 | } |
||
| 1106 | |||
| 1107 | // The next one is gonna be the other one. |
||
| 1108 | $isTag = !$isTag; |
||
| 1109 | } |
||
| 1110 | |||
| 1111 | // We're still inside a tag and had no chance for closure? |
||
| 1112 | if ($insideTag !== null) |
||
| 1113 | $matches[] = '[/' . $insideTag . ']'; |
||
| 1114 | |||
| 1115 | // And a complete text string again. |
||
| 1116 | $text = implode('', $matches); |
||
| 1117 | } |
||
| 1118 | |||
| 1119 | // Quickly remove any tags which are back to back. |
||
| 1120 | $backToBackPattern = '~\\[(' . implode('|', array_diff(array_keys($valid_tags), array('td', 'anchor'))) . ')[^<>\\[\\]]*\\]\s*\\[/\\1\\]~'; |
||
| 1121 | $lastlen = 0; |
||
| 1122 | View Code Duplication | while (strlen($text) !== $lastlen) |
|
| 1123 | $lastlen = strlen($text = preg_replace($backToBackPattern, '', $text)); |
||
| 1124 | |||
| 1125 | // Need to sort the tags my name length. |
||
| 1126 | uksort($valid_tags, 'sort_array_length'); |
||
| 1127 | |||
| 1128 | // These inline tags can compete with each other regarding style. |
||
| 1129 | $competing_tags = array( |
||
| 1130 | 'color', |
||
| 1131 | 'size', |
||
| 1132 | ); |
||
| 1133 | |||
| 1134 | // These keep track of where we are! |
||
| 1135 | if (count($parts = preg_split(sprintf('~(\\[)(/?)(%1$s)((?:[\\s=][^\\]\\[]*)?\\])~', implode('|', array_keys($valid_tags))), $text, -1, PREG_SPLIT_DELIM_CAPTURE)) > 1) |
||
| 1136 | { |
||
| 1137 | // Start outside [nobbc] or [code] blocks. |
||
| 1138 | $inCode = false; |
||
| 1139 | $inNoBbc = false; |
||
| 1140 | |||
| 1141 | // A buffer containing all opened inline elements. |
||
| 1142 | $inlineElements = array(); |
||
| 1143 | |||
| 1144 | // A buffer containing all opened block elements. |
||
| 1145 | $blockElements = array(); |
||
| 1146 | |||
| 1147 | // A buffer containing the opened inline elements that might compete. |
||
| 1148 | $competingElements = array(); |
||
| 1149 | |||
| 1150 | // $i: text, $i + 1: '[', $i + 2: '/', $i + 3: tag, $i + 4: tag tail. |
||
| 1151 | for ($i = 0, $n = count($parts) - 1; $i < $n; $i += 5) |
||
| 1152 | { |
||
| 1153 | $tag = $parts[$i + 3]; |
||
| 1154 | $isOpeningTag = $parts[$i + 2] === ''; |
||
| 1155 | $isClosingTag = $parts[$i + 2] === '/'; |
||
| 1156 | $isBlockLevelTag = isset($valid_tags[$tag]) && $valid_tags[$tag] && !in_array($tag, $self_closing_tags); |
||
| 1157 | $isCompetingTag = in_array($tag, $competing_tags); |
||
| 1158 | |||
| 1159 | // Check if this might be one of those cleaned out tags. |
||
| 1160 | if ($tag === '') |
||
| 1161 | continue; |
||
| 1162 | |||
| 1163 | // Special case: inside [code] blocks any code is left untouched. |
||
| 1164 | View Code Duplication | elseif ($tag === 'code') |
|
| 1165 | { |
||
| 1166 | // We're inside a code block and closing it. |
||
| 1167 | if ($inCode && $isClosingTag) |
||
| 1168 | { |
||
| 1169 | $inCode = false; |
||
| 1170 | |||
| 1171 | // Reopen tags that were closed before the code block. |
||
| 1172 | if (!empty($inlineElements)) |
||
| 1173 | $parts[$i + 4] .= '[' . implode('][', array_keys($inlineElements)) . ']'; |
||
| 1174 | } |
||
| 1175 | |||
| 1176 | // We're outside a coding and nobbc block and opening it. |
||
| 1177 | elseif (!$inCode && !$inNoBbc && $isOpeningTag) |
||
| 1178 | { |
||
| 1179 | // If there are still inline elements left open, close them now. |
||
| 1180 | if (!empty($inlineElements)) |
||
| 1181 | { |
||
| 1182 | $parts[$i] .= '[/' . implode('][/', array_reverse($inlineElements)) . ']'; |
||
| 1183 | //$inlineElements = array(); |
||
| 1184 | } |
||
| 1185 | |||
| 1186 | $inCode = true; |
||
| 1187 | } |
||
| 1188 | |||
| 1189 | // Nothing further to do. |
||
| 1190 | continue; |
||
| 1191 | } |
||
| 1192 | |||
| 1193 | // Special case: inside [nobbc] blocks any BBC is left untouched. |
||
| 1194 | View Code Duplication | elseif ($tag === 'nobbc') |
|
| 1195 | { |
||
| 1196 | // We're inside a nobbc block and closing it. |
||
| 1197 | if ($inNoBbc && $isClosingTag) |
||
| 1198 | { |
||
| 1199 | $inNoBbc = false; |
||
| 1200 | |||
| 1201 | // Some inline elements might've been closed that need reopening. |
||
| 1202 | if (!empty($inlineElements)) |
||
| 1203 | $parts[$i + 4] .= '[' . implode('][', array_keys($inlineElements)) . ']'; |
||
| 1204 | } |
||
| 1205 | |||
| 1206 | // We're outside a nobbc and coding block and opening it. |
||
| 1207 | elseif (!$inNoBbc && !$inCode && $isOpeningTag) |
||
| 1208 | { |
||
| 1209 | // Can't have inline elements still opened. |
||
| 1210 | if (!empty($inlineElements)) |
||
| 1211 | { |
||
| 1212 | $parts[$i] .= '[/' . implode('][/', array_reverse($inlineElements)) . ']'; |
||
| 1213 | //$inlineElements = array(); |
||
| 1214 | } |
||
| 1215 | |||
| 1216 | $inNoBbc = true; |
||
| 1217 | } |
||
| 1218 | |||
| 1219 | continue; |
||
| 1220 | } |
||
| 1221 | |||
| 1222 | // So, we're inside one of the special blocks: ignore any tag. |
||
| 1223 | elseif ($inCode || $inNoBbc) |
||
| 1224 | continue; |
||
| 1225 | |||
| 1226 | // We're dealing with an opening tag. |
||
| 1227 | if ($isOpeningTag) |
||
| 1228 | { |
||
| 1229 | // Everyting inside the square brackets of the opening tag. |
||
| 1230 | $elementContent = $parts[$i + 3] . substr($parts[$i + 4], 0, -1); |
||
| 1231 | |||
| 1232 | // A block level opening tag. |
||
| 1233 | if ($isBlockLevelTag) |
||
| 1234 | { |
||
| 1235 | // Are there inline elements still open? |
||
| 1236 | View Code Duplication | if (!empty($inlineElements)) |
|
| 1237 | { |
||
| 1238 | // Close all the inline tags, a block tag is coming... |
||
| 1239 | $parts[$i] .= '[/' . implode('][/', array_reverse($inlineElements)) . ']'; |
||
| 1240 | |||
| 1241 | // Now open them again, we're inside the block tag now. |
||
| 1242 | $parts[$i + 5] = '[' . implode('][', array_keys($inlineElements)) . ']' . $parts[$i + 5]; |
||
| 1243 | } |
||
| 1244 | |||
| 1245 | $blockElements[] = $tag; |
||
| 1246 | } |
||
| 1247 | |||
| 1248 | // Inline opening tag. |
||
| 1249 | elseif (!in_array($tag, $self_closing_tags)) |
||
| 1250 | { |
||
| 1251 | // Can't have two opening elements with the same contents! |
||
| 1252 | if (isset($inlineElements[$elementContent])) |
||
| 1253 | { |
||
| 1254 | // Get rid of this tag. |
||
| 1255 | $parts[$i + 1] = $parts[$i + 2] = $parts[$i + 3] = $parts[$i + 4] = ''; |
||
| 1256 | |||
| 1257 | // Now try to find the corresponding closing tag. |
||
| 1258 | $curLevel = 1; |
||
| 1259 | for ($j = $i + 5, $m = count($parts) - 1; $j < $m; $j += 5) |
||
| 1260 | { |
||
| 1261 | // Find the tags with the same tagname |
||
| 1262 | if ($parts[$j + 3] === $tag) |
||
| 1263 | { |
||
| 1264 | // If it's an opening tag, increase the level. |
||
| 1265 | if ($parts[$j + 2] === '') |
||
| 1266 | $curLevel++; |
||
| 1267 | |||
| 1268 | // A closing tag, decrease the level. |
||
| 1269 | else |
||
| 1270 | { |
||
| 1271 | $curLevel--; |
||
| 1272 | |||
| 1273 | // Gotcha! Clean out this closing tag gone rogue. |
||
| 1274 | if ($curLevel === 0) |
||
| 1275 | { |
||
| 1276 | $parts[$j + 1] = $parts[$j + 2] = $parts[$j + 3] = $parts[$j + 4] = ''; |
||
| 1277 | break; |
||
| 1278 | } |
||
| 1279 | } |
||
| 1280 | } |
||
| 1281 | } |
||
| 1282 | } |
||
| 1283 | |||
| 1284 | // Otherwise, add this one to the list. |
||
| 1285 | else |
||
| 1286 | { |
||
| 1287 | if ($isCompetingTag) |
||
| 1288 | { |
||
| 1289 | if (!isset($competingElements[$tag])) |
||
| 1290 | $competingElements[$tag] = array(); |
||
| 1291 | |||
| 1292 | $competingElements[$tag][] = $parts[$i + 4]; |
||
| 1293 | |||
| 1294 | if (count($competingElements[$tag]) > 1) |
||
| 1295 | $parts[$i] .= '[/' . $tag . ']'; |
||
| 1296 | } |
||
| 1297 | |||
| 1298 | $inlineElements[$elementContent] = $tag; |
||
| 1299 | } |
||
| 1300 | } |
||
| 1301 | |||
| 1302 | } |
||
| 1303 | |||
| 1304 | // Closing tag. |
||
| 1305 | else |
||
| 1306 | { |
||
| 1307 | // Closing the block tag. |
||
| 1308 | if ($isBlockLevelTag) |
||
| 1309 | { |
||
| 1310 | // Close the elements that should've been closed by closing this tag. |
||
| 1311 | if (!empty($blockElements)) |
||
| 1312 | { |
||
| 1313 | $addClosingTags = array(); |
||
| 1314 | while ($element = array_pop($blockElements)) |
||
| 1315 | { |
||
| 1316 | if ($element === $tag) |
||
| 1317 | break; |
||
| 1318 | |||
| 1319 | // Still a block tag was open not equal to this tag. |
||
| 1320 | $addClosingTags[] = $element['type']; |
||
| 1321 | } |
||
| 1322 | |||
| 1323 | if (!empty($addClosingTags)) |
||
| 1324 | $parts[$i + 1] = '[/' . implode('][/', array_reverse($addClosingTags)) . ']' . $parts[$i + 1]; |
||
| 1325 | |||
| 1326 | // Apparently the closing tag was not found on the stack. |
||
| 1327 | if (!is_string($element) || $element !== $tag) |
||
| 1328 | { |
||
| 1329 | // Get rid of this particular closing tag, it was never opened. |
||
| 1330 | $parts[$i + 1] = substr($parts[$i + 1], 0, -1); |
||
| 1331 | $parts[$i + 2] = $parts[$i + 3] = $parts[$i + 4] = ''; |
||
| 1332 | continue; |
||
| 1333 | } |
||
| 1334 | } |
||
| 1335 | View Code Duplication | else |
|
| 1336 | { |
||
| 1337 | // Get rid of this closing tag! |
||
| 1338 | $parts[$i + 1] = $parts[$i + 2] = $parts[$i + 3] = $parts[$i + 4] = ''; |
||
| 1339 | continue; |
||
| 1340 | } |
||
| 1341 | |||
| 1342 | // Inline elements are still left opened? |
||
| 1343 | View Code Duplication | if (!empty($inlineElements)) |
|
| 1344 | { |
||
| 1345 | // Close them first.. |
||
| 1346 | $parts[$i] .= '[/' . implode('][/', array_reverse($inlineElements)) . ']'; |
||
| 1347 | |||
| 1348 | // Then reopen them. |
||
| 1349 | $parts[$i + 5] = '[' . implode('][', array_keys($inlineElements)) . ']' . $parts[$i + 5]; |
||
| 1350 | } |
||
| 1351 | } |
||
| 1352 | // Inline tag. |
||
| 1353 | else |
||
| 1354 | { |
||
| 1355 | // Are we expecting this tag to end? |
||
| 1356 | if (in_array($tag, $inlineElements)) |
||
| 1357 | { |
||
| 1358 | foreach (array_reverse($inlineElements, true) as $tagContentToBeClosed => $tagToBeClosed) |
||
| 1359 | { |
||
| 1360 | // Closing it one way or the other. |
||
| 1361 | unset($inlineElements[$tagContentToBeClosed]); |
||
| 1362 | |||
| 1363 | // Was this the tag we were looking for? |
||
| 1364 | if ($tagToBeClosed === $tag) |
||
| 1365 | break; |
||
| 1366 | |||
| 1367 | // Nope, close it and look further! |
||
| 1368 | else |
||
| 1369 | $parts[$i] .= '[/' . $tagToBeClosed . ']'; |
||
| 1370 | } |
||
| 1371 | |||
| 1372 | if ($isCompetingTag && !empty($competingElements[$tag])) |
||
| 1373 | { |
||
| 1374 | array_pop($competingElements[$tag]); |
||
| 1375 | |||
| 1376 | if (count($competingElements[$tag]) > 0) |
||
| 1377 | $parts[$i + 5] = '[' . $tag . $competingElements[$tag][count($competingElements[$tag]) - 1] . $parts[$i + 5]; |
||
| 1378 | } |
||
| 1379 | } |
||
| 1380 | |||
| 1381 | // Unexpected closing tag, ex-ter-mi-nate. |
||
| 1382 | View Code Duplication | else |
|
| 1383 | $parts[$i + 1] = $parts[$i + 2] = $parts[$i + 3] = $parts[$i + 4] = ''; |
||
| 1384 | } |
||
| 1385 | } |
||
| 1386 | } |
||
| 1387 | |||
| 1388 | // Close the code tags. |
||
| 1389 | if ($inCode) |
||
| 1390 | $parts[$i] .= '[/code]'; |
||
| 1391 | |||
| 1392 | // The same for nobbc tags. |
||
| 1393 | elseif ($inNoBbc) |
||
| 1394 | $parts[$i] .= '[/nobbc]'; |
||
| 1395 | |||
| 1396 | // Still inline tags left unclosed? Close them now, better late than never. |
||
| 1397 | elseif (!empty($inlineElements)) |
||
| 1398 | $parts[$i] .= '[/' . implode('][/', array_reverse($inlineElements)) . ']'; |
||
| 1399 | |||
| 1400 | // Now close the block elements. |
||
| 1401 | if (!empty($blockElements)) |
||
| 1402 | $parts[$i] .= '[/' . implode('][/', array_reverse($blockElements)) . ']'; |
||
| 1403 | |||
| 1404 | $text = implode('', $parts); |
||
| 1405 | } |
||
| 1406 | |||
| 1407 | // Final clean up of back to back tags. |
||
| 1408 | $lastlen = 0; |
||
| 1409 | View Code Duplication | while (strlen($text) !== $lastlen) |
|
| 1410 | $lastlen = strlen($text = preg_replace($backToBackPattern, '', $text)); |
||
| 1411 | |||
| 1412 | return $text; |
||
| 1413 | } |
||
| 1414 | |||
| 1415 | /** |
||
| 1416 | * !!!Compatibility!!! |
||
| 1417 | * A help function for legalise_bbc for sorting arrays based on length. |
||
| 1418 | * @param string $a A string |
||
| 1419 | * @param string $b Another string |
||
| 1420 | * @return int 1 if $a is shorter than $b, -1 otherwise |
||
| 1421 | */ |
||
| 1422 | function sort_array_length($a, $b) |
||
| 1423 | { |
||
| 1424 | return strlen($a) < strlen($b) ? 1 : -1; |
||
| 1425 | } |
||
| 1426 | |||
| 1427 | /** |
||
| 1428 | * Creates the javascript code for localization of the editor (SCEditor) |
||
| 1429 | */ |
||
| 1430 | function loadLocale() |
||
| 1431 | { |
||
| 1432 | global $context, $txt, $editortxt, $modSettings; |
||
| 1433 | |||
| 1434 | loadLanguage('Editor'); |
||
| 1435 | |||
| 1436 | $context['template_layers'] = array(); |
||
| 1437 | // Lets make sure we aren't going to output anything nasty. |
||
| 1438 | @ob_end_clean(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 1439 | if (!empty($modSettings['enableCompressedOutput'])) |
||
| 1440 | @ob_start('ob_gzhandler'); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 1441 | else |
||
| 1442 | @ob_start(); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 1443 | |||
| 1444 | // If we don't have any locale better avoid broken js |
||
| 1445 | if (empty($txt['lang_locale'])) |
||
| 1446 | die(); |
||
| 1447 | |||
| 1448 | $file_data = '(function ($) { |
||
| 1449 | \'use strict\'; |
||
| 1450 | |||
| 1451 | $.sceditor.locale[' . javaScriptEscape($txt['lang_locale']) . '] = {'; |
||
| 1452 | foreach ($editortxt as $key => $val) |
||
| 1453 | $file_data .= ' |
||
| 1454 | ' . javaScriptEscape($key) . ': ' . javaScriptEscape($val) . ','; |
||
| 1455 | |||
| 1456 | $file_data .= ' |
||
| 1457 | dateFormat: "day.month.year" |
||
| 1458 | } |
||
| 1459 | })(jQuery);'; |
||
| 1460 | |||
| 1461 | // Make sure they know what type of file we are. |
||
| 1462 | header('Content-Type: text/javascript'); |
||
| 1463 | echo $file_data; |
||
| 1464 | obExit(false); |
||
| 1465 | } |
||
| 1466 | |||
| 1467 | /** |
||
| 1468 | * Retrieves a list of message icons. |
||
| 1469 | * - Based on the settings, the array will either contain a list of default |
||
| 1470 | * message icons or a list of custom message icons retrieved from the database. |
||
| 1471 | * - The board_id is needed for the custom message icons (which can be set for |
||
| 1472 | * each board individually). |
||
| 1473 | * |
||
| 1474 | * @param int $board_id The ID of the board |
||
| 1475 | * @return array An array of info about available icons |
||
| 1476 | */ |
||
| 1477 | function getMessageIcons($board_id) |
||
| 1478 | { |
||
| 1479 | global $modSettings, $txt, $settings, $smcFunc; |
||
| 1480 | |||
| 1481 | if (empty($modSettings['messageIcons_enable'])) |
||
| 1482 | { |
||
| 1483 | loadLanguage('Post'); |
||
| 1484 | |||
| 1485 | $icons = array( |
||
| 1486 | array('value' => 'xx', 'name' => $txt['standard']), |
||
| 1487 | array('value' => 'thumbup', 'name' => $txt['thumbs_up']), |
||
| 1488 | array('value' => 'thumbdown', 'name' => $txt['thumbs_down']), |
||
| 1489 | array('value' => 'exclamation', 'name' => $txt['exclamation_point']), |
||
| 1490 | array('value' => 'question', 'name' => $txt['question_mark']), |
||
| 1491 | array('value' => 'lamp', 'name' => $txt['lamp']), |
||
| 1492 | array('value' => 'smiley', 'name' => $txt['icon_smiley']), |
||
| 1493 | array('value' => 'angry', 'name' => $txt['icon_angry']), |
||
| 1494 | array('value' => 'cheesy', 'name' => $txt['icon_cheesy']), |
||
| 1495 | array('value' => 'grin', 'name' => $txt['icon_grin']), |
||
| 1496 | array('value' => 'sad', 'name' => $txt['icon_sad']), |
||
| 1497 | array('value' => 'wink', 'name' => $txt['icon_wink']), |
||
| 1498 | array('value' => 'poll', 'name' => $txt['icon_poll']), |
||
| 1499 | ); |
||
| 1500 | |||
| 1501 | foreach ($icons as $k => $dummy) |
||
| 1502 | { |
||
| 1503 | $icons[$k]['url'] = $settings['images_url'] . '/post/' . $dummy['value'] . '.png'; |
||
| 1504 | $icons[$k]['is_last'] = false; |
||
| 1505 | } |
||
| 1506 | } |
||
| 1507 | // Otherwise load the icons, and check we give the right image too... |
||
| 1508 | else |
||
| 1509 | { |
||
| 1510 | if (($temp = cache_get_data('posting_icons-' . $board_id, 480)) == null) |
||
| 1511 | { |
||
| 1512 | $request = $smcFunc['db_query']('', ' |
||
| 1513 | SELECT title, filename |
||
| 1514 | FROM {db_prefix}message_icons |
||
| 1515 | WHERE id_board IN (0, {int:board_id}) |
||
| 1516 | ORDER BY icon_order', |
||
| 1517 | array( |
||
| 1518 | 'board_id' => $board_id, |
||
| 1519 | ) |
||
| 1520 | ); |
||
| 1521 | $icon_data = array(); |
||
| 1522 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1523 | $icon_data[] = $row; |
||
| 1524 | $smcFunc['db_free_result']($request); |
||
| 1525 | |||
| 1526 | $icons = array(); |
||
| 1527 | foreach ($icon_data as $icon) |
||
| 1528 | { |
||
| 1529 | $icons[$icon['filename']] = array( |
||
| 1530 | 'value' => $icon['filename'], |
||
| 1531 | 'name' => $icon['title'], |
||
| 1532 | 'url' => $settings[file_exists($settings['theme_dir'] . '/images/post/' . $icon['filename'] . '.png') ? 'images_url' : 'default_images_url'] . '/post/' . $icon['filename'] . '.png', |
||
| 1533 | 'is_last' => false, |
||
| 1534 | ); |
||
| 1535 | } |
||
| 1536 | |||
| 1537 | cache_put_data('posting_icons-' . $board_id, $icons, 480); |
||
| 1538 | } |
||
| 1539 | else |
||
| 1540 | $icons = $temp; |
||
| 1541 | } |
||
| 1542 | call_integration_hook('integrate_load_message_icons', array(&$icons)); |
||
| 1543 | |||
| 1544 | return array_values($icons); |
||
| 1545 | } |
||
| 1546 | |||
| 1547 | /** |
||
| 1548 | * Compatibility function - used in 1.1 for showing a post box. |
||
| 1549 | * |
||
| 1550 | * @param string $msg The message |
||
| 1551 | * @return string The HTML for an editor |
||
| 1552 | */ |
||
| 1553 | function theme_postbox($msg) |
||
| 1554 | { |
||
| 1555 | global $context; |
||
| 1556 | |||
| 1557 | return template_control_richedit($context['post_box_name']); |
||
| 1558 | } |
||
| 1559 | |||
| 1560 | /** |
||
| 1561 | * Creates a box that can be used for richedit stuff like BBC, Smileys etc. |
||
| 1562 | * @param array $editorOptions Various options for the editor |
||
| 1563 | */ |
||
| 1564 | function create_control_richedit($editorOptions) |
||
| 1565 | { |
||
| 1566 | global $txt, $modSettings, $options, $smcFunc, $editortxt; |
||
| 1567 | global $context, $settings, $user_info, $scripturl; |
||
| 1568 | |||
| 1569 | // Load the Post language file... for the moment at least. |
||
| 1570 | loadLanguage('Post'); |
||
| 1571 | |||
| 1572 | // Every control must have a ID! |
||
| 1573 | assert(isset($editorOptions['id'])); |
||
| 1574 | assert(isset($editorOptions['value'])); |
||
| 1575 | |||
| 1576 | // Is this the first richedit - if so we need to ensure some template stuff is initialised. |
||
| 1577 | if (empty($context['controls']['richedit'])) |
||
| 1578 | { |
||
| 1579 | // Some general stuff. |
||
| 1580 | $settings['smileys_url'] = $modSettings['smileys_url'] . '/' . $user_info['smiley_set']; |
||
| 1581 | if (!empty($context['drafts_autosave'])) |
||
| 1582 | $context['drafts_autosave_frequency'] = empty($modSettings['drafts_autosave_frequency']) ? 60000 : $modSettings['drafts_autosave_frequency'] * 1000; |
||
| 1583 | |||
| 1584 | // This really has some WYSIWYG stuff. |
||
| 1585 | loadCSSFile('jquery.sceditor.css', array('force_current' => false, 'validate' => true), 'smf_jquery_sceditor'); |
||
| 1586 | loadTemplate('GenericControls'); |
||
| 1587 | |||
| 1588 | // JS makes the editor go round |
||
| 1589 | loadJavaScriptFile('editor.js', array(), 'smf_editor'); |
||
| 1590 | loadJavaScriptFile('jquery.sceditor.bbcode.min.js', array(), 'smf_sceditor_bbcode'); |
||
| 1591 | loadJavaScriptFile('jquery.sceditor.smf.js', array(), 'smf_sceditor_smf'); |
||
| 1592 | addInlineJavaScript(' |
||
| 1593 | var smf_smileys_url = \'' . $settings['smileys_url'] . '\'; |
||
| 1594 | var bbc_quote_from = \'' . addcslashes($txt['quote_from'], "'") . '\'; |
||
| 1595 | var bbc_quote = \'' . addcslashes($txt['quote'], "'") . '\'; |
||
| 1596 | var bbc_search_on = \'' . addcslashes($txt['search_on'], "'") . '\';'); |
||
| 1597 | // editor language file |
||
| 1598 | if (!empty($txt['lang_locale']) && $txt['lang_locale'] != 'en_US') |
||
| 1599 | loadJavaScriptFile($scripturl . '?action=loadeditorlocale', array('external' => true), 'sceditor_language'); |
||
| 1600 | |||
| 1601 | $context['shortcuts_text'] = $txt['shortcuts' . (!empty($context['drafts_save']) ? '_drafts' : '') . (stripos($_SERVER['HTTP_USER_AGENT'], 'Macintosh') !== false ? '_mac' : (isBrowser('is_firefox') ? '_firefox' : ''))]; |
||
| 1602 | $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && (function_exists('pspell_new') || (function_exists('enchant_broker_init') && ($txt['lang_charset'] == 'UTF-8' || function_exists('iconv')))); |
||
| 1603 | if ($context['show_spellchecking']) |
||
| 1604 | { |
||
| 1605 | loadJavaScriptFile('spellcheck.js', array(), 'smf_spellcheck'); |
||
| 1606 | |||
| 1607 | // Some hidden information is needed in order to make the spell checking work. |
||
| 1608 | if (!isset($_REQUEST['xml'])) |
||
| 1609 | $context['insert_after_template'] .= ' |
||
| 1610 | <form name="spell_form" id="spell_form" method="post" accept-charset="' . $context['character_set'] . '" target="spellWindow" action="' . $scripturl . '?action=spellcheck"> |
||
| 1611 | <input type="hidden" name="spellstring" value=""> |
||
| 1612 | </form>'; |
||
| 1613 | } |
||
| 1614 | } |
||
| 1615 | |||
| 1616 | // Start off the editor... |
||
| 1617 | $context['controls']['richedit'][$editorOptions['id']] = array( |
||
| 1618 | 'id' => $editorOptions['id'], |
||
| 1619 | 'value' => $editorOptions['value'], |
||
| 1620 | 'rich_value' => $editorOptions['value'], // 2.0 editor compatibility |
||
| 1621 | 'rich_active' => empty($modSettings['disable_wysiwyg']) && (!empty($options['wysiwyg_default']) || !empty($editorOptions['force_rich']) || !empty($_REQUEST[$editorOptions['id'] . '_mode'])), |
||
| 1622 | 'disable_smiley_box' => !empty($editorOptions['disable_smiley_box']), |
||
| 1623 | 'columns' => isset($editorOptions['columns']) ? $editorOptions['columns'] : 60, |
||
| 1624 | 'rows' => isset($editorOptions['rows']) ? $editorOptions['rows'] : 18, |
||
| 1625 | 'width' => isset($editorOptions['width']) ? $editorOptions['width'] : '70%', |
||
| 1626 | 'height' => isset($editorOptions['height']) ? $editorOptions['height'] : '250px', |
||
| 1627 | 'form' => isset($editorOptions['form']) ? $editorOptions['form'] : 'postmodify', |
||
| 1628 | 'bbc_level' => !empty($editorOptions['bbc_level']) ? $editorOptions['bbc_level'] : 'full', |
||
| 1629 | 'preview_type' => isset($editorOptions['preview_type']) ? (int) $editorOptions['preview_type'] : 1, |
||
| 1630 | 'labels' => !empty($editorOptions['labels']) ? $editorOptions['labels'] : array(), |
||
| 1631 | 'locale' => !empty($txt['lang_locale']) && substr($txt['lang_locale'], 0, 5) != 'en_US' ? $txt['lang_locale'] : '', |
||
| 1632 | 'required' => !empty($editorOptions['required']), |
||
| 1633 | ); |
||
| 1634 | |||
| 1635 | if (empty($context['bbc_tags'])) |
||
| 1636 | { |
||
| 1637 | // The below array makes it dead easy to add images to this control. Add it to the array and everything else is done for you! |
||
| 1638 | /* |
||
| 1639 | array( |
||
| 1640 | 'image' => 'bold', |
||
| 1641 | 'code' => 'b', |
||
| 1642 | 'before' => '[b]', |
||
| 1643 | 'after' => '[/b]', |
||
| 1644 | 'description' => $txt['bold'], |
||
| 1645 | ), |
||
| 1646 | */ |
||
| 1647 | $context['bbc_tags'] = array(); |
||
| 1648 | $context['bbc_tags'][] = array( |
||
| 1649 | array( |
||
| 1650 | 'code' => 'bold', |
||
| 1651 | 'description' => $editortxt['bold'], |
||
| 1652 | ), |
||
| 1653 | array( |
||
| 1654 | 'code' => 'italic', |
||
| 1655 | 'description' => $editortxt['italic'], |
||
| 1656 | ), |
||
| 1657 | array( |
||
| 1658 | 'code' => 'underline', |
||
| 1659 | 'description' => $editortxt['underline'] |
||
| 1660 | ), |
||
| 1661 | array( |
||
| 1662 | 'code' => 'strike', |
||
| 1663 | 'description' => $editortxt['strike'] |
||
| 1664 | ), |
||
| 1665 | array(), |
||
| 1666 | array( |
||
| 1667 | 'code' => 'pre', |
||
| 1668 | 'description' => $editortxt['preformatted'] |
||
| 1669 | ), |
||
| 1670 | array( |
||
| 1671 | 'code' => 'left', |
||
| 1672 | 'description' => $editortxt['left_align'] |
||
| 1673 | ), |
||
| 1674 | array( |
||
| 1675 | 'code' => 'center', |
||
| 1676 | 'description' => $editortxt['center'] |
||
| 1677 | ), |
||
| 1678 | array( |
||
| 1679 | 'code' => 'right', |
||
| 1680 | 'description' => $editortxt['right_align'] |
||
| 1681 | ), |
||
| 1682 | ); |
||
| 1683 | $context['bbc_tags'][] = array( |
||
| 1684 | array( |
||
| 1685 | 'code' => 'floatleft', |
||
| 1686 | 'description' => $editortxt['float_left'] |
||
| 1687 | ), |
||
| 1688 | array( |
||
| 1689 | 'code' => 'floatright', |
||
| 1690 | 'description' => $editortxt['float_right'] |
||
| 1691 | ), |
||
| 1692 | array(), |
||
| 1693 | array( |
||
| 1694 | 'code' => 'flash', |
||
| 1695 | 'description' => $editortxt['flash'] |
||
| 1696 | ), |
||
| 1697 | array( |
||
| 1698 | 'code' => 'image', |
||
| 1699 | 'description' => $editortxt['image'] |
||
| 1700 | ), |
||
| 1701 | array( |
||
| 1702 | 'code' => 'link', |
||
| 1703 | 'description' => $editortxt['hyperlink'] |
||
| 1704 | ), |
||
| 1705 | array( |
||
| 1706 | 'code' => 'email', |
||
| 1707 | 'description' => $editortxt['insert_email'] |
||
| 1708 | ), |
||
| 1709 | array(), |
||
| 1710 | array( |
||
| 1711 | 'code' => 'superscript', |
||
| 1712 | 'description' => $editortxt['superscript'] |
||
| 1713 | ), |
||
| 1714 | array( |
||
| 1715 | 'code' => 'subscript', |
||
| 1716 | 'description' => $editortxt['subscript'] |
||
| 1717 | ), |
||
| 1718 | array(), |
||
| 1719 | array( |
||
| 1720 | 'code' => 'table', |
||
| 1721 | 'description' => $editortxt['table'] |
||
| 1722 | ), |
||
| 1723 | array( |
||
| 1724 | 'code' => 'code', |
||
| 1725 | 'description' => $editortxt['bbc_code'] |
||
| 1726 | ), |
||
| 1727 | array( |
||
| 1728 | 'code' => 'quote', |
||
| 1729 | 'description' => $editortxt['bbc_quote'] |
||
| 1730 | ), |
||
| 1731 | array(), |
||
| 1732 | array( |
||
| 1733 | 'code' => 'bulletlist', |
||
| 1734 | 'description' => $editortxt['list_unordered'] |
||
| 1735 | ), |
||
| 1736 | array( |
||
| 1737 | 'code' => 'orderedlist', |
||
| 1738 | 'description' => $editortxt['list_ordered'] |
||
| 1739 | ), |
||
| 1740 | array( |
||
| 1741 | 'code' => 'horizontalrule', |
||
| 1742 | 'description' => $editortxt['horizontal_rule'] |
||
| 1743 | ), |
||
| 1744 | ); |
||
| 1745 | |||
| 1746 | $editor_tag_map = array( |
||
| 1747 | 'b' => 'bold', |
||
| 1748 | 'i' => 'italic', |
||
| 1749 | 'u' => 'underline', |
||
| 1750 | 's' => 'strike', |
||
| 1751 | 'img' => 'image', |
||
| 1752 | 'url' => 'link', |
||
| 1753 | 'sup' => 'superscript', |
||
| 1754 | 'sub' => 'subscript', |
||
| 1755 | 'hr' => 'horizontalrule', |
||
| 1756 | ); |
||
| 1757 | |||
| 1758 | // Allow mods to modify BBC buttons. |
||
| 1759 | // Note: pass the array here is not necessary and is deprecated, but it is kept for backward compatibility with 2.0 |
||
| 1760 | call_integration_hook('integrate_bbc_buttons', array(&$context['bbc_tags'], &$editor_tag_map)); |
||
| 1761 | |||
| 1762 | // Show the toggle? |
||
| 1763 | if (empty($modSettings['disable_wysiwyg'])) |
||
| 1764 | { |
||
| 1765 | $context['bbc_tags'][count($context['bbc_tags']) - 1][] = array(); |
||
| 1766 | $context['bbc_tags'][count($context['bbc_tags']) - 1][] = array( |
||
| 1767 | 'code' => 'unformat', |
||
| 1768 | 'description' => $editortxt['unformat_text'], |
||
| 1769 | ); |
||
| 1770 | $context['bbc_tags'][count($context['bbc_tags']) - 1][] = array( |
||
| 1771 | 'code' => 'toggle', |
||
| 1772 | 'description' => $editortxt['toggle_view'], |
||
| 1773 | ); |
||
| 1774 | } |
||
| 1775 | |||
| 1776 | // Generate a list of buttons that shouldn't be shown - this should be the fastest way to do this. |
||
| 1777 | $disabled_tags = array(); |
||
| 1778 | if (!empty($modSettings['disabledBBC'])) |
||
| 1779 | $disabled_tags = explode(',', $modSettings['disabledBBC']); |
||
| 1780 | if (empty($modSettings['enableEmbeddedFlash'])) |
||
| 1781 | $disabled_tags[] = 'flash'; |
||
| 1782 | |||
| 1783 | foreach ($disabled_tags as $tag) |
||
| 1784 | { |
||
| 1785 | if ($tag === 'list') |
||
| 1786 | { |
||
| 1787 | $context['disabled_tags']['bulletlist'] = true; |
||
| 1788 | $context['disabled_tags']['orderedlist'] = true; |
||
| 1789 | } |
||
| 1790 | |||
| 1791 | foreach ($editor_tag_map as $thisTag => $tagNameBBC) |
||
| 1792 | if ($tag === $thisTag) |
||
| 1793 | $context['disabled_tags'][$tagNameBBC] = true; |
||
| 1794 | |||
| 1795 | $context['disabled_tags'][trim($tag)] = true; |
||
| 1796 | } |
||
| 1797 | |||
| 1798 | $bbcodes_styles = ''; |
||
| 1799 | $context['bbcodes_handlers'] = ''; |
||
| 1800 | $context['bbc_toolbar'] = array(); |
||
| 1801 | foreach ($context['bbc_tags'] as $row => $tagRow) |
||
| 1802 | { |
||
| 1803 | if (!isset($context['bbc_toolbar'][$row])) |
||
| 1804 | $context['bbc_toolbar'][$row] = array(); |
||
| 1805 | $tagsRow = array(); |
||
| 1806 | foreach ($tagRow as $tag) |
||
| 1807 | { |
||
| 1808 | if ((!empty($tag['code'])) && empty($context['disabled_tags'][$tag['code']])) |
||
| 1809 | { |
||
| 1810 | $tagsRow[] = $tag['code']; |
||
| 1811 | if (isset($tag['image'])) |
||
| 1812 | $bbcodes_styles .= ' |
||
| 1813 | .sceditor-button-' . $tag['code'] . ' div { |
||
| 1814 | background: url(\'' . $settings['default_theme_url'] . '/images/bbc/' . $tag['image'] . '.png\'); |
||
| 1815 | }'; |
||
| 1816 | if (isset($tag['before'])) |
||
| 1817 | { |
||
| 1818 | $context['bbcodes_handlers'] .= ' |
||
| 1819 | $.sceditor.command.set( |
||
| 1820 | ' . javaScriptEscape($tag['code']) . ', { |
||
| 1821 | exec: function () { |
||
| 1822 | this.wysiwygEditorInsertHtml(' . javaScriptEscape($tag['before']) . (isset($tag['after']) ? ', ' . javaScriptEscape($tag['after']) : '') . '); |
||
| 1823 | }, |
||
| 1824 | txtExec: [' . javaScriptEscape($tag['before']) . (isset($tag['after']) ? ', ' . javaScriptEscape($tag['after']) : '') . '], |
||
| 1825 | tooltip: ' . javaScriptEscape($tag['description']) . ' |
||
| 1826 | });'; |
||
| 1827 | } |
||
| 1828 | |||
| 1829 | } |
||
| 1830 | else |
||
| 1831 | { |
||
| 1832 | $context['bbc_toolbar'][$row][] = implode(',', $tagsRow); |
||
| 1833 | $tagsRow = array(); |
||
| 1834 | } |
||
| 1835 | } |
||
| 1836 | |||
| 1837 | if ($row == 0) |
||
| 1838 | { |
||
| 1839 | $context['bbc_toolbar'][$row][] = implode(',', $tagsRow); |
||
| 1840 | $tagsRow = array(); |
||
| 1841 | if (!isset($context['disabled_tags']['font'])) |
||
| 1842 | $tagsRow[] = 'font'; |
||
| 1843 | if (!isset($context['disabled_tags']['size'])) |
||
| 1844 | $tagsRow[] = 'size'; |
||
| 1845 | if (!isset($context['disabled_tags']['color'])) |
||
| 1846 | $tagsRow[] = 'color'; |
||
| 1847 | } |
||
| 1848 | elseif ($row == 1 && empty($modSettings['disable_wysiwyg'])) |
||
| 1849 | { |
||
| 1850 | $tmp = array(); |
||
| 1851 | $tagsRow[] = 'removeformat'; |
||
| 1852 | $tagsRow[] = 'source'; |
||
| 1853 | if (!empty($tmp)) |
||
| 1854 | { |
||
| 1855 | $tagsRow[] = '|' . implode(',', $tmp); |
||
| 1856 | } |
||
| 1857 | } |
||
| 1858 | |||
| 1859 | if (!empty($tagsRow)) |
||
| 1860 | $context['bbc_toolbar'][$row][] = implode(',', $tagsRow); |
||
| 1861 | } |
||
| 1862 | if (!empty($bbcodes_styles)) |
||
| 1863 | $context['html_headers'] .= ' |
||
| 1864 | <style>' . $bbcodes_styles . ' |
||
| 1865 | </style>'; |
||
| 1866 | } |
||
| 1867 | |||
| 1868 | // Initialize smiley array... if not loaded before. |
||
| 1869 | if (empty($context['smileys']) && empty($editorOptions['disable_smiley_box'])) |
||
| 1870 | { |
||
| 1871 | $context['smileys'] = array( |
||
| 1872 | 'postform' => array(), |
||
| 1873 | 'popup' => array(), |
||
| 1874 | ); |
||
| 1875 | |||
| 1876 | // Load smileys - don't bother to run a query if we're not using the database's ones anyhow. |
||
| 1877 | if (empty($modSettings['smiley_enable']) && $user_info['smiley_set'] != 'none') |
||
| 1878 | $context['smileys']['postform'][] = array( |
||
| 1879 | 'smileys' => array( |
||
| 1880 | array( |
||
| 1881 | 'code' => ':)', |
||
| 1882 | 'filename' => 'smiley.gif', |
||
| 1883 | 'description' => $txt['icon_smiley'], |
||
| 1884 | ), |
||
| 1885 | array( |
||
| 1886 | 'code' => ';)', |
||
| 1887 | 'filename' => 'wink.gif', |
||
| 1888 | 'description' => $txt['icon_wink'], |
||
| 1889 | ), |
||
| 1890 | array( |
||
| 1891 | 'code' => ':D', |
||
| 1892 | 'filename' => 'cheesy.gif', |
||
| 1893 | 'description' => $txt['icon_cheesy'], |
||
| 1894 | ), |
||
| 1895 | array( |
||
| 1896 | 'code' => ';D', |
||
| 1897 | 'filename' => 'grin.gif', |
||
| 1898 | 'description' => $txt['icon_grin'] |
||
| 1899 | ), |
||
| 1900 | array( |
||
| 1901 | 'code' => '>:(', |
||
| 1902 | 'filename' => 'angry.gif', |
||
| 1903 | 'description' => $txt['icon_angry'], |
||
| 1904 | ), |
||
| 1905 | array( |
||
| 1906 | 'code' => ':(', |
||
| 1907 | 'filename' => 'sad.gif', |
||
| 1908 | 'description' => $txt['icon_sad'], |
||
| 1909 | ), |
||
| 1910 | array( |
||
| 1911 | 'code' => ':o', |
||
| 1912 | 'filename' => 'shocked.gif', |
||
| 1913 | 'description' => $txt['icon_shocked'], |
||
| 1914 | ), |
||
| 1915 | array( |
||
| 1916 | 'code' => '8)', |
||
| 1917 | 'filename' => 'cool.gif', |
||
| 1918 | 'description' => $txt['icon_cool'], |
||
| 1919 | ), |
||
| 1920 | array( |
||
| 1921 | 'code' => '???', |
||
| 1922 | 'filename' => 'huh.gif', |
||
| 1923 | 'description' => $txt['icon_huh'], |
||
| 1924 | ), |
||
| 1925 | array( |
||
| 1926 | 'code' => '::)', |
||
| 1927 | 'filename' => 'rolleyes.gif', |
||
| 1928 | 'description' => $txt['icon_rolleyes'], |
||
| 1929 | ), |
||
| 1930 | array( |
||
| 1931 | 'code' => ':P', |
||
| 1932 | 'filename' => 'tongue.gif', |
||
| 1933 | 'description' => $txt['icon_tongue'], |
||
| 1934 | ), |
||
| 1935 | array( |
||
| 1936 | 'code' => ':-[', |
||
| 1937 | 'filename' => 'embarrassed.gif', |
||
| 1938 | 'description' => $txt['icon_embarrassed'], |
||
| 1939 | ), |
||
| 1940 | array( |
||
| 1941 | 'code' => ':-X', |
||
| 1942 | 'filename' => 'lipsrsealed.gif', |
||
| 1943 | 'description' => $txt['icon_lips'], |
||
| 1944 | ), |
||
| 1945 | array( |
||
| 1946 | 'code' => ':-\\', |
||
| 1947 | 'filename' => 'undecided.gif', |
||
| 1948 | 'description' => $txt['icon_undecided'], |
||
| 1949 | ), |
||
| 1950 | array( |
||
| 1951 | 'code' => ':-*', |
||
| 1952 | 'filename' => 'kiss.gif', |
||
| 1953 | 'description' => $txt['icon_kiss'], |
||
| 1954 | ), |
||
| 1955 | array( |
||
| 1956 | 'code' => ':\'(', |
||
| 1957 | 'filename' => 'cry.gif', |
||
| 1958 | 'description' => $txt['icon_cry'], |
||
| 1959 | 'isLast' => true, |
||
| 1960 | ), |
||
| 1961 | ), |
||
| 1962 | 'isLast' => true, |
||
| 1963 | ); |
||
| 1964 | elseif ($user_info['smiley_set'] != 'none') |
||
| 1965 | { |
||
| 1966 | if (($temp = cache_get_data('posting_smileys', 480)) == null) |
||
| 1967 | { |
||
| 1968 | $request = $smcFunc['db_query']('', ' |
||
| 1969 | SELECT code, filename, description, smiley_row, hidden |
||
| 1970 | FROM {db_prefix}smileys |
||
| 1971 | WHERE hidden IN (0, 2) |
||
| 1972 | ORDER BY smiley_row, smiley_order', |
||
| 1973 | array( |
||
| 1974 | ) |
||
| 1975 | ); |
||
| 1976 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1977 | { |
||
| 1978 | $row['filename'] = $smcFunc['htmlspecialchars']($row['filename']); |
||
| 1979 | $row['description'] = $smcFunc['htmlspecialchars']($row['description']); |
||
| 1980 | |||
| 1981 | $context['smileys'][empty($row['hidden']) ? 'postform' : 'popup'][$row['smiley_row']]['smileys'][] = $row; |
||
| 1982 | } |
||
| 1983 | $smcFunc['db_free_result']($request); |
||
| 1984 | |||
| 1985 | foreach ($context['smileys'] as $section => $smileyRows) |
||
| 1986 | { |
||
| 1987 | foreach ($smileyRows as $rowIndex => $smileys) |
||
| 1988 | $context['smileys'][$section][$rowIndex]['smileys'][count($smileys['smileys']) - 1]['isLast'] = true; |
||
| 1989 | |||
| 1990 | if (!empty($smileyRows)) |
||
| 1991 | $context['smileys'][$section][count($smileyRows) - 1]['isLast'] = true; |
||
| 1992 | } |
||
| 1993 | |||
| 1994 | cache_put_data('posting_smileys', $context['smileys'], 480); |
||
| 1995 | } |
||
| 1996 | else |
||
| 1997 | $context['smileys'] = $temp; |
||
| 1998 | } |
||
| 1999 | } |
||
| 2000 | |||
| 2001 | // Set a flag so the sub template knows what to do... |
||
| 2002 | $context['show_bbc'] = !empty($modSettings['enableBBC']); |
||
| 2003 | } |
||
| 2004 | |||
| 2005 | /** |
||
| 2006 | * Create a anti-bot verification control? |
||
| 2007 | * @param array &$verificationOptions Options for the verification control |
||
| 2008 | * @param bool $do_test Whether to check to see if the user entered the code correctly |
||
| 2009 | * @return bool|array False if there's nothing to show, true if everything went well or an array containing error indicators if the test failed |
||
| 2010 | */ |
||
| 2011 | function create_control_verification(&$verificationOptions, $do_test = false) |
||
| 2012 | { |
||
| 2013 | global $modSettings, $smcFunc; |
||
| 2014 | global $context, $user_info, $scripturl, $language; |
||
| 2015 | |||
| 2016 | // First verification means we need to set up some bits... |
||
| 2017 | if (empty($context['controls']['verification'])) |
||
| 2018 | { |
||
| 2019 | // The template |
||
| 2020 | loadTemplate('GenericControls'); |
||
| 2021 | |||
| 2022 | // Some javascript ma'am? |
||
| 2023 | if (!empty($verificationOptions['override_visual']) || (!empty($modSettings['visual_verification_type']) && !isset($verificationOptions['override_visual']))) |
||
| 2024 | loadJavaScriptFile('captcha.js', array(), 'smf_captcha'); |
||
| 2025 | |||
| 2026 | $context['use_graphic_library'] = in_array('gd', get_loaded_extensions()); |
||
| 2027 | |||
| 2028 | // Skip I, J, L, O, Q, S and Z. |
||
| 2029 | $context['standard_captcha_range'] = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P', 'R'), range('T', 'Y')); |
||
| 2030 | } |
||
| 2031 | |||
| 2032 | // Always have an ID. |
||
| 2033 | assert(isset($verificationOptions['id'])); |
||
| 2034 | $isNew = !isset($context['controls']['verification'][$verificationOptions['id']]); |
||
| 2035 | |||
| 2036 | // Log this into our collection. |
||
| 2037 | if ($isNew) |
||
| 2038 | $context['controls']['verification'][$verificationOptions['id']] = array( |
||
| 2039 | 'id' => $verificationOptions['id'], |
||
| 2040 | 'empty_field' => empty($verificationOptions['no_empty_field']), |
||
| 2041 | 'show_visual' => !empty($verificationOptions['override_visual']) || (!empty($modSettings['visual_verification_type']) && !isset($verificationOptions['override_visual'])), |
||
| 2042 | 'number_questions' => isset($verificationOptions['override_qs']) ? $verificationOptions['override_qs'] : (!empty($modSettings['qa_verification_number']) ? $modSettings['qa_verification_number'] : 0), |
||
| 2043 | 'max_errors' => isset($verificationOptions['max_errors']) ? $verificationOptions['max_errors'] : 3, |
||
| 2044 | 'image_href' => $scripturl . '?action=verificationcode;vid=' . $verificationOptions['id'] . ';rand=' . md5(mt_rand()), |
||
| 2045 | 'text_value' => '', |
||
| 2046 | 'questions' => array(), |
||
| 2047 | 'can_recaptcha' => !empty($modSettings['recaptcha_enabled']) && !empty($modSettings['recaptcha_site_key']) && !empty($modSettings['recaptcha_secret_key']), |
||
| 2048 | ); |
||
| 2049 | $thisVerification = &$context['controls']['verification'][$verificationOptions['id']]; |
||
| 2050 | |||
| 2051 | // Is there actually going to be anything? |
||
| 2052 | if (empty($thisVerification['show_visual']) && empty($thisVerification['number_questions']) && empty($thisVerification['can_recaptcha'])) |
||
| 2053 | return false; |
||
| 2054 | elseif (!$isNew && !$do_test) |
||
| 2055 | return true; |
||
| 2056 | |||
| 2057 | // Sanitize reCAPTCHA fields? |
||
| 2058 | if ($thisVerification['can_recaptcha']) |
||
| 2059 | { |
||
| 2060 | // Only allow 40 alphanumeric, underscore and dash characters. |
||
| 2061 | $thisVerification['recaptcha_site_key'] = preg_replace('/(0-9a-zA-Z_){40}/', '$1', $modSettings['recaptcha_site_key']); |
||
| 2062 | |||
| 2063 | // Light or dark theme... |
||
| 2064 | $thisVerification['recaptcha_theme'] = preg_replace('/(light|dark)/', '$1', $modSettings['recaptcha_theme']); |
||
| 2065 | } |
||
| 2066 | |||
| 2067 | // Add javascript for the object. |
||
| 2068 | if ($context['controls']['verification'][$verificationOptions['id']]['show_visual']) |
||
| 2069 | $context['insert_after_template'] .= ' |
||
| 2070 | <script> |
||
| 2071 | var verification' . $verificationOptions['id'] . 'Handle = new smfCaptcha("' . $thisVerification['image_href'] . '", "' . $verificationOptions['id'] . '", ' . ($context['use_graphic_library'] ? 1 : 0) . '); |
||
| 2072 | </script>'; |
||
| 2073 | |||
| 2074 | // If we want questions do we have a cache of all the IDs? |
||
| 2075 | if (!empty($thisVerification['number_questions']) && empty($modSettings['question_id_cache'])) |
||
| 2076 | { |
||
| 2077 | if (($modSettings['question_id_cache'] = cache_get_data('verificationQuestions', 300)) == null) |
||
| 2078 | { |
||
| 2079 | $request = $smcFunc['db_query']('', ' |
||
| 2080 | SELECT id_question, lngfile, question, answers |
||
| 2081 | FROM {db_prefix}qanda', |
||
| 2082 | array() |
||
| 2083 | ); |
||
| 2084 | $modSettings['question_id_cache'] = array( |
||
| 2085 | 'questions' => array(), |
||
| 2086 | 'langs' => array(), |
||
| 2087 | ); |
||
| 2088 | // This is like Captain Kirk climbing a mountain in some ways. This is L's fault, mkay? :P |
||
| 2089 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 2090 | { |
||
| 2091 | $id_question = $row['id_question']; |
||
| 2092 | unset ($row['id_question']); |
||
| 2093 | // Make them all lowercase. We can't directly use $smcFunc['strtolower'] with array_walk, so do it manually, eh? |
||
| 2094 | $row['answers'] = $smcFunc['json_decode']($row['answers'], true); |
||
| 2095 | foreach ($row['answers'] as $k => $v) |
||
| 2096 | $row['answers'][$k] = $smcFunc['strtolower']($v); |
||
| 2097 | |||
| 2098 | $modSettings['question_id_cache']['questions'][$id_question] = $row; |
||
| 2099 | $modSettings['question_id_cache']['langs'][$row['lngfile']][] = $id_question; |
||
| 2100 | } |
||
| 2101 | $smcFunc['db_free_result']($request); |
||
| 2102 | |||
| 2103 | cache_put_data('verificationQuestions', $modSettings['question_id_cache'], 300); |
||
| 2104 | } |
||
| 2105 | } |
||
| 2106 | |||
| 2107 | if (!isset($_SESSION[$verificationOptions['id'] . '_vv'])) |
||
| 2108 | $_SESSION[$verificationOptions['id'] . '_vv'] = array(); |
||
| 2109 | |||
| 2110 | // Do we need to refresh the verification? |
||
| 2111 | if (!$do_test && (!empty($_SESSION[$verificationOptions['id'] . '_vv']['did_pass']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) || $_SESSION[$verificationOptions['id'] . '_vv']['count'] > 3) && empty($verificationOptions['dont_refresh'])) |
||
| 2112 | $force_refresh = true; |
||
| 2113 | else |
||
| 2114 | $force_refresh = false; |
||
| 2115 | |||
| 2116 | // This can also force a fresh, although unlikely. |
||
| 2117 | View Code Duplication | if (($thisVerification['show_visual'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['code'])) || ($thisVerification['number_questions'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['q']))) |
|
| 2118 | $force_refresh = true; |
||
| 2119 | |||
| 2120 | $verification_errors = array(); |
||
| 2121 | // Start with any testing. |
||
| 2122 | if ($do_test) |
||
| 2123 | { |
||
| 2124 | // This cannot happen! |
||
| 2125 | if (!isset($_SESSION[$verificationOptions['id'] . '_vv']['count'])) |
||
| 2126 | fatal_lang_error('no_access', false); |
||
| 2127 | // ... nor this! |
||
| 2128 | if ($thisVerification['number_questions'] && (!isset($_SESSION[$verificationOptions['id'] . '_vv']['q']) || !isset($_REQUEST[$verificationOptions['id'] . '_vv']['q']))) |
||
| 2129 | fatal_lang_error('no_access', false); |
||
| 2130 | // Hmm, it's requested but not actually declared. This shouldn't happen. |
||
| 2131 | if ($thisVerification['empty_field'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['empty_field'])) |
||
| 2132 | fatal_lang_error('no_access', false); |
||
| 2133 | // While we're here, did the user do something bad? |
||
| 2134 | View Code Duplication | if ($thisVerification['empty_field'] && !empty($_SESSION[$verificationOptions['id'] . '_vv']['empty_field']) && !empty($_REQUEST[$_SESSION[$verificationOptions['id'] . '_vv']['empty_field']])) |
|
| 2135 | $verification_errors[] = 'wrong_verification_answer'; |
||
| 2136 | |||
| 2137 | if ($thisVerification['can_recaptcha']) |
||
| 2138 | { |
||
| 2139 | $reCaptcha = new \ReCaptcha\ReCaptcha($modSettings['recaptcha_secret_key']); |
||
| 2140 | |||
| 2141 | // Was there a reCAPTCHA response? |
||
| 2142 | if (isset($_POST['g-recaptcha-response'])) |
||
| 2143 | { |
||
| 2144 | $resp = $reCaptcha->verify($_POST['g-recaptcha-response'], $user_info['ip']); |
||
| 2145 | |||
| 2146 | if (!$resp->isSuccess()) |
||
| 2147 | $verification_errors[] = 'wrong_verification_code'; |
||
| 2148 | } |
||
| 2149 | else |
||
| 2150 | $verification_errors[] = 'wrong_verification_code'; |
||
| 2151 | } |
||
| 2152 | if ($thisVerification['show_visual'] && (empty($_REQUEST[$verificationOptions['id'] . '_vv']['code']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['code']) || strtoupper($_REQUEST[$verificationOptions['id'] . '_vv']['code']) !== $_SESSION[$verificationOptions['id'] . '_vv']['code'])) |
||
| 2153 | $verification_errors[] = 'wrong_verification_code'; |
||
| 2154 | if ($thisVerification['number_questions']) |
||
| 2155 | { |
||
| 2156 | $incorrectQuestions = array(); |
||
| 2157 | foreach ($_SESSION[$verificationOptions['id'] . '_vv']['q'] as $q) |
||
| 2158 | { |
||
| 2159 | // We don't have this question any more, thus no answers. |
||
| 2160 | if (!isset($modSettings['question_id_cache']['questions'][$q])) |
||
| 2161 | continue; |
||
| 2162 | // This is quite complex. We have our question but it might have multiple answers. |
||
| 2163 | // First, did they actually answer this question? |
||
| 2164 | if (!isset($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) || trim($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) == '') |
||
| 2165 | { |
||
| 2166 | $incorrectQuestions[] = $q; |
||
| 2167 | continue; |
||
| 2168 | } |
||
| 2169 | // Second, is their answer in the list of possible answers? |
||
| 2170 | else |
||
| 2171 | { |
||
| 2172 | $given_answer = trim($smcFunc['htmlspecialchars'](strtolower($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]))); |
||
| 2173 | if (!in_array($given_answer, $modSettings['question_id_cache']['questions'][$q]['answers'])) |
||
| 2174 | $incorrectQuestions[] = $q; |
||
| 2175 | } |
||
| 2176 | } |
||
| 2177 | |||
| 2178 | if (!empty($incorrectQuestions)) |
||
| 2179 | $verification_errors[] = 'wrong_verification_answer'; |
||
| 2180 | } |
||
| 2181 | } |
||
| 2182 | |||
| 2183 | // Any errors means we refresh potentially. |
||
| 2184 | if (!empty($verification_errors)) |
||
| 2185 | { |
||
| 2186 | if (empty($_SESSION[$verificationOptions['id'] . '_vv']['errors'])) |
||
| 2187 | $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0; |
||
| 2188 | // Too many errors? |
||
| 2189 | elseif ($_SESSION[$verificationOptions['id'] . '_vv']['errors'] > $thisVerification['max_errors']) |
||
| 2190 | $force_refresh = true; |
||
| 2191 | |||
| 2192 | // Keep a track of these. |
||
| 2193 | $_SESSION[$verificationOptions['id'] . '_vv']['errors']++; |
||
| 2194 | } |
||
| 2195 | |||
| 2196 | // Are we refreshing then? |
||
| 2197 | if ($force_refresh) |
||
| 2198 | { |
||
| 2199 | // Assume nothing went before. |
||
| 2200 | $_SESSION[$verificationOptions['id'] . '_vv']['count'] = 0; |
||
| 2201 | $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0; |
||
| 2202 | $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = false; |
||
| 2203 | $_SESSION[$verificationOptions['id'] . '_vv']['q'] = array(); |
||
| 2204 | $_SESSION[$verificationOptions['id'] . '_vv']['code'] = ''; |
||
| 2205 | |||
| 2206 | // Make our magic empty field. |
||
| 2207 | if ($thisVerification['empty_field']) |
||
| 2208 | { |
||
| 2209 | // We're building a field that lives in the template, that we hope to be empty later. But at least we give it a believable name. |
||
| 2210 | $terms = array('gadget', 'device', 'uid', 'gid', 'guid', 'uuid', 'unique', 'identifier'); |
||
| 2211 | $second_terms = array('hash', 'cipher', 'code', 'key', 'unlock', 'bit', 'value'); |
||
| 2212 | $start = mt_rand(0, 27); |
||
| 2213 | $hash = substr(md5(time()), $start, 4); |
||
| 2214 | $_SESSION[$verificationOptions['id'] . '_vv']['empty_field'] = $terms[array_rand($terms)] . '-' . $second_terms[array_rand($second_terms)] . '-' . $hash; |
||
| 2215 | } |
||
| 2216 | |||
| 2217 | // Generating a new image. |
||
| 2218 | if ($thisVerification['show_visual']) |
||
| 2219 | { |
||
| 2220 | // Are we overriding the range? |
||
| 2221 | $character_range = !empty($verificationOptions['override_range']) ? $verificationOptions['override_range'] : $context['standard_captcha_range']; |
||
| 2222 | |||
| 2223 | for ($i = 0; $i < 6; $i++) |
||
| 2224 | $_SESSION[$verificationOptions['id'] . '_vv']['code'] .= $character_range[array_rand($character_range)]; |
||
| 2225 | } |
||
| 2226 | |||
| 2227 | // Getting some new questions? |
||
| 2228 | if ($thisVerification['number_questions']) |
||
| 2229 | { |
||
| 2230 | // Attempt to try the current page's language, followed by the user's preference, followed by the site default. |
||
| 2231 | $possible_langs = array(); |
||
| 2232 | if (isset($_SESSION['language'])) |
||
| 2233 | $possible_langs[] = strtr($_SESSION['language'], array('-utf8' => '')); |
||
| 2234 | if (!empty($user_info['language'])); |
||
| 2235 | $possible_langs[] = $user_info['language']; |
||
| 2236 | $possible_langs[] = $language; |
||
| 2237 | |||
| 2238 | $questionIDs = array(); |
||
| 2239 | foreach ($possible_langs as $lang) |
||
| 2240 | { |
||
| 2241 | $lang = strtr($lang, array('-utf8' => '')); |
||
| 2242 | if (isset($modSettings['question_id_cache']['langs'][$lang])) |
||
| 2243 | { |
||
| 2244 | // If we find questions for this, grab the ids from this language's ones, randomize the array and take just the number we need. |
||
| 2245 | $questionIDs = $modSettings['question_id_cache']['langs'][$lang]; |
||
| 2246 | shuffle($questionIDs); |
||
| 2247 | $questionIDs = array_slice($questionIDs, 0, $thisVerification['number_questions']); |
||
| 2248 | break; |
||
| 2249 | } |
||
| 2250 | } |
||
| 2251 | } |
||
| 2252 | } |
||
| 2253 | else |
||
| 2254 | { |
||
| 2255 | // Same questions as before. |
||
| 2256 | $questionIDs = !empty($_SESSION[$verificationOptions['id'] . '_vv']['q']) ? $_SESSION[$verificationOptions['id'] . '_vv']['q'] : array(); |
||
| 2257 | $thisVerification['text_value'] = !empty($_REQUEST[$verificationOptions['id'] . '_vv']['code']) ? $smcFunc['htmlspecialchars']($_REQUEST[$verificationOptions['id'] . '_vv']['code']) : ''; |
||
| 2258 | } |
||
| 2259 | |||
| 2260 | // If we do have an empty field, it would be nice to hide it from legitimate users who shouldn't be populating it anyway. |
||
| 2261 | if (!empty($_SESSION[$verificationOptions['id'] . '_vv']['empty_field'])) |
||
| 2262 | { |
||
| 2263 | if (!isset($context['html_headers'])) |
||
| 2264 | $context['html_headers'] = ''; |
||
| 2265 | $context['html_headers'] .= '<style>.vv_special { display:none; }</style>'; |
||
| 2266 | } |
||
| 2267 | |||
| 2268 | // Have we got some questions to load? |
||
| 2269 | if (!empty($questionIDs)) |
||
| 2270 | { |
||
| 2271 | $_SESSION[$verificationOptions['id'] . '_vv']['q'] = array(); |
||
| 2272 | foreach ($questionIDs as $q) |
||
| 2273 | { |
||
| 2274 | // Bit of a shortcut this. |
||
| 2275 | $row = &$modSettings['question_id_cache']['questions'][$q]; |
||
| 2276 | $thisVerification['questions'][] = array( |
||
| 2277 | 'id' => $q, |
||
| 2278 | 'q' => parse_bbc($row['question']), |
||
| 2279 | 'is_error' => !empty($incorrectQuestions) && in_array($q, $incorrectQuestions), |
||
| 2280 | // Remember a previous submission? |
||
| 2281 | 'a' => isset($_REQUEST[$verificationOptions['id'] . '_vv'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) ? $smcFunc['htmlspecialchars']($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) : '', |
||
| 2282 | ); |
||
| 2283 | $_SESSION[$verificationOptions['id'] . '_vv']['q'][] = $q; |
||
| 2284 | } |
||
| 2285 | } |
||
| 2286 | |||
| 2287 | $_SESSION[$verificationOptions['id'] . '_vv']['count'] = empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) ? 1 : $_SESSION[$verificationOptions['id'] . '_vv']['count'] + 1; |
||
| 2288 | |||
| 2289 | // Return errors if we have them. |
||
| 2290 | if (!empty($verification_errors)) |
||
| 2291 | return $verification_errors; |
||
| 2292 | // If we had a test that one, make a note. |
||
| 2293 | elseif ($do_test) |
||
| 2294 | $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = true; |
||
| 2295 | |||
| 2296 | // Say that everything went well chaps. |
||
| 2297 | return true; |
||
| 2298 | } |
||
| 2299 | |||
| 2300 | /** |
||
| 2301 | * This keeps track of all registered handling functions for auto suggest functionality and passes execution to them. |
||
| 2302 | * @param bool $checkRegistered If set to something other than null, checks whether the callback function is registered |
||
| 2303 | * @return void|bool Returns whether the callback function is registered if $checkRegistered isn't null |
||
| 2304 | */ |
||
| 2305 | function AutoSuggestHandler($checkRegistered = null) |
||
| 2306 | { |
||
| 2307 | global $smcFunc, $context; |
||
| 2308 | |||
| 2309 | // These are all registered types. |
||
| 2310 | $searchTypes = array( |
||
| 2311 | 'member' => 'Member', |
||
| 2312 | 'membergroups' => 'MemberGroups', |
||
| 2313 | 'versions' => 'SMFVersions', |
||
| 2314 | ); |
||
| 2315 | |||
| 2316 | call_integration_hook('integrate_autosuggest', array(&$searchTypes)); |
||
| 2317 | |||
| 2318 | // If we're just checking the callback function is registered return true or false. |
||
| 2319 | if ($checkRegistered != null) |
||
| 2320 | return isset($searchTypes[$checkRegistered]) && function_exists('AutoSuggest_Search_' . $checkRegistered); |
||
| 2321 | |||
| 2322 | checkSession('get'); |
||
| 2323 | loadTemplate('Xml'); |
||
| 2324 | |||
| 2325 | // Any parameters? |
||
| 2326 | $context['search_param'] = isset($_REQUEST['search_param']) ? $smcFunc['json_decode'](base64_decode($_REQUEST['search_param']), true) : array(); |
||
| 2327 | |||
| 2328 | if (isset($_REQUEST['suggest_type'], $_REQUEST['search']) && isset($searchTypes[$_REQUEST['suggest_type']])) |
||
| 2329 | { |
||
| 2330 | $function = 'AutoSuggest_Search_' . $searchTypes[$_REQUEST['suggest_type']]; |
||
| 2331 | $context['sub_template'] = 'generic_xml'; |
||
| 2332 | $context['xml_data'] = $function(); |
||
| 2333 | } |
||
| 2334 | } |
||
| 2335 | |||
| 2336 | /** |
||
| 2337 | * Search for a member - by real_name or member_name by default. |
||
| 2338 | * |
||
| 2339 | * @return array An array of information for displaying the suggestions |
||
| 2340 | */ |
||
| 2341 | function AutoSuggest_Search_Member() |
||
| 2342 | { |
||
| 2343 | global $user_info, $smcFunc, $context; |
||
| 2344 | |||
| 2345 | $_REQUEST['search'] = trim($smcFunc['strtolower']($_REQUEST['search'])) . '*'; |
||
| 2346 | $_REQUEST['search'] = strtr($_REQUEST['search'], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '&' => '&')); |
||
| 2347 | |||
| 2348 | // Find the member. |
||
| 2349 | $request = $smcFunc['db_query']('', ' |
||
| 2350 | SELECT id_member, real_name |
||
| 2351 | FROM {db_prefix}members |
||
| 2352 | WHERE {raw:real_name} LIKE {string:search}' . (!empty($context['search_param']['buddies']) ? ' |
||
| 2353 | AND id_member IN ({array_int:buddy_list})' : '') . ' |
||
| 2354 | AND is_activated IN (1, 11) |
||
| 2355 | LIMIT ' . ($smcFunc['strlen']($_REQUEST['search']) <= 2 ? '100' : '800'), |
||
| 2356 | array( |
||
| 2357 | 'real_name' => $smcFunc['db_case_sensitive'] ? 'LOWER(real_name)' : 'real_name', |
||
| 2358 | 'buddy_list' => $user_info['buddies'], |
||
| 2359 | 'search' => $_REQUEST['search'], |
||
| 2360 | ) |
||
| 2361 | ); |
||
| 2362 | $xml_data = array( |
||
| 2363 | 'items' => array( |
||
| 2364 | 'identifier' => 'item', |
||
| 2365 | 'children' => array(), |
||
| 2366 | ), |
||
| 2367 | ); |
||
| 2368 | View Code Duplication | while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
| 2369 | { |
||
| 2370 | $row['real_name'] = strtr($row['real_name'], array('&' => '&', '<' => '<', '>' => '>', '"' => '"')); |
||
| 2371 | |||
| 2372 | $xml_data['items']['children'][] = array( |
||
| 2373 | 'attributes' => array( |
||
| 2374 | 'id' => $row['id_member'], |
||
| 2375 | ), |
||
| 2376 | 'value' => $row['real_name'], |
||
| 2377 | ); |
||
| 2378 | } |
||
| 2379 | $smcFunc['db_free_result']($request); |
||
| 2380 | |||
| 2381 | return $xml_data; |
||
| 2382 | } |
||
| 2383 | |||
| 2384 | /** |
||
| 2385 | * Search for a membergroup by name |
||
| 2386 | * |
||
| 2387 | * @return array An array of information for displaying the suggestions |
||
| 2388 | */ |
||
| 2389 | function AutoSuggest_Search_MemberGroups() |
||
| 2390 | { |
||
| 2391 | global $smcFunc; |
||
| 2392 | |||
| 2393 | $_REQUEST['search'] = trim($smcFunc['strtolower']($_REQUEST['search'])) . '*'; |
||
| 2394 | $_REQUEST['search'] = strtr($_REQUEST['search'], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '&' => '&')); |
||
| 2395 | |||
| 2396 | // Find the group. |
||
| 2397 | // Only return groups which are not post-based and not "Hidden", but not the "Administrators" or "Moderators" groups. |
||
| 2398 | $request = $smcFunc['db_query']('', ' |
||
| 2399 | SELECT id_group, group_name |
||
| 2400 | FROM {db_prefix}membergroups |
||
| 2401 | WHERE {raw:group_name} LIKE {string:search} |
||
| 2402 | AND min_posts = {int:min_posts} |
||
| 2403 | AND id_group NOT IN ({array_int:invalid_groups}) |
||
| 2404 | AND hidden != {int:hidden} |
||
| 2405 | ', |
||
| 2406 | array( |
||
| 2407 | 'group_name' => $smcFunc['db_case_sensitive'] ? 'LOWER(group_name}' : 'group_name', |
||
| 2408 | 'min_posts' => -1, |
||
| 2409 | 'invalid_groups' => array(1, 3), |
||
| 2410 | 'hidden' => 2, |
||
| 2411 | 'search' => $_REQUEST['search'], |
||
| 2412 | ) |
||
| 2413 | ); |
||
| 2414 | $xml_data = array( |
||
| 2415 | 'items' => array( |
||
| 2416 | 'identifier' => 'item', |
||
| 2417 | 'children' => array(), |
||
| 2418 | ), |
||
| 2419 | ); |
||
| 2420 | View Code Duplication | while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
| 2421 | { |
||
| 2422 | $row['group_name'] = strtr($row['group_name'], array('&' => '&', '<' => '<', '>' => '>', '"' => '"')); |
||
| 2423 | |||
| 2424 | $xml_data['items']['children'][] = array( |
||
| 2425 | 'attributes' => array( |
||
| 2426 | 'id' => $row['id_group'], |
||
| 2427 | ), |
||
| 2428 | 'value' => $row['group_name'], |
||
| 2429 | ); |
||
| 2430 | } |
||
| 2431 | $smcFunc['db_free_result']($request); |
||
| 2432 | |||
| 2433 | return $xml_data; |
||
| 2434 | } |
||
| 2435 | |||
| 2436 | /** |
||
| 2437 | * Provides a list of possible SMF versions to use in emulation |
||
| 2438 | * |
||
| 2439 | * @return array An array of data for displaying the suggestions |
||
| 2440 | */ |
||
| 2441 | function AutoSuggest_Search_SMFVersions() |
||
| 2442 | { |
||
| 2443 | global $smcFunc; |
||
| 2444 | |||
| 2445 | $xml_data = array( |
||
| 2446 | 'items' => array( |
||
| 2447 | 'identifier' => 'item', |
||
| 2448 | 'children' => array(), |
||
| 2449 | ), |
||
| 2450 | ); |
||
| 2451 | |||
| 2452 | // First try and get it from the database. |
||
| 2453 | $versions = array(); |
||
| 2454 | $request = $smcFunc['db_query']('', ' |
||
| 2455 | SELECT data |
||
| 2456 | FROM {db_prefix}admin_info_files |
||
| 2457 | WHERE filename = {string:latest_versions} |
||
| 2458 | AND path = {string:path}', |
||
| 2459 | array( |
||
| 2460 | 'latest_versions' => 'latest-versions.txt', |
||
| 2461 | 'path' => '/smf/', |
||
| 2462 | ) |
||
| 2463 | ); |
||
| 2464 | if (($smcFunc['db_num_rows']($request) > 0) && ($row = $smcFunc['db_fetch_assoc']($request)) && !empty($row['data'])) |
||
| 2465 | { |
||
| 2466 | // The file can be either Windows or Linux line endings, but let's ensure we clean it as best we can. |
||
| 2467 | $possible_versions = explode("\n", $row['data']); |
||
| 2468 | foreach ($possible_versions as $ver) |
||
| 2469 | { |
||
| 2470 | $ver = trim($ver); |
||
| 2471 | if (strpos($ver, 'SMF') === 0) |
||
| 2472 | $versions[] = $ver; |
||
| 2473 | } |
||
| 2474 | } |
||
| 2475 | $smcFunc['db_free_result']($request); |
||
| 2476 | |||
| 2477 | // Just in case we don't have ANYthing. |
||
| 2478 | if (empty($versions)) |
||
| 2479 | $versions = array('SMF 2.0'); |
||
| 2480 | |||
| 2481 | foreach ($versions as $id => $version) |
||
| 2482 | if (strpos($version, strtoupper($_REQUEST['search'])) !== false) |
||
| 2483 | $xml_data['items']['children'][] = array( |
||
| 2484 | 'attributes' => array( |
||
| 2485 | 'id' => $id, |
||
| 2486 | ), |
||
| 2487 | 'value' => $version, |
||
| 2488 | ); |
||
| 2489 | |||
| 2490 | return $xml_data; |
||
| 2491 | } |
||
| 2492 | |||
| 2493 | ?> |
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
integervalues, zero is a special case, in particular the following results might be unexpected: