PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/_core_/tags/spip-3.0.3/plugins/svp/inc/svp_phraser.php

https://bitbucket.org/pombredanne/spip-zone-treemap
PHP | 326 lines | 187 code | 57 blank | 82 comment | 31 complexity | b1764c752721e3110219e25df8caa607 MD5 | raw file
  1. <?php
  2. if (!defined("_ECRIRE_INC_VERSION")) return;
  3. include_spip('inc/xml');
  4. include_spip('inc/config');
  5. // Mode d'utilisation de SVP runtime ou pas :
  6. // - En mode runtime (true), on ne charge que les plugins compatibles avec la version courante
  7. // - En mode non runtime (false) on charge tous les plugins : cas du site Plugins SPIP
  8. // Runtime est le mode par defaut
  9. if (!defined('_SVP_MODE_RUNTIME')) {
  10. define('_SVP_MODE_RUNTIME', (lire_config('svp/mode_runtime', 'oui') == 'oui' ? true : false));
  11. }
  12. // Type parseur XML a appliquer pour recuperer les infos du plugin
  13. // - plugin, pour utiliser plugin.xml
  14. // - paquet, pour paquet.xml
  15. define('_SVP_DTD_PLUGIN', 'plugin');
  16. define('_SVP_DTD_PAQUET', 'paquet');
  17. // Regexp de recherche des balises principales de archives.xml
  18. define('_SVP_REGEXP_BALISE_DEPOT', '#<depot[^>]*>(.*)</depot>#Uims');
  19. define('_SVP_REGEXP_BALISE_ARCHIVES', '#<archives[^>]*>(.*)</archives>#Uims');
  20. define('_SVP_REGEXP_BALISE_ARCHIVE', '#<archive[^s][^>]*>(.*)</archive>#Uims');
  21. define('_SVP_REGEXP_BALISE_ZIP', '#<zip[^>]*>(.*)</zip>#Uims');
  22. define('_SVP_REGEXP_BALISE_TRADUCTIONS', '#<traductions[^>]*>(.*)</traductions>#Uims');
  23. define('_SVP_REGEXP_BALISE_PLUGIN', '#<plugin[^>]*>(.*)</plugin>#Uims');
  24. define('_SVP_REGEXP_BALISE_PAQUET', '#<paquet[^>]*>(.*)</paquet>#Uims');
  25. define('_SVP_REGEXP_BALISE_MULTIS', '#<multis[^>]*>(.*)</multis>#Uims');
  26. // Liste des categories de plugin
  27. # define('_CATEGORIES_PLUGIN', serialize($categories_plugin));
  28. $GLOBALS['categories_plugin'] = array(
  29. 'communication',
  30. 'edition',
  31. 'multimedia',
  32. 'navigation',
  33. 'date',
  34. 'divers',
  35. 'auteur',
  36. 'statistique',
  37. 'performance',
  38. 'maintenance',
  39. 'outil',
  40. 'theme',
  41. 'squelette',
  42. 'aucune'
  43. );
  44. // Liste des balises techniques autorisees dans la balise <spip> et des balises autorisant une traduction
  45. # define('_BALISES_TECHNIQUES', serialize($balises_techniques));
  46. $GLOBALS['balises_techniques'] = array(
  47. 'menu', 'chemin', 'lib', 'necessite', 'onglet', 'procure', 'pipeline', 'utilise',
  48. 'options', 'fonctions', 'install');
  49. # define('_BALISES_MULTIS', serialize($balises_multis));
  50. $GLOBALS['balises_multis'] = array(
  51. 'nom', 'slogan', 'description');
  52. /**
  53. * Phraser un fichier de source dont l'url est donnee
  54. * Le fichier est un fichier XML contenant deux balises principales :
  55. * - <depot>...</depot> : informations de description du depot (facultatif)
  56. * - <archives>...</archives> : liste des informations sur chaque archive (obligatoire)
  57. *
  58. * @param string $fichier_xml
  59. * nom du fichier XML de description du depot
  60. * @return array|bool
  61. */
  62. function svp_phraser_depot($fichier_xml) {
  63. // le fichier xml fournit sous forme de fichier
  64. lire_fichier($fichier_xml,$xml);
  65. // Initialisation du tableau des informations
  66. // -- Si aucun bloc depot n'est trouve le titre et le type prennent une valeur par defaut
  67. $infos = array(
  68. 'depot' => array(
  69. 'titre' => _T('svp:titre_nouveau_depot'),
  70. 'type' => 'manuel'),
  71. 'paquets' => array());
  72. // Extraction et phrasage du bloc depot si il existe
  73. // -- Si le bloc <depot> n'est pas renseigne on ne considere pas cela comme une erreur
  74. $balises_depot = array('titre', 'descriptif', 'type', 'url_serveur', 'url_brouteur', 'url_archives', 'url_commits');
  75. if (preg_match(_SVP_REGEXP_BALISE_DEPOT, $xml, $matches)) {
  76. if (is_array($arbre_depot = spip_xml_parse($matches[1]))) {
  77. $infos['depot'] = svp_aplatir_balises($balises_depot, $arbre_depot, 'nonvide', $infos['depot']);
  78. }
  79. }
  80. // Extraction et phrasage du bloc des archives si il existe
  81. // -- Le bloc <archives> peut etre une chaine de grande taille et provoquer une erreur
  82. // sur une recherche de regexp. On ne teste donc pas l'existence de cette balise
  83. // -- Si aucun bloc <archive> c'est aussi une erreur
  84. if (!preg_match_all(_SVP_REGEXP_BALISE_ARCHIVE, $xml, $matches))
  85. return false;
  86. // lire le cache des md5 pour ne parser que ce qui a change
  87. $fichier_xml_md5 = $fichier_xml . ".md5.txt";
  88. lire_fichier($fichier_xml_md5,$cache_md5);
  89. if (!$cache_md5
  90. OR !$cache_md5 = unserialize($cache_md5))
  91. $cache_md5 = array();
  92. $infos['paquets'] = svp_phraser_archives($matches[0], $cache_md5);
  93. ecrire_fichier($fichier_xml_md5,serialize($cache_md5));
  94. // -- Si aucun paquet extrait c'est aussi une erreur
  95. if (!$infos['paquets'])
  96. return false;
  97. return $infos;
  98. }
  99. // Phraser la liste des balises <archive>
  100. // Chaque bloc XML est constitue de 3 sous-blocs principaux :
  101. // - <zip> : contient les balises d'information sur le zip (obligatoire)
  102. // - <traductions> : contient la compilation des informations de traduction (facultatif)
  103. // - <plugin> ou <paquet> suivant la DTD : le contenu du fichier plugin.xml ou paquet.xml (facultatif)
  104. function svp_phraser_archives($archives,&$md5_cache=array()) {
  105. include_spip('inc/plugin');
  106. $seen = array();
  107. $paquets = array();
  108. $version_spip = $GLOBALS['spip_version_branche'].".".$GLOBALS['spip_version_code'];
  109. // On verifie qu'il existe au moins une archive
  110. if (!$archives)
  111. return $paquets;
  112. // On phrase chacune des archives
  113. // Seul le bloc <zip> est obligatoire
  114. foreach ($archives as $_cle => $_archive){
  115. // quand version spip ou mode runtime changent,
  116. // il faut mettre le xml a jour pour voir les plugins compatibles ou non
  117. $md5 = md5($_archive.":$version_spip:"._SVP_MODE_RUNTIME);
  118. if (isset($md5_cache[$md5])){
  119. if (is_array($p=$md5_cache[$md5]))
  120. $paquets[$p['file']] = $p; // ce paquet est connu
  121. $seen[] = $md5;
  122. }
  123. elseif (preg_match(_SVP_REGEXP_BALISE_ZIP, $_archive, $matches)) {
  124. // Extraction de la balise <zip>
  125. $zip = svp_phraser_zip($matches[1]);
  126. if ($zip) {
  127. // Extraction de la balise traductions
  128. $traductions = array();
  129. if (preg_match(_SVP_REGEXP_BALISE_TRADUCTIONS, $_archive, $matches))
  130. $traductions = svp_phraser_traductions($matches[1]);
  131. // La balise <archive> peut posseder un attribut qui precise la DTD utilisee pour les plugins (plugin ou paquet)
  132. // Sinon, c'est la DTD plugin qui est utilisee
  133. list($tag, $attributs) = spip_xml_decompose_tag($_archive);
  134. // -- On stocke la DTD d'extraction des infos du plugin
  135. $dtd = (isset($attributs['dtd']) AND $attributs['dtd']) ? $attributs['dtd'] : _SVP_DTD_PLUGIN;
  136. // Extraction *des balises* plugin ou *de la balise* paquet suivant la DTD et la version SPIP
  137. // -- DTD : si on utilise plugin.xml on extrait la balise <plugin> sinon la balise <paquet>
  138. $xml = svp_phraser_plugin($dtd, $_archive);
  139. // Si on est en mode runtime, on est seulement interesse par les plugins compatibles avec
  140. // la version courant de SPIP. On ne stocke donc pas les autres plugins.
  141. // Si on est pas en mode runtime on prend tout !
  142. if (!_SVP_MODE_RUNTIME
  143. OR (_SVP_MODE_RUNTIME AND plugin_version_compatible($xml['compatibilite'], $version_spip))) {
  144. $paquets[$zip['file']] = $zip;
  145. $paquets[$zip['file']]['traductions'] = $traductions;
  146. $paquets[$zip['file']]['dtd'] = $dtd;
  147. $paquets[$zip['file']]['plugin'] = $xml;
  148. $paquets[$zip['file']]['md5'] = $md5;
  149. $md5_cache[$md5] = $paquets[$zip['file']];
  150. $seen[] = $md5;
  151. }
  152. else{
  153. $md5_cache[$md5] = $zip['file'];
  154. $seen[] = $md5;
  155. }
  156. }
  157. }
  158. }
  159. // supprimer du cache les zip qui ne sont pas dans le nouveau $archives
  160. $oldies = array_diff(array_keys($md5_cache),$seen);
  161. foreach ($oldies as $old_md5){
  162. unset($md5_cache[$old_md5]);
  163. }
  164. return $paquets;
  165. }
  166. // Phrase le contenu du xml, soit la ou les balises <plugin> ou <paquet> suivant la DTD
  167. // (peut etre appelee via archives.xml ou via un xml de plugin)
  168. // et phrase la balise <multis> dans le cas d'une DTD paquet qui contient les traductions du
  169. // nom, slogan et description
  170. function svp_phraser_plugin($dtd, $contenu) {
  171. global $balises_multis;
  172. static $informer = array();
  173. $plugin = array();
  174. // On initialise les informations du plugin avec le contenu du plugin.xml ou paquet.xml
  175. $regexp = ($dtd == 'plugin') ? _SVP_REGEXP_BALISE_PLUGIN : _SVP_REGEXP_BALISE_PAQUET;
  176. if ($nb_balises = preg_match_all($regexp, $contenu, $matches)) {
  177. $plugins = array();
  178. // Pour chacune des occurences de la balise on extrait les infos
  179. foreach ($matches[0] as $_balise_plugin) {
  180. // Extraction des informations du plugin suivant le standard SPIP
  181. if (!isset($informer[$dtd])) {
  182. $informer[$dtd] = charger_fonction('infos_' . $dtd, 'plugins');
  183. }
  184. $plugins[] = $informer[$dtd]($_balise_plugin);
  185. }
  186. // On appelle systematiquement une fonction de mise a jour de la structure de donnees du plugin :
  187. // -- Si DTD plugin et que le nombre de balises plugin > 1 ou si DTD paquet avec une presence de balise spip
  188. // alors on fusionne donc les informations recoltees
  189. // -- sinon on arrange la structure pour deplacer le contenu des balises dites techniques dans un sous tableau
  190. // d'index 0 par similitude avec la structure fusionnee
  191. $fusionner = charger_fonction('fusion_' . $dtd, 'plugins');
  192. if ($dtd == 'plugin')
  193. $plugin = $fusionner($plugins);
  194. else
  195. $plugin = $fusionner($plugins[0]);
  196. // Pour la DTD paquet, les traductions du nom, slogan et description sont compilees dans une balise
  197. // du fichier archives.xml. Il faut donc completer les informations precedentes avec cette balise
  198. if (($dtd == _SVP_DTD_PAQUET) AND (preg_match(_SVP_REGEXP_BALISE_MULTIS, $contenu, $matches))) {
  199. $multis = array();
  200. if (is_array($arbre = spip_xml_parse($matches[1])))
  201. $multis = svp_aplatir_balises($balises_multis, $arbre);
  202. // Le nom peut etre traduit ou pas, il faut donc le tester
  203. if ($multis['nom'])
  204. $plugin['nom'] = $multis['nom'];
  205. // Slogan et description sont forcement des items de langue
  206. $plugin['slogan'] = $multis['slogan'];
  207. $plugin['description'] = $multis['description'];
  208. }
  209. }
  210. return $plugin;
  211. }
  212. // Phrase le contenu de la balise <zip>
  213. // -- nom du zip, taille, date, dernier commit, arborescence relative des sources...
  214. function svp_phraser_zip($contenu) {
  215. static $balises_zip = array('file', 'size', 'date', 'source', 'last_commit');
  216. $zip = array();
  217. if (is_array($arbre = spip_xml_parse($contenu)))
  218. $zip = svp_aplatir_balises($balises_zip, $arbre);
  219. return $zip;
  220. }
  221. // Phrase le contenu d'une balise <traductions> en un tableau plus facilement utilisable
  222. // -- Par module, la langue de reference, le gestionnaire, les langues traduites et leurs traducteurs
  223. function svp_phraser_traductions($contenu) {
  224. $traductions = array();
  225. if (is_array($arbre = spip_xml_parse($contenu))) {
  226. foreach ($arbre as $_tag => $_langues) {
  227. // On commence par les balises <traduction> et leurs attributs
  228. list($tag, $attributs_traduction) = spip_xml_decompose_tag($_tag);
  229. $traductions[$attributs_traduction['module']]['reference'] = $attributs_traduction['reference'];
  230. $traductions[$attributs_traduction['module']]['gestionnaire'] = isset($attributs_traduction['gestionnaire']) ? $attributs_traduction['gestionnaire'] : '' ;
  231. // On continue par les balises <langue> qui donnent le code en attribut
  232. // et les balises <traducteur> qui donnent uniquement le nom en attribut
  233. if (is_array($_langues[0])) {
  234. foreach ($_langues[0] as $_tag => $_traducteurs) {
  235. list($tag, $attributs_langue) = spip_xml_decompose_tag($_tag);
  236. $traducteurs = array();
  237. if (is_array($_traducteurs[0])) {
  238. foreach ($_traducteurs[0] as $_tag => $_vide) {
  239. list($tag, $attributs_traducteur) = spip_xml_decompose_tag($_tag);
  240. $traducteurs[] = $attributs_traducteur;
  241. }
  242. }
  243. $traductions[$attributs_traduction['module']]['langues'][$attributs_langue['code']] = $traducteurs;
  244. }
  245. }
  246. }
  247. }
  248. return $traductions;
  249. }
  250. // Aplatit plusieurs cles d'un arbre xml dans un tableau
  251. // -- Effectue un trim() au passage
  252. // -- le mode 'nonvide' permet de ne pas modifier une valeur du tableau si sa valeur dans
  253. // l'arbre est vide et d'y affecter sa valeur par defaut si elle existe, la chaine vide sinon
  254. function svp_aplatir_balises($balises, $arbre_xml, $mode='vide_et_nonvide', $tableau_initial=array()) {
  255. $tableau_aplati = array();
  256. if (!$balises)
  257. return $tableau_initial;
  258. foreach ($balises as $_cle => $_valeur){
  259. $tag = (is_string($_cle)) ? $_cle : $_valeur;
  260. $valeur_aplatie = trim(spip_xml_aplatit($arbre_xml[$tag]));
  261. if (($mode == 'vide_et_nonvide')
  262. OR (($mode == 'nonvide') AND $valeur_aplatie))
  263. $tableau_aplati[$_valeur] = $valeur_aplatie;
  264. else
  265. $tableau_aplati[$_valeur] = isset($tableau_initial[$_valeur]) ? $tableau_initial[$_valeur] : '';
  266. }
  267. return $tableau_aplati;
  268. }
  269. ?>