PageRenderTime 108ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/protected/extensions/tiny_mce/assets/plugins/jaretypograph/Jare/Typograph/Tool.php

https://bitbucket.org/graaaf/erso
PHP | 363 lines | 199 code | 40 blank | 124 comment | 29 complexity | 2eeb6a1411a21c280a880805fd619e5d MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, LGPL-2.1, BSD-3-Clause, BSD-2-Clause
  1. <?php
  2. /**
  3. * Jare_Typograph_Tool
  4. *
  5. * @copyright Copyright (c) 2009 E.Muravjev Studio (http://emuravjev.ru)
  6. * @license http://emuravjev.ru/works/tg/eula/
  7. * @version 2.0.0
  8. * @author Arthur Rusakov <arthur@emuravjev.ru>
  9. * @category Jare
  10. * @package Jare_Typograph
  11. */
  12. class Jare_Typograph_Tool
  13. {
  14. /**
  15. * Режимы очистки текста
  16. */
  17. const CLEAR_MODE_UTF8_NATIVE = 1;
  18. const CLEAR_MODE_HTML_MATTER = 2;
  19. /**
  20. * Таблица символов
  21. *
  22. * @var array
  23. */
  24. protected static $_charsTable = array(
  25. '"' => array('html' => array('&laquo;', '&raquo;', '&ldquo;', '&lsquo;', '&bdquo;', '&ldquo;', '&quot;', '&#171;', '&#187;'),
  26. 'utf8' => array(0x201E, 0x201C, 0x201F, 0x201D, 0x00AB, 0x00BB)),
  27. ' ' => array('html' => array('&nbsp;', '&thinsp;', '&#160;'),
  28. 'utf8' => array(0x00A0, 0x2002, 0x2003, 0x2008, 0x2009)),
  29. '-' => array('html' => array('&mdash;', '&ndash;', '&minus;', '&#151;', '&#8212;', '&#8211;'),
  30. 'utf8' => array(0x002D, 0x2014, 0x2010, 0x2012, 0x2013)),
  31. '==' => array('html' => array('&equiv;'),
  32. 'utf8' => array(0x2261)),
  33. '...' => array('html' => array('&hellip;', '&#0133;'),
  34. 'utf8' => array(0x2026)),
  35. '!=' => array('html' => array('&ne;', '&#8800;'),
  36. 'utf8' => array(0x2260)),
  37. '<=' => array('html' => array('&le;', '&#8804;'),
  38. 'utf8' => array(0x2264)),
  39. '>=' => array('html' => array('&ge;', '&#8805;'),
  40. 'utf8' => array(0x2265)),
  41. '1/2' => array('html' => array('&frac12;', '&#189;'),
  42. 'utf8' => array(0x00BD)),
  43. '1/4' => array('html' => array('&frac14;', '&#188;'),
  44. 'utf8' => array(0x00BC)),
  45. '3/4' => array('html' => array('&frac34;', '&#190;'),
  46. 'utf8' => array(0x00BE)),
  47. '+-' => array('html' => array('&plusmn;', '&#177;'),
  48. 'utf8' => array(0x00B1)),
  49. '&' => array('html' => array('&amp;', '&#38;')),
  50. '(tm)' => array('html' => array('&trade;', '&#153;'),
  51. 'utf8' => array(0x2122)),
  52. '(r)' => array('html' => array('&reg;', '&#174;'),
  53. 'utf8' => array(0x00AE)),
  54. '(c)' => array('html' => array('&copy;', '&#169;'),
  55. 'utf8' => array(0x00A9)),
  56. '`' => array('html' => array('&#769;')),
  57. '\'' => array('html' => array('&rsquo;', '’')),
  58. 'x' => array('html' => array('&times;', '&#215;'),
  59. 'utf8' => array('×') /* какой же у него может быть код? */),
  60. );
  61. /**
  62. * Список из элементов, в которых текст не будет типографироваться
  63. *
  64. * @var array
  65. */
  66. protected static $_customBlocks = array();
  67. /**
  68. * Добавление к тегам атрибута 'id', благодаря которому
  69. * при повторном типографирование текста будут удалены теги,
  70. * расставленные данным типографом
  71. *
  72. * @var array
  73. */
  74. protected static $_typographSpecificTagId = false;
  75. /**
  76. * Удаление кодов HTML из текста
  77. *
  78. * <code>
  79. * // Remove UTF-8 chars:
  80. * $str = Jare_Typograph_Tool::clearSpecialChars('your text', Jare_Typograph_Tool::CLEAR_MODE_UTF8_NATIVE);
  81. * // ... or HTML codes only:
  82. * $str = Jare_Typograph_Tool::clearSpecialChars('your text', Jare_Typograph_Tool::CLEAR_MODE_HTML_MATTER);
  83. * // ... or combo:
  84. * $str = Jare_Typograph_Tool::clearSpecialChars('your text', Jare_Typograph_Tool::CLEAR_MODE_UTF8_NATIVE|Jare_Typograph_Tool::CLEAR_MODE_HTML_MATTER);
  85. * </code>
  86. *
  87. * @param string $text
  88. * @param int $mode
  89. * @return string
  90. */
  91. public static function clearSpecialChars($text, $mode)
  92. {
  93. $mode = (int) $mode;
  94. switch($mode) {
  95. case self::CLEAR_MODE_UTF8_NATIVE:
  96. $mode = array('utf8');
  97. break;
  98. case self::CLEAR_MODE_HTML_MATTER:
  99. $mode = array('html');
  100. break;
  101. case self::CLEAR_MODE_UTF8_NATIVE | self::CLEAR_MODE_HTML_MATTER:
  102. $mode = array('utf8', 'html');
  103. break;
  104. }
  105. if (!is_array($mode)) {
  106. require_once 'Jare/Typograph/Tool/Exception.php';
  107. throw new Jare_Typograph_Tool_Exception("Incorrect mode");
  108. }
  109. foreach (self::$_charsTable as $char => $vals) {
  110. foreach ($mode as $type) {
  111. if (isset($vals[$type])) {
  112. foreach ($vals[$type] as $v) {
  113. if ('utf8' === $type && is_int($v)) {
  114. $v = self::_getUnicodeChar($v);
  115. }
  116. $text = str_replace($v, $char, $text);
  117. }
  118. }
  119. }
  120. }
  121. return $text;
  122. }
  123. /**
  124. * Удаление тегов HTML из текста
  125. * Тег <br /> будет преобразов в перенос строки \n, сочетание тегов </p><p> -
  126. * в двойной перенос
  127. *
  128. * @param string $text
  129. * @param array $allowableTag массив из тегов, которые будут проигнорированы
  130. * @return string
  131. */
  132. public static function removeHtmlTags($text, $allowableTag = null)
  133. {
  134. $ignore = null;
  135. if (null !== $allowableTag) {
  136. if (is_string($allowableTag)) {
  137. $allowableTag = array($allowableTag);
  138. }
  139. if (is_array($allowableTag)) {
  140. require_once 'Jare/Typograph/Tool/Exception.php';
  141. throw new Jare_Typograph_Tool_Exception('Bad type of param #2');
  142. }
  143. foreach ($allowableTag as $tag) {
  144. if ('<' !== substr($tag, 0, 1) || '>' !== substr($tag, -1, 1)) {
  145. require_once 'Jare/Typograph/Tool/Exception.php';
  146. throw new Jare_Typograph_Tool_Exception("Incorrect tag $tag");
  147. }
  148. if ('/' === substr($tag, 1, 1)) {
  149. require_once 'Jare/Typograph/Tool/Exception.php';
  150. throw new Jare_Typograph_Tool_Exception("Incorrect tag $tag");
  151. }
  152. }
  153. $ignore = implode('', $allowableTag);
  154. }
  155. $text = preg_replace('/\<br\s*\/?>/i', "\n", $text);
  156. $text = preg_replace('/\<\/p\>\s*\<p\>/', "\n\n", $text);
  157. $text = strip_tags($text, $ignore);
  158. return $text;
  159. }
  160. /**
  161. * Сохраняем содержимое тегов HTML
  162. *
  163. * Тег 'a' кодируется со специальным префиксом для дальнейшей
  164. * возможности выносить за него кавычки.
  165. *
  166. * @param string $text
  167. * @param bool $safe
  168. * @return string
  169. */
  170. public static function safeTagChars($text, $safe)
  171. {
  172. $safe = (bool) $safe;
  173. if (true === $safe) {
  174. $text = preg_replace('/(\<\/?)(.+?)(\>)/se', '"\1" . ( substr(trim("\2"), 0, 1) === "a" ? "%%___" : "" ) . self::_encrypteContent(trim("\2")) . "\3"', $text);
  175. } else {
  176. $text = preg_replace('/(\<\/?)(.+?)(\>)/se', '"\1" . ( substr(trim("\2"), 0, 3) === "%%___" ? self::_decrypteContent(substr(trim("\2"), 4)) : self::_decrypteContent(trim("\2")) ) . "\3"', $text);
  177. }
  178. return $text;
  179. }
  180. /**
  181. * Создание тега с защищенным содержимым
  182. *
  183. * @param string $content текст, который будет обрамлен тегом
  184. * @param string $tag
  185. * @param array $attribute список атрибутов, где ключ - имя атрибута, а значение - само значение данного атрибута
  186. * @return string
  187. */
  188. public static function buildSafedTag($content, $tag = 'span', $attribute = array())
  189. {
  190. $htmlTag = $tag;
  191. if (self::$_typographSpecificTagId) {
  192. if(!isset($attribute['id'])) {
  193. $attribute['id'] = 'jt-2' . mt_rand(1000,9999);
  194. }
  195. }
  196. if (count($attribute)) {
  197. foreach ($attribute as $attr => $value) {
  198. $htmlTag .= " $attr=\"$value\"";
  199. }
  200. }
  201. return "<" . self::_encrypteContent($htmlTag) . ">$content</" . self::_encrypteContent($tag) . ">";
  202. }
  203. /**
  204. * Список защищенных блоков
  205. *
  206. * @return array
  207. */
  208. public static function getCustomBlocks()
  209. {
  210. return self::$_customBlocks;
  211. }
  212. /**
  213. * Удаленного блока по его номеру ключа
  214. *
  215. * @param int $blockId
  216. * @return void
  217. */
  218. public static function removeCustomBlock($blockId)
  219. {
  220. if (!is_int($blockId)) {
  221. require_once 'Jare/Typograph/Tool/Exception.php';
  222. throw new Jare_Typograph_Tool_Exception("Incorrect type of value");
  223. }
  224. if (!isset(self::$_customBlocks[$blockId])) {
  225. require_once 'Jare/Typograph/Tool/Exception.php';
  226. throw new Jare_Typograph_Tool_Exception("Incorrect index");
  227. }
  228. unset(self::$_customBlocks[$blockId]);
  229. }
  230. /**
  231. * Добавление защищенного блока
  232. *
  233. * <code>
  234. * Jare_Typograph_Tool::addCustomBlocks('<span>', '</span>');
  235. * Jare_Typograph_Tool::addCustomBlocks('\<nobr\>', '\<\/span\>', true);
  236. * </code>
  237. *
  238. * @param string $open начало блока
  239. * @param string $close конец защищенного блока
  240. * @param bool $quoted специальные символы в начале и конце блока экранированы
  241. * @return void
  242. */
  243. public static function addCustomBlocks($open, $close, $quoted = false)
  244. {
  245. $open = trim($open);
  246. $close = trim($close);
  247. if (empty($open) || empty($close)) {
  248. require_once 'Jare/Typograph/Tool/Exception.php';
  249. throw new Jare_Typograph_Tool_Exception("Bad value");
  250. }
  251. if (false === $quoted) {
  252. $open = preg_quote($open, '/');
  253. $close = preg_quote($close, '/');
  254. }
  255. self::$_customBlocks[] = array($open, $close);
  256. }
  257. /**
  258. * Сохранение содержимого защищенных блоков
  259. *
  260. * @param string $text
  261. * @param bool $safe если true, то содержимое блоков будет сохранено, иначе - раскодировано.
  262. * @return string
  263. */
  264. public static function safeCustomBlocks($text, $safe)
  265. {
  266. $safe = (bool) $safe;
  267. if (count(self::$_customBlocks)) {
  268. $safeType = true === $safe ? "self::_encrypteContent('\\2')" : "stripslashes(self::_decrypteContent('\\2'))";
  269. foreach (self::$_customBlocks as $block) {
  270. $text = preg_replace("/({$block[0]})(.+?)({$block[1]})/se", "'\\1' . $safeType . '\\3'" , $text);
  271. }
  272. }
  273. return $text;
  274. }
  275. /**
  276. * Метод, осуществляющий кодирование (сохранение) информации
  277. * с целью невозможности типографировать ее
  278. *
  279. * @param string $text
  280. * @return string
  281. */
  282. protected static function _encrypteContent($text)
  283. {
  284. return base64_encode($text);
  285. }
  286. /**
  287. * Метод, осуществляющий декодирование информации
  288. *
  289. * @param string $text
  290. * @return string
  291. */
  292. protected static function _decrypteContent($text)
  293. {
  294. return base64_decode($text);
  295. }
  296. /**
  297. * Костыли для работы с символами UTF-8
  298. *
  299. * @author somebody?
  300. * @param int $c код символа в кодировке UTF-8 (например, 0x00AB)
  301. * @return bool|string
  302. */
  303. protected static function _getUnicodeChar($c)
  304. {
  305. if ($c <= 0x7F) {
  306. return chr($c);
  307. } else if ($c <= 0x7FF) {
  308. return chr(0xC0 | $c >> 6)
  309. . chr(0x80 | $c & 0x3F);
  310. } else if ($c <= 0xFFFF) {
  311. return chr(0xE0 | $c >> 12)
  312. . chr(0x80 | $c >> 6 & 0x3F)
  313. . chr(0x80 | $c & 0x3F);
  314. } else if ($c <= 0x10FFFF) {
  315. return chr(0xF0 | $c >> 18)
  316. . chr(0x80 | $c >> 12 & 0x3F)
  317. . chr(0x80 | $c >> 6 & 0x3F)
  318. . chr(0x80 | $c & 0x3F);
  319. } else {
  320. return false;
  321. }
  322. }
  323. }