6 * @plugin SVP pour SPIP
8 * @package SPIP\SVP\Fonctions
11 if (!defined('_ECRIRE_INC_VERSION')) {
16 if (!defined('_SVP_VERSION_SPIP_MIN')) {
18 * Version SPIP minimale quand un plugin ne le precise pas
20 * Version SPIP correspondant à l'apparition des plugins */
21 define('_SVP_VERSION_SPIP_MIN', '1.9.0');
24 if (!defined('_SVP_VERSION_SPIP_MAX')) {
26 * Version SPIP maximale
28 * Pour l'instant on ne connait pas la borne sup exacte */
29 define('_SVP_VERSION_SPIP_MAX', '3.2.99');
33 * Liste des branches significatives de SPIP et de leurs bornes (versions min et max)
35 * À mettre a jour en fonction des sorties
37 * @global array $GLOBALS ['infos_branches_spip']
39 $GLOBALS['infos_branches_spip'] = array(
40 '1.9' => array(_SVP_VERSION_SPIP_MIN
, '1.9.2'),
41 '2.0' => array('2.0.0', '2.0.99'),
42 '2.1' => array('2.1.0', '2.1.99'),
43 '3.0' => array('3.0.0', '3.0.99'),
44 '3.1' => array('3.1.0', '3.1.99'),
45 '3.2' => array('3.2.0', _SVP_VERSION_SPIP_MAX
)
47 # define('_INFOS_BRANCHES_SPIP', serialize($infos_branches_spip));
50 * Liste des licences de plugin
52 * @global array $GLOBALS ['licences_plugin']
54 $GLOBALS['licences_plugin'] = array(
56 'versions' => array('2.0', '1.1', '1.0'),
57 'nom' => 'Apache licence, version @version@',
58 'url' => 'http://www.apache.org/licenses/LICENSE-@version@'
61 'versions' => array('1.3'),
62 'nom' => 'Art libre @version@',
63 'url' => 'http://artlibre.org/licence/lal'
66 'versions' => array(),
68 'url' => 'http://opensource.org/licenses/mit-license.php'
71 'versions' => array(),
73 'url' => 'http://www.freebsd.org/copyright/license.html'
76 'versions' => array('3'),
77 'nom' => 'AGPL @version@',
78 'url' => 'http://www.gnu.org/licenses/agpl.html'
81 'versions' => array('1.3', '1.2', '1.1'),
82 'nom' => 'FDL @version@',
83 'url' => 'http://www.gnu.org/licenses/fdl-@version@.html'
86 'versions' => array('3.0', '2.1'),
87 'nom' => array('3.0' => 'LGPL 3', '2.1' => 'LGPL 2.1'),
88 'url' => 'http://www.gnu.org/licenses/lgpl-@version@.html'
91 'versions' => array('3', '2', '1'),
92 'nom' => 'GPL @version@',
93 'url' => 'http://www.gnu.org/licenses/gpl-@version@.0.html'
96 'versions' => array('2.0', '2.5', '3.0'),
97 'suffixes' => array('-sa', '-nc', '-nd', '-nc-nd', '-nc-sa'),
98 'nom' => 'CC BY@suffixe@ @version@',
99 'url' => 'http://creativecommons.org/licenses/by@suffixe@/@version@/'
102 # define('_LICENCES_PLUGIN', serialize($licences_plugin));
105 * Fusionne 2 intervalles de compatibilité
107 * Soit '[1.9;2.1]' et '[2.1;3.0.*]', la fonction retourne '[1.9;3.0.*]'
109 * En gros la fonction est utilisé pour calculer l'intervalle de validité
110 * d'un plugin ayant plusieurs paquets avec des compatibilités différentes.
111 * La compatibilité du plugin est le total de toutes les compatibilités.
113 * @uses extraire_bornes()
114 * @uses construire_intervalle()
115 * @param string $intervalle_a
116 * Intervalle de compatibilité
117 * @param string $intervalle_b
118 * Intervalle de compatibilité
120 * Intervalle de compatibilité
122 function fusionner_intervalles($intervalle_a, $intervalle_b) {
124 // On recupere les bornes de chaque intervalle
125 $borne_a = extraire_bornes($intervalle_a);
126 $borne_b = extraire_bornes($intervalle_b);
128 // On initialise la borne min de chaque intervalle a 1.9.0 inclus si vide
129 if (!$borne_a['min']['valeur']) {
130 $borne_a['min']['valeur'] = _SVP_VERSION_SPIP_MIN
;
131 $borne_a['min']['incluse'] = true;
133 if (!$borne_b['min']['valeur']) {
134 $borne_b['min']['valeur'] = _SVP_VERSION_SPIP_MIN
;
135 $borne_b['min']['incluse'] = true;
138 // On initialise la borne max de chaque intervalle a la version SPIP max incluse si vide
139 if (!$borne_a['max']['valeur']) {
140 $borne_a['max']['valeur'] = _SVP_VERSION_SPIP_MAX
;
141 $borne_a['max']['incluse'] = true;
143 if (!$borne_b['max']['valeur']) {
144 $borne_b['max']['valeur'] = _SVP_VERSION_SPIP_MAX
;
145 $borne_b['max']['incluse'] = true;
148 // On calcul maintenant :
149 // -- la borne min de l'intervalle fusionne = min(min_a, min_b)
150 if (spip_version_compare($borne_a['min']['valeur'], $borne_b['min']['valeur'], '<=')) {
151 $bornes_fusionnees['min'] = $borne_a['min'];
153 $bornes_fusionnees['min'] = $borne_b['min'];
155 // -- la borne max de l'intervalle fusionne = max(max_a, max_b)
156 if (spip_version_compare($borne_a['max']['valeur'], $borne_b['max']['valeur'], '<=')) {
157 $bornes_fusionnees['max'] = $borne_b['max'];
159 $bornes_fusionnees['max'] = $borne_a['max'];
162 return construire_intervalle($bornes_fusionnees);
166 * Extrait les valeurs d'un intervalle de compatibilité.
168 * Calcule les valeurs min, max et si ces valeurs sont intégrées ou non
171 * @param string $intervalle
172 * Intervalle de compatibilité, tel que '[2.1;3.0]'
173 * @param bool $initialiser
174 * - True pour mettre les valeurs connues mini et maxi de SPIP lorsque
175 * les bornes ne sont pas renseignées dans l'intervalle.
176 * - False pour ne rien mettre sinon.
178 * Tableau avec les index :
179 * - min : la borne inférieure, qui contient les index 'valeur' et 'incluse'
180 * - max : la borne supérieure, qui contient les index 'valeur' et 'incluse'
181 * Le sous index 'incluse' vaut true si cette borne est incluse dans l'intervalle.
183 function extraire_bornes($intervalle, $initialiser = false) {
184 static $borne_vide = array('valeur' => '', 'incluse' => false);
185 static $borne_inf_init = array('valeur' => _SVP_VERSION_SPIP_MIN
, 'incluse' => true);
186 static $borne_sup_init = array('valeur' => _SVP_VERSION_SPIP_MAX
, 'incluse' => true);
189 $bornes = array('min' => $borne_inf_init, 'max' => $borne_sup_init);
191 $bornes = array('min' => $borne_vide, 'max' => $borne_vide);
195 and preg_match(',^[\[\(\]]([0-9.a-zRC\s\-]*)[;]([0-9.a-zRC\s\-\*]*)[\]\)\[]$,Uis', $intervalle, $matches)
198 $bornes['min']['valeur'] = trim($matches[1]);
199 $bornes['min']['incluse'] = ($intervalle{0} == "[");
202 $bornes['max']['valeur'] = trim($matches[2]);
203 $bornes['max']['incluse'] = (substr($intervalle, -1) == "]");
211 * Contruit un intervalle de compatibilité
213 * @param array $bornes
214 * L'intervalle décrit sous forme de tableau avec pour index :
215 * - min : la borne inférieure, qui contient les index 'valeur' et 'incluse'
216 * - max : la borne supérieure, qui contient les index 'valeur' et 'incluse'
217 * Le sous index 'incluse' vaut true si cette borne est incluse dans l'intervalle.
219 * DTD de destination (paquet ou plugin) qui influera sur l'écriture à faire
220 * en utilisant des parenthèses ou des crochets pour définir l'exclusion d'une intervalle
221 * tel que ']2.1.2,3.0.1[' (paquet) ou '(2.1.2,3.0.1)' (plugin)
223 * Intervalle de compatibilité tel que '[2.1;3.0]'
225 function construire_intervalle($bornes, $dtd = 'paquet') {
226 return ($bornes['min']['incluse'] ?
'[' : ($dtd == 'paquet' ?
']' : '('))
227 . $bornes['min']['valeur'] . ';' . $bornes['max']['valeur']
228 . ($bornes['max']['incluse'] ?
']' : ($dtd == 'paquet' ?
'[' : ')'));
233 * Retourne la liste des branches de SPIP comprises dans un intervalle
234 * de compatibilité donné.
236 * @uses extraire_bornes()
237 * @param string $intervalle
238 * Intervalle de compatibilité, tel que [2.0.0;3.0.0]
240 * Branches de SPIP séparées par des virgules, tel que 2.0,2.1,3.0
242 function compiler_branches_spip($intervalle) {
243 include_spip('plugins/installer');
245 global $infos_branches_spip;
246 $liste_branches_spip = array_keys($GLOBALS['infos_branches_spip']);
248 $bornes = extraire_bornes($intervalle, false);
249 // On traite d'abord les cas ou l'intervalle est :
251 // - non vide mais avec les deux bornes vides
252 // Dans ces cas la compatibilite est totale, on renvoie toutes les branches
253 if (!$intervalle or (!$bornes['min']['valeur'] and !$bornes['max']['valeur'])) {
254 return implode(',', $liste_branches_spip);
257 // On force l'initialisation des bornes et on les nettoie des suffixes d'etat
258 $bornes = extraire_bornes($intervalle, true);
259 // Si les bornes sont en dehors de l'intervalle [_SVP_VERSION_SPIP_MIN;_SVP_VERSION_SPIP_MAX] on le reduit
260 if (spip_version_compare($bornes['min']['valeur'], _SVP_VERSION_SPIP_MIN
, '<')) {
261 $bornes['min']['valeur'] = _SVP_VERSION_SPIP_MIN
;
262 $bornes['min']['incluse'] = true;
264 if (spip_version_compare(_SVP_VERSION_SPIP_MAX
, $bornes['max']['valeur'], '<=')) {
265 $bornes['max']['valeur'] = _SVP_VERSION_SPIP_MAX
;
266 $bornes['max']['incluse'] = true;
268 // On les nettoie des suffixes d'etat
269 $borne_inf = strtolower(preg_replace(',([0-9])[\s.-]?(dev|alpha|a|beta|b|rc|pl|p),i', '\\1',
270 $bornes['min']['valeur']));
271 $borne_sup = strtolower(preg_replace(',([0-9])[\s.-]?(dev|alpha|a|beta|b|rc|pl|p),i', '\\1',
272 $bornes['max']['valeur']));
274 // On determine les branches inf et sup issues du phrasage de l'intervalle
275 // -- on initialise la branche inf de l'intervalle que l'on va preciser ensuite
276 $t = explode('.', $borne_inf);
277 $branche_inf = $t[0] . '.' . $t[1];
278 // -- pour eviter toutes erreur fatale on verifie que la branche est bien dans la liste des possibles
279 // -- -> si non, on renvoie vide
280 if (!in_array($branche_inf, $liste_branches_spip)) {
283 // -- on complete la borne inf de l'intervalle de x.y en x.y.z et on determine la vraie branche
284 if (!isset($t[2]) or !$t[2]) {
285 if ($bornes['min']['incluse']) {
286 $borne_inf = $infos_branches_spip[$branche_inf][0];
288 $branche_inf = $liste_branches_spip[array_search($branche_inf, $liste_branches_spip) +
1];
289 $borne_inf = $infos_branches_spip[$branche_inf][0];
293 // -- on initialise la branche sup de l'intervalle que l'on va preciser ensuite
294 $t = explode('.', $borne_sup);
295 // des gens mettent juste * (pas glop)
296 $branche_sup = $t[0] . (isset($t[1]) ?
'.' . $t[1] : '');
298 // -- pour eviter toutes erreur fatale on verifie que la branche est bien dans la liste des possibles
299 // -- -> si non, on renvoie vide
300 if (!in_array($branche_sup, $liste_branches_spip)) {
303 // -- on complete la borne sup de l'intervalle de x.y en x.y.z et on determine la vraie branche
304 if (!isset($t[2]) or !$t[2]) {
305 if ($bornes['max']['incluse']) {
306 $borne_sup = $infos_branches_spip[$branche_sup][1];
308 $branche_sup = $liste_branches_spip[array_search($branche_sup, $liste_branches_spip) - 1];
309 $borne_sup = $infos_branches_spip[$branche_sup][1];
313 // -- on verifie que les bornes sont bien dans l'ordre :
314 // -> sinon on retourne la branche sup uniquement
315 if (spip_version_compare($borne_inf, $borne_sup, '>=')) {
319 // A ce stade, on a un intervalle ferme en bornes ou en branches
320 // Il suffit de trouver les branches qui y sont incluses, sachant que les branches inf et sup
321 // le sont a coup sur maintenant
322 $index_inf = array_search($branche_inf, $liste_branches_spip);
323 $index_sup = array_search($branche_sup, $liste_branches_spip);
325 for ($i = $index_inf; $i <= $index_sup; $i++
) {
326 $liste[] = $liste_branches_spip[$i];
329 return implode(',', $liste);
334 * Transforme un texte écrit en entités HTML, dans le charset du site
336 * @param string $texte
337 * Texte avec des entités HTML
338 * @param string $charset
339 * @return string $texte
340 * Texte dans le charset du site
342 function entite2charset($texte, $charset = null) {
343 if (!strlen($texte)) {
347 $charset = $GLOBALS['meta']['charset'];
349 include_spip('inc/charsets');
351 return unicode2charset(html_entity_decode(preg_replace('/&([lg]t;)/S', '&\1', $texte), ENT_NOQUOTES
, $charset));
355 * Teste si 2 balises XML sont identiques
357 * @param array|string $balise1
359 * @param array|string $balise2
362 * True si elles sont identiques, false sinon.
364 function balise_identique($balise1, $balise2) {
365 if (is_array($balise1)) {
366 foreach ($balise1 as $_attribut1 => $_valeur1) {
367 if (!array_key_exists($_attribut1, $balise2)) {
370 if ($_valeur1 != $balise2[$_attribut1]) {
378 return ($balise1 == $balise2);
384 * Déterminer la licence exacte avec un nom et un lien de doc standardisé
386 * @param string $prefixe
387 * Préfixe de la licence tel que gnu, free, cc, creative common
389 * Nom de la licence tel que gpl, lgpl, agpl, fdl, mit, bsd...
390 * @param string $suffixe
391 * Suffixe de la licence tel que licence, -sharealike, -nc-nd ...
392 * @param string $version
393 * Version de la licence tel que 3.0
395 * Si la licence est connu, retourne 2 index :
396 * - nom : le nom le la licence
397 * - url : lien vers la licence
399 function definir_licence($prefixe, $nom, $suffixe, $version) {
400 global $licences_plugin;
403 $prefixe = strtolower($prefixe);
404 $nom = strtolower($nom);
405 $suffixe = strtolower($suffixe);
407 if (((trim($prefixe) == 'creative common') and ($nom == 'attribution'))
408 or (($prefixe == 'cc') and ($nom == 'by'))
413 if (array_key_exists($nom, $licences_plugin)) {
414 if (!$licences_plugin[$nom]['versions']) {
415 // La licence n'est pas versionnee : on affecte donc directement le nom et l'url
416 $licence['nom'] = $licences_plugin[$nom]['nom'];
417 $licence['url'] = $licences_plugin[$nom]['url'];
419 // Si la version est pas bonne on prend la plus recente
420 if (!$version or !in_array($version, $licences_plugin[$nom]['versions'], true)) {
421 $version = $licences_plugin[$nom]['versions'][0];
423 if (is_array($licences_plugin[$nom]['nom'])) {
424 $licence['nom'] = $licences_plugin[$nom]['nom'][$version];
426 $licence['nom'] = str_replace('@version@', $version, $licences_plugin[$nom]['nom']);
428 $licence['url'] = str_replace('@version@', $version, $licences_plugin[$nom]['url']);
430 if ($nom == 'ccby') {
431 if ($suffixe == '-sharealike') {
434 if (!$suffixe or !in_array($suffixe, $licences_plugin[$nom]['suffixes'], true)) {
437 $licence['nom'] = str_replace('@suffixe@', strtoupper($suffixe), $licence['nom']);
438 $licence['url'] = str_replace('@suffixe@', $suffixe, $licence['url']);
447 * Liste les librairies présentes
449 * Cherche des librairie dans tous les dossiers 'lib' présents dans chaque
450 * chemin déclaré (plugins, squelettes, SPIP). Un répertoire dans un dossier
451 * 'lib' est considéré comme une librairie, et le nom de ce répertoire est
452 * utilisé comme nom de la librairie.
455 * Tableau de couples (nom de la librairie => répertoire de la librairie)
457 function svp_lister_librairies() {
459 foreach (array_reverse(creer_chemin()) as $d) {
460 if (is_dir($dir = $d . 'lib/') and $t = opendir($dir)) {
461 while (($f = readdir($t)) !== false) {
462 if ($f[0] != '.' and is_dir("$dir/$f")) {
474 * Retourne '00x.00y.00z' à partir de 'x.y.z'
476 * Retourne la chaine de la version x.y.z sous une forme normalisée
477 * permettant le tri naturel. On complète à gauche d'un nombre de zéro
478 * manquant pour aller à 3 caractères entre chaque point.
480 * @see denormaliser_version()
481 * @param string $version
482 * Numéro de version dénormalisée
484 * Numéro de version normalisée
486 function normaliser_version($version = '') {
488 $version_normalisee = '';
490 if (preg_match(',([0-9.]+)[\s.-]?(dev|alpha|a|beta|b|rc|pl|p)?,i', $version, $matches)) {
491 if (isset($matches[1]) and $matches[1]) {
492 $v = explode('.', $matches[1]);
494 foreach ($v as $_nombre) {
495 $vn[] = str_pad($_nombre, 3, '0', STR_PAD_LEFT
);
497 $version_normalisee = implode('.', $vn);
498 if (isset($matches[2]) and $matches[2]) {
499 $version_normalisee = $version_normalisee . '-' . $matches[2];
504 return $version_normalisee;