source: spip-zone/_plugins_/step/inc/step.php @ 37400

Last change on this file since 37400 was 37400, checked in by marcimat@…, 10 years ago

Pétouilles oubliées évidemment :)

File size: 18.9 KB
Line 
1<?php
2
3if (!defined("_ECRIRE_INC_VERSION")) return;
4
5define('_FILE_PLUGIN_CONFIG', "plugin.xml");
6
7include_spip('inc/plugin'); // pour spip_version_compare()
8                               
9// ---------------------- LIBS -------------------------------
10
11// Faire la liste des librairies disponibles
12// retourne un array ( nom de la lib => repertoire , ... )
13function step_lister_librairies() {
14        $libs = array();
15        foreach (array_reverse(creer_chemin()) as $d) {
16                if (is_dir($dir = $d.'lib/')
17                AND $t = @opendir($dir)) {
18                        while (($f = readdir($t)) !== false) {
19                                if ($f[0] != '.'
20                                AND is_dir("$dir/$f"))
21                                        $libs[$f] = $dir;
22                        }
23                }
24        }
25        return $libs;
26}
27
28
29
30// retourne un cadre contenant la liste des librairies disponibles dans /lib
31function step_html_liste_librairies_presentes(){
32        // Lister les librairies disponibles
33        $res = "";
34        if ($libs = step_lister_librairies()) {
35                ksort($libs);
36                $res = '<ul>';
37                foreach ($libs as $lib => $rep)
38                        $res .= "<li title='".joli_repertoire($rep)."'>$lib</li>\n";
39                $res .= '</ul>';
40        }
41        return $res;   
42}
43
44
45
46
47// ---------------------- ZONES de PLUGINS -------------------------------
48
49// Met a jour les zones de plugins
50function step_update(){
51
52
53        // proposition d'action :
54        // 1) lister tous les plugins locaux actifs et les afficher
55        // 2) lister tous les plugins locaux inactifs (prefixe different des actifs)
56        //   3) lister les plugins locaux actifs dont une maj existe en local (?)
57        //   4) lister les plugins locaux inactifs plus anciens (?)
58        // 5) lister les plugins distants : comparer a la fois l'etat (stable...) et la version
59        //    et lister 1 prefix par etat (la version la plus recente)
60        // 6) si ce plugin est deja present en local... on propose une mise a jour.
61       
62        // actualiser les plugins locaux
63        step_actualiser_plugins_locaux();
64       
65        // actualiser les plugins distants
66        $res = sql_select(array('id_zone','adresse'),'spip_zones_plugins');
67        while ($r = sql_fetch($res)){
68                step_actualiser_zone($r['adresse']);
69        }
70}
71
72
73
74// Teste la validite d'une url d'une zone de paquets
75function step_verifier_adresse_zone($url){
76        return preg_match(',^https?://[^.]+\.[^.]+.*/.*[^/]$,', $url);
77}
78
79
80
81
82
83// Ajoute une zone de paquets
84// (xml d'une liste de plugin)
85// a la liste des zones de SPIP
86// et ajoute les plugins associes dans la table spip_plugins
87function step_ajouter_zone($url){
88        $url = trim($url);
89
90        // mauvaise adresse
91        if (!step_verifier_adresse_zone($url))
92                return;
93               
94        // adresse deja presente
95        if (sql_countsel('spip_zones_plugins', 'adresse='.sql_quote($url))){
96                return;
97        }
98
99        // lire les donnees d'une zone de plugins
100        $paquets = step_xml_parse_zone($url);
101       
102        if (count($paquets)){
103                // nom et description a definir dans le fichier xml de la source ?
104                $nom = $url;
105                $id_zone = sql_insertq('spip_zones_plugins', array('nom'=>$nom, 'adresse'=>$url, 'nombre_plugins'=>count($paquets)));
106               
107                // ajouter les plugins dans spip_plugins
108                step_maj_liste_plugins($id_zone, $paquets);
109        }
110       
111        return count($paquets);
112}
113
114
115
116
117
118// actualise une zone de plugins
119// $id = adresse zone OU id_zone dans la table spip_zones_plugins
120function step_actualiser_zone($id){
121        $id = trim($id);
122       
123        // pas de zone a cette adresse ?
124        if (!$z = sql_fetsel(array('id_zone', 'adresse'), 'spip_zones_plugins', 'adresse=' . sql_quote($id) . ' OR id_zone='. sql_quote($id)) ){
125                return;
126        }
127       
128        // lire les donnees d'une zone de plugins
129        $paquets = step_xml_parse_zone($z['adresse']);
130       
131        if (count($paquets)){
132                // nom et description a definir dans le fichier xml de la source ?
133                $nom = $url = $z['adresse'];
134                sql_updateq('spip_zones_plugins', array(
135                                'nom'=>$nom, 
136                                'adresse'=>$url, 
137                                'nombre_plugins'=>count($paquets)), 
138                                'id_zone=' . sql_quote($z['id_zone'])
139                );
140               
141                // actualiser les plugins dans spip_plugins
142                step_maj_liste_plugins($z['id_zone'], $paquets);
143        }
144}
145
146
147
148// actualise la liste des plugins locaux presents et installes
149function step_actualiser_plugins_locaux(){
150       
151        if ($plugins = step_liste_plugin_files()) {
152                // connaitre la liste des plugins actuellement actifs
153                $actifs = step_liste_plugin_actifs();
154                $recents = step_liste_plugin_recents();
155
156                include_spip('inc/xml');
157                // recuperer les plugins.xml
158                // et mettre a jour la bdd...
159                // si le plugin n'est pas activable,
160                // on ne l'affiche pas non plus
161                sql_delete('spip_plugins','id_zone=' . sql_quote(0));
162
163                foreach($plugins as $constante=>$liste) {
164                        foreach ($liste as $p) {
165                                step_actualiser_plugin_local($constante, $p, $actifs, $recents);
166                        }               
167                }
168        }
169}
170
171
172function step_actualiser_plugin_local($constante, $p, $actifs, $recents) {
173        $dir = constant($constante);
174        lire_fichier($dir . $p . '/' . _FILE_PLUGIN_CONFIG, $xml);
175        // enlever la balise doctype qui provoque une erreur "balise non fermee" lors du parsage
176        $xml = preg_replace('#<!DOCTYPE[^>]*>#','',$xml);
177        // traduire le xml en php
178        if (is_array($plugin = spip_xml_parse($xml)) and $plugin = $plugin['plugin'][0]){
179                // applatir les champs du plugin (ie les balises <multi> sont des chaines...)
180                if ($insert = step_xml_parse_plugin($plugin)) {
181                        // recuperer les champs sql utiles
182                        if ($insert = step_selectionner_champs_sql_plugin($insert)) {
183                                $insert['id_zone'] = 0;
184                                $insert['present'] = 'oui';
185                                $insert['constante'] = $constante; 
186                                $insert['dossier'] = $p . '/'; 
187                                $prefix = strtoupper($insert['prefixe']);
188                                // flag sur plugin actif et installe
189                                if (is_array($actifs[$prefix])
190                                and ($actifs[$prefix]['dir'] == $p)) {
191                                        $insert['actif'] = 'oui';
192                                        if (step_plugin_est_installe($p))
193                                                $insert['installe'] = 'oui';
194                                }
195                                // flag sur plugin utilise recemment
196                                if (isset($recents[$p]) and $recents[$p]) {
197                                        $insert['recent'] = 1; // si on met la valeur, il sera difficile d'appliquer {recent?}
198                                }
199                                // flag s'il existe une version plus stable ou plus recente
200                                // (seulement si le plugin n'est pas actif)
201                                // et on rend obsolete, inversement, les plugins que l'on perime                                       
202                                if ($res = sql_select(array('id_plugin','version','etatnum'),'spip_plugins',array(
203                                        'id_zone=' . sql_quote(0),
204                                        'prefixe=' . sql_quote($insert['prefixe'])))
205                                AND sql_count($res)) {
206                                        $invalides = array();
207                                        while ($r = sql_fetch($res)) {
208                                                // nota ; idem aux plugs des zones... il faudrait
209                                                // par defaut ne juger que le numero de version, et non l'etat
210                                                // en attandant, si (v3 stable et v4 test) on affiche les 2
211                                               
212                                                // si version <= moi et etat <= moi, on invalide ce plugin
213                                                if (spip_version_compare($r['version'],$insert['version'],'<=') and ($r['etatnum'] <= $insert['etatnum'])) {
214                                                        $invalides[] = $r['id_plugin'];
215                                                }
216                                                if ($insert['actif'] != 'oui') {
217                                                        // s'il existe un plugin en tout point mieux, je m'invalide
218                                                        if ((spip_version_compare($r['version'],$insert['version'],'>') and ($r['etatnum'] >= $insert['etatnum']))
219                                                        or  (spip_version_compare($r['version'],$insert['version'],'>=') and ($r['etatnum'] > $insert['etatnum']))
220                                                        ) {
221                                                                $insert['obsolete'] = 'oui';
222                                                        }
223                                                }
224                                        }
225                                        if ($invalides) {
226                                                sql_updateq('spip_plugins',array('obsolete'=>'oui'), sql_in('id_plugin', $invalides));
227                                        }
228                                }                                                               
229
230                                // on recherche d'eventuelle mises a jour existantes
231                                if ($res = sql_select(array('id_plugin','version','superieur'),'spip_plugins',array(
232                                        'actif=' . sql_quote('non'),
233                                        'id_zone>' . sql_quote(0),
234                                        'prefixe=' . sql_quote($insert['prefixe']),
235                                        'etatnum>=' . sql_quote($insert['etatnum'])))
236                                AND sql_count($res)) {
237                                        $superieurs = array();
238                                        while ($r = sql_fetch($res)) {
239                                                // si version superieure et etat identique ou meilleur,
240                                                // c'est que c'est une mise a jour possible !
241                                                if (spip_version_compare($r['version'],$insert['version'],'>')) {
242                                                        if (!$insert['maj_version'] or spip_version_compare($r['version'], $insert['maj_version'],'>')) {
243                                                                $insert['maj_version'] = $r['version'];
244                                                        }
245                                                }
246                                                if ($r['superieur'] != 'oui') {
247                                                        $superieurs[] = $r['id_plugin'];
248                                                }
249                                        }
250                                        if ($superieurs) {
251                                                sql_updateq('spip_plugins',array('superieur'=>'oui'), sql_in('id_plugin', $superieurs));
252                                        }
253                                }                               
254                               
255                                return sql_insertq('spip_plugins', $insert);   
256                        }
257                }                                       
258        }
259}
260
261
262// supprime une zone de plugins (et sa liste de plugins)
263// $id = adresse zone OU id_zone dans la table spip_zones_plugins
264// ainsi que les entrees associes dans la table spip_plugins
265function step_supprimer_zone($id){
266        $id = trim($id);
267       
268        // pas de zone a cette adresse ?
269        if (!$id_zone = sql_getfetsel('id_zone', 'spip_zones_plugins', 'adresse=' . sql_quote($id) . ' OR id_zone='. sql_quote($id)) ){
270                return;
271        }
272
273        sql_delete('spip_plugins','id_zone='.sql_quote($id_zone));
274        sql_delete('spip_zones_plugins','id_zone='.sql_quote($id_zone));
275        return true;
276}
277
278
279
280// met a jour la liste des plugins d'une zone donnee
281function step_maj_liste_plugins($id_zone, $liste) {
282
283        if ($id_zone and is_array($liste)) {
284                sql_delete('spip_plugins','id_zone=' . sql_quote($id_zone));
285                foreach ($liste as $file=>$p) {
286                        if ($insert = step_selectionner_champs_sql_plugin($p['plugin'])) {
287                                $insert['id_zone'] = $id_zone;
288                                $insert['paquet'] = $file;
289                                // on ajoute le plugin uniquement s'il est nouveau
290                                // ou de version superieure (etat et prefixe identiques)
291
292                                // le jour ou on aura des zones de plugins / etat, on pourra
293                                // rendre obsolete uniquement avec le numero de version
294                                // en attendant lorsque (v3 stable, et v4 test existent, on propose les 2)
295                                if ($res = sql_select(array('id_plugin','id_zone','version'),'spip_plugins',array(
296                                        'etatnum<=' . sql_quote($insert['etatnum']),
297                                        'prefixe=' . sql_quote($insert['prefixe'])))
298                                AND sql_count($res))
299                                {
300                                        $add = false;
301                                        while ($r = sql_fetch($res)) {
302                                                // 2 possibilites :
303                                                // - plus recent : on le met,
304                                                //     + on met un flag sur les locaux... (maj_version)
305                                                //     + on supprime les distants plus vieux
306                                                // - plus ancien : on le met pas...
307                                                if (spip_version_compare($insert['version'], $r['version'],'>')) {
308                                                        $add = true;
309                                                        if ($r['id_zone'] == 0) {
310                                                                sql_updateq('spip_plugins',array('maj_version'=>$insert['version']),'id_plugin='.sql_quote($r['id_plugin']));
311                                                                $insert['superieur'] = 'oui'; // dire que ce plugin est une mise a jour d'un plugin deja actif
312                                                        } else {
313                                                                // il y a un cas qui pose probleme :
314                                                                // - si on ne met pas les plugins aux versions identiques des zones distantes
315                                                                // - si on supprime le paquet local (avec ses fichiers)
316                                                                // - une recherche ne trouvera plus le paquet (vu qu'il ne sera pas dans la bdd)
317                                                                // cela oblige a actualiser les sources de plugins pour recalculer.
318                                                                // on laisse comme cela pour l'instant.
319                                                                sql_delete('spip_plugins','id_plugin='.sql_quote($r['id_plugin']));
320                                                        }
321                                                }
322                                        }
323                                        if ($add) sql_insertq('spip_plugins',$insert);
324                                } else {
325                                        sql_insertq('spip_plugins',$insert);
326                                }
327                        }
328                }
329        } 
330}
331
332
333// passe simplement un '[version;version]'
334function step_verifier_plugin_compatible_version_spip($version){
335        $version_spip = $GLOBALS['spip_version_branche'].".".$GLOBALS['spip_version_code'];
336        return step_plugin_version_compatible($version, $version_spip);
337}
338
339
340
341// Les archives xml sont deja applaties, pas la peine de se compliquer.
342function step_selectionner_champs_sql_plugin($p) {
343
344        // calcul du tableau de dependances
345        // Et on ne propose pas de plugin ne fonctionnant pas
346        // avec notre version de SPIP
347        $dependances = array();
348        if (is_array($p['necessite'])) {
349                foreach ($p['necessite'] as $c=>$n) {
350                        if ($n['id'] == 'SPIP') {
351                                if (!step_verifier_plugin_compatible_version_spip($n['version'])) {
352                                        return false;
353                                }
354                                break;
355                        }
356                        $p['necessite'][$c]['id'] = strtolower($n['id']);
357                }
358                $dependances['necessite'] = $p['necessite'];
359        }
360       
361        if (is_array($p['utilise'])) {
362                foreach ($p['utilise'] as $c=>$n) {
363                        $p['utilise'][$c]['id'] = strtolower($n['id']);
364                }
365                $dependances['utilise'] = $p['utilise'];
366        }
367
368        // etat numerique (pour simplifier la recherche de maj)
369        $num = array('stable'=>4, 'test'=>3, 'dev'=>2, 'experimental'=>1);
370        $etatnum = isset($num[$p['etat']]) ? $num[$p['etat']] : 0;
371        return array(
372                'nom' => $p['nom'],
373                'prefixe' => $p['prefix'],
374                'auteur' => $p['auteur'],
375                'version' => $p['version'],
376                'version_base' => $p['version_base'],
377                'licence' => $p['licence'],
378                'shortdesc' => $p['shortdesc'],
379                'description' => $p['description'],
380                'dependances' => serialize($dependances),
381                'etat' => $p['etat'],
382                'etatnum' => $etatnum,
383                'actif' => 'non',
384                'installe' => 'non',
385                'logo' => $p['icon'],
386                'categorie' => $p['categorie'],
387                'tags' => $p['tags'],
388        );
389}
390
391
392
393// ----------------------- Verifications de versions
394
395// fonction de SPIP inc/plugins
396function step_plugin_version_compatible($intervalle,$version){
397        if (!strlen($intervalle)) return true;
398        if (!preg_match(',^[\[\(]([0-9.a-zRC\s]*)[;]([0-9.a-zRC\s]*)[\]\)]$,',$intervalle,$regs)) return false;
399        $mineure = $regs[1];
400        $majeure = $regs[2];
401        $mineure_inc = $intervalle{0}=="[";
402        $majeure_inc = substr($intervalle,-1)=="]";
403        #var_dump("$mineure_inc-$mineure-$majeure-$majeure_inc");
404        if (strlen($mineure)){
405                if ($mineure_inc AND spip_version_compare($version,$mineure,'<')) return false;
406                if (!$mineure_inc AND spip_version_compare($version,$mineure,'<=')) return false;
407        }
408        if (strlen($majeure)){
409                if ($majeure_inc AND spip_version_compare($version,$majeure,'>')) return false;
410                if (!$majeure_inc AND spip_version_compare($version,$majeure,'>=')) return false;
411        }
412        return true;
413}
414
415
416
417
418
419// ----------------------- Analyses XML ---------------------------------
420
421
422// parse un fichier de source dont l'url est donnee
423// ce fichier est un fichier XML contenant <zone><zone_elt/></zone>
424function step_xml_parse_zone($url){
425        include_spip('inc/xml');
426
427        $arbre = array();
428       
429        include_spip('inc/distant');
430        if (!$xml = recuperer_page($url)) {
431                return false;
432        }
433
434        // enlever la balise doctype qui provoque une erreur "balise non fermee" lors du parsage
435        $xml = preg_replace('#<!DOCTYPE[^>]*>#','',$xml);
436        if (!is_array($arbre = spip_xml_parse($xml)) OR !is_array($arbre = $arbre['archives'][0])){
437                return false;
438        }
439
440        // boucle sur les elements pour creer un tableau array (url_zip => datas)
441        $paquets = array();                     
442        foreach ($arbre as $z=>$c){
443                $c = $c[0];
444                // si plugin et fichier zip, on ajoute le paquet dans la liste
445                if ((is_array($c['plugin'])) AND ($url = $c['file'][0])) {
446                        $paquets[$url] = array(
447                                'plugin' => step_xml_parse_plugin($c['plugin'][0]), 
448                                'file' => $url, 
449                        );
450                }
451        }
452        if (!$paquets) {
453                return false;
454        }
455       
456        return $paquets;
457}
458
459// aplatit plusieurs cles d'un arbre xml dans un tableau
460// effectue un trim() au passage
461function step_xml_aplatit_multiple($array, $arbre){
462        $a = array();
463        // array('uri','archive'=>'zip',...)
464        foreach ($array as $i=>$n){
465                if (is_string($i)) $cle = $i;
466                else $cle = $n;
467                $a[$n] = trim(spip_xml_aplatit($arbre[$cle]));
468        }
469        return $a;     
470}
471
472
473// parse un plugin.xml genere par spip_xml_parse()
474// en un tableau plus facilement utilisable
475// cette fonction doit permettre de mapper des changements
476// de syntaxe entre plugin.xml et step
477function step_xml_parse_plugin($arbre){
478
479        if (!is_array($arbre)) 
480                return false;
481       
482        // on commence par les simples !
483        $plug_arbre = step_xml_aplatit_multiple(
484                                array('nom','icon','auteur','licence','version','version_base','etat','shortdesc','categorie','tags',
485                                'description','lien','options','fonctions','prefix','install'), 
486                                $arbre);
487        $plug_arbre['prefix'] = strtolower($plug_arbre['prefix']);
488       
489        // on continue avec les plus complexes...       
490        // 1) balises avec attributs
491        foreach (array(
492                        'necessite'=>array('necessite', null),
493                        'utilise'=>array('utilise', null),
494                        'chemin'=>array('path', array('dir'=>'')))
495                                as $balise=>$p){
496                $params = $res = array();
497                // recherche de la balise et extraction des attributs
498                if (spip_xml_match_nodes(",^$balise,",$arbre, $res)){
499                        foreach(array_keys($res) as $tag){
500                                list($tag,$att) = spip_xml_decompose_tag($tag);
501                                $params[] = $att;
502                        }
503                } 
504                // valeur par defaut
505                else {
506                        if ($p[1]!==null)
507                                $params[] = $p[1];
508                }
509                $plug_arbre[$p[0]] = $params;           
510        }
511
512        // 2) balises impriquees
513        // (pipeline, boutons, onglets)
514        // on verra plus tard si besoin !
515
516        return $plug_arbre;
517}
518
519
520
521
522
523
524// ------------------- A peu de chose pres dans le core ----------------
525
526
527// retourne le chemin d'une image contenu dans images/
528function step_chemin_image($icone){
529        return find_in_path($icone, _NOM_IMG_PACK);
530}
531
532
533
534// -------------------- Autorisations ----------------------------
535
536// teste si l'on peut ecrire un plugin dans un repertoire donne
537function autoriser_plugins_telecharger($faire, $type, $id, $qui, $opt){
538       
539        if (
540                !_AUTORISER_TELECHARGER_PLUGINS
541                OR !step_verifier_droit_ecriture()
542                OR !autoriser('configurer', $type, $id, $qui, $opt)
543        ) return false;
544       
545        return true;
546}
547
548// verifie que l'on peut ecrire dans le repertoire donne
549function step_verifier_droit_ecriture($dir = _DIR_PLUGINS2){
550        if ($dir)
551                return is_dir($dir) AND is_writable($dir);
552        else 
553                return false;   
554}
555
556
557// ------------------------ Recherche des plugins locaux ------------
558
559// Retourne la liste de tous les plugins d'un repertoire donne
560// ou d'un tableau de repertoires
561// (modif de la fonction de spip 2.1)
562function step_liste_plugin_files($dir_plugins = ""){
563        static $plugin_files=array();
564
565        if (!$dir_plugins) {
566                $dir_plugins = array(
567                        '_DIR_PLUGINS',
568                        '_DIR_EXTENSIONS',
569                );
570                // plugins supp (1 seul dossier)
571                if (defined('_DIR_PLUGINS_SUPP')) {$dir_plugins[] = '_DIR_PLUGINS_SUPP';}
572        }
573       
574        // tableau
575        if (is_array($dir_plugins)) {
576                foreach ($dir_plugins as $dir) {
577                        $plugin_files[$dir] = step_liste_plugin_files($dir);
578                }
579                return $plugin_files;
580        }
581       
582        // solo
583        if (!isset($plugin_files[$dir_plugins])
584        OR count($plugin_files[$dir_plugins]) == 0){
585                $plugin_files[$dir_plugins] = array();
586                foreach (preg_files(constant($dir_plugins), '/plugin[.]xml$') as $plugin) {
587                        $plugin_files[$dir_plugins][] = str_replace(constant($dir_plugins),'',dirname($plugin));
588                }
589                sort($plugin_files[$dir_plugins]);
590        }
591
592        return $plugin_files[$dir_plugins];
593}
594
595
596
597// ----------------------- Connaitre les plugins actifs, recents et desinstallables
598
599
600// de inc/plugins
601function step_liste_plugin_actifs(){
602        $meta_plugin = isset($GLOBALS['meta']['plugin'])?$GLOBALS['meta']['plugin']:'';
603        if (strlen($meta_plugin)>0){
604                if (is_array($t=unserialize($meta_plugin)))
605                        return $t;
606        }
607        return array();
608}
609
610
611// liste des plugins utilises recemment
612function step_liste_plugin_recents(){
613        $meta_plugin = isset($GLOBALS['meta']['plugins_interessants'])?$GLOBALS['meta']['plugins_interessants']:'';
614        if (strlen($meta_plugin)>0){
615                if (is_array($t=unserialize($meta_plugin)))
616                        return $t;
617        }
618        return array();
619}
620
621
622
623function step_plugin_est_installe($plug_path){
624        $plugin_installes = isset($GLOBALS['meta']['plugin_installes'])?unserialize($GLOBALS['meta']['plugin_installes']):array();
625        if (!$plugin_installes) return false;
626        return in_array($plug_path,$plugin_installes);
627}
628
629
630function step_selectionner_maj() {
631        $ids = array();
632        if ($res = sql_select('id_plugin','spip_plugins',array(
633                'maj_version<>' .sql_quote(''),
634                'id_zone='.sql_quote(0),
635                'obsolete='.sql_quote('non')))) {
636                        while ($r = sql_fetch($res)) {
637                                $ids[] = $r['id_plugin'];
638                        }
639        }
640        return $ids;
641}
642
643?>
Note: See TracBrowser for help on using the repository browser.