source: spip-zone/_core_/plugins/svp/inc/svp_actionner.php @ 59372

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

Dénormaliser la version du répertoire de destination au téchargement d'un plugin.

File size: 31.0 KB
Line 
1<?php
2
3if (!defined("_ECRIRE_INC_VERSION")) return;
4
5// l'actionneur calcule l'ordre des actions
6// et permet de les stocker et de les effectuer.
7
8class Actionneur {
9
10        var $decideur;
11
12        // loggue t'on ?
13        var $log = false;
14
15        // actions au debut (avant analyse)
16        var $start = array();
17
18        // actions en cours d'analyse
19        var $middle = array(
20                'off' => array(),
21                'lib' => array(),
22                'on' => array(),
23                'neutre' => array(),
24        );
25
26        // actions a la fin (apres analyse, et dans l'ordre)
27        var $end = array();  // a faire...
28        var $done = array(); // faites
29        var $work = array(); // en cours
30
31        // listing des erreurs rencontrées
32        var $err = array();
33       
34        // Verrou.
35        // Le verrou est posé au moment de passer à l'action.
36        var $lock = array('id_auteur'=>0, 'time'=>'');
37
38        // SVP (ce plugin) est a desactiver ?
39        var $svp_off = false;
40
41        function Actionneur(){
42                include_spip('inc/config');
43                $this->log = (lire_config('svp/mode_log_verbeux') == 'oui');
44               
45                include_spip('inc/svp_decider');
46                $this->decideur = new Decideur();
47                #$this->decideur->start();
48
49                // pour denormaliser_version()
50                include_spip('svp_fonctions');
51        }
52
53
54        /**
55         * Ajoute un log
56         * lorsqu'on a activé les logs sur notre objet
57         * $actionneur->log = true;
58         *
59         * @param string $quoi : le texte du log
60        **/
61        function log($quoi) {
62                if ($this->log) {
63                        spip_log($quoi,'actionneur');
64                }
65        }
66
67        /**
68         * Ajoute une erreur
69         * a la liste des erreurs presentees au moment de traiter les actions.
70         *
71         * @param string $erreur : le texte de l'erreur
72        **/
73        function err($erreur) {
74                if ($erreur) {
75                        $this->err[] = $erreur;
76                }
77        }
78
79        function clear() {
80                $this->middle = array(
81                        'off' => array(),
82                        'lib' => array(),
83                        'on' => array(),
84                        'neutre' => array(),
85                );
86                $this->end = array();
87                $this->done = array();
88                $this->work = array();
89        }
90
91        function ajouter_actions($todo) {
92                foreach ($todo as $id => $action) {
93                        $this->start[$id] = $action;
94                }
95                $this->ordonner_actions();
96        }
97
98
99        // ajouter une librairie a installer.
100        function add_lib($nom, $source) {
101                if (!$this->decideur->est_presente_lib($nom)) {
102                        if (is_writable(_DIR_LIB)) {
103                                $this->middle['lib'][$nom] = array(
104                                        'todo'=>'getlib',
105                                        'n'=>$nom,
106                                        'p'=>$nom,
107                                        'v'=>$source,
108                                        's'=>$source,
109                                );
110                        } else {
111                                // erreur : impossible d'ecrire dans _DIR_LIB !
112                                // TODO : message et retour d'erreur a gerer...
113                                return false;
114                        }
115                }
116                return true;
117        }
118
119
120        function ordonner_actions() {
121                // il faut deja definir quels sont les
122                // actions graduellement realisables.
123                // Pour tout ce qui est a installer : ordre des dependances
124                // Pour tout ce qui est a desinstaller : ordre inverse des dependances.
125
126                // on commence par separer
127                // - ce qui est a desinstaller.
128                // - ce qui est a installer
129                // - les actions neutres (get, up sur non actif, kill)
130
131                // on commencera par faire ce qui est a desinstaller
132                // (il est possible que certains plugins necessitent la desinstallation
133                //  d'autres present - tel que : 1 seul service d'envoi de mail)
134                // puis ce qui est a installer
135                // puis les actions neutres
136                $this->clear();
137
138                foreach ($this->start as $id=>$action) {
139                        $i = $this->decideur->infos_courtes_id($id);
140                        $i = $i['i'][$id];
141                        switch ($action) {
142                                case 'getlib':
143                                        // le plugin en ayant besoin le fera
144                                        // comme un grand...
145                                        break;
146                                case 'geton':
147                                case 'on':
148                                        $this->on($i, $action);
149                                        break;
150                                case 'up':
151                                        // si le plugin est actif
152                                        if ($i['a'] == 'oui') { 
153                                                $this->on($i, $action);
154                                        } else {
155                                                $this->neutre($i, $action);
156                                        }
157                                        break;
158                                case 'upon':
159                                        $this->on($i, $action);
160                                        break;
161                                case 'off':
162                                case 'stop':
163                                        $this->off($i, $action);
164                                        break;
165                                case 'get':
166                                case 'kill':
167                                        $this->neutre($i, $action);
168                                        break;
169                        }
170                }
171
172                // c'est termine, on passe tout dans la fin...
173                foreach ($this->middle as $acts) {
174                        $this->end = array_merge($this->end, $acts);
175                }
176
177                // si on a vu une desactivation de SVP
178                // on le met comme derniere action...
179                // sinon on ne pourrait pas faire les suivantes !
180                if ($this->svp_off) {
181                        $this->log("SVP a desactiver a la fin.");
182                        foreach ($this->end as $c => $info) {
183                                if ($info['p'] == 'SVP') {
184                                        unset($this->end[$c]);
185                                        $this->end[] = $info;
186                                        break;
187                                }
188                        }
189                }
190       
191                $this->log("------------");
192                #$this->log("Fin du tri :");
193                #$this->log($this->end);
194        }
195
196
197        // a chaque fois qu'une action arrive,
198        // on compare avec celles deja presentes
199        // pour savoir si on doit la traiter avant ou apres
200
201        function on($info, $action) {
202                $info['todo'] = $action;
203                $p = $info['p'];
204                $this->log("ON: $p $action");
205
206                // si dependance, il faut le mettre avant !
207                $in = $out = $deps = $deps_all = array();
208                // raz des cles pour avoir les memes que $out (utile reellement ?)
209                $this->middle['on'] = array_values($this->middle['on']);
210                // ajout des dependance
211                foreach ($info['dn'] as $dep) {
212                        $in[]  = $dep['nom'];
213                }
214                // ajout des librairies
215                foreach ($info['dl'] as $lib) {
216                        // il faudrait gerer un retour d'erreur eventuel !
217                        $this->add_lib($lib['nom'], $lib['lien']);
218                }
219
220                // on recupere : tous les prefix de plugin a activer (out)
221                // ie. ce plugin peut dependre d'un de ceux la
222                //
223                // ainsi que les dependences de ces plugins (deps)
224                // ie. ces plugins peuvent dependre de ce nouveau a activer.
225                foreach ($this->middle['on'] as $inf) {
226                        $out[] = $inf['p'];
227                        foreach ($inf['dn'] as $dep) {
228                                $deps[$inf['p']][] = $dep['nom'];
229                                $deps_all[] = $dep['nom'];
230                        }
231                }
232
233
234                if (!$in) {
235
236                        // pas de dependance, on le met en premier !
237                        $this->log("- placer $p tout en haut");
238                        array_unshift($this->middle['on'], $info);
239
240                } else {
241
242                        // intersection = dependance presente aussi
243                        // on place notre action juste apres la derniere dependance
244                        if ($diff = array_intersect($in, $out)) {
245                                $key = array();
246                                foreach($diff as $d) {$key[] = array_search($d, $out);}
247                                $key = max($key);
248                                $this->log("- placer $p apres " . $this->middle['on'][$key]['p']);
249                                if ($key == count($this->middle['on'])) {
250                                        $this->middle['on'][] = $info;
251                                } else {
252                                        array_splice($this->middle['on'], $key+1, 0, array($info));
253                                }
254
255                        // intersection = plugin dependant de celui-ci
256                        // on place notre plugin juste avant la premiere dependance a lui trouvee
257                        } elseif (in_array($p, $deps_all)) {
258                                foreach ($deps as $prefix=>$dep) {
259                                        if (in_array($p, $dep)) {
260                                                $key = array_search($prefix, $out);
261                                                $this->log("- placer $p avant $prefix qui en depend ($key)");
262                                                if ($key == 0) {
263                                                        array_unshift($this->middle['on'], $info);
264                                                } else {
265                                                        array_splice($this->middle['on'], $key, 0, array($info));
266                                                }
267                                                break;
268                                        }
269                                }
270
271                        // rien de particulier, il a des dependances mais les plugins
272                        // ne sont pas encore la ou les dependances sont deja actives
273                        // donc on le place tout en bas
274                        } else {
275                                $this->log("- placer $p tout en bas");
276                                $this->middle['on'][] = $info;
277                        }
278                }
279                unset($diff, $in, $out);
280        }
281
282
283        function neutre($info, $action) {
284                $info['todo'] = $action;
285                $this->log("NEUTRE:  $info[p] $action");
286                $this->middle['neutre'][] = $info;
287        }
288
289
290        function off($info, $action) {
291                $info['todo'] = $action;
292                $p = $info['p'];
293                $this->log("OFF: $p $action");
294
295                // signaler la desactivation de SVP
296                if ($p == 'SVP') {
297                        $this->svp_off = true;
298                }
299               
300                // si dependance, il faut le mettre avant !
301                $in = $out = array();
302                // raz des cles pour avoir les memes que $out (utile reellement ?)
303                $this->middle['off'] = array_values($this->middle['off']);
304                foreach ($info['dn'] as $dep) {
305                        $in[]  = $dep['nom'];
306                }
307                foreach ($this->middle['off'] as $inf)  {
308                        $out[] = $inf['p'];
309                }
310
311                if (!$in) {
312                        // ce plugin n'a pas de dependance, on le met en dernier !
313                        $this->log("- placer $p tout en bas");
314                        $this->middle['off'][] = $info;
315                } else {
316                        // ce plugin a des dependances,
317                        // on le desactive juste avant elles.
318                       
319                        // intersection = dependance presente aussi
320                        // on place notre action juste avant la premiere dependance
321                        if ($diff = array_intersect($in, $out)) {
322                                $key = array();
323                                foreach($diff as $d) {$key[] = array_search($d, $out);}
324                                $key = min($key);
325                                $this->log("- placer $p avant " . $this->middle['off'][$key]['p']);
326                                array_splice($this->middle['off'], $key, 0, array($info));
327                        } else {
328                                // aucune des dependances n'est a desactiver
329                                // (du moins à ce tour ci),
330                                // on le met en premier !
331                                $this->log("- placer $p tout en haut");
332                                array_unshift($this->middle['off'], $info); // etait ->middle['on'] ?? ...
333                        }
334                }
335                unset($diff, $in, $out);
336        }
337
338
339
340        function presenter_actions($fin = false) {
341                $affiche = "";
342
343                include_spip('inc/filtres_boites');
344               
345                if (count($this->err)) {
346                        $erreurs = "<ul>";
347                        foreach ($this->err as $i) {
348                                $erreurs .= "\t<li class='erreur'>" . $i . "</li>\n";
349                        }
350                        $erreurs .= "</ul>"; 
351                        $affiche .= boite_ouvrir(_T('svp:actions_en_erreur'), 'error') . $erreurs . boite_fermer();
352                }
353
354                if (count($this->done)) {
355                        $oks = true;
356                        $done .= "<ul>";
357                        foreach ($this->done as $i) {
358                                $ok = ($i['done'] ? true : false);
359                                $oks = &$ok;
360                                $ok_texte = $ok ? 'ok' : 'fail';
361                                $cle_t = 'svp:message_action_finale_' . $i['todo'] . '_' . $ok_texte;
362                                $texte = _T($cle_t, array(
363                                        'plugin' => $i['n'],
364                                        'version' => denormaliser_version($i['v']),
365                                        'version_maj' => denormaliser_version($i['maj'])));
366                                if (is_string($i['done'])) {
367                                        $texte .= " <span class='$ok_texte'>$i[done]</span>";
368                                }
369                                $done .= "\t<li class='$ok_texte'>$texte</li>\n";
370                        }
371                        $done .= "</ul>";
372                        $affiche .= boite_ouvrir(_T('svp:actions_realises'), ($oks ? 'success' : 'notice')) . $done . boite_fermer();
373                }
374
375                if (count($this->end)) {
376                        $todo .= "<ul>";
377                        foreach ($this->end as $i) {
378                                $todo .= "\t<li>"._T('svp:message_action_'.$i['todo'],array(
379                                        'plugin'=>$i['n'],
380                                        'version'=>denormaliser_version($i['v']),
381                                        'version_maj'=>denormaliser_version($i['maj'])))."</li>\n";
382                        }
383                        $todo .= "</ul>\n";
384                        $titre = ($fin ? _T('svp:actions_non_traitees') : _T('svp:actions_a_faire'));
385
386                        // s'il reste des actions à faire alors que c'est la fin qui est affichée,
387                        // on met un lien pour vider. C'est un cas anormal qui peut surgir :
388                        // - en cas d'erreur sur une des actions bloquant l'espace privé
389                        // - en cas d'appel d'admin_plugins concurrent par le même admin ou 2 admins...
390                        if ($fin) {
391                                include_spip('inc/filtres');
392                                if ($this->lock['time']) {
393                                        $time = $this->lock['time'];
394                                } else {
395                                        $time = time();
396                                }
397                                $date = date('Y-m-d H:i:s', $time);
398                                $todo .= "<br />\n";
399                                $todo .= "<p class='error'>" . _T('svp:erreur_actions_non_traitees', array(
400                                        'auteur' => sql_getfetsel('nom', 'spip_auteurs', 'id_auteur=' . sql_quote($this->lock['id_auteur'])),
401                                        'date' => affdate_heure($date)
402                                )) . "</p>\n";
403                                $todo .= "<a href='" . parametre_url(self(), 'nettoyer_actions', '1'). "'>" . _T('svp:nettoyer_actions') . "</a>\n";
404                        }
405                        $affiche .= boite_ouvrir($titre, 'notice') . $todo . boite_fermer();
406                }
407
408                if ($affiche) {
409                        include_spip('inc/filtres');
410                        $affiche = wrap($affiche, "<div id='actionner'>");
411                }
412               
413                return $affiche;
414        }
415
416
417        function est_verrouille($id_auteur = '') {
418                if ($id_auteur == '') {
419                        return ($this->lock['id_auteur'] ? true : false);
420                }
421                return ($this->lock['id_auteur'] == $id_auteur);
422        }
423
424       
425        function verrouiller() {
426                $this->lock = array(
427                        'id_auteur' => $GLOBALS['visiteur_session']['id_auteur'],
428                        'time' => time(),
429                );
430        }
431
432
433        function deverrouiller() {
434                $this->lock = array(
435                        'id_auteur' => 0,
436                        'time' => '',
437                );
438        }
439
440
441        function sauver_actions() {
442                $contenu = serialize(array(
443                        'todo' => $this->end,
444                        'done' => $this->done,
445                        'work' => $this->work,
446                        'err'  => $this->err,
447                        'lock' => $this->lock,
448                ));
449                ecrire_fichier(_DIR_TMP . 'stp_actions.txt', $contenu);
450        }
451
452
453        function get_actions() {
454                lire_fichier(_DIR_TMP . 'stp_actions.txt', $contenu);
455                $infos = unserialize($contenu);
456                $this->end  = $infos['todo'];
457                $this->work = $infos['work'];
458                $this->done = $infos['done'];
459                $this->err  = $infos['err'];
460                $this->lock = $infos['lock'];
461        }
462
463        function nettoyer_actions() {
464                $this->todo = array();
465                $this->done = array();
466                $this->work = array();
467                $this->err  = array();
468                $this->deverrouiller();
469                $this->sauver_actions();
470        }
471
472        /**
473         * Effectue une des actions qui reste a faire. 
474        **/
475        function one_action() {
476                // s'il reste des actions, on en prend une, et on la fait
477                // de meme si une action est en cours mais pas terminee (timeout)
478                // on tente de la refaire...
479                if (count($this->end) OR $this->work) {
480                        // on verrouille avec l'auteur en cours pour
481                        // que seul lui puisse effectuer des actions a ce moment la
482                        if (!$this->est_verrouille()) {
483                                $this->verrouiller();
484                        }
485                        // si ce n'est pas verrouille par l'auteur en cours...
486                        // ce n'est pas normal, donc on quitte sans rien faire.
487                        elseif (!$this->est_verrouille($GLOBALS['visiteur_session']['id_auteur'])) {
488                                return false;
489                        }
490
491                        // si pas d'action en cours
492                        if (!$this->work) {
493                                // on prend une des actions en attente
494                                $this->work = array_shift($this->end);
495                        }
496                        $action = $this->work;
497                        $this->sauver_actions();
498                        // effectue l'action dans work
499                        $this->do_action();
500
501                        // si la liste des actions en attente est maintenant vide
502                        // on deverrouille aussitot.
503                        if (!count($this->end)) {
504                                $this->deverrouiller();
505                                $this->sauver_actions();
506                        }
507                        return $action;
508                } else {
509                        // on ne devrait normalement plus tomber sur un cas de verrouillage ici
510                        // mais sait-on jamais. Tester ne couter rien :)
511                        if ($this->est_verrouille()) {
512                                $this->deverrouiller();
513                                $this->sauver_actions();
514                        }
515                }
516                return false;
517        }
518
519        /**
520         * Effectue l'action en attente. 
521        **/
522        function do_action() {
523                if ($do = $this->work) {
524                        $todo = 'do_' . $do['todo'];
525                        lire_metas(); // avoir les metas a jour
526                        $this->log("Faire $todo avec $do[n]");
527                        $do['done'] = $this->$todo($do);
528                        $this->done[] = $do;
529                        $this->work = array();
530                        $this->sauver_actions();
531                }
532        }
533
534
535        // attraper et activer un plugin
536        function do_geton($info) {
537                if (!$this->tester_repertoire_plugins_auto()) {
538                        return false;
539                }
540                $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
541                if ($dirs = $this->get_paquet_id($i)) {
542                        $this->activer_plugin_dossier($dirs['dossier'], $i);
543                        return true;
544                }
545               
546                $this->log("GetOn : Erreur de chargement du paquet " .$info['n']);
547                return false;
548        }
549
550        // activer un plugin
551        // soit il est la... soit il est a telecharger...
552        function do_on($info) {
553                $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
554                if ($i['id_zone'] > 0) {
555                        return $this->do_geton($info);
556                }
557               
558                // a activer uniquement
559                // il faudra prendre en compte les autres _DIR_xx
560                if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))) {
561                        $dossier = rtrim($i['src_archive'], '/');
562                        $this->activer_plugin_dossier($dossier, $i, $i['constante']);
563                        return true;
564                }
565               
566                return false;
567        }
568
569
570
571        // mettre a jour un plugin
572        function do_up($info) {
573                // ecriture du nouveau
574                // suppression de l'ancien (si dans auto, et pas au meme endroit)
575                // OU suppression des anciens fichiers
576                if (!$this->tester_repertoire_plugins_auto()) {
577                        return false;
578                }
579
580                // $i est le paquet a mettre à jour (donc present)
581                // $maj est le paquet a telecharger qui est a jour (donc distant)
582               
583                $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
584
585                // on cherche la mise a jour...
586                // c'est a dire le paquet source que l'on met a jour.
587                if ($maj = sql_fetsel('pa.*',
588                        array('spip_paquets AS pa', 'spip_plugins AS pl'),
589                        array(
590                        'pl.prefixe='.sql_quote($info['p']),
591                        'pa.version='.sql_quote($info['maj']),
592                        'pa.id_depot>'.sql_quote(0)),
593                        '', 'pa.etatnum DESC', '0,1')) {
594                               
595                        if ($dirs = $this->get_paquet_id($maj)) {
596                                // Si le plugin a jour n'est pas dans le meme dossier que l'ancien...
597                                // il faut :
598                                // - activer le plugin sur son nouvel emplacement (uniquement si l'ancien est actif)...
599                                // - supprimer l'ancien (si faisable)
600                                if (($dirs['dossier'] . '/') != $i['src_archive']) {
601                                        if ($i['actif'] == 'oui') {
602                                                $this->activer_plugin_dossier($dirs['dossier'], $maj);
603                                        }
604
605                                        // l'ancien repertoire a supprimer pouvait etre auto/X
606                                        // alors que le nouveau est auto/X/Y ...
607                                        // il faut prendre en compte ce cas particulier et ne pas ecraser auto/X !
608                                        if (substr($i['src_archive'], 0, 5) == 'auto/' and (false === strpos($dirs['dossier'], $i['src_archive']))) {
609                                                if (supprimer_repertoire( constant($i['constante']) . $i['src_archive']) ) {
610                                                        sql_delete('spip_paquets', 'id_paquet=' . sql_quote($info['i']));
611                                                }
612                                        }
613                                }
614                                                       
615                                $this->ajouter_plugin_interessants_meta($dirs['dossier']);
616                                return $dirs;
617                        }
618                }
619                return false;
620        }
621
622
623        // mettre a jour et activer un plugin
624        function do_upon($info) {
625                $i = sql_fetsel('*', 'spip_paquets', 'id_paquet='.sql_quote($info['i']));
626                if ($dirs = $this->do_up($info)) {
627                        $this->activer_plugin_dossier($dirs['dossier'], $i, $i['constante']);
628                        return true;
629                }
630                return false;
631        }
632
633
634        // desactiver un plugin
635        function do_off($info) {
636                $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
637                // il faudra prendre en compte les autres _DIR_xx
638                if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))) {
639                        include_spip('inc/plugin');
640                        $dossier = ($i['constante'] == '_DIR_PLUGINS') ? $i['src_archive'] : '../' . constant($i['constante']) . $i['src_archive'];
641                        ecrire_plugin_actifs(array(rtrim($dossier,'/')), false, 'enleve');
642                        sql_updateq('spip_paquets', array('actif'=>'non', 'installe'=>'non'), 'id_paquet='.sql_quote($info['i']));
643                        $this->actualiser_plugin_interessants();
644                        // ce retour est un rien faux...
645                        // il faudrait que la fonction ecrire_plugin_actifs()
646                        // retourne au moins d'eventuels message d'erreur !
647                        return true;
648                }
649                return false;
650        }
651
652
653        // desinstaller un plugin
654        function do_stop($info) {
655                $i = sql_fetsel('*','spip_paquets','id_paquet=' . sql_quote($info['i']));
656                // il faudra prendre en compte les autres _DIR_xx
657                if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))) {
658                        include_spip('inc/plugin');
659                        $dossier = rtrim($i['src_archive'],'/');
660                        $constante = $i['constante'];
661
662                        # $constante = $this->donner_chemin_constante_plugins( $i['constante'] );
663                               
664                        $installer_plugins = charger_fonction('installer', 'plugins');
665                        $infos = $installer_plugins($dossier, 'uninstall');
666                        if ($infos AND !$infos['install_test'][0]) {
667                                include_spip('inc/plugin');
668                                ecrire_plugin_actifs(array($dossier), false, 'enleve');
669                                sql_updateq('spip_paquets', array('actif'=>'non', 'installe'=>'non'), 'id_paquet='.sql_quote($info['i']));
670                                return true;
671                        } else {
672                                // echec
673                                $this->log("Échec de la désinstallation de " . $i['src_archive']);
674                        }
675                }
676                $this->actualiser_plugin_interessants();
677                return false;
678        }
679
680
681        // effacer les fichiers d'un plugin
682        function do_kill($info) {
683                // on reverifie que c'est bien un plugin auto !
684                // il faudrait aussi faire tres attention sur un site mutualise
685                // cette option est encore plus delicate que les autres...
686                $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
687
688                if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))
689                and substr($i['src_archive'], 0, 5) == 'auto/') {
690                       
691                        $dir = constant($i['constante']) . $i['src_archive'];
692                        if (supprimer_repertoire($dir)) {
693                                $id_plugin = sql_getfetsel('id_plugin', 'spip_paquets', 'id_paquet=' . sql_quote($info['i']));
694
695                                // on supprime le paquet
696                                sql_delete('spip_paquets', 'id_paquet=' . sql_quote($info['i']));
697
698                                // ainsi que le plugin s'il n'est plus utilise
699                                $utilise = sql_allfetsel(
700                                        'pl.id_plugin',
701                                        array('spip_paquets AS pa', 'spip_plugins AS pl'),
702                                        array('pa.id_plugin = pl.id_plugin', 'pa.id_plugin=' . sql_quote($id_plugin)));
703                                if (!$utilise) {
704                                        sql_delete('spip_plugins', 'id_plugin=' . sql_quote($id_plugin));
705                                } else {
706                                        // on met a jour d'eventuels obsoletes qui ne le sont plus maintenant
707                                        // ie si on supprime une version superieure à une autre qui existe en local...
708                                        include_spip('inc/svp_depoter_local');
709                                        svp_corriger_obsolete_paquets(array($id_plugin));
710                                }
711                                       
712                                // on tente un nettoyage jusqu'a la racine de auto/
713                                // si la suppression concerne une profondeur d'au moins 2
714                                // et que les repertoires sont vides
715                                $chemins = explode('/', $i['src_archive']); // auto / prefixe / version
716                                // le premier c'est auto
717                                array_shift($chemins);
718                                // le dernier est deja fait...
719                                array_pop($chemins);
720                                // entre les deux...
721                                while (count($chemins)) {
722                                        $vide = true;
723                                        $dir = constant($i['constante']) . 'auto/' . implode('/', $chemins);
724                                        $fichiers = scandir($dir);
725                                        if ($fichiers) {
726                                                foreach ($fichiers as $f) {
727                                                        if ($f[0] != '.') {
728                                                                $vide = false;
729                                                                break;
730                                                        }
731                                                }
732                                        }
733                                        // on tente de supprimer si c'est effectivement vide.
734                                        if ($vide and !supprimer_repertoire($dir)) {
735                                                break;
736                                        }
737                                        array_pop($chemins);
738                                }
739                                return true;
740                        }
741                }
742
743                return false;
744        }
745
746       
747        // installer une librairie
748        function do_getlib($info) {
749                if (!defined('_DIR_LIB') or !_DIR_LIB) {
750                        $this->err(_T('svp:erreur_dir_dib_indefini'));
751                        $this->log("/!\ Pas de _DIR_LIB defini !");
752                        return false;
753                }
754                if (!is_writable(_DIR_LIB)) {
755                        $this->err(_T('svp:erreur_dir_dib_ecriture', array('dir' => _DIR_LIB )));
756                        $this->log("/!\ Ne peut pas écrire dans _DIR_LIB !");
757                        return false;
758                }
759
760                $this->log("Recuperer la librairie : " . $info['n'] );
761
762                // on recupere la mise a jour...
763                include_spip('action/teleporter');
764                $teleporter_composant = charger_fonction('teleporter_composant', 'action');
765                $ok = $teleporter_composant('http', $info['v'], _DIR_LIB . $info['n']);
766                if ($ok === true) {
767                        return true;
768                }
769               
770                $this->err($ok);
771                $this->log("Téléporteur en erreur : " . $ok);
772                return false;
773        }
774
775
776        // telecharger un plugin
777        function do_get($info) {
778                if (!$this->tester_repertoire_plugins_auto()) {
779                        return false;
780                }
781
782                $i = sql_fetsel('*', 'spip_paquets', 'id_paquet=' . sql_quote($info['i']));
783       
784                if ($dirs = $this->get_paquet_id($info['i'])) {
785                        $this->ajouter_plugin_interessants_meta($dirs['dossier']);
786                        return true;
787                }
788
789                return false;
790        }
791
792
793
794        // lancer l'installation d'un plugin
795        function do_install($info) {
796                $message_install = $this->installer_plugin($info);
797                return $message_install;
798        }
799
800
801        // adresse du dossier, et row SQL du plugin en question
802        function activer_plugin_dossier($dossier, $i, $constante='_DIR_PLUGINS') {
803                include_spip('inc/plugin');
804                $this->log("Demande d'activation de : " . $dossier);
805               
806                //il faut absolument que tous les fichiers de cache
807                // soient inclus avant modification, sinon un appel ulterieur risquerait
808                // de charger des fichiers deja charges par un autre !
809                // C'est surtout le ficher de fonction le probleme (options et pipelines
810                // sont normalement deja charges).
811                if (@is_readable(_CACHE_PLUGINS_OPT)) {include_once(_CACHE_PLUGINS_OPT);}
812                if (@is_readable(_CACHE_PLUGINS_FCT)) {include_once(_CACHE_PLUGINS_FCT);}
813                if (@is_readable(_CACHE_PIPELINES))   {include_once(_CACHE_PIPELINES);}
814
815                $dossier = ($constante == '_DIR_PLUGINS')? $dossier : '../'.constant($constante).$dossier;
816                include_spip('inc/plugin');
817                ecrire_plugin_actifs(array($dossier), false, 'ajoute');
818                $installe = $i['version_base'] ? 'oui' : 'non';
819                if ($installe == 'oui') {
820                        if(!$i['constante'])
821                                $i['constante'] = '_DIR_PLUGINS';
822                        // installer le plugin au prochain tour
823                        $new_action = array_merge($this->work, array(
824                                'todo'=>'install',
825                                'dossier'=>rtrim($dossier,'/'),
826                                'constante'=>$i['constante'],
827                                'v'=>$i['version'], // pas forcement la meme version qu'avant lors d'une mise a jour.
828                        ));
829                        array_unshift($this->end, $new_action);
830                        $this->log("Demande d'installation de $dossier");
831                        #$this->installer_plugin($dossier);
832                }
833
834                $this->ajouter_plugin_interessants_meta($dossier);
835                $this->actualiser_plugin_interessants();
836        }
837
838
839        // actualiser les plugins interessants
840        function actualiser_plugin_interessants() {
841                // Chaque fois que l'on valide des plugins,
842                // on memorise la liste de ces plugins comme etant "interessants",
843                // avec un score initial, qui sera decremente a chaque tour :
844                // ainsi un plugin active pourra reter visible a l'ecran,
845                // jusqu'a ce qu'il tombe dans l'oubli.
846                $plugins_interessants = @unserialize($GLOBALS['meta']['plugins_interessants']);
847                if (!is_array($plugins_interessants)) {
848                        $plugins_interessants = array();
849                }
850               
851                $dossiers = array();
852                $dossiers_old = array();
853                foreach($plugins_interessants as $p => $score) {
854                        if (--$score > 0) {
855                                $plugins_interessants[$p] = $score;
856                                $dossiers[$p.'/'] = true;
857                        } else {
858                                unset($plugins_interessants[$p]);
859                                $dossiers_old[$p.'/'] = true;
860                        }
861                }
862
863                // enlever les anciens
864                if ($dossiers_old) {
865                        // ATTENTION, il faudra prendre en compte les _DIR_xx
866                        sql_updateq('spip_paquets', array('recent'=>0), sql_in('src_archive', array_keys($dossiers_old)));
867                }
868
869                $plugs = sql_allfetsel('src_archive','spip_paquets', 'actif='.sql_quote('oui'));
870                $plugs = array_map('array_shift', $plugs);
871                foreach ($plugs as $dossier) {
872                        $dossiers[$dossier] = true;
873                        $plugins_interessants[ rtrim($dossier, '/') ] = 30; // score initial
874                }
875
876                $plugs = sql_updateq('spip_paquets', array('recent'=>1), sql_in('src_archive', array_keys($dossiers)));
877                ecrire_meta('plugins_interessants', serialize($plugins_interessants));
878        }
879
880
881
882        function ajouter_plugin_interessants_meta($dir) {
883                $plugins_interessants = @unserialize($GLOBALS['meta']['plugins_interessants']);
884                if (!is_array($plugins_interessants)) {
885                        $plugins_interessants = array();
886                }
887                $plugins_interessants[$dir] = 30;
888                ecrire_meta('plugins_interessants', serialize($plugins_interessants));
889        }
890
891
892        function installer_plugin($info){
893                // il faut info['dossier'] et info['constante'] pour installer
894                if ($plug = $info['dossier']) {
895                        $installer_plugins = charger_fonction('installer', 'plugins');
896                        $infos = $installer_plugins($plug, 'install', $info['constante']);
897                        if ($infos) {
898                                // en absence d'erreur, on met a jour la liste des plugins installes...
899                                if (!is_array($infos) OR $infos['install_test'][0]) {
900                                        $meta_plug_installes = @unserialize($GLOBALS['meta']['plugin_installes']);
901                                        if (!$meta_plug_installes) {
902                                                $meta_plug_installes=array();
903                                        }
904                                        $meta_plug_installes[] = $plug;
905                                        ecrire_meta('plugin_installes',serialize($meta_plug_installes),'non');
906                                }
907
908                                if (!is_array($infos)) {
909                                        // l'installation avait deja ete faite un autre jour
910                                        return true; 
911                                } else {
912                                        // l'installation est neuve
913                                        list($ok, $trace) = $infos['install_test'];
914                                        if ($ok) {
915                                                return true;
916                                        }
917                                        // l'installation est en erreur
918                                        $this->err(_T('svp:message_action_finale_install_fail',
919                                                array('plugin' => $info['n'], 'version'=>denormaliser_version($info['v']))) . "<br />" . $trace);
920                                }
921                        }
922                }
923                return false;
924        }
925       
926
927
928        // telecharge un paquet
929        // et supprime les fichiers obsoletes (si presents)
930        function get_paquet_id($id_or_row) {
931                // on peut passer direct le row sql...
932                if (!is_array($id_or_row)) {
933                        $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($id_or_row));
934                } else {
935                        $i = $id_or_row;
936                }
937                unset($id_or_row);
938
939                if ($i['nom_archive'] and $i['id_depot']) {
940                        $this->log("Recuperer l'archive : " . $i['nom_archive'] );
941                        if ($adresse = sql_getfetsel('url_archives', 'spip_depots', 'id_depot='.sql_quote($i['id_depot']))) {
942                                $zip = $adresse . '/' . $i['nom_archive'];
943
944                                // destination : auto/prefixe/version (sinon auto/nom_archive/version)
945                                $prefixe = sql_getfetsel('pl.prefixe',
946                                        array('spip_paquets AS pa', 'spip_plugins AS pl'),
947                                        array('pa.id_plugin = pl.id_plugin', 'pa.id_paquet=' . sql_quote($i['id_paquet'])));
948
949                                // prefixe
950                                $base =  ($prefixe ? strtolower($prefixe) : substr($i['nom_archive'], 0, -4) ); // enlever .zip ...
951
952                                // prefixe/version
953                                $dest = $base . '/v' . denormaliser_version($i['version']);
954                               
955                                // si on tombe sur un auto/X ayant des fichiers (et pas uniquement des dossiers)
956                                // ou un dossier qui ne commence pas par 'v'
957                                // c'est que auto/X n'était pas chargé avec SVP
958                                // ce qui peut arriver lorsqu'on migre de SPIP 2.1 à 3.0
959                                // dans ce cas, on supprime auto X pour mettre notre nouveau paquet.
960                                $ecraser_base = false;
961                                if (is_dir(_DIR_PLUGINS_AUTO . $base)) {
962                                        $base_files = scandir(_DIR_PLUGINS_AUTO . $base);
963                                        if (is_array($base_files)) {
964                                                $base_files = array_diff($base_files, array('.', '..'));
965                                                foreach ($base_files as $f) {
966                                                        if (($f[0] != '.' and $f[0] != 'v') // commence pas par v
967                                                        OR ($f[0] != '.' and !is_dir(_DIR_PLUGINS_AUTO . $base . '/' . $f))) { // commence par v mais pas repertoire
968                                                                $ecraser_base = true;
969                                                                break;
970                                                        }
971                                                }
972                                        }
973                                }
974                                if ($ecraser_base) {
975                                        supprimer_repertoire(_DIR_PLUGINS_AUTO . $base);
976                                }
977
978
979
980                                // on recupere la mise a jour...
981                                include_spip('action/teleporter');
982                                $teleporter_composant = charger_fonction('teleporter_composant', 'action');
983                                $ok = $teleporter_composant('http', $zip, _DIR_PLUGINS_AUTO . $dest);                           
984                                if ($ok === true) {
985                                        return array(
986                                                'dir'=> _DIR_PLUGINS_AUTO . $dest,
987                                                'dossier' => 'auto/' . $dest, // c'est depuis _DIR_PLUGINS ... pas bien en dur...
988                                        );
989                                }
990                                $this->err($ok);
991                                $this->log("Téléporteur en erreur : " . $ok);   
992                        } else {
993                                $this->log("Aucune adresse pour le dépot " . $i['id_depot'] );
994                        }
995                }
996                return false;
997        }
998
999
1000        /**
1001         * Teste que le répertoire plugins auto existe et
1002         * que l'on peut ecrire dedans !
1003         *
1004         * @return bool : C'est ok, ou pas
1005        **/
1006        function tester_repertoire_plugins_auto() {
1007                if (!defined('_DIR_PLUGINS_AUTO') or !_DIR_PLUGINS_AUTO) {
1008                        $this->err(_T('svp:erreur_dir_plugins_auto_indefini'));
1009                        $this->log("/!\ Pas de _DIR_PLUGINS_AUTO defini !");
1010                        return false;
1011                }
1012                if (!is_writable(_DIR_PLUGINS_AUTO)) {
1013                        $this->err(_T('svp:erreur_dir_plugins_auto_ecriture', array('dir'=>_DIR_PLUGINS_AUTO)));
1014                        $this->log("/!\ Ne peut pas écrire dans _DIR_PLUGINS_AUTO !");
1015                        return false;
1016                }
1017                return true;
1018        }
1019
1020        /**
1021         * Retourne le chemin relatif d'un repertoire plugins
1022         * depuis _DIR_PLUGINS
1023         *
1024         * Étrange chose que ce _DIR_PLUGINS_SUPPL...
1025        **/
1026        function donner_chemin_constante_plugins($constante) {
1027                if ($i['constante'] == '_DIR_PLUGINS_SUPPL') {
1028                        return _DIR_RACINE . constant($constante);
1029                }
1030                return constant($constante);
1031        }
1032
1033        /**
1034         * Teste si le plugin SVP (celui-ci donc) a ete desinstalle / desactive dans les actions realisees
1035         *
1036         * @return bool C'est le cas ou non.
1037        **/
1038        function tester_si_svp_desactive() {
1039                foreach ($this->done as $d) {
1040                        if ($d['p'] == 'SVP'
1041                        AND $d['done'] == true
1042                        AND in_array($d['todo'], array('off', 'stop'))) {
1043                                return true;
1044                        }
1045                }
1046                return false;
1047        }
1048       
1049}
1050
1051
1052/**
1053 * Fonction pour aider le traitement des actions
1054 * dans un formulaire CVT
1055 *
1056 * @param array $actions la liste des actions a faire (id_paquet => action)
1057 * @param array $retour le tableau de retour du CVT dans la partie traiter
1058 * @return bool Action ok.
1059**/
1060function svp_actionner_traiter_actions_demandees($actions, &$retour) {
1061                $actionneur = new Actionneur();
1062                $actionneur->ajouter_actions($actions);
1063                $actionneur->verrouiller();
1064                $actionneur->sauver_actions();
1065
1066                $retour['redirect'] = generer_url_action('actionner', 'redirect='. generer_url_ecrire('admin_plugin'));
1067                set_request('_todo', '');
1068                $retour['message_ok'] = _T("svp:action_patienter");
1069}
1070?>
Note: See TracBrowser for help on using the repository browser.