PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Molinos/Base/XML.php

https://code.google.com/p/molinos-cms/
PHP | 646 lines | 447 code | 51 blank | 148 comment | 31 complexity | 29254f47caa007f05c254e8742dc9c4c MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * ??????????? ????? ??? ???????????? XML ????.
  4. *
  5. * @package Molinos_CMS
  6. * @subpackage base
  7. * @author Justin Forest <justin.forest@gmail.com>
  8. * @copyright 2006-2009 molinos.ru
  9. * @license http://www.gnu.org/copyleft/gpl.html GPL
  10. */
  11. class Molinos_Base_XML
  12. {
  13. /**
  14. * ???????????? ??? ????? ?????? ? simple().
  15. *
  16. * @var string
  17. */
  18. protected static $xml_errors;
  19. /**
  20. * Renders an HTML element.
  21. *
  22. * Returns the HTML representation of an element described by
  23. * input parameters which are: element name, an array of attributes,
  24. * and the content. Except for the first parameter, all is optional.
  25. *
  26. * @param string $em ??? ???????????? ????????.
  27. * @param array $attrs ????????.
  28. * @param string $content ??????????.
  29. * @return string ??????? XML ???.
  30. */
  31. public static function em()
  32. {
  33. if (func_num_args() == 0 or func_num_args() > 3)
  34. throw new InvalidArgumentException('Molinos_Base_XML::em() expects 1 to 3 arguments.');
  35. else {
  36. $args = func_get_args();
  37. $name = array_shift($args);
  38. if (empty($name))
  39. throw new InvalidArgumentException('Attempting to create an XML element without a name.');
  40. $parts = array();
  41. $content = null;
  42. if (is_array($tmp = array_shift($args)))
  43. $parts = $tmp;
  44. else
  45. $content = $tmp;
  46. if (!empty($args))
  47. $content = array_shift($args);
  48. }
  49. if (array_key_exists('#cdata', $parts)) {
  50. $content = self::cdata($parts['#cdata']);
  51. unset($parts['#cdata']);
  52. } elseif (array_key_exists('#text', $parts)) {
  53. $content = $parts['#text'];
  54. unset($parts['#text']);
  55. }
  56. $name = str_replace('_', '-', $name);
  57. $output = '<'. $name;
  58. if (('td' == $name or 'th' == $name) and empty($content))
  59. $content = '&nbsp;';
  60. if (empty($parts))
  61. $parts = array();
  62. $fixmap = array(
  63. 'a' => 'href',
  64. 'form' => 'action',
  65. );
  66. $output .= self::attrs($parts);
  67. if (null === $content and !in_array($name, array('a', 'script', 'div', 'textarea', 'span', 'base'))) {
  68. $output .= '/>';
  69. } else {
  70. $output .= '>'. $content .'</'. $name .'>';
  71. }
  72. return $output;
  73. }
  74. /**
  75. * ?????????????? ?????????.
  76. *
  77. * ???????????? ????? ????????? (????? ???????), ??????? ?? ? ???????
  78. * ???????? ? ??????? ???????? ????????. ???????? true ???????? ?? "yes",
  79. * ?????? ???????? ?? ?????????.
  80. *
  81. * @param array $attrs ???????? ??? ??????????????.
  82. * @return string ?????? ? ?????????? XML ????????.
  83. */
  84. public static function attrs(array $attrs)
  85. {
  86. $result = '';
  87. ksort($attrs);
  88. foreach ($attrs as $k => $v) {
  89. if (!ctype_alpha(substr($k, 0, 1)))
  90. continue;
  91. if ('class' == $k) {
  92. if (!is_array($v))
  93. $v = preg_split('/\s+/', $v, -1, PREG_SPLIT_NO_EMPTY);
  94. $v = join(' ', array_unique($v));
  95. }
  96. if (empty($v) or is_array($v))
  97. continue;
  98. if (strlen($v)) {
  99. if (true === $v)
  100. $v = 'yes';
  101. else
  102. $v = Molinos_Base_XML::plain($v, false);
  103. $result .= ' '.self::attrname($k).'=\''. $v .'\'';
  104. } elseif ($k == 'value') {
  105. $result .= " value=''";
  106. }
  107. }
  108. return $result;
  109. }
  110. /**
  111. * ??????? ???????????? HTML ??????.
  112. *
  113. * ?????????? ?????????????????? ????????? <li>, ?????? ?? ??????? ????????
  114. * ???? ???????? ?? ???????, ?????????????? ? ??????? htmlspecialchars().
  115. * ????? ??????? ????????????. ??? ?????? (<ul> ??? <ol>) ?? ???????????.
  116. *
  117. * @param array $elements ???????? ??????. ????? ????????????.
  118. * @return string ?????????????????? ????????? <li>.
  119. */
  120. public static function simpleList(array $elements)
  121. {
  122. $result = '';
  123. foreach ($elements as $em)
  124. $result .= self::em('li', htmlspecialchars($em));
  125. return $result;
  126. }
  127. /**
  128. * ???????????? ?????? ????????.
  129. *
  130. * ????? ??????? ????????? ? ??????? value ????????, ???????? — ? ?????,
  131. * ??? ???? (??? ?????????????).
  132. *
  133. * @param array $elements ????????????? ?????? ????????.
  134. * @param string $emName ??? ????????? ?? ??????????.
  135. * @param string $wrapperName ??? ????????, ? ??????? ??????????????
  136. * ?????????, ???? ?????? ?? ????.
  137. * @return string XML ???.
  138. */
  139. public static function simpleOptions(array $elements, $emName = 'option', $wrapperName = null)
  140. {
  141. $output = '';
  142. foreach ($elements as $k => $v)
  143. $output .= Molinos_Base_XML::em($emName, array(
  144. 'value' => $k,
  145. ), $v);
  146. if (null !== $wrapperName and !empty($output))
  147. return Molinos_Base_XML::em($wrapperName, $output);
  148. return $output;
  149. }
  150. /**
  151. * ????????????? ?????? ? CDATA, ???? ?????.
  152. *
  153. * @param string $data ?????????????? ??????.
  154. * @return string ???????? ??????, ???? ?? ???????? ????????????, ??? ???
  155. * ??, ?????????? ? CDATA, ???? ???????? ???? ?? ????????: "<>&".
  156. */
  157. public static function cdata($data)
  158. {
  159. if (empty($data))
  160. return null;
  161. if (is_array($data) or is_object($data))
  162. return null;
  163. if (strlen($data) != strcspn($data, '<>&'))
  164. return '<![CDATA[' . $data . ']]>';
  165. else
  166. return $data;
  167. }
  168. /**
  169. * ?????????????? ????????????.
  170. *
  171. * @return string ?????????????????? ????????? <link> ? <script>.
  172. *
  173. * @deprecated ?????? ?? ????????????, ??????????.
  174. * @todo ???????.
  175. */
  176. public static function formatExtras(array $extras)
  177. {
  178. $output = '';
  179. foreach ($extras as $item) {
  180. switch ($item[0]) {
  181. case 'style':
  182. $output .= Molinos_Base_XML::em('link', array(
  183. 'rel' => 'stylesheet',
  184. 'type' => 'text/css',
  185. 'href' => Molinos_Core_Utils::webpath($item[1]),
  186. ));
  187. break;
  188. case 'script':
  189. $output .= Molinos_Base_XML::em('script', array(
  190. 'type' => 'text/javascript',
  191. 'src' => Molinos_Core_Utils::webpath($item[1]),
  192. ));
  193. break;
  194. }
  195. }
  196. return $output;
  197. }
  198. /**
  199. * ?????????? ??????????? HTML, ??????????? ?????? ?? ?????.
  200. *
  201. * @param string $text ??????????? ?????.
  202. * @param bool $strip true, ???? ????? ??????? ????.
  203. * @return string ?????????????? ?????.
  204. */
  205. public static function plain($text, $strip = true)
  206. {
  207. if (is_object($text) or is_array($text))
  208. throw new InvalidArgumentException('Molinos_Base_XML::plain() expects a string.');
  209. if ($strip)
  210. $text = strip_tags($text);
  211. return str_replace(array('&amp;quot;'), array('&quot;'), htmlspecialchars($text, ENT_QUOTES));
  212. }
  213. /**
  214. * ????????? ??????.
  215. *
  216. * @param string $href ????? ??????.
  217. * @param string $text ????? ??????.
  218. * @param array $options ?????????????? ????????.
  219. * @return string ????????????????? ??????.
  220. *
  221. * @deprecated ??????? ???????????? {@link em()}.
  222. * @todo ???????.
  223. */
  224. public static function link($href, $text, array $options = array())
  225. {
  226. $options['href'] = $href;
  227. return Molinos_Base_XML::em('a', $options, $text);
  228. }
  229. /**
  230. * ????????????? ????????? ??????????? ? ???????.
  231. *
  232. * @param string $em ??? ????????-???????.
  233. * @param string $content ????????????? ??????????.
  234. * @param array $options ?????????????? ????????.
  235. * @return string ?????????? $content, ?????????? ? ??????? $em. ????
  236. * ? $content ?????, ?????????? NULL.
  237. */
  238. public static function wrap($em, $content, $options = null)
  239. {
  240. return empty($content)
  241. ? null
  242. : Molinos_Base_XML::em($em, $options, $content);
  243. }
  244. /**
  245. * ????????? ????? ????????.
  246. *
  247. * @param string $string ??? ????????.
  248. * @return string ??? ????????, ?? ???????? ??????? ??? ???????, ?????
  249. * ????????? ????, ???? ? ???????, ? ????? ? ???????? ???????? ????????.
  250. */
  251. public static function attrname($string)
  252. {
  253. return preg_replace('/[^a-z0-9-]/i', '', str_replace(array('_', '.'), array('-', '-'), $string));
  254. }
  255. /**
  256. * ?????????? ???????? ??????, ????????? ??? ????????????? ? ?????????.
  257. *
  258. * ??????? ??? ???? ? ??????? ? ????? ????? 0x20, ??? ????????? ?????????
  259. * ? ????? ??????????.
  260. *
  261. * @param string $html ???????? ?????.
  262. * @param integer $length ?????, ? ????????.
  263. * @return string ????????? ???????? ?????? ?????? ?????.
  264. */
  265. public static function snippet($html, $length = 200)
  266. {
  267. $snippet = mb_strimwidth(strip_tags(html_entity_decode($html)), 0, $length, '…', 'utf-8');
  268. $snippet = preg_replace('/[\x01-\x20]+/', ' ', $snippet);
  269. return trim($snippet);
  270. }
  271. /**
  272. * ?????????? SimpleXMLElement.
  273. *
  274. * ????? ???????? ?????????? ????????? ???????? ??????, ??????? ??????????,
  275. * ????????? ? ???, ????? ????????? ??????????.
  276. *
  277. * @param string $xml ???, ??????? ????? ??????????.
  278. * @return SimpleXMLElement ????????? ???????.
  279. */
  280. public static function simple($xml)
  281. {
  282. $xml = self::decode_entities($xml);
  283. self::$xml_errors = '';
  284. set_error_handler(array(__CLASS__, 'simple_error'), -1);
  285. try {
  286. $em = new SimpleXMLElement($xml);
  287. restore_error_handler();
  288. } catch (Exception $e) {
  289. restore_error_handler();
  290. $logger = Molinos_Core_Logger::getInstance();
  291. $logger->error(self::$xml_errors . "The full XML document follows.\n" . $xml);
  292. throw new RuntimeException(t('Could not process the XML document, see the log file for details.'));
  293. }
  294. return $em;
  295. }
  296. public static function simple_error($errno, $errstr, $errfile, $errline)
  297. {
  298. self::$xml_errors .= trim($errstr) . "\n";
  299. }
  300. /**
  301. * ?????? HTML ????????? ?? ?????????? ?????????????.
  302. *
  303. * ?????? ???????? ???????? HTML ? ??????? SimpleXML (issue 2155).
  304. *
  305. * @param string $xml ???????? ?????.
  306. * @return string ????? ? ???????? ?????? ????? ?????????.
  307. */
  308. public static function decode_entities($xml)
  309. {
  310. return str_replace(array_keys(self::$entity_map), array_values(self::$entity_map), $xml);
  311. }
  312. /**
  313. * ?????????? ????? ?????????.
  314. *
  315. * ????? ?? ????????????. ??? ???????? ?? ?????? ??????.
  316. */
  317. public static function build_entity_map()
  318. {
  319. // Resources used:
  320. // http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
  321. // http://www.intuitive.com/coolweb/entities.html
  322. // $base_url = './';
  323. $base_url = 'http://www.w3.org/TR/html4/';
  324. $fileNames = array('HTMLlat1.ent', 'HTMLspecial.ent', 'HTMLsymbol.ent');
  325. $result = array();
  326. foreach ($fileNames as $fileName) {
  327. $contents = file_get_contents($base_url . $fileName);
  328. if (preg_match_all('/<!ENTITY\s+(\S+)\s+CDATA\s+"([^"]+)"/', $contents, $m))
  329. foreach ($m[1] as $idx => $src) {
  330. if (!in_array($src, array('quot', 'apos', 'amp', 'lt', 'gt'))) {
  331. $dst = $m[2][$idx];
  332. $dst = html_entity_decode($dst, ENT_QUOTES, 'utf-8');
  333. $result['&' . $src . ';'] = $dst;
  334. }
  335. }
  336. }
  337. ksort($result);
  338. file_put_contents('entities.php', '<?php return ' . var_export($result, true) . ';');
  339. }
  340. /**
  341. * ????? ?????????, ????????? ? ??????? build_entity_map().
  342. *
  343. * @var array
  344. */
  345. protected static $entity_map = array(
  346. '&AElig;' => 'Ć',
  347. '&Aacute;' => 'Á',
  348. '&Acirc;' => 'Â',
  349. '&Agrave;' => 'Ŕ',
  350. '&Alpha;' => '?',
  351. '&Aring;' => 'Ĺ',
  352. '&Atilde;' => 'Ă',
  353. '&Auml;' => 'Ä',
  354. '&Beta;' => '?',
  355. '&Ccedil;' => 'Ç',
  356. '&Chi;' => '?',
  357. '&Dagger;' => '‡',
  358. '&Delta;' => '?',
  359. '&ETH;' => 'Đ',
  360. '&Eacute;' => 'É',
  361. '&Ecirc;' => 'Ę',
  362. '&Egrave;' => 'Č',
  363. '&Epsilon;' => '?',
  364. '&Eta;' => '?',
  365. '&Euml;' => 'Ë',
  366. '&Gamma;' => '?',
  367. '&Iacute;' => 'Í',
  368. '&Icirc;' => 'Î',
  369. '&Igrave;' => 'Ě',
  370. '&Iota;' => '?',
  371. '&Iuml;' => 'Ď',
  372. '&Kappa;' => '?',
  373. '&Lambda;' => '?',
  374. '&Mu;' => '?',
  375. '&Ntilde;' => 'Ń',
  376. '&Nu;' => '?',
  377. '&OElig;' => 'Œ',
  378. '&Oacute;' => 'Ó',
  379. '&Ocirc;' => 'Ô',
  380. '&Ograve;' => 'Ň',
  381. '&Omega;' => '?',
  382. '&Omicron;' => '?',
  383. '&Oslash;' => 'Ř',
  384. '&Otilde;' => 'Ő',
  385. '&Ouml;' => 'Ö',
  386. '&Phi;' => '?',
  387. '&Pi;' => '?',
  388. '&Prime;' => '?',
  389. '&Psi;' => '?',
  390. '&Rho;' => '?',
  391. '&Scaron;' => 'Š',
  392. '&Sigma;' => '?',
  393. '&THORN;' => 'Ţ',
  394. '&Tau;' => '?',
  395. '&Theta;' => '?',
  396. '&Uacute;' => 'Ú',
  397. '&Ucirc;' => 'Ű',
  398. '&Ugrave;' => 'Ů',
  399. '&Upsilon;' => '?',
  400. '&Uuml;' => 'Ü',
  401. '&Xi;' => '?',
  402. '&Yacute;' => 'Ý',
  403. '&Yuml;' => 'Ÿ',
  404. '&Zeta;' => '?',
  405. '&aacute;' => 'á',
  406. '&acirc;' => 'â',
  407. '&acute;' => '´',
  408. '&aelig;' => 'ć',
  409. '&agrave;' => 'ŕ',
  410. '&alefsym;' => '?',
  411. '&alpha;' => '?',
  412. '&and;' => '?',
  413. '&ang;' => '?',
  414. '&aring;' => 'ĺ',
  415. '&asymp;' => '?',
  416. '&atilde;' => 'ă',
  417. '&auml;' => 'ä',
  418. '&bdquo;' => '„',
  419. '&beta;' => '?',
  420. '&brvbar;' => 'Ś',
  421. '&bull;' => '•',
  422. '&cap;' => '?',
  423. '&ccedil;' => 'ç',
  424. '&cedil;' => '¸',
  425. '&cent;' => '˘',
  426. '&chi;' => '?',
  427. '&circ;' => 'ˆ',
  428. '&clubs;' => '?',
  429. '&cong;' => '?',
  430. '&copy;' => 'Š',
  431. '&crarr;' => '?',
  432. '&cup;' => '?',
  433. '&curren;' => '¤',
  434. '&dArr;' => '?',
  435. '&dagger;' => '†',
  436. '&darr;' => '?',
  437. '&deg;' => '°',
  438. '&delta;' => '?',
  439. '&diams;' => '?',
  440. '&divide;' => '÷',
  441. '&eacute;' => 'é',
  442. '&ecirc;' => 'ę',
  443. '&egrave;' => 'č',
  444. '&empty;' => '?',
  445. '&emsp;' => '?',
  446. '&ensp;' => '?',
  447. '&epsilon;' => '?',
  448. '&equiv;' => '?',
  449. '&eta;' => '?',
  450. '&eth;' => 'đ',
  451. '&euml;' => 'ë',
  452. '&euro;' => '€',
  453. '&exist;' => '?',
  454. '&fnof;' => 'ƒ',
  455. '&forall;' => '?',
  456. '&frac12;' => '˝',
  457. '&frac14;' => 'ź',
  458. '&frac34;' => 'ž',
  459. '&frasl;' => '?',
  460. '&gamma;' => '?',
  461. '&ge;' => '?',
  462. '&hArr;' => '?',
  463. '&harr;' => '?',
  464. '&hearts;' => '?',
  465. '&hellip;' => '…',
  466. '&iacute;' => 'í',
  467. '&icirc;' => 'î',
  468. '&iexcl;' => 'Ą',
  469. '&igrave;' => 'ě',
  470. '&image;' => '?',
  471. '&infin;' => '?',
  472. '&int;' => '?',
  473. '&iota;' => '?',
  474. '&iquest;' => 'ż',
  475. '&isin;' => '?',
  476. '&iuml;' => 'ď',
  477. '&kappa;' => '?',
  478. '&lArr;' => '?',
  479. '&lambda;' => '?',
  480. '&lang;' => '?',
  481. '&laquo;' => 'Ť',
  482. '&larr;' => '?',
  483. '&lceil;' => '?',
  484. '&ldquo;' => '“',
  485. '&le;' => '?',
  486. '&lfloor;' => '?',
  487. '&lowast;' => '?',
  488. '&loz;' => '?',
  489. '&lrm;' => '?',
  490. '&lsaquo;' => '‹',
  491. '&lsquo;' => '‘',
  492. '&macr;' => 'Ż',
  493. '&mdash;' => '—',
  494. '&micro;' => 'ľ',
  495. '&middot;' => 'ˇ',
  496. '&minus;' => '?',
  497. '&mu;' => '?',
  498. '&nabla;' => '?',
  499. '&nbsp;' => ' ',
  500. '&ndash;' => '–',
  501. '&ne;' => '?',
  502. '&ni;' => '?',
  503. '&not;' => 'Ź',
  504. '&notin;' => '?',
  505. '&nsub;' => '?',
  506. '&ntilde;' => 'ń',
  507. '&nu;' => '?',
  508. '&oacute;' => 'ó',
  509. '&ocirc;' => 'ô',
  510. '&oelig;' => 'œ',
  511. '&ograve;' => 'ň',
  512. '&oline;' => '?',
  513. '&omega;' => '?',
  514. '&omicron;' => '?',
  515. '&oplus;' => '?',
  516. '&or;' => '?',
  517. '&ordf;' => 'Ş',
  518. '&ordm;' => 'ş',
  519. '&oslash;' => 'ř',
  520. '&otilde;' => 'ő',
  521. '&otimes;' => '?',
  522. '&ouml;' => 'ö',
  523. '&para;' => 'ś',
  524. '&part;' => '?',
  525. '&permil;' => '‰',
  526. '&perp;' => '?',
  527. '&phi;' => '?',
  528. '&pi;' => '?',
  529. '&piv;' => '?',
  530. '&plusmn;' => 'ą',
  531. '&pound;' => 'Ł',
  532. '&prime;' => '?',
  533. '&prod;' => '?',
  534. '&prop;' => '?',
  535. '&psi;' => '?',
  536. '&rArr;' => '?',
  537. '&radic;' => '?',
  538. '&rang;' => '?',
  539. '&raquo;' => 'ť',
  540. '&rarr;' => '?',
  541. '&rceil;' => '?',
  542. '&rdquo;' => '”',
  543. '&real;' => '?',
  544. '&reg;' => 'Ž',
  545. '&rfloor;' => '?',
  546. '&rho;' => '?',
  547. '&rlm;' => '?',
  548. '&rsaquo;' => '›',
  549. '&rsquo;' => '’',
  550. '&sbquo;' => '‚',
  551. '&scaron;' => 'š',
  552. '&sdot;' => '?',
  553. '&sect;' => '§',
  554. '&shy;' => '­',
  555. '&sigma;' => '?',
  556. '&sigmaf;' => '?',
  557. '&sim;' => '?',
  558. '&spades;' => '?',
  559. '&sub;' => '?',
  560. '&sube;' => '?',
  561. '&sum;' => '?',
  562. '&sup1;' => 'š',
  563. '&sup2;' => '˛',
  564. '&sup3;' => 'ł',
  565. '&sup;' => '?',
  566. '&supe;' => '?',
  567. '&szlig;' => 'ß',
  568. '&tau;' => '?',
  569. '&there4;' => '?',
  570. '&theta;' => '?',
  571. '&thetasym;' => '?',
  572. '&thinsp;' => '?',
  573. '&thorn;' => 'ţ',
  574. '&tilde;' => '˜',
  575. '&times;' => '×',
  576. '&trade;' => '™',
  577. '&uArr;' => '?',
  578. '&uacute;' => 'ú',
  579. '&uarr;' => '?',
  580. '&ucirc;' => 'ű',
  581. '&ugrave;' => 'ů',
  582. '&uml;' => '¨',
  583. '&upsih;' => '?',
  584. '&upsilon;' => '?',
  585. '&uuml;' => 'ü',
  586. '&weierp;' => '?',
  587. '&xi;' => '?',
  588. '&yacute;' => 'ý',
  589. '&yen;' => 'Ľ',
  590. '&yuml;' => '˙',
  591. '&zeta;' => '?',
  592. '&zwj;' => '?',
  593. '&zwnj;' => '?',
  594. );
  595. }