9c4be415dcaa545fcc1452aba4c3c2bbc0efb87b
[lhc/web/www.git] / www / ecrire / plugins / installer.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Gestion de l'installation des plugins
15 *
16 * @package SPIP\Core\Plugins
17 **/
18
19
20 if (!defined('_ECRIRE_INC_VERSION')) {
21 return;
22 }
23
24 /**
25 * Installe ou retire un plugin
26 *
27 * Permet d'installer ou retirer un plugin en incluant les fichiers
28 * associés et en lançant les fonctions spécifiques.
29 *
30 * 1. d'abord sur l'argument `test`,
31 * 2. ensuite sur l'action demandée si le test repond `false`
32 * 3. enfin sur l'argument `test` à nouveau.
33 *
34 * L'index `install_test` du tableau résultat est un tableau formé :
35 *
36 * - du résultat 3
37 * - des echo de l'étape 2
38 *
39 * @note
40 * La fonction quitte (retourne false) si le plugin
41 * n'a pas de version d'installation définie
42 * (information `version_base` dans le paquet.xml)
43 *
44 * @param string $plug
45 * Nom du plugin
46 * @param string $action
47 * Nom de l'action (install|uninstall)
48 * @param string $dir_type
49 * Répertoire du plugin
50 * @return array|bool
51 * - False si le plugin n'a pas d'installation,
52 * - true si déjà installé,
53 * - le tableau de get_infos sinon
54 */
55 function plugins_installer_dist($plug, $action, $dir_type = '_DIR_PLUGINS') {
56 $get_infos = charger_fonction('get_infos', 'plugins');
57 $infos = $get_infos($plug, false, constant($dir_type));
58 if (!isset($infos['install']) or !$infos['install']) {
59 return false;
60 }
61 // passer en chemin absolu si possible, c'est plus efficace
62 $dir = str_replace('_DIR_', '_ROOT_', $dir_type);
63 if (!defined($dir)) {
64 $dir = $dir_type;
65 }
66 $dir = constant($dir);
67 foreach ($infos['install'] as $file) {
68 $file = $dir . $plug . "/" . trim($file);
69 if (file_exists($file)) {
70 include_once($file);
71 }
72 }
73 $version = isset($infos['schema']) ? $infos['schema'] : '';
74 $arg = $infos;
75 $f = $infos['prefix'] . "_install";
76 if (!function_exists($f)) {
77 $f = isset($infos['schema']) ? 'spip_plugin_install' : '';
78 } else {
79 $arg = $infos['prefix'];
80 } // stupide: info deja dans le nom
81
82 if (!$f) {
83 // installation sans operation particuliere
84 $infos['install_test'] = array(true, '');
85
86 return $infos;
87 }
88 $test = $f('test', $arg, $version);
89 if ($action == 'uninstall') {
90 $test = !$test;
91 }
92 // Si deja fait, on ne dit rien
93 if ($test) {
94 return true;
95 }
96 // Si install et que l'on a la meta d'installation, c'est un upgrade
97 if ($action == 'install' && !is_null(lire_meta($infos['prefix'] . '_base_version'))) {
98 $infos['upgrade'] = true;
99 }
100
101 // executer l'installation ou l'inverse
102 // et renvoyer la trace (mais il faudrait passer en AJAX plutot)
103 ob_start();
104 $f($action, $arg, $version);
105 $aff = ob_get_contents();
106 ob_end_clean();
107 // vider le cache des descriptions de tables a chaque (de)installation
108 $trouver_table = charger_fonction('trouver_table', 'base');
109 $trouver_table('');
110 $infos['install_test'] = array($f('test', $arg, $version), $aff);
111
112 return $infos;
113 }
114
115 // Fonction par defaut pour install/desinstall
116
117 // http://code.spip.net/@spip_plugin_install
118 function spip_plugin_install($action, $infos, $version_cible) {
119 $prefix = $infos['prefix'];
120 if (isset($infos['meta']) and (($table = $infos['meta']) !== 'meta')) {
121 $nom_meta = "base_version";
122 } else {
123 $nom_meta = $prefix . "_base_version";
124 $table = 'meta';
125 }
126 switch ($action) {
127 case 'test':
128 return (isset($GLOBALS[$table])
129 and isset($GLOBALS[$table][$nom_meta])
130 and spip_version_compare($GLOBALS[$table][$nom_meta], $version_cible, '>='));
131 break;
132 case 'install':
133 if (function_exists($upgrade = $prefix . "_upgrade")) {
134 $upgrade($nom_meta, $version_cible, $table);
135 }
136 break;
137 case 'uninstall':
138 if (function_exists($vider_tables = $prefix . "_vider_tables")) {
139 $vider_tables($nom_meta, $table);
140 }
141 break;
142 }
143 }
144
145
146 /**
147 * Compare 2 numéros de version entre elles.
148 *
149 * Cette fonction est identique (arguments et retours) a la fonction PHP
150 * version_compare() qu'elle appelle. Cependant, cette fonction reformate
151 * les numeros de versions pour ameliorer certains usages dans SPIP ou bugs
152 * dans PHP. On permet ainsi de comparer 3.0.4 à 3.0.* par exemple.
153 *
154 * @param string $v1
155 * Numero de version servant de base a la comparaison.
156 * Ce numero ne peut pas comporter d'etoile.
157 * @param string $v2
158 * Numero de version a comparer.
159 * Il peut posseder des etoiles tel que 3.0.*
160 * @param string $op
161 * Un operateur eventuel (<, >, <=, >=, =, == ...)
162 * @return int|bool
163 * Sans operateur : int. -1 pour inferieur, 0 pour egal, 1 pour superieur
164 * Avec operateur : bool.
165 **/
166 function spip_version_compare($v1, $v2, $op = null) {
167 $v1 = strtolower(preg_replace(',([0-9])[\s-.]?(dev|alpha|a|beta|b|rc|pl|p),i', '\\1.\\2', $v1));
168 $v2 = strtolower(preg_replace(',([0-9])[\s-.]?(dev|alpha|a|beta|b|rc|pl|p),i', '\\1.\\2', $v2));
169 $v1 = str_replace('rc', 'RC', $v1); // certaines versions de PHP ne comprennent RC qu'en majuscule
170 $v2 = str_replace('rc', 'RC', $v2); // certaines versions de PHP ne comprennent RC qu'en majuscule
171
172 $v1 = explode('.', $v1);
173 $v2 = explode('.', $v2);
174 // $v1 est toujours une version, donc sans etoile
175 while (count($v1) < count($v2)) {
176 $v1[] = '0';
177 }
178
179 // $v2 peut etre une borne, donc accepte l'etoile
180 $etoile = false;
181 foreach ($v1 as $k => $v) {
182 if (!isset($v2[$k])) {
183 $v2[] = ($etoile and (is_numeric($v) or $v == 'pl' or $v == 'p')) ? $v : '0';
184 } else {
185 if ($v2[$k] == '*') {
186 $etoile = true;
187 $v2[$k] = $v;
188 }
189 }
190 }
191 $v1 = implode('.', $v1);
192 $v2 = implode('.', $v2);
193
194 return $op ? version_compare($v1, $v2, $op) : version_compare($v1, $v2);
195 }
196
197
198 /**
199 * Retourne un tableau des plugins activés sur le site
200 *
201 * Retourne la meta `plugin` désérialisée.
202 * Chaque élément du tableau est lui-même un tableau contenant
203 * les détails du plugin en question : répertoire et version.
204 *
205 * @note
206 * Si le contenu de la meta n’est pas un tableau, cette fonction transforme
207 * l’ancien format en tableau sérialisé pour être conforme au nouveau fonctionnement (SPIP >= 1.9.2)
208 *
209 * @return array Tableau des plugins actifs
210 **/
211 function liste_plugin_actifs() {
212 $liste = isset($GLOBALS['meta']['plugin']) ? $GLOBALS['meta']['plugin'] : '';
213 if (!$liste) {
214 return array();
215 }
216 if (!is_array($liste = unserialize($liste))) {
217 // compatibilite pre 1.9.2, mettre a jour la meta
218 spip_log("MAJ meta plugin vieille version : $liste", "plugin");
219 $new = true;
220 list(, $liste) = liste_plugin_valides(explode(",", $liste));
221 } else {
222 $new = false;
223 // compat au moment d'une migration depuis version anterieure
224 // si pas de dir_type, alors c'est _DIR_PLUGINS
225 foreach ($liste as $prefix => $infos) {
226 if (!isset($infos['dir_type'])) {
227 $liste[$prefix]['dir_type'] = "_DIR_PLUGINS";
228 $new = true;
229 }
230 }
231 }
232 if ($new) {
233 ecrire_meta('plugin', serialize($liste));
234 }
235
236 return $liste;
237 }