1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/spip_ynh.git synced 2024-09-03 20:25:59 +02:00
spip_ynh/sources/plugins-dist/svp/inc/svp_phraser.php
2015-04-28 17:10:23 +02:00

419 lines
15 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Fichier permettant de phraser les XML des fichiers paquet.xml et plugin.xml
* ainsi que des fichiers décrivant le contenu d'un dépot de paquets.
*
* @plugin SVP pour SPIP
* @license GPL
* @package SPIP\SVP\Plugins
**/
if (!defined("_ECRIRE_INC_VERSION")) return;
include_spip('inc/xml');
include_spip('inc/config');
if (!defined('_SVP_MODE_RUNTIME')) {
/**
* Mode d'utilisation de SVP runtime ou pas :
* - En mode runtime (true), on ne charge que les plugins compatibles avec la version courante
* - En mode non runtime (false) on charge tous les plugins : cas du site Plugins SPIP
* Runtime est le mode par defaut
* @var bool */
define('_SVP_MODE_RUNTIME', (lire_config('svp/mode_runtime', 'oui') == 'oui' ? true : false));
}
// Type parseur XML à appliquer pour récupérer les infos du plugin
/** @var string Phraseur à utiliser pour un XML de plugin.xml */
define('_SVP_DTD_PLUGIN', 'plugin');
/** @var string Phraseur à utiliser pour un XML de paquet.xml */
define('_SVP_DTD_PAQUET', 'paquet');
// Regexp de recherche des balises principales de archives.xml
define('_SVP_REGEXP_BALISE_DEPOT', '#<depot[^>]*>(.*)</depot>#Uims');
define('_SVP_REGEXP_BALISE_ARCHIVES', '#<archives[^>]*>(.*)</archives>#Uims');
define('_SVP_REGEXP_BALISE_ARCHIVE', '#<archive[^s][^>]*>(.*)</archive>#Uims');
define('_SVP_REGEXP_BALISE_ZIP', '#<zip[^>]*>(.*)</zip>#Uims');
define('_SVP_REGEXP_BALISE_TRADUCTIONS', '#<traductions[^>]*>(.*)</traductions>#Uims');
define('_SVP_REGEXP_BALISE_PLUGIN', '#<plugin[^>]*>(.*)</plugin>#Uims');
define('_SVP_REGEXP_BALISE_PAQUET', '#<paquet[^>]*>(.*)</paquet>#Uims');
define('_SVP_REGEXP_BALISE_MULTIS', '#<multis[^>]*>(.*)</multis>#Uims');
// Liste des categories de plugin
# define('_CATEGORIES_PLUGIN', serialize($categories_plugin));
$GLOBALS['categories_plugin'] = array(
'communication',
'edition',
'multimedia',
'navigation',
'date',
'divers',
'auteur',
'statistique',
'performance',
'maintenance',
'outil',
'theme',
'squelette',
'aucune'
);
/** Liste des balises techniques autorisées dans la balise <spip> */
$GLOBALS['balises_techniques'] = array(
'menu', 'chemin', 'lib', 'necessite', 'onglet', 'procure', 'pipeline', 'utilise',
'options', 'fonctions', 'install');
# define('_BALISES_TECHNIQUES', serialize($balises_techniques));
/** Liste des balises autorisant une traduction */
$GLOBALS['balises_multis'] = array(
'nom', 'slogan', 'description');
# define('_BALISES_MULTIS', serialize($balises_multis));
/**
* Phrase un fichier décrivant un dépot, dont le chemin local est donné
*
* Le fichier est au format XML et contient deux balises principales :
* - <depot>...</depot> : informations de description du depot (facultatif)
* - <archives>...</archives> : liste des informations sur chaque archive (obligatoire)
*
* La fonction met en cache le résultat du phrasage de chaque archive et ne
* rephrase que les archives ayant changées.
*
* @param string $fichier_xml
* Chemin local du fichier XML de description du dépot
* @return array|bool
* false si erreur,
* Tableau de 2 index sinon :
* - depot : description du dépot
* - paquets :
*/
function svp_phraser_depot($fichier_xml) {
// le fichier xml fournit sous forme de fichier
lire_fichier($fichier_xml,$xml);
// Initialisation du tableau des informations
// -- Si aucun bloc depot n'est trouve le titre et le type prennent une valeur par defaut
$infos = array(
'depot' => array(
'titre' => _T('svp:titre_nouveau_depot'),
'type' => 'manuel'),
'paquets' => array());
// Extraction et phrasage du bloc depot si il existe
// -- Si le bloc <depot> n'est pas renseigne on ne considere pas cela comme une erreur
$balises_depot = array('titre', 'descriptif', 'type', 'url_serveur', 'url_brouteur', 'url_archives', 'url_commits');
if (preg_match(_SVP_REGEXP_BALISE_DEPOT, $xml, $matches)) {
if (is_array($arbre_depot = spip_xml_parse($matches[1]))) {
$infos['depot'] = svp_aplatir_balises($balises_depot, $arbre_depot, 'nonvide', $infos['depot']);
}
}
// Extraction et phrasage du bloc des archives si il existe
// -- Le bloc <archives> peut etre une chaine de grande taille et provoquer une erreur
// sur une recherche de regexp. On ne teste donc pas l'existence de cette balise
// -- Si aucun bloc <archive> c'est aussi une erreur
if (!preg_match_all(_SVP_REGEXP_BALISE_ARCHIVE, $xml, $matches))
return false;
// lire le cache des md5 pour ne parser que ce qui a change
$fichier_xml_md5 = $fichier_xml . ".md5.txt";
lire_fichier($fichier_xml_md5,$cache_md5);
if (!$cache_md5
OR !$cache_md5 = unserialize($cache_md5))
$cache_md5 = array();
$infos['paquets'] = svp_phraser_archives($matches[0], $cache_md5);
ecrire_fichier($fichier_xml_md5,serialize($cache_md5));
// -- Si aucun paquet extrait c'est aussi une erreur
if (!$infos['paquets'])
return false;
return $infos;
}
/**
* Phrase la liste des balises <archive>
*
* Chaque bloc XML est constitue de 3 sous-blocs principaux :
* - <zip> : contient les balises d'information sur le zip (obligatoire)
* - <traductions> : contient la compilation des informations de traduction (facultatif)
* - <plugin> ou <paquet> suivant la DTD : le contenu du fichier plugin.xml ou paquet.xml (facultatif)
*
* @param array $archives
* Tableau de la liste des archives trouvées dans la description d'un dépot
* @param array $md5_cache
* Tableau des descriptions d'archives déjà connues : on supprime
* à la fin celles qui ne font plus parties du dépot.
* @return array
* Tableau décrivant chaque archive, avec en index l'url de l'archive.
* Tableau (url => Tableau de description de l'archive)
*/
function svp_phraser_archives($archives,&$md5_cache=array()) {
include_spip('inc/plugin');
$seen = array();
$paquets = array();
$version_spip = $GLOBALS['spip_version_branche'].".".$GLOBALS['spip_version_code'];
// On verifie qu'il existe au moins une archive
if (!$archives)
return $paquets;
// On phrase chacune des archives
// Seul le bloc <zip> est obligatoire
foreach ($archives as $_cle => $_archive){
// quand version spip ou mode runtime changent,
// il faut mettre le xml a jour pour voir les plugins compatibles ou non
$md5 = md5($_archive.":$version_spip:"._SVP_MODE_RUNTIME);
if (isset($md5_cache[$md5])){
if (is_array($p=$md5_cache[$md5]))
$paquets[$p['file']] = $p; // ce paquet est connu
$seen[] = $md5;
}
elseif (preg_match(_SVP_REGEXP_BALISE_ZIP, $_archive, $matches)) {
// Extraction de la balise <zip>
$zip = svp_phraser_zip($matches[1]);
if ($zip) {
// Extraction de la balise traductions
$traductions = array();
if (preg_match(_SVP_REGEXP_BALISE_TRADUCTIONS, $_archive, $matches))
$traductions = svp_phraser_traductions($matches[1]);
// La balise <archive> peut posseder un attribut qui precise la DTD utilisee pour les plugins (plugin ou paquet)
// Sinon, c'est la DTD plugin qui est utilisee
list($tag, $attributs) = spip_xml_decompose_tag($_archive);
// -- On stocke la DTD d'extraction des infos du plugin
$dtd = (isset($attributs['dtd']) AND $attributs['dtd']) ? $attributs['dtd'] : _SVP_DTD_PLUGIN;
// Extraction *des balises* plugin ou *de la balise* paquet suivant la DTD et la version SPIP
// -- DTD : si on utilise plugin.xml on extrait la balise <plugin> sinon la balise <paquet>
$xml = svp_phraser_plugin($dtd, $_archive);
// Si on est en mode runtime, on est seulement interesse par les plugins compatibles avec
// la version courant de SPIP. On ne stocke donc pas les autres plugins.
// Si on est pas en mode runtime on prend tout !
if (!_SVP_MODE_RUNTIME
OR (_SVP_MODE_RUNTIME AND isset($xml['compatibilite']) AND plugin_version_compatible($xml['compatibilite'], $version_spip, 'spip'))) {
$paquets[$zip['file']] = $zip;
$paquets[$zip['file']]['traductions'] = $traductions;
$paquets[$zip['file']]['dtd'] = $dtd;
$paquets[$zip['file']]['plugin'] = $xml;
$paquets[$zip['file']]['md5'] = $md5;
$md5_cache[$md5] = $paquets[$zip['file']];
$seen[] = $md5;
}
else{
$md5_cache[$md5] = $zip['file'];
$seen[] = $md5;
}
}
}
}
// supprimer du cache les zip qui ne sont pas dans le nouveau $archives
$oldies = array_diff(array_keys($md5_cache),$seen);
foreach ($oldies as $old_md5){
unset($md5_cache[$old_md5]);
}
return $paquets;
}
/**
* Phrase le contenu du XML décrivant une archive suivant une DTD
* de plugin.xml ou de paquet.xml donnée
*
* La fonction peut-être appelée via archives.xml ou via un xml de plugin.
* Elle phrase la balise <multi> dans le cas d'une DTD paquet qui contient
* les traductions du nom, slogan et description
*
* @global $balises_multis
*
* @param string $dtd
* Nom du type de dtd : plugin ou paquet (pour phraser un plugin.xml ou un paquet.xml)
* @param string $contenu
* Contenu XML à phraser
* @return array
* Description du plugin
**/
function svp_phraser_plugin($dtd, $contenu) {
global $balises_multis;
static $informer = array();
$plugin = array();
// On initialise les informations du plugin avec le contenu du plugin.xml ou paquet.xml
$regexp = ($dtd == 'plugin') ? _SVP_REGEXP_BALISE_PLUGIN : _SVP_REGEXP_BALISE_PAQUET;
if ($nb_balises = preg_match_all($regexp, $contenu, $matches)) {
$plugins = array();
// Pour chacune des occurences de la balise on extrait les infos
foreach ($matches[0] as $_balise_plugin) {
// Extraction des informations du plugin suivant le standard SPIP
if (!isset($informer[$dtd])) {
$informer[$dtd] = charger_fonction('infos_' . $dtd, 'plugins');
}
$plugins[] = $informer[$dtd]($_balise_plugin);
}
// On appelle systematiquement une fonction de mise a jour de la structure de donnees du plugin :
// -- Si DTD plugin et que le nombre de balises plugin > 1 ou si DTD paquet avec une presence de balise spip
// alors on fusionne donc les informations recoltees
// -- sinon on arrange la structure pour deplacer le contenu des balises dites techniques dans un sous tableau
// d'index 0 par similitude avec la structure fusionnee
$fusionner = charger_fonction('fusion_' . $dtd, 'plugins');
if ($dtd == 'plugin')
$plugin = $fusionner($plugins);
else
$plugin = $fusionner($plugins[0]);
// Pour la DTD paquet, les traductions du nom, slogan et description sont compilees dans une balise
// du fichier archives.xml. Il faut donc completer les informations precedentes avec cette balise
if (($dtd == _SVP_DTD_PAQUET) AND (preg_match(_SVP_REGEXP_BALISE_MULTIS, $contenu, $matches))) {
$multis = array();
if (is_array($arbre = spip_xml_parse($matches[1])))
$multis = svp_aplatir_balises($balises_multis, $arbre);
// Le nom peut etre traduit ou pas, il faut donc le tester
if ($multis['nom'])
$plugin['nom'] = $multis['nom'];
// Slogan et description sont forcement des items de langue
$plugin['slogan'] = $multis['slogan'];
$plugin['description'] = $multis['description'];
}
}
return $plugin;
}
/**
* Phrase le contenu de la balise <zip>
*
* Extrait du XML les informations du zip
*
* @param string $contenu
* Description XML de l'archive
* @return array
* Description du zip.
* - Index 'file' : nom du zip
* - Index 'size' : taille
* - Index 'date' : date de création
* - Index 'last_commit' : date du dernier commit
* - Index 'source' : arborescence relative des sources
*/
function svp_phraser_zip($contenu) {
static $balises_zip = array('file', 'size', 'date', 'source', 'last_commit');
$zip = array();
if (is_array($arbre = spip_xml_parse($contenu)))
$zip = svp_aplatir_balises($balises_zip, $arbre);
return $zip;
}
/**
* Phrase le contenu d'une balise <traductions> en un tableau plus
* facilement utilisable
*
* @param string $contenu
* Contenu XML de la balise <traductions>
* @return array
* Tableau complexe avec pour index les noms des modules de langue et pour
* valeur leur description. Chaque description contient dedans 3 index :
* - reference : la langue de référence
* - gestionnaire : quel logiciel à servi à gérer les traductions
* - langues : tableau classé par langue puis par traducteurs, qui indique
* l'ensemble des traducteurs pour chacune des langues présentes
*/
function svp_phraser_traductions($contenu) {
$traductions = array();
if (is_array($arbre = spip_xml_parse($contenu))) {
foreach ($arbre as $_tag => $_langues) {
// On commence par les balises <traduction> et leurs attributs
list($tag, $attributs_traduction) = spip_xml_decompose_tag($_tag);
$traductions[$attributs_traduction['module']]['reference'] = $attributs_traduction['reference'];
$traductions[$attributs_traduction['module']]['gestionnaire'] = isset($attributs_traduction['gestionnaire']) ? $attributs_traduction['gestionnaire'] : '' ;
// On continue par les balises <langue> qui donnent le code en attribut
// et les balises <traducteur> qui donnent uniquement le nom en attribut
if (is_array($_langues[0])) {
foreach ($_langues[0] as $_tag => $_traducteurs) {
list($tag, $attributs_langue) = spip_xml_decompose_tag($_tag);
$traducteurs = array();
if (is_array($_traducteurs[0])) {
foreach ($_traducteurs[0] as $_tag => $_vide) {
list($tag, $attributs_traducteur) = spip_xml_decompose_tag($_tag);
$traducteurs[] = $attributs_traducteur;
}
}
$traductions[$attributs_traduction['module']]['langues'][$attributs_langue['code']] = $traducteurs;
}
}
}
}
return $traductions;
}
/**
* Aplatit plusieurs clés d'un arbre xml dans un tableau
*
* Effectue un trim() de la valeur trouvée dans l'arbre
*
* @param array $balises
* Liste de noms de balises XML.
* Peut aussi être un tableau indiquant un renommage d'une balise
* au passage tel que 'x' => 'y' qui cherchera x dans l'arbre XML et
* l'applatira dans y.
* @param array $arbre_xml
* Un arbre issu de spip_xml_parse()
* @param string $mode
* Mode d'affectation des valeurs trouvées
* - 'vide_et_nonvide' : Affecte une chaine vide si la balise n'est
* pas trouvée dans l'arbre et affecte la valeur de la balise sinon.
* - 'nonvide' : Si la balise n'est pas trouvée dans l'arbre ou si son
* contenu est vide, affecte la valeur du tableau initial concernant
* cette balise si elle est connue.
* @param array
* Tableau initial pouvant contenir des valeurs par défaut à affecter
* à chaque balise avec 'x' => 'valeur'
*/
function svp_aplatir_balises($balises, $arbre_xml, $mode='vide_et_nonvide', $tableau_initial=array()) {
$tableau_aplati = array();
if (!$balises)
return $tableau_initial;
foreach ($balises as $_cle => $_valeur){
$tag = (is_string($_cle)) ? $_cle : $_valeur;
$valeur_aplatie = '';
if (isset($arbre_xml[$tag])) {
$valeur_aplatie = trim(spip_xml_aplatit($arbre_xml[$tag]));
}
if (($mode == 'vide_et_nonvide')
OR (($mode == 'nonvide') AND $valeur_aplatie))
$tableau_aplati[$_valeur] = $valeur_aplatie;
else
$tableau_aplati[$_valeur] = isset($tableau_initial[$_valeur]) ? $tableau_initial[$_valeur] : '';
}
return $tableau_aplati;
}
?>