|
1 <?php |
|
2 /* |
|
3 This is a compressed copy of NBBC. Do not edit! |
|
4 |
|
5 Copyright (c) 2008-9, the Phantom Inker. All rights reserved. |
|
6 Portions Copyright (c) 2004-2008 AddedBytes.com |
|
7 |
|
8 Redistribution and use in source and binary forms, with or without |
|
9 modification, are permitted provided that the following conditions |
|
10 are met: |
|
11 |
|
12 * Redistributions of source code must retain the above copyright |
|
13 notice, this list of conditions and the following disclaimer. |
|
14 |
|
15 * Redistributions in binary form must reproduce the above copyright |
|
16 notice, this list of conditions and the following disclaimer in |
|
17 the documentation and/or other materials provided with the |
|
18 distribution. |
|
19 |
|
20 THIS SOFTWARE IS PROVIDED BY THE PHANTOM INKER "AS IS" AND ANY EXPRESS |
|
21 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
27 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
28 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
29 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
30 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 define("BBCODE_VERSION", "1.4.5"); |
|
34 define("BBCODE_RELEASE", "2010-09-17"); |
|
35 define("BBCODE_VERBATIM", 2); |
|
36 define("BBCODE_REQUIRED", 1); |
|
37 define("BBCODE_OPTIONAL", 0); |
|
38 define("BBCODE_PROHIBIT", -1); |
|
39 define("BBCODE_CHECK", 1); |
|
40 define("BBCODE_OUTPUT", 2); |
|
41 define("BBCODE_ENDTAG", 5); |
|
42 define("BBCODE_TAG", 4); |
|
43 define("BBCODE_TEXT", 3); |
|
44 define("BBCODE_NL", 2); |
|
45 define("BBCODE_WS", 1); |
|
46 define("BBCODE_EOI", 0); |
|
47 define("BBCODE_LEXSTATE_TEXT", 0); |
|
48 define("BBCODE_LEXSTATE_TAG", 1); |
|
49 define("BBCODE_MODE_SIMPLE", 0); |
|
50 define("BBCODE_MODE_CALLBACK", 1); |
|
51 define("BBCODE_MODE_INTERNAL", 2); |
|
52 define("BBCODE_MODE_LIBRARY", 3); |
|
53 define("BBCODE_MODE_ENHANCED", 4); |
|
54 define("BBCODE_STACK_TOKEN", 0); |
|
55 define("BBCODE_STACK_TEXT", 1); |
|
56 define("BBCODE_STACK_TAG", 2); |
|
57 define("BBCODE_STACK_CLASS", 3); |
|
58 if (!function_exists('str_split')) { |
|
59 function str_split($string, $split_length = 1) { |
|
60 $array = explode("\r\n", chunk_split($string, $split_length)); |
|
61 array_pop($array); |
|
62 return $array; |
|
63 } |
|
64 } |
|
65 $BBCode_SourceDir = dirname(__FILE__); |
|
66 |
|
67 class BBCodeLexer { |
|
68 var $token; |
|
69 var $text; |
|
70 var $tag; |
|
71 var $state; |
|
72 var $input; |
|
73 var $ptr; |
|
74 var $unget; |
|
75 var $verbatim; |
|
76 var $debug; |
|
77 var $tagmarker; |
|
78 var $end_tagmarker; |
|
79 var $pat_main; |
|
80 var $pat_comment; |
|
81 var $pat_comment2; |
|
82 var $pat_wiki; |
|
83 function BBCodeLexer($string, $tagmarker = '[') { |
|
84 $regex_beginmarkers = Array( '[' => '\[', '<' => '<', '{' => '\{', '(' => '\(' ); |
|
85 $regex_endmarkers = Array( '[' => '\]', '<' => '>', '{' => '\}', '(' => '\)' ); |
|
86 $endmarkers = Array( '[' => ']', '<' => '>', '{' => '}', '(' => ')' ); |
|
87 if (!isset($regex_endmarkers[$tagmarker])) $tagmarker = '['; |
|
88 $e = $regex_endmarkers[$tagmarker]; |
|
89 $b = $regex_beginmarkers[$tagmarker]; |
|
90 $this->tagmarker = $tagmarker; |
|
91 $this->end_tagmarker = $endmarkers[$tagmarker]; |
|
92 $this->pat_main = "/( " |
|
93 . "{$b}" |
|
94 . "(?! -- | ' | !-- | {$b}{$b} )" |
|
95 . "(?: [^\\n\\r{$b}{$e}] | \\\" [^\\\"\\n\\r]* \\\" | \\' [^\\'\\n\\r]* \\' )*" |
|
96 . "{$e}" |
|
97 . "| {$b}{$b} (?: [^{$e}\\r\\n] | {$e}[^{$e}\\r\\n] )* {$e}{$e}" |
|
98 . "| {$b} (?: -- | ' ) (?: [^{$e}\\n\\r]* ) {$e}" |
|
99 . "| {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e}" |
|
100 . "| -----+" |
|
101 . "| \\x0D\\x0A | \\x0A\\x0D | \\x0D | \\x0A" |
|
102 . "| [\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+(?=[\\x0D\\x0A{$b}]|-----|$)" |
|
103 . "| (?<=[\\x0D\\x0A{$e}]|-----|^)[\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+" |
|
104 . " )/Dx"; |
|
105 $this->input = preg_split($this->pat_main, $string, -1, PREG_SPLIT_DELIM_CAPTURE); |
|
106 $this->pat_comment = "/^ {$b} (?: -- | ' ) /Dx"; |
|
107 $this->pat_comment2 = "/^ {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e} $/Dx"; |
|
108 $this->pat_wiki = "/^ {$b}{$b} ([^\\|]*) (?:\\|(.*))? {$e}{$e} $/Dx"; |
|
109 $this->ptr = 0; |
|
110 $this->unget = false; |
|
111 $this->state = BBCODE_LEXSTATE_TEXT; |
|
112 $this->verbatim = false; |
|
113 $this->token = BBCODE_EOI; |
|
114 $this->tag = false; |
|
115 $this->text = ""; |
|
116 } |
|
117 function GuessTextLength() { |
|
118 $length = 0; |
|
119 $ptr = 0; |
|
120 $state = BBCODE_LEXSTATE_TEXT; |
|
121 while ($ptr < count($this->input)) { |
|
122 $text = $this->input[$ptr++]; |
|
123 if ($state == BBCODE_LEXSTATE_TEXT) { |
|
124 $state = BBCODE_LEXSTATE_TAG; |
|
125 $length += strlen($text); |
|
126 } |
|
127 else { |
|
128 switch (ord(substr($this->text, 0, 1))) { |
|
129 case 10: |
|
130 case 13: |
|
131 $state = BBCODE_LEXSTATE_TEXT; |
|
132 $length++; |
|
133 break; |
|
134 default: |
|
135 $state = BBCODE_LEXSTATE_TEXT; |
|
136 $length += strlen($text); |
|
137 break; |
|
138 case 40: |
|
139 case 60: |
|
140 case 91: |
|
141 case 123: |
|
142 $state = BBCODE_LEXSTATE_TEXT; |
|
143 break; |
|
144 } |
|
145 } |
|
146 } |
|
147 return $length; |
|
148 } |
|
149 function NextToken() { |
|
150 if ($this->unget) { |
|
151 $this->unget = false; |
|
152 return $this->token; |
|
153 } |
|
154 while (true) { |
|
155 if ($this->ptr >= count($this->input)) { |
|
156 $this->text = ""; |
|
157 $this->tag = false; |
|
158 return $this->token = BBCODE_EOI; |
|
159 } |
|
160 $this->text = preg_replace("/[\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F]/", "", |
|
161 $this->input[$this->ptr++]); |
|
162 if ($this->verbatim) { |
|
163 $this->tag = false; |
|
164 if ($this->state == BBCODE_LEXSTATE_TEXT) { |
|
165 $this->state = BBCODE_LEXSTATE_TAG; |
|
166 $token_type = BBCODE_TEXT; |
|
167 } |
|
168 else { |
|
169 $this->state = BBCODE_LEXSTATE_TEXT; |
|
170 switch (ord(substr($this->text, 0, 1))) { |
|
171 case 10: |
|
172 case 13: |
|
173 $token_type = BBCODE_NL; |
|
174 break; |
|
175 default: |
|
176 $token_type = BBCODE_WS; |
|
177 break; |
|
178 case 45: |
|
179 case 40: |
|
180 case 60: |
|
181 case 91: |
|
182 case 123: |
|
183 $token_type = BBCODE_TEXT; |
|
184 break; |
|
185 } |
|
186 } |
|
187 if (strlen($this->text) > 0) |
|
188 return $this->token = $token_type; |
|
189 } |
|
190 else if ($this->state == BBCODE_LEXSTATE_TEXT) { |
|
191 $this->state = BBCODE_LEXSTATE_TAG; |
|
192 $this->tag = false; |
|
193 if (strlen($this->text) > 0) |
|
194 return $this->token = BBCODE_TEXT; |
|
195 } |
|
196 else { |
|
197 switch (ord(substr($this->text, 0, 1))) { |
|
198 case 10: |
|
199 case 13: |
|
200 $this->tag = false; |
|
201 $this->state = BBCODE_LEXSTATE_TEXT; |
|
202 return $this->token = BBCODE_NL; |
|
203 case 45: |
|
204 if (preg_match("/^-----/", $this->text)) { |
|
205 $this->tag = Array('_name' => 'rule', '_endtag' => false, '_default' => ''); |
|
206 $this->state = BBCODE_LEXSTATE_TEXT; |
|
207 return $this->token = BBCODE_TAG; |
|
208 } |
|
209 else { |
|
210 $this->tag = false; |
|
211 $this->state = BBCODE_LEXSTATE_TEXT; |
|
212 if (strlen($this->text) > 0) |
|
213 return $this->token = BBCODE_TEXT; |
|
214 continue; |
|
215 } |
|
216 default: |
|
217 $this->tag = false; |
|
218 $this->state = BBCODE_LEXSTATE_TEXT; |
|
219 return $this->token = BBCODE_WS; |
|
220 case 40: |
|
221 case 60: |
|
222 case 91: |
|
223 case 123: |
|
224 if (preg_match($this->pat_comment, $this->text)) { |
|
225 $this->state = BBCODE_LEXSTATE_TEXT; |
|
226 continue; |
|
227 } |
|
228 if (preg_match($this->pat_comment2, $this->text)) { |
|
229 $this->state = BBCODE_LEXSTATE_TEXT; |
|
230 continue; |
|
231 } |
|
232 if (preg_match($this->pat_wiki, $this->text, $matches)) { |
|
233 $this->tag = Array('_name' => 'wiki', '_endtag' => false, |
|
234 '_default' => @$matches[1], 'title' => @$matches[2]); |
|
235 $this->state = BBCODE_LEXSTATE_TEXT; |
|
236 return $this->token = BBCODE_TAG; |
|
237 } |
|
238 $this->tag = $this->Internal_DecodeTag($this->text); |
|
239 $this->state = BBCODE_LEXSTATE_TEXT; |
|
240 return $this->token = ($this->tag['_end'] ? BBCODE_ENDTAG : BBCODE_TAG); |
|
241 } |
|
242 } |
|
243 } |
|
244 } |
|
245 function UngetToken() { |
|
246 if ($this->token !== BBCODE_EOI) |
|
247 $this->unget = true; |
|
248 } |
|
249 function PeekToken() { |
|
250 $result = $this->NextToken(); |
|
251 if ($this->token !== BBCODE_EOI) |
|
252 $this->unget = true; |
|
253 return $result; |
|
254 } |
|
255 function SaveState() { |
|
256 return Array( |
|
257 'token' => $this->token, |
|
258 'text' => $this->text, |
|
259 'tag' => $this->tag, |
|
260 'state' => $this->state, |
|
261 'input' => $this->input, |
|
262 'ptr' => $this->ptr, |
|
263 'unget' => $this->unget, |
|
264 'verbatim' => $this->verbatim |
|
265 ); |
|
266 } |
|
267 function RestoreState($state) { |
|
268 if (!is_array($state)) return; |
|
269 $this->token = @$state['token']; |
|
270 $this->text = @$state['text']; |
|
271 $this->tag = @$state['tag']; |
|
272 $this->state = @$state['state']; |
|
273 $this->input = @$state['input']; |
|
274 $this->ptr = @$state['ptr']; |
|
275 $this->unget = @$state['unget']; |
|
276 $this->verbatim = @$state['verbatim']; |
|
277 } |
|
278 function Internal_StripQuotes($string) { |
|
279 if (preg_match("/^\\\"(.*)\\\"$/", $string, $matches)) |
|
280 return $matches[1]; |
|
281 else if (preg_match("/^\\'(.*)\\'$/", $string, $matches)) |
|
282 return $matches[1]; |
|
283 else return $string; |
|
284 } |
|
285 function Internal_ClassifyPiece($ptr, $pieces) { |
|
286 if ($ptr >= count($pieces)) return -1; |
|
287 $piece = $pieces[$ptr]; |
|
288 if ($piece == '=') return '='; |
|
289 else if (preg_match("/^[\\'\\\"]/", $piece)) return '"'; |
|
290 else if (preg_match("/^[\\x00-\\x20]+$/", $piece)) return ' '; |
|
291 else return 'A'; |
|
292 } |
|
293 function Internal_DecodeTag($tag) { |
|
294 $result = Array('_tag' => $tag, '_endtag' => '', '_name' => '', |
|
295 '_hasend' => false, '_end' => false, '_default' => false); |
|
296 $tag = substr($tag, 1, strlen($tag)-2); |
|
297 $ch = ord(substr($tag, 0, 1)); |
|
298 if ($ch >= 0 && $ch <= 32) return $result; |
|
299 $pieces = preg_split("/(\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|=|[\\x00-\\x20]+)/", |
|
300 $tag, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); |
|
301 $ptr = 0; |
|
302 if (count($pieces) < 1) return $result; |
|
303 if (@substr($pieces[$ptr], 0, 1) == '/') { |
|
304 $result['_name'] = strtolower(substr($pieces[$ptr++], 1)); |
|
305 $result['_end'] = true; |
|
306 } |
|
307 else { |
|
308 $result['_name'] = strtolower($pieces[$ptr++]); |
|
309 $result['_end'] = false; |
|
310 } |
|
311 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') |
|
312 $ptr++; |
|
313 $params = Array(); |
|
314 if ($type != '=') { |
|
315 $result['_default'] = false; |
|
316 $params[] = Array('key' => '', 'value' => ''); |
|
317 } |
|
318 else { |
|
319 $ptr++; |
|
320 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') |
|
321 $ptr++; |
|
322 if ($type == "\"") |
|
323 $value = $this->Internal_StripQuotes($pieces[$ptr++]); |
|
324 else { |
|
325 $after_space = false; |
|
326 $start = $ptr; |
|
327 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) { |
|
328 if ($type == ' ') $after_space = true; |
|
329 if ($type == '=' && $after_space) break; |
|
330 $ptr++; |
|
331 } |
|
332 if ($type == -1) $ptr--; |
|
333 if ($type == '=') { |
|
334 $ptr--; |
|
335 while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) == ' ') |
|
336 $ptr--; |
|
337 while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) != ' ') |
|
338 $ptr--; |
|
339 } |
|
340 $value = ""; |
|
341 for (; $start <= $ptr; $start++) { |
|
342 if ($this->Internal_ClassifyPiece($start, $pieces) == ' ') |
|
343 $value .= " "; |
|
344 else $value .= $this->Internal_StripQuotes($pieces[$start]); |
|
345 } |
|
346 $value = trim($value); |
|
347 $ptr++; |
|
348 } |
|
349 $result['_default'] = $value; |
|
350 $params[] = Array('key' => '', 'value' => $value); |
|
351 } |
|
352 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) { |
|
353 while ($type == ' ') { |
|
354 $ptr++; |
|
355 $type = $this->Internal_ClassifyPiece($ptr, $pieces); |
|
356 } |
|
357 if ($type == 'A' || $type == '"') |
|
358 $key = strtolower($this->Internal_StripQuotes(@$pieces[$ptr++])); |
|
359 else if ($type == '=') { |
|
360 $ptr++; |
|
361 continue; |
|
362 } |
|
363 else if ($type == -1) break; |
|
364 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') |
|
365 $ptr++; |
|
366 if ($type != '=') |
|
367 $value = $this->Internal_StripQuotes($key); |
|
368 else { |
|
369 $ptr++; |
|
370 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') |
|
371 $ptr++; |
|
372 if ($type == '"') { |
|
373 $value = $this->Internal_StripQuotes($pieces[$ptr++]); |
|
374 } |
|
375 else if ($type != -1) { |
|
376 $value = $pieces[$ptr++]; |
|
377 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1 |
|
378 && $type != ' ') |
|
379 $value .= $pieces[$ptr++]; |
|
380 } |
|
381 else $value = ""; |
|
382 } |
|
383 if (substr($key, 0, 1) != '_') |
|
384 $result[$key] = $value; |
|
385 $params[] = Array('key' => $key, 'value' => $value); |
|
386 } |
|
387 $result['_params'] = $params; |
|
388 return $result; |
|
389 } |
|
390 } |
|
391 |
|
392 class BBCodeLibrary { |
|
393 var $default_smileys = Array( |
|
394 ':)' => 'smile.gif', ':-)' => 'smile.gif', |
|
395 '=)' => 'smile.gif', '=-)' => 'smile.gif', |
|
396 ':(' => 'frown.gif', ':-(' => 'frown.gif', |
|
397 '=(' => 'frown.gif', '=-(' => 'frown.gif', |
|
398 ':D' => 'bigsmile.gif', ':-D' => 'bigsmile.gif', |
|
399 '=D' => 'bigsmile.gif', '=-D' => 'bigsmile.gif', |
|
400 '>:('=> 'angry.gif', '>:-('=> 'angry.gif', |
|
401 '>=('=> 'angry.gif', '>=-('=> 'angry.gif', |
|
402 'D:' => 'angry.gif', 'D-:' => 'angry.gif', |
|
403 'D=' => 'angry.gif', 'D-=' => 'angry.gif', |
|
404 '>:)'=> 'evil.gif', '>:-)'=> 'evil.gif', |
|
405 '>=)'=> 'evil.gif', '>=-)'=> 'evil.gif', |
|
406 '>:D'=> 'evil.gif', '>:-D'=> 'evil.gif', |
|
407 '>=D'=> 'evil.gif', '>=-D'=> 'evil.gif', |
|
408 '>;)'=> 'sneaky.gif', '>;-)'=> 'sneaky.gif', |
|
409 '>;D'=> 'sneaky.gif', '>;-D'=> 'sneaky.gif', |
|
410 'O:)' => 'saint.gif', 'O:-)' => 'saint.gif', |
|
411 'O=)' => 'saint.gif', 'O=-)' => 'saint.gif', |
|
412 ':O' => 'surprise.gif', ':-O' => 'surprise.gif', |
|
413 '=O' => 'surprise.gif', '=-O' => 'surprise.gif', |
|
414 ':?' => 'confuse.gif', ':-?' => 'confuse.gif', |
|
415 '=?' => 'confuse.gif', '=-?' => 'confuse.gif', |
|
416 ':s' => 'worry.gif', ':-S' => 'worry.gif', |
|
417 '=s' => 'worry.gif', '=-S' => 'worry.gif', |
|
418 ':|' => 'neutral.gif', ':-|' => 'neutral.gif', |
|
419 '=|' => 'neutral.gif', '=-|' => 'neutral.gif', |
|
420 ':I' => 'neutral.gif', ':-I' => 'neutral.gif', |
|
421 '=I' => 'neutral.gif', '=-I' => 'neutral.gif', |
|
422 ':/' => 'irritated.gif', ':-/' => 'irritated.gif', |
|
423 '=/' => 'irritated.gif', '=-/' => 'irritated.gif', |
|
424 ':\\' => 'irritated.gif', ':-\\' => 'irritated.gif', |
|
425 '=\\' => 'irritated.gif', '=-\\' => 'irritated.gif', |
|
426 ':P' => 'tongue.gif', ':-P' => 'tongue.gif', |
|
427 '=P' => 'tongue.gif', '=-P' => 'tongue.gif', |
|
428 'X-P' => 'tongue.gif', |
|
429 '8)' => 'bigeyes.gif', '8-)' => 'bigeyes.gif', |
|
430 'B)' => 'cool.gif', 'B-)' => 'cool.gif', |
|
431 ';)' => 'wink.gif', ';-)' => 'wink.gif', |
|
432 ';D' => 'bigwink.gif', ';-D' => 'bigwink.gif', |
|
433 '^_^'=> 'anime.gif', '^^;' => 'sweatdrop.gif', |
|
434 '>_>'=> 'lookright.gif', '>.>' => 'lookright.gif', |
|
435 '<_<'=> 'lookleft.gif', '<.<' => 'lookleft.gif', |
|
436 'XD' => 'laugh.gif', 'X-D' => 'laugh.gif', |
|
437 ';D' => 'bigwink.gif', ';-D' => 'bigwink.gif', |
|
438 ':3' => 'smile3.gif', ':-3' => 'smile3.gif', |
|
439 '=3' => 'smile3.gif', '=-3' => 'smile3.gif', |
|
440 ';3' => 'wink3.gif', ';-3' => 'wink3.gif', |
|
441 '<g>' => 'teeth.gif', '<G>' => 'teeth.gif', |
|
442 'o.O' => 'boggle.gif', 'O.o' => 'boggle.gif', |
|
443 ':blue:' => 'blue.gif', |
|
444 ':zzz:' => 'sleepy.gif', |
|
445 '<3' => 'heart.gif', |
|
446 ':star:' => 'star.gif', |
|
447 ); |
|
448 var $default_tag_rules = Array( |
|
449 'b' => Array( |
|
450 'simple_start' => "<b>", |
|
451 'simple_end' => "</b>", |
|
452 'class' => 'inline', |
|
453 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
454 'plain_start' => "<b>", |
|
455 'plain_end' => "</b>", |
|
456 ), |
|
457 'i' => Array( |
|
458 'simple_start' => "<i>", |
|
459 'simple_end' => "</i>", |
|
460 'class' => 'inline', |
|
461 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
462 'plain_start' => "<i>", |
|
463 'plain_end' => "</i>", |
|
464 ), |
|
465 'u' => Array( |
|
466 'simple_start' => "<u>", |
|
467 'simple_end' => "</u>", |
|
468 'class' => 'inline', |
|
469 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
470 'plain_start' => "<u>", |
|
471 'plain_end' => "</u>", |
|
472 ), |
|
473 's' => Array( |
|
474 'simple_start' => "<strike>", |
|
475 'simple_end' => "</strike>", |
|
476 'class' => 'inline', |
|
477 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
478 'plain_start' => "<i>", |
|
479 'plain_end' => "</i>", |
|
480 ), |
|
481 'font' => Array( |
|
482 'mode' => BBCODE_MODE_LIBRARY, |
|
483 'allow' => Array('_default' => '/^[a-zA-Z0-9._ -]+$/'), |
|
484 'method' => 'DoFont', |
|
485 'class' => 'inline', |
|
486 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
487 ), |
|
488 'color' => Array( |
|
489 'mode' => BBCODE_MODE_ENHANCED, |
|
490 'allow' => Array('_default' => '/^#?[a-zA-Z0-9._ -]+$/'), |
|
491 'template' => '<span style="color:{$_default/tw}">{$_content/v}</span>', |
|
492 'class' => 'inline', |
|
493 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
494 ), |
|
495 'size' => Array( |
|
496 'mode' => BBCODE_MODE_LIBRARY, |
|
497 'allow' => Array('_default' => '/^[0-9.]+$/D'), |
|
498 'method' => 'DoSize', |
|
499 'class' => 'inline', |
|
500 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
501 ), |
|
502 'sup' => Array( |
|
503 'simple_start' => "<sup>", |
|
504 'simple_end' => "</sup>", |
|
505 'class' => 'inline', |
|
506 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
507 ), |
|
508 'sub' => Array( |
|
509 'simple_start' => "<sub>", |
|
510 'simple_end' => "</sub>", |
|
511 'class' => 'inline', |
|
512 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
513 ), |
|
514 'spoiler' => Array( |
|
515 'simple_start' => "<span class=\"bbcode_spoiler\">", |
|
516 'simple_end' => "</span>", |
|
517 'class' => 'inline', |
|
518 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
519 ), |
|
520 'acronym' => Array( |
|
521 'mode' => BBCODE_MODE_ENHANCED, |
|
522 'template' => '<span class="bbcode_acronym" title="{$_default/e}">{$_content/v}</span>', |
|
523 'class' => 'inline', |
|
524 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
525 ), |
|
526 'url' => Array( |
|
527 'mode' => BBCODE_MODE_LIBRARY, |
|
528 'method' => 'DoURL', |
|
529 'class' => 'link', |
|
530 'allow_in' => Array('listitem', 'block', 'columns', 'inline'), |
|
531 'content' => BBCODE_REQUIRED, |
|
532 'plain_start' => "<a href=\"{\$link}\">", |
|
533 'plain_end' => "</a>", |
|
534 'plain_content' => Array('_content', '_default'), |
|
535 'plain_link' => Array('_default', '_content'), |
|
536 ), |
|
537 'email' => Array( |
|
538 'mode' => BBCODE_MODE_LIBRARY, |
|
539 'method' => 'DoEmail', |
|
540 'class' => 'link', |
|
541 'allow_in' => Array('listitem', 'block', 'columns', 'inline'), |
|
542 'content' => BBCODE_REQUIRED, |
|
543 'plain_start' => "<a href=\"mailto:{\$link}\">", |
|
544 'plain_end' => "</a>", |
|
545 'plain_content' => Array('_content', '_default'), |
|
546 'plain_link' => Array('_default', '_content'), |
|
547 ), |
|
548 'wiki' => Array( |
|
549 'mode' => BBCODE_MODE_LIBRARY, |
|
550 'method' => "DoWiki", |
|
551 'class' => 'link', |
|
552 'allow_in' => Array('listitem', 'block', 'columns', 'inline'), |
|
553 'end_tag' => BBCODE_PROHIBIT, |
|
554 'content' => BBCODE_PROHIBIT, |
|
555 'plain_start' => "<b>[", |
|
556 'plain_end' => "]</b>", |
|
557 'plain_content' => Array('title', '_default'), |
|
558 'plain_link' => Array('_default', '_content'), |
|
559 ), |
|
560 'img' => Array( |
|
561 'mode' => BBCODE_MODE_LIBRARY, |
|
562 'method' => "DoImage", |
|
563 'class' => 'image', |
|
564 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
565 'end_tag' => BBCODE_REQUIRED, |
|
566 'content' => BBCODE_REQUIRED, |
|
567 'plain_start' => "[image]", |
|
568 'plain_content' => Array(), |
|
569 ), |
|
570 'rule' => Array( |
|
571 'mode' => BBCODE_MODE_LIBRARY, |
|
572 'method' => "DoRule", |
|
573 'class' => 'block', |
|
574 'allow_in' => Array('listitem', 'block', 'columns'), |
|
575 'end_tag' => BBCODE_PROHIBIT, |
|
576 'content' => BBCODE_PROHIBIT, |
|
577 'before_tag' => "sns", |
|
578 'after_tag' => "sns", |
|
579 'plain_start' => "\n-----\n", |
|
580 'plain_end' => "", |
|
581 'plain_content' => Array(), |
|
582 ), |
|
583 'br' => Array( |
|
584 'mode' => BBCODE_MODE_SIMPLE, |
|
585 'simple_start' => "<br />\n", |
|
586 'simple_end' => "", |
|
587 'class' => 'inline', |
|
588 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), |
|
589 'end_tag' => BBCODE_PROHIBIT, |
|
590 'content' => BBCODE_PROHIBIT, |
|
591 'before_tag' => "s", |
|
592 'after_tag' => "s", |
|
593 'plain_start' => "\n", |
|
594 'plain_end' => "", |
|
595 'plain_content' => Array(), |
|
596 ), |
|
597 'left' => Array( |
|
598 'simple_start' => "\n<div class=\"bbcode_left\" style=\"text-align:left\">\n", |
|
599 'simple_end' => "\n</div>\n", |
|
600 'allow_in' => Array('listitem', 'block', 'columns'), |
|
601 'before_tag' => "sns", |
|
602 'after_tag' => "sns", |
|
603 'before_endtag' => "sns", |
|
604 'after_endtag' => "sns", |
|
605 'plain_start' => "\n", |
|
606 'plain_end' => "\n", |
|
607 ), |
|
608 'right' => Array( |
|
609 'simple_start' => "\n<div class=\"bbcode_right\" style=\"text-align:right\">\n", |
|
610 'simple_end' => "\n</div>\n", |
|
611 'allow_in' => Array('listitem', 'block', 'columns'), |
|
612 'before_tag' => "sns", |
|
613 'after_tag' => "sns", |
|
614 'before_endtag' => "sns", |
|
615 'after_endtag' => "sns", |
|
616 'plain_start' => "\n", |
|
617 'plain_end' => "\n", |
|
618 ), |
|
619 'center' => Array( |
|
620 'simple_start' => "\n<div class=\"bbcode_center\" style=\"text-align:center\">\n", |
|
621 'simple_end' => "\n</div>\n", |
|
622 'allow_in' => Array('listitem', 'block', 'columns'), |
|
623 'before_tag' => "sns", |
|
624 'after_tag' => "sns", |
|
625 'before_endtag' => "sns", |
|
626 'after_endtag' => "sns", |
|
627 'plain_start' => "\n", |
|
628 'plain_end' => "\n", |
|
629 ), |
|
630 'indent' => Array( |
|
631 'simple_start' => "\n<div class=\"bbcode_indent\" style=\"margin-left:4em\">\n", |
|
632 'simple_end' => "\n</div>\n", |
|
633 'allow_in' => Array('listitem', 'block', 'columns'), |
|
634 'before_tag' => "sns", |
|
635 'after_tag' => "sns", |
|
636 'before_endtag' => "sns", |
|
637 'after_endtag' => "sns", |
|
638 'plain_start' => "\n", |
|
639 'plain_end' => "\n", |
|
640 ), |
|
641 'columns' => Array( |
|
642 'simple_start' => "\n<table class=\"bbcode_columns\"><tbody><tr><td class=\"bbcode_column bbcode_firstcolumn\">\n", |
|
643 'simple_end' => "\n</td></tr></tbody></table>\n", |
|
644 'class' => 'columns', |
|
645 'allow_in' => Array('listitem', 'block', 'columns'), |
|
646 'end_tag' => BBCODE_REQUIRED, |
|
647 'content' => BBCODE_REQUIRED, |
|
648 'before_tag' => "sns", |
|
649 'after_tag' => "sns", |
|
650 'before_endtag' => "sns", |
|
651 'after_endtag' => "sns", |
|
652 'plain_start' => "\n", |
|
653 'plain_end' => "\n", |
|
654 ), |
|
655 'nextcol' => Array( |
|
656 'simple_start' => "\n</td><td class=\"bbcode_column\">\n", |
|
657 'class' => 'nextcol', |
|
658 'allow_in' => Array('columns'), |
|
659 'end_tag' => BBCODE_PROHIBIT, |
|
660 'content' => BBCODE_PROHIBIT, |
|
661 'before_tag' => "sns", |
|
662 'after_tag' => "sns", |
|
663 'before_endtag' => "sns", |
|
664 'after_endtag' => "sns", |
|
665 'plain_start' => "\n", |
|
666 'plain_end' => "", |
|
667 ), |
|
668 'code' => Array( |
|
669 'mode' => BBCODE_MODE_ENHANCED, |
|
670 'template' => "\n<div class=\"bbcode_code\">\n<div class=\"bbcode_code_head\">Code:</div>\n<div class=\"bbcode_code_body\" style=\"white-space:pre\">{\$_content/v}</div>\n</div>\n", |
|
671 'class' => 'code', |
|
672 'allow_in' => Array('listitem', 'block', 'columns'), |
|
673 'content' => BBCODE_VERBATIM, |
|
674 'before_tag' => "sns", |
|
675 'after_tag' => "sn", |
|
676 'before_endtag' => "sn", |
|
677 'after_endtag' => "sns", |
|
678 'plain_start' => "\n<b>Code:</b>\n", |
|
679 'plain_end' => "\n", |
|
680 ), |
|
681 'quote' => Array( |
|
682 'mode' => BBCODE_MODE_LIBRARY, |
|
683 'method' => "DoQuote", |
|
684 'allow_in' => Array('listitem', 'block', 'columns'), |
|
685 'before_tag' => "sns", |
|
686 'after_tag' => "sns", |
|
687 'before_endtag' => "sns", |
|
688 'after_endtag' => "sns", |
|
689 'plain_start' => "\n<b>Quote:</b>\n", |
|
690 'plain_end' => "\n", |
|
691 ), |
|
692 'list' => Array( |
|
693 'mode' => BBCODE_MODE_LIBRARY, |
|
694 'method' => 'DoList', |
|
695 'class' => 'list', |
|
696 'allow_in' => Array('listitem', 'block', 'columns'), |
|
697 'before_tag' => "sns", |
|
698 'after_tag' => "sns", |
|
699 'before_endtag' => "sns", |
|
700 'after_endtag' => "sns", |
|
701 'plain_start' => "\n", |
|
702 'plain_end' => "\n", |
|
703 ), |
|
704 '*' => Array( |
|
705 'simple_start' => "<li>", |
|
706 'simple_end' => "</li>\n", |
|
707 'class' => 'listitem', |
|
708 'allow_in' => Array('list'), |
|
709 'end_tag' => BBCODE_OPTIONAL, |
|
710 'before_tag' => "s", |
|
711 'after_tag' => "s", |
|
712 'before_endtag' => "sns", |
|
713 'after_endtag' => "sns", |
|
714 'plain_start' => "\n * ", |
|
715 'plain_end' => "\n", |
|
716 ), |
|
717 ); |
|
718 function DoURL($bbcode, $action, $name, $default, $params, $content) { |
|
719 if ($action == BBCODE_CHECK) return true; |
|
720 $url = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content)); |
|
721 if ($bbcode->IsValidURL($url)) { |
|
722 if ($bbcode->debug) |
|
723 print "ISVALIDURL<br />"; |
|
724 if ($bbcode->url_targetable !== false && isset($params['target'])) |
|
725 $target = " target=\"" . htmlspecialchars($params['target']) . "\""; |
|
726 else $target = ""; |
|
727 if ($bbcode->url_target !== false) |
|
728 if (!($bbcode->url_targetable == 'override' && isset($params['target']))) |
|
729 $target = " target=\"" . htmlspecialchars($bbcode->url_target) . "\""; |
|
730 return '<a href="' . htmlspecialchars($url) . '" class="bbcode_url"' . $target . '>' . $content . '</a>'; |
|
731 } |
|
732 else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']); |
|
733 } |
|
734 function DoEmail($bbcode, $action, $name, $default, $params, $content) { |
|
735 if ($action == BBCODE_CHECK) return true; |
|
736 $email = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content)); |
|
737 if ($bbcode->IsValidEmail($email)) |
|
738 return '<a href="mailto:' . htmlspecialchars($email) . '" class="bbcode_email">' . $content . '</a>'; |
|
739 else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']); |
|
740 } |
|
741 function DoSize($bbcode, $action, $name, $default, $params, $content) { |
|
742 switch ($default) { |
|
743 case '0': $size = '.5em'; break; |
|
744 case '1': $size = '.67em'; break; |
|
745 case '2': $size = '.83em'; break; |
|
746 default: |
|
747 case '3': $size = '1.0em'; break; |
|
748 case '4': $size = '1.17em'; break; |
|
749 case '5': $size = '1.5em'; break; |
|
750 case '6': $size = '2.0em'; break; |
|
751 case '7': $size = '2.5em'; break; |
|
752 } |
|
753 return "<span style=\"font-size:$size\">$content</span>"; |
|
754 } |
|
755 function DoFont($bbcode, $action, $name, $default, $params, $content) { |
|
756 $fonts = explode(",", $default); |
|
757 $result = ""; |
|
758 $special_fonts = Array( |
|
759 'serif' => 'serif', |
|
760 'sans-serif' => 'sans-serif', |
|
761 'sans serif' => 'sans-serif', |
|
762 'sansserif' => 'sans-serif', |
|
763 'sans' => 'sans-serif', |
|
764 'cursive' => 'cursive', |
|
765 'fantasy' => 'fantasy', |
|
766 'monospace' => 'monospace', |
|
767 'mono' => 'monospace', |
|
768 ); |
|
769 foreach ($fonts as $font) { |
|
770 $font = trim($font); |
|
771 if (isset($special_fonts[$font])) { |
|
772 if (strlen($result) > 0) $result .= ","; |
|
773 $result .= $special_fonts[$font]; |
|
774 } |
|
775 else if (strlen($font) > 0) { |
|
776 if (strlen($result) > 0) $result .= ","; |
|
777 $result .= "'$font'"; |
|
778 } |
|
779 } |
|
780 return "<span style=\"font-family:$result\">$content</span>"; |
|
781 } |
|
782 function DoWiki($bbcode, $action, $name, $default, $params, $content) { |
|
783 $name = $bbcode->Wikify($default); |
|
784 if ($action == BBCODE_CHECK) |
|
785 return strlen($name) > 0; |
|
786 $title = trim(@$params['title']); |
|
787 if (strlen($title) <= 0) $title = trim($default); |
|
788 return "<a href=\"{$bbcode->wiki_url}$name\" class=\"bbcode_wiki\">" |
|
789 . htmlspecialchars($title) . "</a>"; |
|
790 } |
|
791 function DoImage($bbcode, $action, $name, $default, $params, $content) { |
|
792 if ($action == BBCODE_CHECK) return true; |
|
793 $content = trim($bbcode->UnHTMLEncode(strip_tags($content))); |
|
794 if (preg_match("/\\.(?:gif|jpeg|jpg|jpe|png)$/", $content)) { |
|
795 if (preg_match("/^[a-zA-Z0-9_][^:]+$/", $content)) { |
|
796 if (!preg_match("/(?:\\/\\.\\.\\/)|(?:^\\.\\.\\/)|(?:^\\/)/", $content)) { |
|
797 $info = @getimagesize("{$bbcode->local_img_dir}/{$content}"); |
|
798 if ($info[2] == IMAGETYPE_GIF || $info[2] == IMAGETYPE_JPEG || $info[2] == IMAGETYPE_PNG) { |
|
799 return "<img src=\"" |
|
800 . htmlspecialchars("{$bbcode->local_img_url}/{$content}") . "\" alt=\"" |
|
801 . htmlspecialchars(basename($content)) . "\" width=\"" |
|
802 . htmlspecialchars($info[0]) . "\" height=\"" |
|
803 . htmlspecialchars($info[1]) . "\" class=\"bbcode_img\" />"; |
|
804 } |
|
805 } |
|
806 } |
|
807 else if ($bbcode->IsValidURL($content, false)) { |
|
808 return "<img src=\"" . htmlspecialchars($content) . "\" alt=\"" |
|
809 . htmlspecialchars(basename($content)) . "\" class=\"bbcode_img\" />"; |
|
810 } |
|
811 } |
|
812 return htmlspecialchars($params['_tag']) . htmlspecialchars($content) . htmlspecialchars($params['_endtag']); |
|
813 } |
|
814 function DoRule($bbcode, $action, $name, $default, $params, $content) { |
|
815 if ($action == BBCODE_CHECK) return true; |
|
816 else return $bbcode->rule_html; |
|
817 } |
|
818 function DoQuote($bbcode, $action, $name, $default, $params, $content) { |
|
819 if ($action == BBCODE_CHECK) return true; |
|
820 if (isset($params['name'])) { |
|
821 $title = htmlspecialchars(trim($params['name'])) . " wrote"; |
|
822 if (isset($params['date'])) |
|
823 $title .= " on " . htmlspecialchars(trim($params['date'])); |
|
824 $title .= ":"; |
|
825 if (isset($params['url'])) { |
|
826 $url = trim($params['url']); |
|
827 if ($bbcode->IsValidURL($url)) |
|
828 $title = "<a href=\"" . htmlspecialchars($params['url']) . "\">" . $title . "</a>"; |
|
829 } |
|
830 } |
|
831 else if (!is_string($default)) |
|
832 $title = "Quote:"; |
|
833 else $title = htmlspecialchars(trim($default)) . " wrote:"; |
|
834 return "\n<div class=\"bbcode_quote\">\n<div class=\"bbcode_quote_head\">" |
|
835 . $title . "</div>\n<div class=\"bbcode_quote_body\">" |
|
836 . $content . "</div>\n</div>\n"; |
|
837 } |
|
838 function DoList($bbcode, $action, $name, $default, $params, $content) { |
|
839 $list_styles = Array( |
|
840 '1' => 'decimal', |
|
841 '01' => 'decimal-leading-zero', |
|
842 'i' => 'lower-roman', |
|
843 'I' => 'upper-roman', |
|
844 'a' => 'lower-alpha', |
|
845 'A' => 'upper-alpha', |
|
846 ); |
|
847 $ci_list_styles = Array( |
|
848 'circle' => 'circle', |
|
849 'disc' => 'disc', |
|
850 'square' => 'square', |
|
851 'greek' => 'lower-greek', |
|
852 'armenian' => 'armenian', |
|
853 'georgian' => 'georgian', |
|
854 ); |
|
855 $ul_types = Array( |
|
856 'circle' => 'circle', |
|
857 'disc' => 'disc', |
|
858 'square' => 'square', |
|
859 ); |
|
860 $default = trim($default); |
|
861 if ($action == BBCODE_CHECK) { |
|
862 if (!is_string($default) || strlen($default) == "") return true; |
|
863 else if (isset($list_styles[$default])) return true; |
|
864 else if (isset($ci_list_styles[strtolower($default)])) return true; |
|
865 else return false; |
|
866 } |
|
867 if (!is_string($default) || strlen($default) == "") { |
|
868 $elem = 'ul'; |
|
869 $type = ''; |
|
870 } |
|
871 else if ($default == '1') { |
|
872 $elem = 'ol'; |
|
873 $type = ''; |
|
874 } |
|
875 else if (isset($list_styles[$default])) { |
|
876 $elem = 'ol'; |
|
877 $type = $list_styles[$default]; |
|
878 } |
|
879 else { |
|
880 $default = strtolower($default); |
|
881 if (isset($ul_types[$default])) { |
|
882 $elem = 'ul'; |
|
883 $type = $ul_types[$default]; |
|
884 } |
|
885 else if (isset($ci_list_styles[$default])) { |
|
886 $elem = 'ol'; |
|
887 $type = $ci_list_styles[$default]; |
|
888 } |
|
889 } |
|
890 if (strlen($type)) |
|
891 return "\n<$elem class=\"bbcode_list\" style=\"list-style-type:$type\">\n$content</$elem>\n"; |
|
892 else return "\n<$elem class=\"bbcode_list\">\n$content</$elem>\n"; |
|
893 } |
|
894 } |
|
895 |
|
896 class BBCodeEmailAddressValidator { |
|
897 function check_email_address($strEmailAddress) { |
|
898 if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) { |
|
899 return false; |
|
900 } |
|
901 $intAtSymbol = strrpos($strEmailAddress, '@'); |
|
902 if ($intAtSymbol === false) { |
|
903 return false; |
|
904 } |
|
905 $arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol); |
|
906 $arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1); |
|
907 $arrTempAddress[0] = preg_replace('/"[^"]+"/' |
|
908 ,'' |
|
909 ,$arrEmailAddress[0]); |
|
910 $arrTempAddress[1] = $arrEmailAddress[1]; |
|
911 $strTempAddress = $arrTempAddress[0] . $arrTempAddress[1]; |
|
912 if (strrpos($strTempAddress, '@') !== false) { |
|
913 return false; |
|
914 } |
|
915 if (!$this->check_local_portion($arrEmailAddress[0])) { |
|
916 return false; |
|
917 } |
|
918 if (!$this->check_domain_portion($arrEmailAddress[1])) { |
|
919 return false; |
|
920 } |
|
921 return true; |
|
922 } |
|
923 function check_local_portion($strLocalPortion) { |
|
924 if (!$this->check_text_length($strLocalPortion, 1, 64)) { |
|
925 return false; |
|
926 } |
|
927 $arrLocalPortion = explode('.', $strLocalPortion); |
|
928 for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) { |
|
929 if (!preg_match('.^(' |
|
930 . '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]' |
|
931 . '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})' |
|
932 .'|' |
|
933 . '("[^\\\"]{0,62}")' |
|
934 .')$.' |
|
935 ,$arrLocalPortion[$i])) { |
|
936 return false; |
|
937 } |
|
938 } |
|
939 return true; |
|
940 } |
|
941 function check_domain_portion($strDomainPortion) { |
|
942 if (!$this->check_text_length($strDomainPortion, 1, 255)) { |
|
943 return false; |
|
944 } |
|
945 if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])' |
|
946 .'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/' |
|
947 ,$strDomainPortion) || |
|
948 preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])' |
|
949 .'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/' |
|
950 ,$strDomainPortion)) { |
|
951 return true; |
|
952 } else { |
|
953 $arrDomainPortion = explode('.', $strDomainPortion); |
|
954 if (sizeof($arrDomainPortion) < 2) { |
|
955 return false; |
|
956 } |
|
957 for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) { |
|
958 if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) { |
|
959 return false; |
|
960 } |
|
961 if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|' |
|
962 .'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) { |
|
963 return false; |
|
964 } |
|
965 } |
|
966 } |
|
967 return true; |
|
968 } |
|
969 function check_text_length($strText, $intMinimum, $intMaximum) { |
|
970 $intTextLength = strlen($strText); |
|
971 if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) { |
|
972 return false; |
|
973 } else { |
|
974 return true; |
|
975 } |
|
976 } |
|
977 } |
|
978 |
|
979 class BBCode { |
|
980 var $tag_rules; |
|
981 var $defaults; |
|
982 var $current_class; |
|
983 var $root_class; |
|
984 var $lost_start_tags; |
|
985 var $start_tags; |
|
986 var $allow_ampersand; |
|
987 var $tag_marker; |
|
988 var $ignore_newlines; |
|
989 var $plain_mode; |
|
990 var $detect_urls; |
|
991 var $url_pattern; |
|
992 var $output_limit; |
|
993 var $text_length; |
|
994 var $was_limited; |
|
995 var $limit_tail; |
|
996 var $limit_precision; |
|
997 var $smiley_dir; |
|
998 var $smiley_url; |
|
999 var $smileys; |
|
1000 var $smiley_regex; |
|
1001 var $enable_smileys; |
|
1002 var $wiki_url; |
|
1003 var $local_img_dir; |
|
1004 var $local_img_url; |
|
1005 var $url_targetable; |
|
1006 var $url_target; |
|
1007 var $rule_html; |
|
1008 var $pre_trim; |
|
1009 var $post_trim; |
|
1010 var $debug; |
|
1011 |
|
1012 |
|
1013 /* ADDED */ |
|
1014 // singleton instance |
|
1015 private static $instance; |
|
1016 |
|
1017 // private constructor function |
|
1018 // to prevent external instantiation |
|
1019 private function __construct() |
|
1020 { |
|
1021 $this->defaults = new BBCodeLibrary; |
|
1022 $this->tag_rules = $this->defaults->default_tag_rules; |
|
1023 $this->smileys = $this->defaults->default_smileys; |
|
1024 $this->enable_smileys = true; |
|
1025 $this->smiley_regex = false; |
|
1026 $this->smiley_dir = $this->GetDefaultSmileyDir(); |
|
1027 $this->smiley_url = $this->GetDefaultSmileyURL(); |
|
1028 $this->wiki_url = $this->GetDefaultWikiURL(); |
|
1029 $this->local_img_dir = $this->GetDefaultLocalImgDir(); |
|
1030 $this->local_img_url = $this->GetDefaultLocalImgURL(); |
|
1031 $this->rule_html = $this->GetDefaultRuleHTML(); |
|
1032 $this->pre_trim = ""; |
|
1033 $this->post_trim = ""; |
|
1034 $this->root_class = 'block'; |
|
1035 $this->lost_start_tags = Array(); |
|
1036 $this->start_tags = Array(); |
|
1037 $this->tag_marker = '['; |
|
1038 $this->allow_ampsersand = false; |
|
1039 $this->current_class = $this->root_class; |
|
1040 $this->debug = false; |
|
1041 $this->ignore_newlines = false; |
|
1042 $this->output_limit = 0; |
|
1043 $this->plain_mode = false; |
|
1044 $this->was_limited = false; |
|
1045 $this->limit_tail = "..."; |
|
1046 $this->limit_precision = 0.15; |
|
1047 $this->detect_urls = false; |
|
1048 $this->url_pattern = '<a href="{$url/h}">{$text/h}</a>'; |
|
1049 $this->url_targetable = false; |
|
1050 $this->url_target = false; |
|
1051 } |
|
1052 |
|
1053 // getInstance method |
|
1054 public static function getInstance() |
|
1055 { |
|
1056 if(!self::$instance) |
|
1057 { |
|
1058 self::$instance = new self(); |
|
1059 } |
|
1060 |
|
1061 return self::$instance; |
|
1062 } |
|
1063 /* ADDED */ |
|
1064 |
|
1065 |
|
1066 function SetPreTrim($trim = "a") { $this->pre_trim = $trim; } |
|
1067 function GetPreTrim() { return $this->pre_trim; } |
|
1068 function SetPostTrim($trim = "a") { $this->post_trim = $trim; } |
|
1069 function GetPostTrim() { return $this->post_trim; } |
|
1070 function SetRoot($class = 'block') { $this->root_class = $class; } |
|
1071 function SetRootInline() { $this->root_class = 'inline'; } |
|
1072 function SetRootBlock() { $this->root_class = 'block'; } |
|
1073 function GetRoot() { return $this->root_class; } |
|
1074 function SetDebug($enable = true) { $this->debug = $enable; } |
|
1075 function GetDebug() { return $this->debug; } |
|
1076 function SetAllowAmpersand($enable = true) { $this->allow_ampersand = $enable; } |
|
1077 function GetAllowAmpersand() { return $this->allow_ampersand; } |
|
1078 function SetTagMarker($marker = '[') { $this->tag_marker = $marker; } |
|
1079 function GetTagMarker() { return $this->tag_marker; } |
|
1080 function SetIgnoreNewlines($ignore = true) { $this->ignore_newlines = $ignore; } |
|
1081 function GetIgnoreNewlines() { return $this->ignore_newlines; } |
|
1082 function SetLimit($limit = 0) { $this->output_limit = $limit; } |
|
1083 function GetLimit() { return $this->output_limit; } |
|
1084 function SetLimitTail($tail = "...") { $this->limit_tail = $tail; } |
|
1085 function GetLimitTail() { return $this->limit_tail; } |
|
1086 function SetLimitPrecision($prec = 0.15) { $this->limit_precision = $prec; } |
|
1087 function GetLimitPrecision() { return $this->limit_precision; } |
|
1088 function WasLimited() { return $this->was_limited; } |
|
1089 function SetPlainMode($enable = true) { $this->plain_mode = $enable; } |
|
1090 function GetPlainMode() { return $this->plain_mode; } |
|
1091 function SetDetectURLs($enable = true) { $this->detect_urls = $enable; } |
|
1092 function GetDetectURLs() { return $this->detect_urls; } |
|
1093 function SetURLPattern($pattern) { $this->url_pattern = $pattern; } |
|
1094 function GetURLPattern() { return $this->url_pattern; } |
|
1095 function SetURLTargetable($enable) { $this->url_targetable = $enable; } |
|
1096 function GetURLTargetable() { return $this->url_targetable; } |
|
1097 function SetURLTarget($target) { $this->url_target = $target; } |
|
1098 function GetURLTarget() { return $this->url_target; } |
|
1099 function AddRule($name, $rule) { $this->tag_rules[$name] = $rule; } |
|
1100 function RemoveRule($name) { unset($this->tag_rules[$name]); } |
|
1101 function GetRule($name) { return isset($this->tag_rules[$name]) |
|
1102 ? $this->tag_rules[$name] : false; } |
|
1103 function ClearRules() { $this->tag_rules = Array(); } |
|
1104 function GetDefaultRule($name) { return isset($this->defaults->default_tag_rules[$name]) |
|
1105 ? $this->defaults->default_tag_rules[$name] : false; } |
|
1106 function SetDefaultRule($name) { if (isset($this->defaults->default_tag_rules[$name])) |
|
1107 $this->AddRule($name, $this->defaults->default_tag_rules[$name]); |
|
1108 else $this->RemoveRule($name); } |
|
1109 function GetDefaultRules() { return $this->defaults->default_tag_rules; } |
|
1110 function SetDefaultRules() { $this->tag_rules = $this->defaults->default_tag_rules; } |
|
1111 function SetWikiURL($url) { $this->wiki_url = $url; } |
|
1112 function GetWikiURL($url) { return $this->wiki_url; } |
|
1113 function GetDefaultWikiURL() { return '/?page='; } |
|
1114 function SetLocalImgDir($path) { $this->local_img_dir = $path; } |
|
1115 function GetLocalImgDir() { return $this->local_img_dir; } |
|
1116 function GetDefaultLocalImgDir() { return "img"; } |
|
1117 function SetLocalImgURL($path) { $this->local_img_url = $path; } |
|
1118 function GetLocalImgURL() { return $this->local_img_url; } |
|
1119 function GetDefaultLocalImgURL() { return "img"; } |
|
1120 function SetRuleHTML($html) { $this->rule_html = $html; } |
|
1121 function GetRuleHTML() { return $this->rule_html; } |
|
1122 function GetDefaultRuleHTML() { return "\n<hr class=\"bbcode_rule\" />\n"; } |
|
1123 function AddSmiley($code, $image) { $this->smileys[$code] = $image; $this->smiley_regex = false; } |
|
1124 function RemoveSmiley($code) { unset($this->smileys[$code]); $this->smiley_regex = false; } |
|
1125 function GetSmiley($code) { return isset($this->smileys[$code]) |
|
1126 ? $this->smileys[$code] : false; } |
|
1127 function ClearSmileys() { $this->smileys = Array(); $this->smiley_regex = false; } |
|
1128 function GetDefaultSmiley($code) { return isset($this->defaults->default_smileys[$code]) |
|
1129 ? $this->defaults->default_smileys[$code] : false; } |
|
1130 function SetDefaultSmiley($code) { $this->smileys[$code] = @$this->defaults->default_smileys[$code]; |
|
1131 $this->smiley_regex = false; } |
|
1132 function GetDefaultSmileys() { return $this->defaults->default_smileys; } |
|
1133 function SetDefaultSmileys() { $this->smileys = $this->defaults->default_smileys; |
|
1134 $this->smiley_regex = false; } |
|
1135 function SetSmileyDir($path) { $this->smiley_dir = $path; } |
|
1136 function GetSmileyDir() { return $this->smiley_dir; } |
|
1137 function GetDefaultSmileyDir() { return "smileys"; } |
|
1138 function SetSmileyURL($path) { $this->smiley_url = $path; } |
|
1139 function GetSmileyURL() { return $this->smiley_url; } |
|
1140 function GetDefaultSmileyURL() { return "smileys"; } |
|
1141 function SetEnableSmileys($enable = true) { $this->enable_smileys = $enable; } |
|
1142 function GetEnableSmileys() { return $this->enable_smileys; } |
|
1143 function nl2br($string) { |
|
1144 return preg_replace("/\\x0A|\\x0D|\\x0A\\x0D|\\x0D\\x0A/", "<br />\n", $string); |
|
1145 } |
|
1146 function UnHTMLEncode($string) { |
|
1147 if (function_exists("html_entity_decode")) |
|
1148 return html_entity_decode($string); |
|
1149 $string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string); |
|
1150 $string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string); |
|
1151 $trans_tbl = get_html_translation_table(HTML_ENTITIES); |
|
1152 $trans_tbl = array_flip($trans_tbl); |
|
1153 return strtr($string, $trans_tbl); |
|
1154 } |
|
1155 function Wikify($string) { |
|
1156 return rawurlencode(str_replace(" ", "_", |
|
1157 trim(preg_replace("/[!?;@#\$%\\^&*<>=+`~\\x00-\\x20_-]+/", " ", $string)))); |
|
1158 } |
|
1159 function IsValidURL($string, $email_too = true) { |
|
1160 if (preg_match("/^ |
|
1161 (?:https?|ftp):\\/\\/ |
|
1162 (?: |
|
1163 (?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+ |
|
1164 [a-zA-Z0-9] |
|
1165 (?:[a-zA-Z0-9-]*[a-zA-Z0-9])? |
|
1166 | |
|
1167 \\[ |
|
1168 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3} |
|
1169 (?: |
|
1170 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]: |
|
1171 (?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F] |
|
1172 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+ |
|
1173 ) |
|
1174 \\] |
|
1175 ) |
|
1176 (?::[0-9]{1,5})? |
|
1177 (?:[\\/\\?\\#][^\\n\\r]*)? |
|
1178 $/Dx", $string)) return true; |
|
1179 if (preg_match("/^[^:]+([\\/\\\\?#][^\\r\\n]*)?$/D", $string)) |
|
1180 return true; |
|
1181 if ($email_too) |
|
1182 if (substr($string, 0, 7) == "mailto:") |
|
1183 return $this->IsValidEmail(substr($string, 7)); |
|
1184 return false; |
|
1185 } |
|
1186 function IsValidEmail($string) { |
|
1187 $validator = new BBCodeEmailAddressValidator; |
|
1188 return $validator->check_email_address($string); |
|
1189 /* |
|
1190 return preg_match("/^ |
|
1191 (?: |
|
1192 [a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+ |
|
1193 (?:\.[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+)* |
|
1194 | |
|
1195 \"(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F] |
|
1196 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])*\" |
|
1197 ) |
|
1198 @ |
|
1199 (?: |
|
1200 (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+ |
|
1201 [a-z0-9] |
|
1202 (?:[a-z0-9-]*[a-z0-9])? |
|
1203 | |
|
1204 \\[ |
|
1205 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3} |
|
1206 (?: |
|
1207 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]: |
|
1208 (?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F] |
|
1209 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+ |
|
1210 ) |
|
1211 \\] |
|
1212 ) |
|
1213 $/Dx", $string); |
|
1214 */ |
|
1215 } |
|
1216 function HTMLEncode($string) { |
|
1217 if (!$this->allow_ampersand) |
|
1218 return htmlspecialchars($string); |
|
1219 else return str_replace(Array('<', '>', '"'), |
|
1220 Array('<', '>', '"'), $string); |
|
1221 } |
|
1222 function FixupOutput($string) { |
|
1223 if (!$this->detect_urls) { |
|
1224 $output = $this->Internal_ProcessSmileys($string); |
|
1225 } |
|
1226 else { |
|
1227 $chunks = $this->Internal_AutoDetectURLs($string); |
|
1228 $output = Array(); |
|
1229 if (count($chunks)) { |
|
1230 $is_a_url = false; |
|
1231 foreach ($chunks as $index => $chunk) { |
|
1232 if (!$is_a_url) { |
|
1233 $chunk = $this->Internal_ProcessSmileys($chunk); |
|
1234 } |
|
1235 $output[] = $chunk; |
|
1236 $is_a_url = !$is_a_url; |
|
1237 } |
|
1238 } |
|
1239 $output = implode("", $output); |
|
1240 } |
|
1241 return $output; |
|
1242 } |
|
1243 function Internal_ProcessSmileys($string) { |
|
1244 if (!$this->enable_smileys || $this->plain_mode) { |
|
1245 $output = $this->HTMLEncode($string); |
|
1246 } |
|
1247 else { |
|
1248 if ($this->smiley_regex === false) { |
|
1249 $this->Internal_RebuildSmileys(); |
|
1250 } |
|
1251 $tokens = preg_split($this->smiley_regex, $string, -1, PREG_SPLIT_DELIM_CAPTURE); |
|
1252 if (count($tokens) <= 1) { |
|
1253 $output = $this->HTMLEncode($string); |
|
1254 } |
|
1255 else { |
|
1256 $output = ""; |
|
1257 $is_a_smiley = false; |
|
1258 foreach ($tokens as $token) { |
|
1259 if (!$is_a_smiley) { |
|
1260 $output .= $this->HTMLEncode($token); |
|
1261 } |
|
1262 else { |
|
1263 if (isset($this->smiley_info[$token])) { |
|
1264 $info = $this->smiley_info[$token]; |
|
1265 } |
|
1266 else { |
|
1267 $info = @getimagesize($this->smiley_dir . '/' . $this->smileys[$token]); |
|
1268 $this->smiley_info[$token] = $info; |
|
1269 } |
|
1270 $alt = htmlspecialchars($token); |
|
1271 $output .= "<img src=\"" . htmlspecialchars($this->smiley_url . '/' . $this->smileys[$token]) |
|
1272 . "\" width=\"{$info[0]}\" height=\"{$info[1]}\"" |
|
1273 . " alt=\"$alt\" title=\"$alt\" class=\"bbcode_smiley\" />"; |
|
1274 } |
|
1275 $is_a_smiley = !$is_a_smiley; |
|
1276 } |
|
1277 } |
|
1278 } |
|
1279 return $output; |
|
1280 } |
|
1281 function Internal_RebuildSmileys() { |
|
1282 $regex = Array("/(?<![\\w])("); |
|
1283 $first = true; |
|
1284 foreach ($this->smileys as $code => $filename) { |
|
1285 if (!$first) $regex[] = "|"; |
|
1286 $regex[] = preg_quote("$code", '/'); |
|
1287 $first = false; |
|
1288 } |
|
1289 $regex[] = ")(?![\\w])/"; |
|
1290 $this->smiley_regex = implode("", $regex); |
|
1291 } |
|
1292 function Internal_AutoDetectURLs($string) { |
|
1293 $output = preg_split("/( (?: |
|
1294 (?:https?|ftp) : \\/* |
|
1295 (?: |
|
1296 (?: (?: [a-zA-Z0-9-]{2,} \\. )+ |
|
1297 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2} |
|
1298 | aero | biz | coop | info | museum | name | pro |
|
1299 | example | invalid | localhost | test | local | onion | swift ) ) |
|
1300 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} ) |
|
1301 | (?: [0-9A-Fa-f:]+ : [0-9A-Fa-f]{1,4} ) |
|
1302 ) |
|
1303 (?: : [0-9]+ )? |
|
1304 (?! [a-zA-Z0-9.:-] ) |
|
1305 (?: |
|
1306 \\/ |
|
1307 [^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]* |
|
1308 )? |
|
1309 (?: |
|
1310 [?#] |
|
1311 [^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+ |
|
1312 )? |
|
1313 ) | (?: |
|
1314 (?: |
|
1315 (?: (?: [a-zA-Z0-9-]{2,} \\. )+ |
|
1316 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2} |
|
1317 | aero | biz | coop | info | museum | name | pro |
|
1318 | example | invalid | localhost | test | local | onion | swift ) ) |
|
1319 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} ) |
|
1320 ) |
|
1321 (?: : [0-9]+ )? |
|
1322 (?! [a-zA-Z0-9.:-] ) |
|
1323 (?: |
|
1324 \\/ |
|
1325 [^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]* |
|
1326 )? |
|
1327 (?: |
|
1328 [?#] |
|
1329 [^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+ |
|
1330 )? |
|
1331 ) | (?: |
|
1332 [a-zA-Z0-9._-]{2,} @ |
|
1333 (?: |
|
1334 (?: (?: [a-zA-Z0-9-]{2,} \\. )+ |
|
1335 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2} |
|
1336 | aero | biz | coop | info | museum | name | pro |
|
1337 | example | invalid | localhost | test | local | onion | swift ) ) |
|
1338 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} ) |
|
1339 ) |
|
1340 ) )/Dx", $string, -1, PREG_SPLIT_DELIM_CAPTURE); |
|
1341 if (count($output) > 1) { |
|
1342 $is_a_url = false; |
|
1343 foreach ($output as $index => $token) { |
|
1344 if ($is_a_url) { |
|
1345 if (preg_match("/^[a-zA-Z0-9._-]{2,}@/", $token)) { |
|
1346 $url = "mailto:" . $token; |
|
1347 } |
|
1348 else if (preg_match("/^(https?:|ftp:)\\/*([^\\/&?#]+)\\/*(.*)\$/", $token, $matches)) { |
|
1349 $url = $matches[1] . '/' . '/' . $matches[2] . "/" . $matches[3]; |
|
1350 } |
|
1351 else { |
|
1352 preg_match("/^([^\\/&?#]+)\\/*(.*)\$/", $token, $matches); |
|
1353 $url = "http:/" . "/" . $matches[1] . "/" . $matches[2]; |
|
1354 } |
|
1355 $params = @parse_url($url); |
|
1356 if (!is_array($params)) $params = Array(); |
|
1357 $params['url'] = $url; |
|
1358 $params['link'] = $url; |
|
1359 $params['text'] = $token; |
|
1360 $output[$index] = $this->FillTemplate($this->url_pattern, $params); |
|
1361 } |
|
1362 $is_a_url = !$is_a_url; |
|
1363 } |
|
1364 } |
|
1365 return $output; |
|
1366 } |
|
1367 function FillTemplate($template, $insert_array, $default_array = Array()) { |
|
1368 $pieces = preg_split('/(\{\$[a-zA-Z0-9_.:\/-]+\})/', $template, |
|
1369 -1, PREG_SPLIT_DELIM_CAPTURE); |
|
1370 if (count($pieces) <= 1) |
|
1371 return $template; |
|
1372 $result = Array(); |
|
1373 $is_an_insert = false; |
|
1374 foreach ($pieces as $piece) { |
|
1375 if (!$is_an_insert) { |
|
1376 $result[] = $piece; |
|
1377 } |
|
1378 else if (!preg_match('/\{\$([a-zA-Z0-9_:-]+)((?:\\.[a-zA-Z0-9_:-]+)*)(?:\/([a-zA-Z0-9_:-]+))?\}/', $piece, $matches)) { |
|
1379 $result[] = $piece; |
|
1380 } |
|
1381 else { |
|
1382 if (isset($insert_array[$matches[1]])) |
|
1383 $value = @$insert_array[$matches[1]]; |
|
1384 else $value = @$default_array[$matches[1]]; |
|
1385 if (strlen(@$matches[2])) { |
|
1386 foreach (split(".", substr($matches[2], 1)) as $index) { |
|
1387 if (is_array($value)) |
|
1388 $value = @$value[$index]; |
|
1389 else if (is_object($value)) { |
|
1390 $value = (array)$value; |
|
1391 $value = @$value[$index]; |
|
1392 } |
|
1393 else $value = ""; |
|
1394 } |
|
1395 } |
|
1396 switch (gettype($value)) { |
|
1397 case 'boolean': $value = $value ? "true" : "false"; break; |
|
1398 case 'integer': $value = (string)$value; break; |
|
1399 case 'double': $value = (string)$value; break; |
|
1400 case 'string': break; |
|
1401 default: $value = ""; break; |
|
1402 } |
|
1403 if (strlen(@$matches[3])) |
|
1404 $flags = array_flip(str_split($matches[3])); |
|
1405 else $flags = Array(); |
|
1406 if (!isset($flags['v'])) { |
|
1407 if (isset($flags['w'])) |
|
1408 $value = preg_replace("/[\\x00-\\x09\\x0B-\x0C\x0E-\\x20]+/", " ", $value); |
|
1409 if (isset($flags['t'])) $value = trim($value); |
|
1410 if (isset($flags['b'])) $value = basename($value); |
|
1411 if (isset($flags['e'])) $value = $this->HTMLEncode($value); |
|
1412 else if (isset($flags['k'])) $value = $this->Wikify($value); |
|
1413 else if (isset($flags['h'])) $value = htmlspecialchars($value); |
|
1414 else if (isset($flags['u'])) $value = urlencode($value); |
|
1415 if (isset($flags['n'])) $value = $this->nl2br($value); |
|
1416 } |
|
1417 $result[] = $value; |
|
1418 } |
|
1419 $is_an_insert = !$is_an_insert; |
|
1420 } |
|
1421 return implode("", $result); |
|
1422 } |
|
1423 function Internal_CollectText($array, $start = 0) { |
|
1424 ob_start(); |
|
1425 for ($start = intval($start), $end = count($array); $start < $end; $start++) |
|
1426 print $array[$start][BBCODE_STACK_TEXT]; |
|
1427 $output = ob_get_contents(); |
|
1428 ob_end_clean(); |
|
1429 return $output; |
|
1430 } |
|
1431 function Internal_CollectTextReverse($array, $start = 0, $end = 0) { |
|
1432 ob_start(); |
|
1433 for ($start = intval($start); $start >= $end; $start--) |
|
1434 print $array[$start][BBCODE_STACK_TEXT]; |
|
1435 $output = ob_get_contents(); |
|
1436 ob_end_clean(); |
|
1437 return $output; |
|
1438 } |
|
1439 function Internal_GenerateOutput($pos) { |
|
1440 $output = Array(); |
|
1441 while (count($this->stack) > $pos) { |
|
1442 $token = array_pop($this->stack); |
|
1443 if ($token[BBCODE_STACK_TOKEN] != BBCODE_TAG) { |
|
1444 $output[] = $token; |
|
1445 } |
|
1446 else { |
|
1447 $name = @$token[BBCODE_STACK_TAG]['_name']; |
|
1448 $rule = @$this->tag_rules[$name]; |
|
1449 $end_tag = @$rule['end_tag']; |
|
1450 if (!isset($rule['end_tag'])) $end_tag = BBCODE_REQUIRED; |
|
1451 else $end_tag = $rule['end_tag']; |
|
1452 array_pop($this->start_tags[$name]); |
|
1453 if ($end_tag == BBCODE_PROHIBIT) { |
|
1454 $output[] = Array( |
|
1455 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1456 BBCODE_STACK_TAG => false, |
|
1457 BBCODE_STACK_TEXT => $token[BBCODE_STACK_TEXT], |
|
1458 BBCODE_STACK_CLASS => $this->current_class, |
|
1459 ); |
|
1460 } |
|
1461 else { |
|
1462 if ($end_tag == BBCODE_REQUIRED) |
|
1463 @$this->lost_start_tags[$name] += 1; |
|
1464 $end = $this->Internal_CleanupWSByIteratingPointer(@$rule['before_endtag'], 0, $output); |
|
1465 $this->Internal_CleanupWSByPoppingStack(@$rule['after_tag'], $output); |
|
1466 $tag_body = $this->Internal_CollectTextReverse($output, count($output)-1, $end); |
|
1467 $this->Internal_CleanupWSByPoppingStack(@$rule['before_tag'], $this->stack); |
|
1468 $this->Internal_UpdateParamsForMissingEndTag(@$token[BBCODE_STACK_TAG]); |
|
1469 $tag_output = $this->DoTag(BBCODE_OUTPUT, $name, |
|
1470 @$token[BBCODE_STACK_TAG]['_default'], @$token[BBCODE_STACK_TAG], $tag_body); |
|
1471 $output = Array(Array( |
|
1472 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1473 BBCODE_STACK_TAG => false, |
|
1474 BBCODE_STACK_TEXT => $tag_output, |
|
1475 BBCODE_STACK_CLASS => $this->current_class |
|
1476 )); |
|
1477 } |
|
1478 } |
|
1479 } |
|
1480 $this->Internal_ComputeCurrentClass(); |
|
1481 return $output; |
|
1482 } |
|
1483 function Internal_RewindToClass($class_list) { |
|
1484 $pos = count($this->stack) - 1; |
|
1485 while ($pos >= 0 && !in_array($this->stack[$pos][BBCODE_STACK_CLASS], $class_list)) |
|
1486 $pos--; |
|
1487 if ($pos < 0) { |
|
1488 if (!in_array($this->root_class, $class_list)) |
|
1489 return false; |
|
1490 } |
|
1491 $output = $this->Internal_GenerateOutput($pos+1); |
|
1492 while (count($output)) { |
|
1493 $token = array_pop($output); |
|
1494 $token[BBCODE_STACK_CLASS] = $this->current_class; |
|
1495 $this->stack[] = $token; |
|
1496 } |
|
1497 return true; |
|
1498 } |
|
1499 function Internal_FinishTag($tag_name) { |
|
1500 if (strlen($tag_name) <= 0) |
|
1501 return false; |
|
1502 if (isset($this->start_tags[$tag_name]) |
|
1503 && count($this->start_tags[$tag_name])) |
|
1504 $pos = array_pop($this->start_tags[$tag_name]); |
|
1505 else $pos = -1; |
|
1506 if ($pos < 0) return false; |
|
1507 $newpos = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['after_tag'], |
|
1508 $pos+1, $this->stack); |
|
1509 $delta = $newpos - ($pos+1); |
|
1510 $output = $this->Internal_GenerateOutput($newpos); |
|
1511 $newend = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['before_endtag'], |
|
1512 0, $output); |
|
1513 $output = $this->Internal_CollectTextReverse($output, count($output) - 1, $newend); |
|
1514 while ($delta-- > 0) |
|
1515 array_pop($this->stack); |
|
1516 $this->Internal_ComputeCurrentClass(); |
|
1517 return $output; |
|
1518 } |
|
1519 function Internal_ComputeCurrentClass() { |
|
1520 if (count($this->stack) > 0) |
|
1521 $this->current_class = $this->stack[count($this->stack)-1][BBCODE_STACK_CLASS]; |
|
1522 else $this->current_class = $this->root_class; |
|
1523 } |
|
1524 function Internal_DumpStack($array = false, $raw = false) { |
|
1525 if (!$raw) $string = "<span style='color: #00C;'>"; |
|
1526 else $string = ""; |
|
1527 if ($array === false) |
|
1528 $array = $this->stack; |
|
1529 foreach ($array as $item) { |
|
1530 switch (@$item[BBCODE_STACK_TOKEN]) { |
|
1531 case BBCODE_TEXT: |
|
1532 $string .= "\"" . htmlspecialchars(@$item[BBCODE_STACK_TEXT]) . "\" "; |
|
1533 break; |
|
1534 case BBCODE_WS: |
|
1535 $string .= "WS "; |
|
1536 break; |
|
1537 case BBCODE_NL: |
|
1538 $string .= "NL "; |
|
1539 break; |
|
1540 case BBCODE_TAG: |
|
1541 $string .= "[" . htmlspecialchars(@$item[BBCODE_STACK_TAG]['_name']) . "] "; |
|
1542 break; |
|
1543 default: |
|
1544 $string .= "unknown "; |
|
1545 break; |
|
1546 } |
|
1547 } |
|
1548 if (!$raw) $string .= "</span>"; |
|
1549 return $string; |
|
1550 } |
|
1551 function Internal_CleanupWSByPoppingStack($pattern, &$array) { |
|
1552 if (strlen($pattern) <= 0) return; |
|
1553 $oldlen = count($array); |
|
1554 foreach (str_split($pattern) as $char) { |
|
1555 switch ($char) { |
|
1556 case 's': |
|
1557 while (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_WS) |
|
1558 array_pop($array); |
|
1559 break; |
|
1560 case 'n': |
|
1561 if (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_NL) |
|
1562 array_pop($array); |
|
1563 break; |
|
1564 case 'a': |
|
1565 while (count($array) > 0 |
|
1566 && (($token = $array[count($array)-1][BBCODE_STACK_TOKEN]) == BBCODE_WS |
|
1567 || $token == BBCODE_NL)) |
|
1568 array_pop($array); |
|
1569 break; |
|
1570 } |
|
1571 } |
|
1572 if (count($array) != $oldlen) { |
|
1573 $this->Internal_ComputeCurrentClass(); |
|
1574 } |
|
1575 } |
|
1576 function Internal_CleanupWSByEatingInput($pattern) { |
|
1577 if (strlen($pattern) <= 0) return; |
|
1578 foreach (str_split($pattern) as $char) { |
|
1579 switch ($char) { |
|
1580 case 's': |
|
1581 $token_type = $this->lexer->NextToken(); |
|
1582 while ($token_type == BBCODE_WS) { |
|
1583 $token_type = $this->lexer->NextToken(); |
|
1584 } |
|
1585 $this->lexer->UngetToken(); |
|
1586 break; |
|
1587 case 'n': |
|
1588 $token_type = $this->lexer->NextToken(); |
|
1589 if ($token_type != BBCODE_NL) |
|
1590 $this->lexer->UngetToken(); |
|
1591 break; |
|
1592 case 'a': |
|
1593 $token_type = $this->lexer->NextToken(); |
|
1594 while ($token_type == BBCODE_WS || $token_type == BBCODE_NL) { |
|
1595 $token_type = $this->lexer->NextToken(); |
|
1596 } |
|
1597 $this->lexer->UngetToken(); |
|
1598 break; |
|
1599 } |
|
1600 } |
|
1601 } |
|
1602 function Internal_CleanupWSByIteratingPointer($pattern, $pos, $array) { |
|
1603 if (strlen($pattern) <= 0) return $pos; |
|
1604 foreach (str_split($pattern) as $char) { |
|
1605 switch ($char) { |
|
1606 case 's': |
|
1607 while ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_WS) |
|
1608 $pos++; |
|
1609 break; |
|
1610 case 'n': |
|
1611 if ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_NL) |
|
1612 $pos++; |
|
1613 break; |
|
1614 case 'a': |
|
1615 while ($pos < count($array) |
|
1616 && (($token = $array[$pos][BBCODE_STACK_TOKEN]) == BBCODE_WS || $token == BBCODE_NL)) |
|
1617 $pos++; |
|
1618 break; |
|
1619 } |
|
1620 } |
|
1621 return $pos; |
|
1622 } |
|
1623 function Internal_LimitText($string, $limit) { |
|
1624 $chunks = preg_split("/([\\x00-\\x20]+)/", $string, -1, PREG_SPLIT_DELIM_CAPTURE); |
|
1625 $output = ""; |
|
1626 foreach ($chunks as $chunk) { |
|
1627 if (strlen($output) + strlen($chunk) > $limit) |
|
1628 break; |
|
1629 $output .= $chunk; |
|
1630 } |
|
1631 $output = rtrim($output); |
|
1632 return $output; |
|
1633 } |
|
1634 function Internal_DoLimit() { |
|
1635 $this->Internal_CleanupWSByPoppingStack("a", $this->stack); |
|
1636 if (strlen($this->limit_tail) > 0) { |
|
1637 $this->stack[] = Array( |
|
1638 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1639 BBCODE_STACK_TEXT => $this->limit_tail, |
|
1640 BBCODE_STACK_TAG => false, |
|
1641 BBCODE_STACK_CLASS => $this->current_class, |
|
1642 ); |
|
1643 } |
|
1644 $this->was_limited = true; |
|
1645 } |
|
1646 function DoTag($action, $tag_name, $default_value, $params, $contents) { |
|
1647 $tag_rule = @$this->tag_rules[$tag_name]; |
|
1648 switch ($action) { |
|
1649 case BBCODE_CHECK: |
|
1650 if (isset($tag_rule['allow'])) { |
|
1651 foreach ($tag_rule['allow'] as $param => $pattern) { |
|
1652 if ($param == '_content') $value = $contents; |
|
1653 else if ($param == '_defaultcontent') { |
|
1654 if (strlen($default_value)) |
|
1655 $value = $default_value; |
|
1656 else $value = $contents; |
|
1657 } |
|
1658 else { |
|
1659 if (isset($params[$param])) |
|
1660 $value = $params[$param]; |
|
1661 else $value = @$tag_rule['default'][$param]; |
|
1662 } |
|
1663 if (!preg_match($pattern, $value)) { |
|
1664 return false; |
|
1665 } |
|
1666 } |
|
1667 return true; |
|
1668 } |
|
1669 switch (@$tag_rule['mode']) { |
|
1670 default: |
|
1671 case BBCODE_MODE_SIMPLE: |
|
1672 $result = true; |
|
1673 break; |
|
1674 case BBCODE_MODE_ENHANCED: |
|
1675 $result = true; |
|
1676 break; |
|
1677 case BBCODE_MODE_INTERNAL: |
|
1678 $result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_CHECK, |
|
1679 $tag_name, $default_value, $params, $contents); |
|
1680 break; |
|
1681 case BBCODE_MODE_LIBRARY: |
|
1682 $result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_CHECK, |
|
1683 $tag_name, $default_value, $params, $contents); |
|
1684 break; |
|
1685 case BBCODE_MODE_CALLBACK: |
|
1686 $result = @call_user_func(@$tag_rule['method'], $this, BBCODE_CHECK, |
|
1687 $tag_name, $default_value, $params, $contents); |
|
1688 break; |
|
1689 } |
|
1690 return $result; |
|
1691 case BBCODE_OUTPUT: |
|
1692 if ($this->plain_mode) { |
|
1693 if (!isset($tag_rule['plain_content'])) |
|
1694 $plain_content = Array('_content'); |
|
1695 else $plain_content = $tag_rule['plain_content']; |
|
1696 $result = $possible_content = ""; |
|
1697 foreach ($plain_content as $possible_content) { |
|
1698 if ($possible_content == '_content' |
|
1699 && strlen($contents) > 0) { |
|
1700 $result = $contents; |
|
1701 break; |
|
1702 } |
|
1703 if (isset($params[$possible_content]) |
|
1704 && strlen($params[$possible_content]) > 0) { |
|
1705 $result = htmlspecialchars($params[$possible_content]); |
|
1706 break; |
|
1707 } |
|
1708 } |
|
1709 $start = @$tag_rule['plain_start']; |
|
1710 $end = @$tag_rule['plain_end']; |
|
1711 if (isset($tag_rule['plain_link'])) { |
|
1712 $link = $possible_content = ""; |
|
1713 foreach ($tag_rule['plain_link'] as $possible_content) { |
|
1714 if ($possible_content == '_content' |
|
1715 && strlen($contents) > 0) { |
|
1716 $link = $this->UnHTMLEncode(strip_tags($contents)); |
|
1717 break; |
|
1718 } |
|
1719 if (isset($params[$possible_content]) |
|
1720 && strlen($params[$possible_content]) > 0) { |
|
1721 $link = $params[$possible_content]; |
|
1722 break; |
|
1723 } |
|
1724 } |
|
1725 $params = @parse_url($link); |
|
1726 if (!is_array($params)) $params = Array(); |
|
1727 $params['link'] = $link; |
|
1728 $params['url'] = $link; |
|
1729 $start = $this->FillTemplate($start, $params); |
|
1730 $end = $this->FillTemplate($end, $params); |
|
1731 } |
|
1732 return $start . $result . $end; |
|
1733 } |
|
1734 switch (@$tag_rule['mode']) { |
|
1735 default: |
|
1736 case BBCODE_MODE_SIMPLE: |
|
1737 $result = @$tag_rule['simple_start'] . $contents . @$tag_rule['simple_end']; |
|
1738 break; |
|
1739 case BBCODE_MODE_ENHANCED: |
|
1740 $result = $this->Internal_DoEnhancedTag($tag_rule, $params, $contents); |
|
1741 break; |
|
1742 case BBCODE_MODE_INTERNAL: |
|
1743 $result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_OUTPUT, |
|
1744 $tag_name, $default_value, $params, $contents); |
|
1745 break; |
|
1746 case BBCODE_MODE_LIBRARY: |
|
1747 $result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_OUTPUT, |
|
1748 $tag_name, $default_value, $params, $contents); |
|
1749 break; |
|
1750 case BBCODE_MODE_CALLBACK: |
|
1751 $result = @call_user_func(@$tag_rule['method'], $this, BBCODE_OUTPUT, |
|
1752 $tag_name, $default_value, $params, $contents); |
|
1753 break; |
|
1754 } |
|
1755 return $result; |
|
1756 default: |
|
1757 return false; |
|
1758 } |
|
1759 } |
|
1760 function Internal_DoEnhancedTag($tag_rule, $params, $contents) { |
|
1761 $params['_content'] = $contents; |
|
1762 $params['_defaultcontent'] = strlen(@$params['_default']) ? $params['_default'] : $contents; |
|
1763 return $this->FillTemplate(@$tag_rule['template'], $params, @$tag_rule['default']); |
|
1764 } |
|
1765 function Internal_UpdateParamsForMissingEndTag(&$params) { |
|
1766 switch ($this->tag_marker) { |
|
1767 case '[': $tail_marker = ']'; break; |
|
1768 case '<': $tail_marker = '>'; break; |
|
1769 case '{': $tail_marker = '}'; break; |
|
1770 case '(': $tail_marker = ')'; break; |
|
1771 default: $tail_marker = $this->tag_marker; break; |
|
1772 } |
|
1773 $params['_endtag'] = $this->tag_marker . '/' . $params['_name'] . $tail_marker; |
|
1774 } |
|
1775 function Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule) { |
|
1776 if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) { |
|
1777 $this->stack[] = Array( |
|
1778 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1779 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1780 BBCODE_STACK_TAG => false, |
|
1781 BBCODE_STACK_CLASS => $this->current_class, |
|
1782 ); |
|
1783 return; |
|
1784 } |
|
1785 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack); |
|
1786 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$tag_params['_default'], $tag_params, ""); |
|
1787 $this->Internal_CleanupWSByEatingInput(@$tag_rule['after_tag']); |
|
1788 $this->stack[] = Array( |
|
1789 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1790 BBCODE_STACK_TEXT => $output, |
|
1791 BBCODE_STACK_TAG => false, |
|
1792 BBCODE_STACK_CLASS => $this->current_class, |
|
1793 ); |
|
1794 } |
|
1795 function Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule) { |
|
1796 $state = $this->lexer->SaveState(); |
|
1797 $end_tag = $this->lexer->tagmarker . "/" . $tag_name . $this->lexer->end_tagmarker; |
|
1798 $start = count($this->stack); |
|
1799 $this->lexer->verbatim = true; |
|
1800 while (($token_type = $this->lexer->NextToken()) != BBCODE_EOI) { |
|
1801 if ($this->lexer->text == $end_tag) { |
|
1802 $end_tag_params = $this->lexer->tag; |
|
1803 break; |
|
1804 } |
|
1805 if ($this->output_limit > 0 |
|
1806 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) { |
|
1807 $text = $this->Internal_LimitText($this->lexer->text, |
|
1808 $this->output_limit - $this->text_length); |
|
1809 if (strlen($text) > 0) { |
|
1810 $this->text_length += strlen($text); |
|
1811 $this->stack[] = Array( |
|
1812 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1813 BBCODE_STACK_TEXT => $this->FixupOutput($text), |
|
1814 BBCODE_STACK_TAG => false, |
|
1815 BBCODE_STACK_CLASS => $this->current_class, |
|
1816 ); |
|
1817 } |
|
1818 $this->Internal_DoLimit(); |
|
1819 break; |
|
1820 } |
|
1821 $this->text_length += strlen($this->lexer->text); |
|
1822 $this->stack[] = Array( |
|
1823 BBCODE_STACK_TOKEN => $token_type, |
|
1824 BBCODE_STACK_TEXT => htmlspecialchars($this->lexer->text), |
|
1825 BBCODE_STACK_TAG => $this->lexer->tag, |
|
1826 BBCODE_STACK_CLASS => $this->current_class, |
|
1827 ); |
|
1828 } |
|
1829 $this->lexer->verbatim = false; |
|
1830 if ($token_type == BBCODE_EOI) { |
|
1831 $this->lexer->RestoreState($state); |
|
1832 $this->stack[] = Array( |
|
1833 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1834 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1835 BBCODE_STACK_TAG => false, |
|
1836 BBCODE_STACK_CLASS => $this->current_class, |
|
1837 ); |
|
1838 return; |
|
1839 } |
|
1840 $newstart = $this->Internal_CleanupWSByIteratingPointer(@$tag_rule['after_tag'], $start, $this->stack); |
|
1841 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_endtag'], $this->stack); |
|
1842 $this->Internal_CleanupWSByEatingInput(@$tag_rule['after_endtag']); |
|
1843 $content = $this->Internal_CollectText($this->stack, $newstart); |
|
1844 array_splice($this->stack, $start); |
|
1845 $this->Internal_ComputeCurrentClass(); |
|
1846 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack); |
|
1847 $tag_params['_endtag'] = $end_tag_params['_tag']; |
|
1848 $tag_params['_hasend'] = true; |
|
1849 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, |
|
1850 @$tag_params['_default'], $tag_params, $content); |
|
1851 $this->stack[] = Array( |
|
1852 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1853 BBCODE_STACK_TEXT => $output, |
|
1854 BBCODE_STACK_TAG => false, |
|
1855 BBCODE_STACK_CLASS => $this->current_class, |
|
1856 ); |
|
1857 } |
|
1858 function Internal_ParseStartTagToken() { |
|
1859 $tag_params = $this->lexer->tag; |
|
1860 $tag_name = @$tag_params['_name']; |
|
1861 if (!isset($this->tag_rules[$tag_name])) { |
|
1862 $this->stack[] = Array( |
|
1863 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1864 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1865 BBCODE_STACK_TAG => false, |
|
1866 BBCODE_STACK_CLASS => $this->current_class, |
|
1867 ); |
|
1868 return; |
|
1869 } |
|
1870 $tag_rule = $this->tag_rules[$tag_name]; |
|
1871 $allow_in = is_array($tag_rule['allow_in']) |
|
1872 ? $tag_rule['allow_in'] : Array($this->root_class); |
|
1873 if (!in_array($this->current_class, $allow_in)) { |
|
1874 if (!$this->Internal_RewindToClass($allow_in)) { |
|
1875 $this->stack[] = Array( |
|
1876 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1877 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1878 BBCODE_STACK_TAG => false, |
|
1879 BBCODE_STACK_CLASS => $this->current_class, |
|
1880 ); |
|
1881 return; |
|
1882 } |
|
1883 } |
|
1884 $end_tag = isset($tag_rule['end_tag']) ? $tag_rule['end_tag'] : BBCODE_REQUIRED; |
|
1885 if ($end_tag == BBCODE_PROHIBIT) { |
|
1886 $this->Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule); |
|
1887 return; |
|
1888 } |
|
1889 if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) { |
|
1890 $this->stack[] = Array( |
|
1891 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1892 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1893 BBCODE_STACK_TAG => false, |
|
1894 BBCODE_STACK_CLASS => $this->current_class, |
|
1895 ); |
|
1896 return; |
|
1897 } |
|
1898 if (@$tag_rule['content'] == BBCODE_VERBATIM) { |
|
1899 $this->Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule); |
|
1900 return; |
|
1901 } |
|
1902 if (isset($tag_rule['class'])) |
|
1903 $newclass = $tag_rule['class']; |
|
1904 else $newclass = $this->root_class; |
|
1905 $this->stack[] = Array( |
|
1906 BBCODE_STACK_TOKEN => $this->lexer->token, |
|
1907 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1908 BBCODE_STACK_TAG => $this->lexer->tag, |
|
1909 BBCODE_STACK_CLASS => ($this->current_class = $newclass), |
|
1910 ); |
|
1911 if (!isset($this->start_tags[$tag_name])) |
|
1912 $this->start_tags[$tag_name] = Array(count($this->stack)-1); |
|
1913 else $this->start_tags[$tag_name][] = count($this->stack)-1; |
|
1914 } |
|
1915 function Internal_ParseEndTagToken() { |
|
1916 $tag_params = $this->lexer->tag; |
|
1917 $tag_name = @$tag_params['_name']; |
|
1918 $contents = $this->Internal_FinishTag($tag_name); |
|
1919 if ($contents === false) { |
|
1920 if (@$this->lost_start_tags[$tag_name] > 0) { |
|
1921 $this->lost_start_tags[$tag_name]--; |
|
1922 } |
|
1923 else { |
|
1924 $this->stack[] = Array( |
|
1925 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1926 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
1927 BBCODE_STACK_TAG => false, |
|
1928 BBCODE_STACK_CLASS => $this->current_class, |
|
1929 ); |
|
1930 } |
|
1931 return; |
|
1932 } |
|
1933 $start_tag_node = array_pop($this->stack); |
|
1934 $start_tag_params = $start_tag_node[BBCODE_STACK_TAG]; |
|
1935 $this->Internal_ComputeCurrentClass(); |
|
1936 $this->Internal_CleanupWSByPoppingStack(@$this->tag_rules[$tag_name]['before_tag'], $this->stack); |
|
1937 $start_tag_params['_endtag'] = $tag_params['_tag']; |
|
1938 $start_tag_params['_hasend'] = true; |
|
1939 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$start_tag_params['_default'], |
|
1940 $start_tag_params, $contents); |
|
1941 $this->Internal_CleanupWSByEatingInput(@$this->tag_rules[$tag_name]['after_endtag']); |
|
1942 $this->stack[] = Array( |
|
1943 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1944 BBCODE_STACK_TEXT => $output, |
|
1945 BBCODE_STACK_TAG => false, |
|
1946 BBCODE_STACK_CLASS => $this->current_class, |
|
1947 ); |
|
1948 } |
|
1949 function Parse($string) { |
|
1950 $this->lexer = new BBCodeLexer($string, $this->tag_marker); |
|
1951 $this->lexer->debug = $this->debug; |
|
1952 $old_output_limit = $this->output_limit; |
|
1953 if ($this->output_limit > 0) { |
|
1954 if (strlen($string) < $this->output_limit) { |
|
1955 $this->output_limit = 0; |
|
1956 } |
|
1957 else if ($this->limit_precision > 0) { |
|
1958 $guess_length = $this->lexer->GuessTextLength(); |
|
1959 if ($guess_length < $this->output_limit * ($this->limit_precision + 1.0)) { |
|
1960 $this->output_limit = 0; |
|
1961 } |
|
1962 else { |
|
1963 } |
|
1964 } |
|
1965 } |
|
1966 $this->stack = Array(); |
|
1967 $this->start_tags = Array(); |
|
1968 $this->lost_start_tags = Array(); |
|
1969 $this->text_length = 0; |
|
1970 $this->was_limited = false; |
|
1971 if (strlen($this->pre_trim) > 0) |
|
1972 $this->Internal_CleanupWSByEatingInput($this->pre_trim); |
|
1973 $newline = $this->plain_mode ? "\n" : "<br />\n"; |
|
1974 while (true) { |
|
1975 if (($token_type = $this->lexer->NextToken()) == BBCODE_EOI) { |
|
1976 break; |
|
1977 } |
|
1978 switch ($token_type) { |
|
1979 case BBCODE_TEXT: |
|
1980 if ($this->output_limit > 0 |
|
1981 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) { |
|
1982 $text = $this->Internal_LimitText($this->lexer->text, |
|
1983 $this->output_limit - $this->text_length); |
|
1984 if (strlen($text) > 0) { |
|
1985 $this->text_length += strlen($text); |
|
1986 $this->stack[] = Array( |
|
1987 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1988 BBCODE_STACK_TEXT => $this->FixupOutput($text), |
|
1989 BBCODE_STACK_TAG => false, |
|
1990 BBCODE_STACK_CLASS => $this->current_class, |
|
1991 ); |
|
1992 } |
|
1993 $this->Internal_DoLimit(); |
|
1994 break 2; |
|
1995 } |
|
1996 $this->text_length += strlen($this->lexer->text); |
|
1997 $this->stack[] = Array( |
|
1998 BBCODE_STACK_TOKEN => BBCODE_TEXT, |
|
1999 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), |
|
2000 BBCODE_STACK_TAG => false, |
|
2001 BBCODE_STACK_CLASS => $this->current_class, |
|
2002 ); |
|
2003 break; |
|
2004 case BBCODE_WS: |
|
2005 if ($this->output_limit > 0 |
|
2006 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) { |
|
2007 $this->Internal_DoLimit(); |
|
2008 break 2; |
|
2009 } |
|
2010 $this->text_length += strlen($this->lexer->text); |
|
2011 $this->stack[] = Array( |
|
2012 BBCODE_STACK_TOKEN => BBCODE_WS, |
|
2013 BBCODE_STACK_TEXT => $this->lexer->text, |
|
2014 BBCODE_STACK_TAG => false, |
|
2015 BBCODE_STACK_CLASS => $this->current_class, |
|
2016 ); |
|
2017 break; |
|
2018 case BBCODE_NL: |
|
2019 if ($this->ignore_newlines) { |
|
2020 if ($this->output_limit > 0 |
|
2021 && $this->text_length + 1 >= $this->output_limit) { |
|
2022 $this->Internal_DoLimit(); |
|
2023 break 2; |
|
2024 } |
|
2025 $this->text_length += 1; |
|
2026 $this->stack[] = Array( |
|
2027 BBCODE_STACK_TOKEN => BBCODE_WS, |
|
2028 BBCODE_STACK_TEXT => "\n", |
|
2029 BBCODE_STACK_TAG => false, |
|
2030 BBCODE_STACK_CLASS => $this->current_class, |
|
2031 ); |
|
2032 } |
|
2033 else { |
|
2034 $this->Internal_CleanupWSByPoppingStack("s", $this->stack); |
|
2035 if ($this->output_limit > 0 |
|
2036 && $this->text_length + 1 >= $this->output_limit) { |
|
2037 $this->Internal_DoLimit(); |
|
2038 break 2; |
|
2039 } |
|
2040 $this->text_length += 1; |
|
2041 $this->stack[] = Array( |
|
2042 BBCODE_STACK_TOKEN => BBCODE_NL, |
|
2043 BBCODE_STACK_TEXT => $newline, |
|
2044 BBCODE_STACK_TAG => false, |
|
2045 BBCODE_STACK_CLASS => $this->current_class, |
|
2046 ); |
|
2047 $this->Internal_CleanupWSByEatingInput("s"); |
|
2048 } |
|
2049 break; |
|
2050 case BBCODE_TAG: |
|
2051 $this->Internal_ParseStartTagToken(); |
|
2052 break; |
|
2053 case BBCODE_ENDTAG: |
|
2054 $this->Internal_ParseEndTagToken(); |
|
2055 break; |
|
2056 default: |
|
2057 break; |
|
2058 } |
|
2059 } |
|
2060 if (strlen($this->post_trim) > 0) |
|
2061 $this->Internal_CleanupWSByPoppingStack($this->post_trim, $this->stack); |
|
2062 $result = $this->Internal_GenerateOutput(0); |
|
2063 $result = $this->Internal_CollectTextReverse($result, count($result) - 1); |
|
2064 $this->output_limit = $old_output_limit; |
|
2065 if ($this->plain_mode) { |
|
2066 $result = preg_replace("/[\\x00-\\x09\\x0B-\\x20]+/", " ", $result); |
|
2067 $result = preg_replace("/(?:[\\x20]*\\n){2,}[\\x20]*/", "\n\n", $result); |
|
2068 $result = trim($result); |
|
2069 } |
|
2070 return $result; |
|
2071 } |
|
2072 } |
|
2073 |