PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/template_engines_bench/libs/quicky/Quicky_BBcode.class.php

https://github.com/limb-php-framework/limb-tools
PHP | 412 lines | 399 code | 0 blank | 13 comment | 132 complexity | 23556cdb8ecd82f396ccff2466e705ba MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1
  1. <?php
  2. /**************************************************************************/
  3. /* Quicky: smart and fast templates
  4. /* ver. 0.4
  5. /* ===========================
  6. /*
  7. /* Copyright (c)oded 2007 by WP
  8. /* http://quicky.keeperweb.com
  9. /*
  10. /* Quicky_BBCode.class.php: BB-code class
  11. /**************************************************************************/
  12. class Quicky_BBcode
  13. {
  14. public $smiles = array(
  15. 'acute',
  16. 'angry',
  17. 'big_boss',
  18. 'glare',
  19. 'good',
  20. 'happy',
  21. 'hi',
  22. 'huh',
  23. 'lol',
  24. 'not_i',
  25. 'ohmy',
  26. 'read',
  27. 'smile',
  28. 'smile3',
  29. 'taunt',
  30. 'to_keep_order',
  31. 'wink',
  32. 'yahoo',
  33. 'yes',
  34. 'rose'/*,
  35. 'banned',
  36. 'tema',
  37. 'offtopic',
  38. 'funny_post'*/,
  39. );
  40. public $source;
  41. public $blocks = array();
  42. public $tags = array();
  43. public $left_delimiter = '[';
  44. public $right_delimiter = ']';
  45. public $errors = array();
  46. public $allow_html_tags = FALSE;
  47. public $smiles_dir;
  48. public $smiles_url;
  49. private $_builtin_blocks = '[gm]|email|link|url|code|php|list|plain|literal';
  50. public $cast_unrecognized_tags = FALSE;
  51. public $stat = array();
  52. public $use_stat = TRUE;
  53. public $block_stacks = array();
  54. public $block_stack_n = 0;
  55. public $autourl = TRUE;
  56. public $allow_smiles = TRUE;
  57. public function __construct() {}
  58. public function load($string)
  59. {
  60. $this->source = $string;
  61. }
  62. public function safe_uri($uri)
  63. {
  64. $uri = trim($uri);
  65. if (preg_match('~^(?:java|vb)script:~i',preg_replace('~\s+~','',$uri))) {return FALSE;}
  66. return TRUE;
  67. }
  68. private function _error($msg)
  69. {
  70. $this->errors[] = $msg;
  71. return FALSE;
  72. }
  73. public function register_block($name,$callback) {$this->blocks[strtolower($name)] = $callback;}
  74. public function register_tag($name,$callback) {$this->tags[strtolower($name)] = $callback;}
  75. private function _parse_params($p)
  76. {
  77. $params = array();
  78. preg_match_all('~\w+\s*=|(([\'"]).*?(?<!\\\\)\2|\S+)~s',$p,$m,PREG_SET_ORDER);
  79. $lastkey = '';
  80. foreach ($m as $v)
  81. {
  82. if (trim($v[0]) === '') {continue;}
  83. if (sizeof($v) == 1) {$lastkey = ltrim(rtrim($v[0]," =\t")); continue;}
  84. if ($lastkey === '') {$params[] = $v[0];}
  85. else {$params[$lastkey] = $v[0];}
  86. $lastkey = '';
  87. }
  88. if ($this->use_stat) {$this->stat['numparams'] += sizeof($params);}
  89. return $params;
  90. }
  91. private function _dequote($string)
  92. {
  93. if ((substr($string,0,1) == '"' and substr($string,-1) == '"')
  94. or (substr($string,0,1) == '\'' and substr($string,-1) == '\''))
  95. {return substr($string,1,-1);}
  96. return $string;
  97. }
  98. private function _tag_token($mixed)
  99. {
  100. if (is_array($mixed))
  101. {
  102. if (sizeof($mixed) == 1)
  103. {
  104. if ($mixed[0] == "\n") {return '<br />'."\n";}
  105. return $this->allow_html_tags?$mixed[0]:htmlspecialchars($mixed[0]);
  106. }
  107. if (isset($mixed[7]) and $mixed[7] !== '')
  108. {
  109. if (!$this->allow_smiles) {return $mixed[0];}
  110. $smile = substr($mixed[7],1,-1);
  111. if (file_exists($this->smiles_dir.$smile.'.gif')) {return '<img src="'.htmlspecialchars($this->smiles_url.$smile).'.gif">';}
  112. else {return $mixed[0];}
  113. }
  114. if ($mixed[1] !== '')
  115. {
  116. if ($this->use_stat)
  117. {
  118. ++$this->stat['numblocks'];
  119. if (substr($mixed[2],0,1) == '=') {++$this->stat['numparams'];}
  120. }
  121. $block_type = strtolower($mixed[1]);
  122. $block_content = $mixed[4];
  123. if ($block_type == 'img')
  124. {
  125. if (!$this->safe_uri($block_content)) {return $this->_error('Unsafe uri "'.$block_content.'" in tag '.$block_type);}
  126. return '<img src="'.htmlspecialchars($block_content,ENT_QUOTES).'" />';
  127. }
  128. elseif ($block_type == 'link' or $block_type == 'url')
  129. {
  130. if (substr($mixed[2],0,1) == '=') {$url = substr($mixed[2],1);}
  131. else
  132. {
  133. $block_params = $this->_parse_params($mixed[2]);
  134. $url = isset($block_params['src'])?$block_params['src']:'';
  135. }
  136. $url = $this->_dequote($url);
  137. if ($url === '') {$url = $block_content;}
  138. if (!$this->safe_uri($url)) {return $this->_error('Unsafe uri "'.$url.'" in tag '.$block_type);}
  139. return '<a href="'.htmlspecialchars($url).'">'.$this->_tag_token($block_content).'</a>';
  140. }
  141. elseif ($block_type == 'php')
  142. {
  143. $s = trim($block_content,"\r\n");
  144. if (!preg_match('~<\?php~i',$s)) {$s = str_replace("\r",'','<?php'."\n".$s.' ?>');}
  145. else {$s = str_replace("\r",'','<?php'."\n".$s.' ?>');}
  146. $s = @highlight_string($s,TRUE);
  147. $s = substr_replace($s,'',strpos($s,'&lt;?php'),8);
  148. $s = substr_replace($s,'',strrpos($s,'?&gt;'),5);
  149. $from = 0;
  150. $x = 0;
  151. while ($i = strpos($s,'<br />',$from))
  152. {
  153. $s = substr($s,0,$x == 0?$i:$i+6)."\n".
  154. '<font style="color:#000000;background-color:#eeeeee;">&nbsp;'.sprintf('%03d',$x+1).
  155. '&nbsp;</font>&nbsp;'.substr($s,$i+6);
  156. $from = $i+5;
  157. $x++;
  158. }
  159. return '<div style="background-color:#cccccc">'.$s.'</div>';
  160. }
  161. elseif ($block_type == 'code')
  162. {
  163. $s = trim($block_content);
  164. $r = '';
  165. $x = 0;
  166. $e = explode("\n",$s);
  167. for ($i = 0, $s = sizeof($e); $i < $s; ++$i)
  168. {
  169. $line = $e[$i];
  170. if ($x != 0 or strlen(trim(str_replace('<br />','',$line))) > 0)
  171. {
  172. $r .= '<font style="color:#000000;background-color:#eeeeee;">&nbsp;'.sprintf('%03d',$x+1).
  173. '&nbsp;</font>&nbsp;'.$line."\n";
  174. $x++;
  175. }
  176. }
  177. return '<div style="background-color:#cccccc">'.$r.'</div>';
  178. }
  179. elseif (in_array($block_type,array('b','i','u','s','p'))) {return '<'.$block_type.'>'.$this->_tag_token($block_content).'</'.$block_type.'>';}
  180. elseif ($block_type == 'email')
  181. {
  182. if (substr($mixed[2],0,1) == '=') {$email = substr($mixed[2],1);}
  183. else
  184. {
  185. $block_params = $this->_parse_params($mixed[2]);
  186. $email = isset($block_params['address'])?$this->_dequote($block_params['address']):'';
  187. }
  188. if ($email === '') {$email = $block_content;}
  189. return '<a href="mailto:'.htmlspecialchars($email).'" />'.$this->_tag_token($block_content).'</a>';
  190. }
  191. elseif ($block_type == 'm') {return '<a href="http://php.net/'.urlencode($block_content).'">'.htmlspecialchars($block_content).'</a>';}
  192. elseif ($block_type == 'g') {return '<a href="http://www.google.com/search?q='.urlencode($block_content).'">'.htmlspecialchars($block_content).'</a>';}
  193. elseif ($block_type == 'list')
  194. {
  195. if (substr($mixed[2],0,1) == '=') {$flag = substr($mixed[2],1);}
  196. else {$flag = '0';}
  197. return '<table border=0 width=100%><tr><td width=50></td><td width="95%">'
  198. .($flag == '0'?'<ol>':'<ul>')
  199. .$this->_tag_token($block_content)
  200. .($flag == '0'?'</ol>':'</ul>').'</td></tr></table>';
  201. }
  202. elseif ($block_type == 'plain' or $block_type == 'literal') {return htmlspecialchars($block_content);}
  203. elseif (isset($this->blocks[$block_type])) {return call_user_func($this->blocks[$block_type],$mixed[2],$block_content,$this);}
  204. else {return $this->cast_unrecognized_tags?$mixed[0]:$this->_error('Unrecognized block-type: \''.$block_type.'\'');}
  205. }
  206. elseif (isset($mixed[5]) && $mixed[5] !== '')
  207. {
  208. static $c_offsets = array();
  209. if (!isset($c_offsets[$this->block_stack_n])) {$c_offsets[$this->block_stack_n] = 0;}
  210. preg_match('~^\s*(/?)([^\s=]*)(.*?)$~s',$mixed[5],$m);
  211. if (!isset($m[0])) {$m[0] = '';}
  212. if (!isset($m[1])) {$m[1] = '';}
  213. if (!isset($m[2])) {$m[2] = '';}
  214. if (!isset($m[3])) {$m[3] = '';}
  215. $close = $m[1];
  216. $tag = strtolower($m[2]);
  217. $param = $m[3];
  218. if ($this->use_stat) {++$this->stat['numtags'];}
  219. $bs = &$this->block_stacks[$this->block_stack_n];
  220. if ($close and ($tag == ''))
  221. {
  222. $el = array_slice($bs,-$c_offsets[$this->block_stack_n],1);
  223. $tag = current($el);
  224. ++$c_offsets[$this->block_stack_n];
  225. if ($tag === FALSE or $tag[1]) {return '';}
  226. $tag = $tag[0];
  227. $bs[key($el)][1] = TRUE;
  228. }
  229. elseif ($close)
  230. {
  231. $found = FALSE;
  232. for ($i = sizeof($bs)-1; $i >= 0; --$i)
  233. {
  234. if ((!$bs[$i][1]) and ($bs[$i][0] == $tag))
  235. {
  236. $bs[$i][1] = TRUE;
  237. $found = TRUE; break;
  238. }
  239. }
  240. if (!$found) {return '';}
  241. }
  242. $return = $this->_exec_tag($close,$tag,$param);
  243. if (!$close and !in_array($tag,array('hr')) and ($return !== FALSE)) {$bs[] = array($tag,FALSE); $c_offsets[$this->block_stack_n] = 0;}
  244. return $return;
  245. }
  246. return;
  247. }
  248. ++$this->block_stack_n;
  249. if (!isset($this->block_stacks[$this->block_stack_n])) {$this->block_stacks[$this->block_stack_n] = array();}
  250. $bs = &$this->block_stacks[$this->block_stack_n];
  251. static $regexp;
  252. if ($regexp === NULL)
  253. {
  254. $ldelim = preg_quote($this->left_delimiter,'~');
  255. $rdelim = preg_quote($this->right_delimiter,'~');
  256. $blocks = array($this->_builtin_blocks);
  257. for ($i = 0,$s = sizeof($this->blocks),$v = array_keys($this->blocks); $i < $s; ++$i) {$blocks[] = preg_quote($v[$i],'~');}
  258. $regexp = '~'
  259. .$ldelim.'\s*('.implode('|',$blocks).')([\s=](?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\3)*.*?)?'.$rdelim.'((?:(?R)|.)*?)'.$ldelim.'/\s*\1?\s*'.$rdelim
  260. .'|'.$ldelim.'(\\??(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\5)*.*?)'.$rdelim.'\r?\n?'
  261. .'|(:\w+:)|[<>&\n\'"]'
  262. .'~si';
  263. }
  264. if ((strpos($mixed,$this->left_delimiter) !== FALSE) or (strpos($mixed,':') !== FALSE))
  265. {
  266. $return = preg_replace_callback($regexp,array($this,'_tag_token'),$mixed);
  267. for ($i = sizeof($bs)-1; $i >= 0; --$i) {if (!$bs[$i][1]) {$return .= $this->_exec_tag('/',$bs[$i][0]);}}
  268. return $return;
  269. }
  270. --$this->block_stack_n;
  271. return $mixed;
  272. }
  273. public function _exec_tag($close,$tag,$param = '')
  274. {
  275. $bs = &$this->block_stacks[$this->block_stack_n];
  276. if ($tag == 'li' or $tag == '*') {$return = $close?'':'<li>';}
  277. elseif (in_array($tag,array('b','i','u','s','p'))) {$return = '<'.$close.$tag.'>';}
  278. elseif ($tag == 'quote')
  279. {
  280. if ($close) {return '</td></tr><tr><td><hr size=1 nowhade></td></tr></table>';}
  281. if (substr($param,0,1) == '=') {$author = substr($param,1);}
  282. else {$author = '';}
  283. return '<table border=0 width=100%><tr><td width="10" rowspan=3>&nbsp;</td><td width=90%><hr size=1 noshade></td></tr><tr><td>'
  284. .($author != ''?'<i>Original by: '.htmlspecialchars($author).'</i><br />':'');
  285. }
  286. elseif ($tag == 'size')
  287. {
  288. if ($close) {return '</font>';}
  289. if (substr($param,0,1) == '=') {$size = substr($param,1);}
  290. else {$size = '10';}
  291. return '<font size="'.htmlspecialchars($this->_dequote($size)).'">';
  292. }
  293. elseif ($tag == 'color')
  294. {
  295. if (substr($param,0,1) == '=') {$color = substr($param,1);}
  296. else {$color = 'black';}
  297. if ($close) {return '</font>';}
  298. return '<font color="'.htmlspecialchars($this->_dequote($color)).'">';
  299. }
  300. elseif ($tag == 'sub')
  301. {
  302. if ($close) {return '</'.$tag.'>';}
  303. return '<'.$tag.'>';
  304. }
  305. elseif ($tag == 'hr')
  306. {
  307. return '<'.$tag.' />';
  308. }
  309. elseif ($tag == 'font')
  310. {
  311. if (substr($param,0,1) == '=') {$face = substr($param,1);}
  312. else {$face = 'Verdana';}
  313. if ($close) {return '</font>';}
  314. return '<font face="'.htmlspecialchars($this->_dequote($face)).'">';
  315. }
  316. elseif ($tag == 'table')
  317. {
  318. if ($close) {return '</table>';}
  319. return '<table border="1">';
  320. }
  321. elseif ($tag == 'row')
  322. {
  323. $found = FALSE;
  324. for ($i = sizeof($bs)-1; $i >= 0; --$i)
  325. {
  326. if ((!$bs[$i][1]) and ($bs[$i][0] == 'table'))
  327. {
  328. $found = TRUE; break;
  329. }
  330. }
  331. if (!$found) {$this->_error('Unexpected tag-type: \''.$tag.'\''); return FALSE;}
  332. if ($close) {return '</tr>';}
  333. return '<tr>';
  334. }
  335. elseif ($tag == 'col')
  336. {
  337. $found = FALSE;
  338. for ($i = sizeof($bs)-1; $i >= 0; --$i)
  339. {
  340. if ((!$bs[$i][1]) and ($bs[$i][0] == 'table'))
  341. {
  342. $found = TRUE; break;
  343. }
  344. }
  345. if (!$found) {return '';}
  346. if ($close) {return '</td>';}
  347. $p = $this->_parse_params($param);
  348. $s = '';
  349. static $col_params = array('width','height');
  350. foreach ($p as $k => $v)
  351. {
  352. if (in_array(strtolower($k),$col_params)) {$s .= ' '.$k.'="'.htmlspecialchars($this->_dequote($v)).'"';}
  353. }
  354. return '<td'.$s.'>';
  355. }
  356. elseif (isset($this->tags[$tag])) {$return = call_user_func($this->tags[$tag],$param,$close);}
  357. else {return $this->cast_unrecognized_tags?NULL:$this->_error('Unrecognized tag-type: \''.$tag.'\' ('.$close.')');}
  358. return $return;
  359. }
  360. public function build()
  361. {
  362. $this->source = &$this->text;
  363. return $this->result = $this->getHTML();
  364. }
  365. public function prepareblock_callback($m)
  366. {
  367. if (empty($m[1])) {return $m[0];}
  368. if (isset($m[7])) {return '[URL="'.$m[7].'"]'.$m[7].'[/URL]';}
  369. $blockname = $m[1];
  370. if ($blockname == 'url' or $blockname == 'php' or $blockname == 'code') {return $m[0];}
  371. else {return '['.$m[1].$m[2].']'.$this->prepareblock($m[4]).$m[5];}
  372. }
  373. public function prepareblock($source)
  374. {
  375. static $regexp = NULL;
  376. if ($regexp === NULL)
  377. {
  378. $ldelim = preg_quote($this->left_delimiter,'~');
  379. $rdelim = preg_quote($this->right_delimiter,'~');
  380. $blocks = array($this->_builtin_blocks);
  381. for ($i = 0,$s = sizeof($this->blocks),$v = array_keys($this->blocks); $i < $s; ++$i) {$blocks[] = preg_quote($v[$i],'~');}
  382. $regexp = '~'
  383. .$ldelim.'\s*('.implode('|',$blocks).')([\s=](?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\3)*.*?)?'.$rdelim.'((?:(?R)|.)*?)('.$ldelim.'/\s*\1?\s*'.$rdelim.')'
  384. .'|'.$ldelim.'(\\??(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\6)*.*?)'.$rdelim.'\r?\n?'
  385. .'|([a-z\d]+://[^\s\]]+)'
  386. .'~si';
  387. }
  388. return preg_replace_callback($regexp,array($this,'prepareblock_callback'),$source);
  389. }
  390. public function getHTML()
  391. {
  392. $this->block_stacks = array();
  393. $this->errors = array();
  394. $this->block_stack_n = 0;
  395. $source = $this->source;
  396. $this->stat = array();
  397. if ($this->use_stat)
  398. {
  399. $this->stat = array(
  400. 'numblocks' => 0,
  401. 'numtags' => 0,
  402. 'numparams' => 0
  403. );
  404. }
  405. if ($this->autourl)
  406. {
  407. $source = $this->source = $this->prepareblock($source);
  408. }
  409. $source = $this->_tag_token($source);
  410. return $source;
  411. }
  412. }