PageRenderTime 52ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/spip/ecrire/xml/sax.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 279 lines | 197 code | 40 blank | 42 comment | 31 complexity | 3ac14d99dc8994e78b4b6c7bc3f780ce MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. include_spip('inc/charsets');
  13. include_spip('xml/interfaces');
  14. // http://doc.spip.org/@xml_debutElement
  15. function xml_debutElement($phraseur, $name, $attrs)
  16. {
  17. $depth = $phraseur->depth;
  18. $t = isset($phraseur->ouvrant[$depth]) ? $phraseur->ouvrant[$depth] : ' ';
  19. // espace initial signifie: deja integree au resultat
  20. if ($t[0] != ' ')
  21. {
  22. $phraseur->res .= '<' . $t . '>';
  23. $phraseur->ouvrant[$depth] = ' ' . $t;
  24. }
  25. $t = $phraseur->contenu[$depth];
  26. // n'indenter que s'il y a un separateur avant
  27. $phraseur->res .= preg_replace("/[\n\t ]+$/", "\n$depth", $t);
  28. $phraseur->contenu[$depth] = "";
  29. $att = '';
  30. $sep = ' ';
  31. foreach ($attrs as $k => $v) {
  32. $delim = strpos($v, "'") === false ? "'" : '"';
  33. $val = htmlspecialchars($v,ENT_QUOTES);
  34. $att .= $sep . $k . "=" . $delim
  35. . ($delim !== '"' ? str_replace('&quot;', '"', $val) : $val)
  36. . $delim;
  37. $sep = "\n $depth";
  38. }
  39. $phraseur->depth .= ' ';
  40. $phraseur->contenu[$phraseur->depth] = "";
  41. $phraseur->ouvrant[$phraseur->depth] = $name . $att;
  42. $phraseur->reperes[$phraseur->depth] = xml_get_current_line_number($phraseur->sax);
  43. }
  44. // http://doc.spip.org/@xml_finElement
  45. function xml_finElement($phraseur, $name, $fusion_bal=false)
  46. {
  47. $ouv = $phraseur->ouvrant[$phraseur->depth];
  48. if ($ouv[0] != ' ')
  49. $phraseur->ouvrant[$phraseur->depth] = ' ' . $ouv;
  50. else $ouv= "";
  51. $t = $phraseur->contenu[$phraseur->depth];
  52. $phraseur->depth = substr($phraseur->depth, 2);
  53. $t = preg_replace("/[\n\t ]+$/", "\n" . $phraseur->depth, $t);
  54. // fusion <balise></balise> en <balise />.
  55. // ATTENTION, certains clients http croient que fusion ==> pas d'atttributs
  56. // en particulier pour les balises Script et A.
  57. // en presence d'attributs ne le faire que si la DTD est dispo et d'accord
  58. // (param fusion_bal)
  59. if ($t || (($ouv != $name) AND !$fusion_bal))
  60. $phraseur->res .= ($ouv ? ('<' . $ouv . '>') : '') . $t . "</" . $name . ">";
  61. else
  62. $phraseur->res .= ($ouv ? ('<' . $ouv . ' />') : ("</" . $name . ">"));
  63. }
  64. // http://doc.spip.org/@xml_textElement
  65. function xml_textElement($phraseur, $data)
  66. {
  67. $depth = $phraseur->depth;
  68. $phraseur->contenu[$depth] .= preg_match('/^script/',$phraseur->ouvrant[$depth])
  69. ? $data
  70. : htmlspecialchars($data,ENT_QUOTES);
  71. }
  72. function xml_piElement($phraseur, $target, $data)
  73. {
  74. $depth = $phraseur->depth;
  75. if (strtolower($target) != "php")
  76. $phraseur->contenu[$depth] .= $data;
  77. else {
  78. ob_start();
  79. eval($data);
  80. $data = ob_get_contents();
  81. ob_end_clean();
  82. $phraseur->contenu[$depth] .= $data;
  83. }
  84. }
  85. // http://doc.spip.org/@xml_defautElement
  86. function xml_defaultElement($phraseur, $data)
  87. {
  88. $depth = $phraseur->depth;
  89. if (!isset($phraseur->contenu[$depth])) $phraseur->contenu[$depth]='';
  90. $phraseur->contenu[$depth] .= $data;
  91. }
  92. // http://doc.spip.org/@xml_parsestring
  93. function xml_parsestring($phraseur, $data)
  94. {
  95. $phraseur->contenu[$phraseur->depth] ='';
  96. if (!xml_parse($phraseur->sax, $data, true)) {
  97. coordonnees_erreur($phraseur,
  98. xml_error_string(xml_get_error_code($phraseur->sax))
  99. . "<br />\n" .
  100. (!$phraseur->depth ? '' :
  101. ('(' .
  102. _T('erreur_balise_non_fermee') .
  103. " <tt>" .
  104. $phraseur->ouvrant[$phraseur->depth] .
  105. "</tt> " .
  106. _T('ligne') .
  107. " " .
  108. $phraseur->reperes[$phraseur->depth] .
  109. ") <br />\n" )));
  110. }
  111. }
  112. // http://doc.spip.org/@coordonnees_erreur
  113. function coordonnees_erreur($phraseur, $msg)
  114. {
  115. $entete_length = substr_count($phraseur->entete,"\n");
  116. $phraseur->err[] = array($msg,
  117. xml_get_current_line_number($phraseur->sax) + $entete_length,
  118. xml_get_current_column_number($phraseur->sax));
  119. }
  120. // http://doc.spip.org/@xml_sax_dist
  121. function xml_sax_dist($page, $apply=false, $phraseur=NULL)
  122. {
  123. // init par defaut si pas fait (compatibilite Tidy espace public)
  124. if (!$phraseur) {
  125. $indenter_xml = charger_fonction('indenter', 'xml');
  126. return $indenter_xml($page, $apply);
  127. }
  128. $xml_parser = xml_parser_create($GLOBALS['meta']['charset']);
  129. xml_set_element_handler($xml_parser,
  130. array($phraseur, "debutElement"),
  131. array($phraseur, "finElement"));
  132. xml_set_character_data_handler($xml_parser,
  133. array($phraseur, "textElement"));
  134. xml_set_processing_instruction_handler($xml_parser,
  135. array($phraseur, 'piElement'));
  136. xml_set_default_handler($xml_parser,
  137. array($phraseur, "defaultElement"));
  138. xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false);
  139. if ($apply) {
  140. ob_start();
  141. if (is_array($apply))
  142. $r = call_user_func_array($page, $apply);
  143. else $r = $page();
  144. $page = ob_get_contents();
  145. ob_end_clean();
  146. // fonction sans aucun "echo", ca doit etre le resultat
  147. if (!$page) $page = $r;
  148. }
  149. // charger la DTD et transcoder les entites,
  150. // et escamoter le doctype que sax mange en php5 mais pas en php4
  151. list($entete,$page, $dtc) = sax_bug($page);
  152. $phraseur->sax = $xml_parser;
  153. $phraseur->entete = $entete;
  154. $phraseur->page = $page;
  155. $phraseur->dtc = $dtc;
  156. $phraseur->phraserTout($xml_parser, $page);
  157. xml_parser_free($xml_parser);
  158. }
  159. // SAX ne dit pas si une Entite est dans un attribut ou non.
  160. // Les eliminer toutes sinon celles des attributs apparaissent en zone texte!
  161. // Celles fondamentales pour la lecture (lt gt quot amp) sont conservees
  162. // (d'ailleurs SAX ne les considere pas comme des entites dans un attribut)
  163. // Si la DTD est dispo, on va chercher les entites dedans
  164. // sinon on se rabat sur ce qu'en connait SPIP en standard.
  165. // http://doc.spip.org/@sax_bug
  166. function sax_bug($data)
  167. {
  168. $r = analyser_doctype($data);
  169. if (!$r) {
  170. $data = _MESSAGE_DOCTYPE . _DOCTYPE_ECRIRE
  171. . preg_replace(_REGEXP_DOCTYPE, '', $data);
  172. $r = analyser_doctype($data);
  173. }
  174. list($doctype, $topelement, $avail, $grammaire, $rotlvl, $len) = $r;
  175. include_spip('xml/analyser_dtd');
  176. $dtc = charger_dtd($grammaire, $avail, $rotlvl);
  177. // l'entete contient eventuellement < ? xml... ? >, le Doctype,
  178. // et des commentaires autour d'eux
  179. $entete = ltrim(substr($data,0,$len));
  180. if ($dtc) {
  181. $trans = array();
  182. foreach($dtc->entites as $k => $v) {
  183. if (!strpos(" amp lt gt quot ", $k))
  184. $trans["&$k;"] = $v;
  185. }
  186. $data = strtr(substr($data,$len), $trans);
  187. } else {
  188. $data = html2unicode(substr($data,$len), true);
  189. }
  190. return array($entete,unicode2charset($data), $dtc);
  191. }
  192. // Reperer le Doctype et le decomposer selon:
  193. // http://www.freebsd.org/doc/fr_FR.ISO8859-1/books/fdp-primer/sgml-primer-doctype-declaration.html
  194. // Si pas de Doctype et premiere balise = RSS prendre la doctype RSS 0.91:
  195. // les autres formats RSS n'ont pas de DTD,
  196. // mais un XML Schema que SPIP ne fait pas encore lire.
  197. // http://doc.spip.org/@analyser_doctype
  198. function analyser_doctype($data)
  199. {
  200. if (!preg_match(_REGEXP_DOCTYPE, $data, $page)) {
  201. if (preg_match(_REGEXP_XML, $data, $page)) {
  202. list(,$pico, $topelement) = $page;
  203. $pico = strlen($pico);
  204. if ($topelement == 'rss')
  205. return array('',
  206. 'rss',
  207. 'PUBLIC',
  208. _DOCTYPE_RSS,
  209. 'rss-0.91.dtd',
  210. $pico);
  211. else {
  212. $dtd = $topelement . '.dtd';
  213. $f = find_in_path($dtd);
  214. if (file_exists($f))
  215. return array('', $topelement, 'SYSTEM', $f, $dtd, $pico);
  216. }
  217. }
  218. spip_log("Dtd pas vu pour " . substr($data, 0, 100));
  219. return array();
  220. }
  221. list($doctype,$pico, $topelement, $avail,$suite) = $page;
  222. if (!preg_match('/^"([^"]*)"\s*(.*)$/', $suite, $r))
  223. if (!preg_match("/^'([^']*)'\s*(.*)$/", $suite, $r))
  224. return array();
  225. list(,$rotlvl, $suite) = $r;
  226. if (!$suite) {
  227. if ($avail != 'SYSTEM') return array();
  228. $grammaire = $rotlvl;
  229. $rotlvl = '';
  230. } else {
  231. if (!preg_match('/^"([^"]*)"\s*$/', $suite, $r))
  232. if (!preg_match("/^'([^']*)'\s*$/", $suite, $r))
  233. return array();
  234. $grammaire = $r[1];
  235. }
  236. return array(substr($doctype,strlen($pico)), $topelement, $avail, $grammaire, $rotlvl, strlen($doctype));
  237. }
  238. ?>