PageRenderTime 26ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/serendipity_event_bbcode/serendipity_event_bbcode.php

http://github.com/s9y/Serendipity
PHP | 332 lines | 287 code | 28 blank | 17 comment | 9 complexity | 1a108b89cc79bb3d88b6cf278cc4ca59 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. <?php
  2. if (IN_serendipity !== true) {
  3. die ("Don't hack!");
  4. }
  5. @serendipity_plugin_api::load_language(dirname(__FILE__));
  6. class serendipity_event_bbcode extends serendipity_event
  7. {
  8. var $title = PLUGIN_EVENT_BBCODE_NAME;
  9. function introspect(&$propbag)
  10. {
  11. global $serendipity;
  12. $propbag->add('name', PLUGIN_EVENT_BBCODE_NAME);
  13. $propbag->add('description', PLUGIN_EVENT_BBCODE_DESC);
  14. $propbag->add('stackable', false);
  15. $propbag->add('author', 'Jez Hancock, Garvin Hicking');
  16. $propbag->add('version', '2.11.1');
  17. $propbag->add('requirements', array(
  18. 'serendipity' => '1.6',
  19. 'smarty' => '2.6.7',
  20. 'php' => '4.1.0'
  21. ));
  22. $propbag->add('cachable_events', array('frontend_display' => true));
  23. $propbag->add('event_hooks', array('frontend_display' => true, 'frontend_comment' => true, 'css' => true));
  24. $propbag->add('groups', array('MARKUP'));
  25. $this->markup_elements = array(
  26. array(
  27. 'name' => 'ENTRY_BODY',
  28. 'element' => 'body',
  29. ),
  30. array(
  31. 'name' => 'EXTENDED_BODY',
  32. 'element' => 'extended',
  33. ),
  34. array(
  35. 'name' => 'COMMENT',
  36. 'element' => 'comment',
  37. ),
  38. array(
  39. 'name' => 'HTML_NUGGET',
  40. 'element' => 'html_nugget',
  41. )
  42. );
  43. $conf_array = array();
  44. $conf_array[] = 'info';
  45. $conf_array[] = 'target';
  46. foreach($this->markup_elements as $element) {
  47. $conf_array[] = $element['name'];
  48. }
  49. $propbag->add('configuration', $conf_array);
  50. }
  51. function bbcode_callback($matches)
  52. {
  53. $type = $matches[1];
  54. $input = trim($matches[2], "\r\n");
  55. switch ($type) {
  56. case 'code':
  57. $search_replace = array(
  58. '&' => '&amp;',
  59. ' ' => '&#160;',
  60. '&lt;' => '&#60;',
  61. '<' => '&#60;',
  62. '&gt;' => '&#62;',
  63. '>' => '&#62;',
  64. '&quot;' => '&#34;',
  65. ':' => '&#58;',
  66. '[' => '&#91;',
  67. ']' => '&#93;',
  68. ')' => '&#41;',
  69. '(' => '&#40;',
  70. '*' => '&#42;',
  71. '\t' => '&#160;&#160;&#160;&#160;',
  72. '\\"' => '"',
  73. "\\'" => "'"
  74. );
  75. $input = strtr($input, $search_replace);
  76. break;
  77. case 'php':
  78. if (substr($input, 0, 2) != '<?') {
  79. $input = "<?php\n\n$input\n\n?>";
  80. }
  81. ob_start();
  82. highlight_string($input);
  83. $input = ob_get_contents();
  84. ob_end_clean();
  85. $input = str_replace('<br />', "\n", $input);
  86. break;
  87. default:
  88. return false;
  89. }
  90. $input = "<div class=\"bb-$type-title\">" . strtoupper($type) . ":</div>"
  91. . "<div class=\"bb-$type\">$input</div>";
  92. return($input);
  93. }
  94. function generate_content(&$title)
  95. {
  96. $title = $this->title;
  97. }
  98. function introspect_config_item($name, &$propbag)
  99. {
  100. switch($name) {
  101. case 'target':
  102. $propbag->add('type', 'boolean');
  103. $propbag->add('name', PLUGIN_EVENT_BBCODE_TARGET);
  104. $propbag->add('default', 'false');
  105. break;
  106. case 'info':
  107. $propbag->add('type', 'info');
  108. $propbag->add('description', PLUGIN_EVENT_BBCODE_TRANSFORM);
  109. break;
  110. default:
  111. $propbag->add('type', 'boolean');
  112. $propbag->add('name', constant($name));
  113. $propbag->add('description', sprintf(APPLY_MARKUP_TO, constant($name)));
  114. $propbag->add('default', 'true');
  115. break;
  116. }
  117. return true;
  118. }
  119. function install()
  120. {
  121. serendipity_plugin_api::hook_event('backend_cache_entries', $this->title);
  122. }
  123. function uninstall(&$propbag)
  124. {
  125. serendipity_plugin_api::hook_event('backend_cache_purge', $this->title);
  126. serendipity_plugin_api::hook_event('backend_cache_entries', $this->title);
  127. }
  128. function bbcode($input)
  129. {
  130. static $bbcodes = null;
  131. // Only allow numbers and characters for CSS: "red", "#FF0000", ...
  132. static $pattern_css = '([ 0-9a-z#-]+?)';
  133. // Only allow strings occuring in emails: .-_@, 0-9, a-z
  134. static $pattern_mail = '([\.\-\+~@_0-9a-z]+?)';
  135. // Only allow strings occuring in URLs: &;?:.-_@/, 0-9, a-z
  136. static $pattern_url = '([@!=~\?:&;0-9a-z#\.\-_\/,%\+]+?)';
  137. // Disallow possibly evil HTML characters which may lead to Javascript XSS: '"();
  138. static $pattern_query = '([^"\'\(\);]+?)';
  139. static $target = null;
  140. if ($target === null) {
  141. $target = serendipity_db_bool($this->get_config('target'));
  142. }
  143. // Note:
  144. // * Anything between <xxx>...</xxx> tags will be caught by htmlspecialchars() and disallows custom HTML tags.
  145. // * (?::\w+)? means "non capturing" match on any word character.
  146. // * (?<!\\\\) means any bbcode which is not prefixed by \[...]
  147. if ($bbcodes === null) {
  148. $bbcodes = array(
  149. '/(?<!\\\\)\[color(?::\w+)?=' . $pattern_css . '\](.*?)\[\/color(?::\w+)?\]/si' => "<span style=\"color:\\1\">\\2</span>",
  150. '/(?<!\\\\)\[size(?::\w+)?=' . $pattern_css . '\](.*?)\[\/size(?::\w+)?\]/si' => "<span style=\"font-size:\\1\">\\2</span>",
  151. '/(?<!\\\\)\[font(?::\w+)?=' . $pattern_css . '\](.*?)\[\/font(?::\w+)?\]/si' => "<span style=\"font-family:\\1\">\\2</span>",
  152. '/(?<!\\\\)\[align(?::\w+)?=' . $pattern_css . '\](.*?)\[\/align(?::\w+)?\]/si' => "<div style=\"text-align:\\1\">\\2</div>",
  153. '/(?<!\\\\)\[b(?::\w+)?\](.*?)\[\/b(?::\w+)?\]/si' => "<span style=\"font-weight:bold\">\\1</span>",
  154. '/(?<!\\\\)\[i(?::\w+)?\](.*?)\[\/i(?::\w+)?\]/si' => "<span style=\"font-style:italic\">\\1</span>",
  155. '/(?<!\\\\)\[u(?::\w+)?\](.*?)\[\/u(?::\w+)?\]/si' => "<span style=\"text-decoration:underline\">\\1</span>",
  156. '/(?<!\\\\)\[center(?::\w+)?\](.*?)\[\/center(?::\w+)?\]/si' => "<div style=\"text-align:center\">\\1</div>",
  157. '/(?<!\\\\)\[strike(?::\w+)?\](.*?)\[\/strike(?::\w+)?\]/si' => "<span style=\"text-decoration:line-through\">\\1</span>",
  158. // [email]
  159. '/(?<!\\\\)\[email(?::\w+)?\]' . $pattern_mail . '\[\/email(?::\w+)?\]/si' => "<a href=\"mailto:\\1\" class=\"bb-email\">\\1</a>",
  160. '/(?<!\\\\)\[email(?::\w+)?=' . $pattern_mail . '\](.*?)\[\/email(?::\w+)?\]/si' => "<a href=\"mailto:\\1\" class=\"bb-email\">\\2</a>",
  161. // [url]
  162. '/(?<!\\\\)\[(google|search)\]' . $pattern_query . '\[\/(google|search)\]/si' => "<a href=\"http://www.google.com/search?q=\\2\" " . ($target ? "target=\"_blank\"" : "") . " class=\"bb-url\">\\2</a>",
  163. '/(?<!\\\\)\[url(?::\w+)?\]www\.' . $pattern_url . '\[\/url(?::\w+)?\]/si' => "<a href=\"http://www.\\1\" " . ($target ? "target=\"_blank\"" : "") . " class=\"bb-url\">\\1</a>",
  164. '/(?<!\\\\)\[url(?::\w+)?\]' . $pattern_url . '\[\/url(?::\w+)?\]/si' => "<a href=\"\\1\" " . ($target ? "target=\"_blank\"" : "") . " class=\"bb-url\">\\1</a>",
  165. '/(?<!\\\\)\[url(?::\w+)?=' . $pattern_url . '?\](.*?)\[\/url(?::\w+)?\]/si' => "<a href=\"\\1\" " . ($target ? "target=\"_blank\"" : "") . " class=\"bb-url\">\\2</a>",
  166. // [img]
  167. '/(?<!\\\\)\[img(?::\w+)?\]' . $pattern_url . '\[\/img(?::\w+)?\]/si' => "<img src=\"\\1\" alt=\"\\1\" class=\"bb-image\" />",
  168. '/(?<!\\\\)\[img(?::\w+)?=([0-9]*?)x([0-9]*?)\]' . $pattern_url . '\[\/img(?::\w+)?\]/si' => "<img width=\"\\1\" height=\"\\2\" src=\"\\3\" alt=\"\\3\" class=\"bb-image\" />",
  169. // [quote]
  170. '/(?<!\\\\)\[quote(?::\w+)?\](.*?)\[\/quote(?::\w+)?\]/si' => "<div class=\"bb-code-title\">QUOTE:</div><div class=\"bb-quote\">\\1</div>",
  171. '/(?<!\\\\)\[quote(?::\w+)?=(?:&quot;|"|\')?(.*?)["\']?(?:&quot;|"|\')?\](.*?)\[\/quote\]/si' => "<div class=\"bb-code-title\">QUOTE \\1:</div><div class=\"bb-quote\">\\2</div>",
  172. // [list]
  173. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[\*(?::\w+)?\](.*?)(?=(?:\s*<br\s*\/?>\s*)?\[\*|(?:\s*<br\s*\/?>\s*)?\[\/?list)/si' => "\n<li class=\"bb-listitem\">\\1</li>",
  174. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[\/list(:(?!u|o)\w+)?\](?:<br\s*\/?>)?/si' => "\n</ul>",
  175. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[\/list:u(:\w+)?\](?:<br\s*\/?>)?/si' => "\n</ul>",
  176. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[\/list:o(:\w+)?\](?:<br\s*\/?>)?/si' => "\n</ul>",
  177. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list(:(?!u|o)\w+)?\]\s*(?:<br\s*\/?>)?/si' => "\n<ul class=\"bb-list-unordered\">",
  178. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list:u(:\w+)?\]\s*(?:<br\s*\/?>)?/si' => "\n<ul class=\"bb-list-unordered\">",
  179. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list:o(:\w+)?\]\s*(?:<br\s*\/?>)?/si' => "\n<ul class=\"bb-list-ordered\">",
  180. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list(?::o)?(:\w+)?=1\]\s*(?:<br\s*\/?>)?/si' => "\n<ul class=\"bb-list-ordered bb-list-ordered-d\">",
  181. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list(?::o)?(:\w+)?=i\]\s*(?:<br\s*\/?>)?/s' => "\n<ul class=\"bb-list-ordered bb-list-ordered-lr\">",
  182. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list(?::o)?(:\w+)?=I\]\s*(?:<br\s*\/?>)?/s' => "\n<ul class=\"bb-list-ordered bb-list-ordered-ur\">",
  183. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list(?::o)?(:\w+)?=a\]\s*(?:<br\s*\/?>)?/s' => "\n<ul class=\"bb-list-ordered bb-list-ordered-la\">",
  184. '/(?<!\\\\)(?:\s*<br\s*\/?>\s*)?\[list(?::o)?(:\w+)?=A\]\s*(?:<br\s*\/?>)?/s' => "\n<ul class=\"bb-list-ordered bb-list-ordered-ua\">",
  185. // escaped tags like \[b], \[color], \[url], ...
  186. '/\\\\(\[\/?\w+(?::\w+)*\])/' => "\\1"
  187. );
  188. }
  189. /* Regular expressions taken from http://smarty.incutio.com/?page=BBCodePlugin Wiki (Andre Rabold) */
  190. $input = preg_replace(array_keys($bbcodes), array_values($bbcodes), $input);
  191. // [code] & [php]
  192. $input = preg_replace_callback('/(?<!\\\\)\[(code|php)(?::\w+)?\](.*?)\[\/\\1(?::\w+)?\]/si', array($this, 'bbcode_callback'), $input);
  193. return $input;
  194. }
  195. function event_hook($event, &$bag, &$eventData, $addData = null)
  196. {
  197. global $serendipity;
  198. $hooks = &$bag->get('event_hooks');
  199. if (isset($hooks[$event])) {
  200. switch($event) {
  201. case 'frontend_display':
  202. foreach ($this->markup_elements as $temp) {
  203. if (serendipity_db_bool($this->get_config($temp['name'], 'true')) && isset($eventData[$temp['element']]) &&
  204. !($eventData['properties']['ep_disable_markup_' . $this->instance] ?? null) &&
  205. !isset($serendipity['POST']['properties']['disable_markup_' . $this->instance])) {
  206. $element = $temp['element'];
  207. $eventData[$element] = $this->bbcode($eventData[$element]);
  208. }
  209. }
  210. break;
  211. case 'frontend_comment':
  212. if (serendipity_db_bool($this->get_config('COMMENT', 'true'))) {
  213. echo '<div class="serendipity_commentDirection serendipity_comment_bbcode">' . PLUGIN_EVENT_BBCODE_TRANSFORM . '</div>';
  214. }
  215. break;
  216. case 'css':
  217. // CSS class does NOT exist by user customized template styles, include default
  218. if (strpos($eventData, '.bb-code') === false) {
  219. $eventData .= '
  220. /* serendipity_event_bbcode start */
  221. .bb-quote, .bb-code, .bb-php, .bb-code-title, .bb-php-title {
  222. margin-left: 20px;
  223. margin-right: 20px;
  224. color: black;
  225. direction: ltr;
  226. }
  227. .bb-code-title, .bb-php-title {
  228. margin-bottom: 2px;
  229. background-color:#CCCCCC;
  230. font-weight: bold;
  231. padding-left: 5px;
  232. }
  233. .bb-code, .bb-php {
  234. font-family: courier, "courier new";
  235. background-color: #DDDDDD;
  236. padding: 10px;
  237. white-space: pre;
  238. overflow: auto;
  239. max-height: 24em;
  240. }
  241. .bb-quote {
  242. background-color: #DDDDDD;
  243. padding: 10px;
  244. }
  245. .bb-list-ordered-d {
  246. list-style-type: decimal;
  247. }
  248. .bb-list-ordered-la {
  249. list-style-type: lower-alpha;
  250. }
  251. .bb-list-ordered-ua {
  252. list-style-type: upper-alpha;
  253. }
  254. .bb-list-ordered-lr {
  255. list-style-type:lower-roman;
  256. }
  257. .bb-list-ordered-ur {
  258. list-style-type:upper-roman;
  259. }
  260. /* serendipity_event_bbcode end */
  261. ';
  262. }
  263. break;
  264. default:
  265. return false;
  266. }
  267. return true;
  268. } else {
  269. return false;
  270. }
  271. }
  272. }
  273. /* vim: set sts=4 ts=4 expandtab : */
  274. ?>