[SPIP] ~v3.0.20-->v3.0.25
[lhc/web/clavette_www.git] / www / ecrire / inc / plugin.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
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 if (!defined('_ECRIRE_INC_VERSION')) return;
14
15 // l'adresse du repertoire de telechargement et de decompactage des plugins
16 define('_DIR_PLUGINS_AUTO', _DIR_PLUGINS.'auto/');
17
18 #include_spip('inc/texte'); // ????? Appelle public/parametrer trop tot avant la reconstruction du chemin des plugins.
19 include_spip('plugins/installer');
20
21 // lecture des sous repertoire plugin existants
22 // $dir_plugins pour forcer un repertoire (ex: _DIR_PLUGINS_DIST)
23 // _DIR_PLUGINS_SUPPL pour aller en chercher ailleurs
24 // (chemins relatifs a la racine du site, separes par des ":")
25 // http://doc.spip.org/@liste_plugin_files
26 function liste_plugin_files($dir_plugins = null){
27 static $plugin_files=array();
28 if (is_null($dir_plugins))
29 $dir_plugins = _DIR_PLUGINS;
30 if (!isset($plugin_files[$dir_plugins])
31 OR count($plugin_files[$dir_plugins]) == 0){
32 $plugin_files[$dir_plugins] = array();
33 foreach (fast_find_plugin_dirs($dir_plugins) as $plugin) {
34 $plugin_files[$dir_plugins][] = substr($plugin,strlen($dir_plugins));
35 }
36
37 sort($plugin_files[$dir_plugins]);
38 // et on lit le XML de tous les plugins pour le mettre en cache
39 // et en profiter pour nettoyer ceux qui n'existent plus du cache
40 $get_infos = charger_fonction('get_infos','plugins');
41 $get_infos($plugin_files[$dir_plugins],false,$dir_plugins,true);
42 }
43 return $plugin_files[$dir_plugins];
44 }
45
46 function fast_find_plugin_dirs($dir, $max_prof=100) {
47 $fichiers = array();
48 // revenir au repertoire racine si on a recu dossier/truc
49 // pour regarder dossier/truc/ ne pas oublier le / final
50 $dir = preg_replace(',/[^/]*$,', '', $dir);
51 if ($dir == '') $dir = '.';
52
53 if (!is_dir($dir))
54 return $fichiers;
55 if (is_plugin_dir($dir,'')) {
56 $fichiers[] = $dir;
57 return $fichiers;
58 }
59 if ($max_prof<=0)
60 return $fichiers;
61
62 $subdirs = array();
63 if (@is_dir($dir) AND is_readable($dir) AND $d = @opendir($dir)) {
64 while (($f = readdir($d)) !== false) {
65 if ($f[0] != '.' # ignorer . .. .svn etc
66 AND $f != 'CVS'
67 AND is_dir($f = "$dir/$f"))
68 $subdirs[] = $f;
69 }
70 closedir($d);
71 }
72
73 foreach($subdirs as $d){
74 $fichiers = array_merge($fichiers,fast_find_plugin_dirs("$d/",$max_prof-1));
75 }
76 return $fichiers;
77 }
78
79 function is_plugin_dir($dir,$dir_plugins = null){
80 if (is_array($dir)){
81 foreach($dir as $k=>$d){
82 if (!is_plugin_dir($d,$dir_plugins))
83 unset($dir[$k]);
84 }
85 return $dir;
86 }
87 if (is_null($dir_plugins))
88 $dir_plugins = _DIR_PLUGINS;
89 $search = array("$dir_plugins$dir/plugin.xml","$dir_plugins$dir/paquet.xml");
90
91 foreach($search as $s){
92 if (file_exists($s)){
93 return $dir;
94 }
95 }
96 return '';
97 }
98
99 // Regexp d'extraction des informations d'un intervalle de compatibilité
100 define('_EXTRAIRE_INTERVALLE', ',^[\[\(\]]([0-9.a-zRC\s\-]*)[;]([0-9.a-zRC\s\-\*]*)[\]\)\[]$,');
101
102 /**
103 * Teste si le numéro de version d'un plugin est dans un intervalle donné.
104 *
105 * Cette fonction peut être volontairement trompée (phase de développement) :
106 * voir commentaire infra sur l'utilisation de la constante _DEV_PLUGINS
107 *
108 * @param string $intervalle
109 * Un intervalle entre 2 versions. ex: [2.0.0-dev;2.1.*]
110 * @param string $version
111 * Un numéro de version. ex: 3.1.99]
112 * @param string $avec_quoi
113 * Ce avec quoi est testée la compatibilité. par défaut ('')
114 * avec un plugin (cas des 'necessite'), parfois ('spip')
115 * avec SPIP.
116 * @return bool
117 * True si dans l'intervalle, false sinon.
118 **/
119 function plugin_version_compatible($intervalle, $version, $avec_quoi = '') {
120
121 if (!strlen($intervalle)) return true;
122 if (!preg_match(_EXTRAIRE_INTERVALLE,$intervalle,$regs)) return false;
123 // Extraction des bornes et traitement de * pour la borne sup :
124 // -- on autorise uniquement les ecritures 3.0.*, 3.*
125 $minimum = $regs[1];
126 $maximum = $regs[2];
127
128 // si une borne de compatibilité supérieure a été définie (dans
129 // mes_options.php, sous la forme : define('_DEV_PLUGINS', '3.1.99');
130 // on l'utilise (phase de dev, de test...) mais *que* en cas de comparaison
131 // avec la version de SPIP (ne nuit donc pas aux tests de necessite
132 // entre plugins)
133 if (defined('_DEV_PLUGINS') && $avec_quoi == 'spip') {
134 $maximum = _DEV_PLUGINS.']';
135 }
136
137 $minimum_inc = $intervalle{0}=="[";
138 $maximum_inc = substr($intervalle,-1)=="]";
139
140 if (strlen($minimum)){
141 if ($minimum_inc AND spip_version_compare($version,$minimum,'<')) return false;
142 if (!$minimum_inc AND spip_version_compare($version,$minimum,'<=')) return false;
143 }
144 if (strlen($maximum)){
145 if ($maximum_inc AND spip_version_compare($version,$maximum,'>')) return false;
146 if (!$maximum_inc AND spip_version_compare($version,$maximum,'>=')) return false;
147 }
148 return true;
149 }
150
151
152 /**
153 * Construire la liste des infos strictement necessaires aux plugins a activer
154 * afin de les memoriser dans une meta pas trop grosse
155 * http://code.spip.net/@liste_plugin_valides
156 *
157 * @param array $liste_plug
158 * @param bool $force
159 * @return array
160 */
161 function liste_plugin_valides($liste_plug, $force = false){
162 $liste_ext = liste_plugin_files(_DIR_PLUGINS_DIST);
163 $get_infos = charger_fonction('get_infos', 'plugins');
164 $infos = array(
165 // lister les extensions qui sont automatiquement actives
166 '_DIR_PLUGINS_DIST' => $get_infos($liste_ext, $force, _DIR_PLUGINS_DIST),
167 '_DIR_PLUGINS' => $get_infos($liste_plug, $force, _DIR_PLUGINS)
168 );
169
170 // creer une premiere liste non ordonnee mais qui ne retient
171 // que les plugins valides, et dans leur derniere version en cas de doublon
172 $infos['_DIR_RESTREINT'][''] = $get_infos('./', $force, _DIR_RESTREINT);
173 $infos['_DIR_RESTREINT']['SPIP']['version'] = $GLOBALS['spip_version_branche'];
174 $infos['_DIR_RESTREINT']['SPIP']['chemin'] = array();
175 $liste_non_classee = array('SPIP' => array(
176 'nom' => 'SPIP',
177 'etat' => 'stable',
178 'version' => $GLOBALS['spip_version_branche'],
179 'dir_type' => '_DIR_RESTREINT',
180 'dir' => '',
181 )
182 );
183
184 foreach ($liste_ext as $plug){
185 if (isset($infos['_DIR_PLUGINS_DIST'][$plug]))
186 plugin_valide_resume($liste_non_classee, $plug, $infos, '_DIR_PLUGINS_DIST');
187 }
188 foreach ($liste_plug as $plug){
189 if (isset($infos['_DIR_PLUGINS'][$plug]))
190 plugin_valide_resume($liste_non_classee, $plug, $infos, '_DIR_PLUGINS');
191 }
192
193 if (defined('_DIR_PLUGINS_SUPPL') and _DIR_PLUGINS_SUPPL){
194 $infos['_DIR_PLUGINS_SUPPL'] = $get_infos($liste_plug, false, _DIR_PLUGINS_SUPPL);
195 foreach ($liste_plug as $plug){
196 if (isset($infos['_DIR_PLUGINS_SUPPL'][$plug]))
197 plugin_valide_resume($liste_non_classee, $plug, $infos, '_DIR_PLUGINS_SUPPL');
198 }
199 }
200
201 plugin_fixer_procure($liste_non_classee, $infos);
202
203 return array($infos, $liste_non_classee);
204 }
205
206 /**
207 * Ne retenir un plugin que s'il est valide
208 * et dans leur plus recente version compatible
209 * avec la version presente de SPIP
210 *
211 * @param array $liste
212 * @param string $plug
213 * @param array $infos
214 * @param string $dir_type
215 */
216 function plugin_valide_resume(&$liste, $plug, $infos, $dir_type){
217 $i = $infos[$dir_type][$plug];
218 if (isset($i['erreur']) AND $i['erreur'])
219 return;
220 if (!plugin_version_compatible($i['compatibilite'], $GLOBALS['spip_version_branche'], 'spip'))
221 return;
222 $p = strtoupper($i['prefix']);
223 if (!isset($liste[$p])
224 OR spip_version_compare($i['version'], $liste[$p]['version'], '>')
225 ){
226 $liste[$p] = array(
227 'nom' => $i['nom'],
228 'etat' => $i['etat'],
229 'version' => $i['version'],
230 'dir' => $plug,
231 'dir_type' => $dir_type
232 );
233 }
234 }
235
236 /**
237 * Completer la liste des plugins avec les eventuels procure
238 *
239 * les <procure> sont consideres comme des plugins proposes,
240 * mais surchargeables (on peut activer un plugin qui procure ca pour l'ameliorer,
241 * donc avec le meme prefixe, qui sera pris en compte si il a une version plus grande)
242 *
243 * @param array $liste
244 * @param array $infos
245 */
246 function plugin_fixer_procure(&$liste, &$infos){
247 foreach($liste as $p=>$resume){
248 $i = $infos[$resume['dir_type']][$resume['dir']];
249 if (isset($i['procure']) AND $i['procure']){
250 foreach($i['procure'] as $procure){
251 $p = strtoupper($procure['nom']);
252 $dir = $resume['dir'];
253 if ($dir) $dir .= "/";
254 $dir .= "procure:".$procure['nom'];
255
256 $procure['etat'] = '?';
257 $procure['dir_type'] = $resume['dir_type'];
258 $procure['dir'] = $dir;
259
260 // si ce plugin n'est pas deja procure, ou dans une version plus ancienne
261 // on ajoute cette version a la liste
262 if (!isset($liste[$p])
263 OR spip_version_compare($procure['version'], $liste[$p]['version'], '>')
264 ){
265 $liste[$p] = $procure;
266
267 // on fournit une information minimale pour ne pas perturber la compilation
268 $infos[$resume['dir_type']][$dir] = array(
269 'prefix' => $procure['nom'],
270 'nom' => $procure['nom'],
271 'etat' => $procure['etat'],
272 'version' => $procure['version'],
273 'chemin' => array(),
274 'necessite' => array(),
275 'utilise' => array(),
276 'lib' => array(),
277 'menu' => array(),
278 'onglet' => array(),
279 'procure' => array(),
280 );
281 }
282 }
283 }
284 }
285 }
286
287 /**
288 * extrait les chemins d'une liste de plugin
289 * selectionne au passage ceux qui sont dans $dir_plugins uniquement
290 * si valeur non vide
291 *
292 * @param array $liste
293 * @param string $dir_plugins
294 * @return array
295 */
296 function liste_chemin_plugin($liste, $dir_plugins=_DIR_PLUGINS){
297 foreach ($liste as $prefix=>$infos) {
298 if (!$dir_plugins
299 OR (
300 defined($infos['dir_type'])
301 AND constant($infos['dir_type'])==$dir_plugins))
302 $liste[$prefix] = $infos['dir'];
303 else
304 unset($liste[$prefix]);
305 }
306 return $liste;
307 }
308
309 /**
310 * Liste les chemins vers les plugins actifs du dossier fourni en argument
311 * a partir d'une liste d'elelements construits par plugin_valide_resume
312 *
313 * @return array
314 */
315 // http://doc.spip.org/@liste_chemin_plugin_actifs
316 function liste_chemin_plugin_actifs($dir_plugins=_DIR_PLUGINS){
317 include_spip('plugins/installer');
318 return liste_chemin_plugin(liste_plugin_actifs(), $dir_plugins);
319 }
320
321 // Pour tester utilise, il faut connaitre tous les plugins
322 // qui seront forcement pas la a la fin,
323 // car absent de la liste des plugins actifs.
324 // Il faut donc construire une liste ordonnee
325 // Cette fonction detecte des dependances circulaires,
326 // avec un doute sur un "utilise" qu'on peut ignorer.
327 // Mais ne pas inserer silencieusement et risquer un bug sournois latent
328
329 function plugin_trier($infos, $liste_non_classee)
330 {
331 $toute_la_liste = $liste_non_classee;
332 $liste = $ordre = array();
333 $count = 0;
334 while ($c=count($liste_non_classee) AND $c!=$count){ // tant qu'il reste des plugins a classer, et qu'on ne stagne pas
335 #echo "tour::";var_dump($liste_non_classee);
336 $count = $c;
337 foreach($liste_non_classee as $p=>$resume) {
338 $plug = $resume['dir'];
339 $dir_type = $resume['dir_type'];
340 $info1 = $infos[$dir_type][$plug];
341 // si des plugins sont necessaires,
342 // on ne peut inserer qu'apres eux
343 foreach($info1['necessite'] as $need){
344 $nom = strtoupper($need['nom']);
345 $compat = isset($need['compatibilite']) ? $need['compatibilite'] : '';
346 if (!isset($liste[$nom]) OR !plugin_version_compatible($compat,$liste[$nom]['version'])) {
347 $info1 = false;
348 break;
349 }
350 }
351 if (!$info1) continue;
352 // idem si des plugins sont utiles,
353 // sauf si ils sont de toute facon absents de la liste
354 foreach($info1['utilise'] as $need){
355 $nom = strtoupper($need['nom']);
356 $compat = isset($need['compatibilite']) ? $need['compatibilite'] : '';
357 if (isset($toute_la_liste[$nom])) {
358 if (!isset($liste[$nom]) OR
359 !plugin_version_compatible($compat, $liste[$nom]['version'])) {
360 $info1 = false;
361 break;
362 }
363 }
364 }
365 if ($info1) {
366 $ordre[$p] = $info1;
367 $liste[$p] = $liste_non_classee[$p];
368 unset($liste_non_classee[$p]);
369 }
370 }
371 }
372 return array($liste, $ordre, $liste_non_classee);
373 }
374
375 // Collecte les erreurs dans la meta
376
377 function plugins_erreurs($liste_non_classee, $liste, $infos, $msg=array())
378 {
379 static $erreurs = array();
380 foreach($liste_non_classee as $p=>$resume){
381 $dir_type = $resume['dir_type'];
382 $plug = $resume['dir'];
383 $k = $infos[$dir_type][$plug];
384 $plug = constant($dir_type) . $plug;
385 if (!isset($msg[$p])) {
386 if (!$msg[$p] = plugin_necessite($k['necessite'], $liste))
387 $msg[$p] = plugin_necessite($k['utilise'], $liste);
388 } else {
389 foreach($msg[$p] as $c => $l)
390 $msg[$p][$c] = plugin_controler_lib($l['nom'], $l['lien']);
391 }
392 $erreurs[$plug] = $msg[$p];
393 }
394 ecrire_meta('plugin_erreur_activation', serialize($erreurs));
395 }
396
397 function plugin_donne_erreurs($raw=false, $raz=true) {
398 if (!isset($GLOBALS['meta']['plugin_erreur_activation'])) return $raw?array():'';
399 $list = @unserialize($GLOBALS['meta']['plugin_erreur_activation']);
400 // Compat ancienne version
401 if (!$list)
402 $list = $raw?array():$GLOBALS['meta']['plugin_erreur_activation'];
403 elseif(!$raw) {
404 foreach($list as $plug => $msg)
405 $list[$plug] = "<li>" . _T('plugin_impossible_activer', array('plugin' => $plug))
406 . "<ul><li>" . implode("</li><li>", $msg) . "</li></ul></li>";
407 $list ="<ul>" . join("\n", $list) . "</ul>";
408 }
409 if ($raz)
410 effacer_meta('plugin_erreur_activation');
411 return $list;
412 }
413
414 /**
415 * Teste des dependances
416 * Et verifie que chaque dependance est presente
417 * dans la liste de plugins donnee
418 *
419 * @param array $n
420 * Tableau de dependances dont on souhaite verifier leur presence
421 * @param array $liste
422 * Tableau des plugins presents
423 * @return array
424 * Tableau des messages d'erreurs recus. Il sera vide si tout va bien.
425 *
426 **/
427 function plugin_necessite($n, $liste) {
428 $msg = array();
429 foreach($n as $need){
430 $id = strtoupper($need['nom']);
431 if ($r = plugin_controler_necessite($liste, $id, $need['compatibilite'])) {
432 $msg[] = $r;
433 }
434 }
435 return $msg;
436 }
437
438 /**
439 * Verifie qu'une dependance (plugin) est bien presente.
440 *
441 * @param $liste
442 * Liste de description des plugins
443 * @param $nom
444 * Le plugin donc on cherche la presence
445 * @param $version
446 * L'éventuelle intervalle de compatibilité de la dependance. ex: [1.1.0;]
447 * @return string.
448 * Vide si ok,
449 * Message d'erreur lorsque la dependance est absente.
450 **/
451 function plugin_controler_necessite($liste, $nom, $version)
452 {
453 if (isset($liste[$nom]) AND plugin_version_compatible($version,$liste[$nom]['version'])) {
454 return '';
455 }
456 // retrouver le minimum
457 if (preg_match(_EXTRAIRE_INTERVALLE, $version, $regs)) {
458 $minimum = $regs[1];
459 if ($minimum) {
460 return _T('plugin_necessite_plugin', array(
461 'plugin' => $nom,
462 'version' => $minimum));
463 }
464 }
465 return _T('plugin_necessite_plugin_sans_version', array('plugin' => $nom));
466 }
467
468 function plugin_controler_lib($lib, $url)
469 {
470 /* Feature sortie du core, voir STP
471 * if ($url) {
472 include_spip('inc/charger_plugin');
473 $url = '<br />' . bouton_telechargement_plugin($url, 'lib');
474 }*/
475 return _T('plugin_necessite_lib', array('lib'=>$lib)) . " <a href='$url'>$url</a>";
476 }
477
478 // Pour compatibilite et lisibilite du code
479 function actualise_plugins_actifs($pipe_recherche = false){
480 return ecrire_plugin_actifs('', $pipe_recherche, 'force');
481 }
482
483 // mise a jour du meta en fonction de l'etat du repertoire
484 // Les ecrire_meta() doivent en principe aussi initialiser la valeur a vide
485 // si elle n'existe pas
486 // risque de pb en php5 a cause du typage ou de null (verifier dans la doc php)
487 // @return true/false si il y a du nouveau
488 // http://doc.spip.org/@ecrire_plugin_actifs
489 function ecrire_plugin_actifs($plugin,$pipe_recherche=false,$operation='raz') {
490
491 // creer le repertoire cache/ si necessaire ! (installation notamment)
492 sous_repertoire(_DIR_CACHE, '', false,true);
493
494 if (!spip_connect()) return false;
495 if ($operation!='raz') {
496 $plugin_valides = liste_chemin_plugin_actifs();
497 $plugin_valides = is_plugin_dir($plugin_valides);
498 if(defined('_DIR_PLUGINS_SUPPL') && _DIR_PLUGINS_SUPPL){
499 $plugin_valides_supp = liste_chemin_plugin_actifs(_DIR_PLUGINS_SUPPL);
500 $plugin_valides_supp = is_plugin_dir($plugin_valides_supp,_DIR_PLUGINS_SUPPL);
501 $plugin_valides = array_merge($plugin_valides,$plugin_valides_supp);
502 }
503 // si des plugins sont en attentes (coches mais impossible a activer)
504 // on les reinjecte ici
505 if (isset($GLOBALS['meta']['plugin_attente'])
506 AND $a = unserialize($GLOBALS['meta']['plugin_attente']))
507 $plugin_valides = $plugin_valides + liste_chemin_plugin($a);
508
509 if ($operation=='ajoute')
510 $plugin = array_merge($plugin_valides,$plugin);
511 elseif ($operation=='enleve')
512 $plugin = array_diff($plugin_valides,$plugin);
513 else $plugin = $plugin_valides;
514 }
515 $actifs_avant = $GLOBALS['meta']['plugin'];
516
517 // si une fonction de gestion de dependances existe, l'appeler ici
518 if ($ajouter_dependances = charger_fonction("ajouter_dependances","plugins",true)){
519 $plugin = $ajouter_dependances($plugin);
520 }
521
522 // recharger le xml des plugins a activer
523 // on forcer le reload ici, meme si le fichier xml n'a pas change
524 // pour ne pas rater l'ajout ou la suppression d'un fichier fonctions/options/administrations
525 // pourra etre evite quand on ne supportera plus les plugin.xml
526 // en deplacant la detection de ces fichiers dans la compilation ci dessous
527 list($infos,$liste) = liste_plugin_valides($plugin,true);
528 // trouver l'ordre d'activation
529 list($plugin_valides,$ordre,$reste) = plugin_trier($infos, $liste);
530 if ($reste) plugins_erreurs($reste, $liste, $infos);
531 // Ignorer les plugins necessitant une lib absente
532 // et preparer la meta d'entete Http
533 $err = $msg = $header = array();
534 foreach($plugin_valides as $p => $resume) {
535 $header[]= $p.($resume['version']?"(".$resume['version'].")":"");
536 if ($resume['dir']){
537 foreach($infos[$resume['dir_type']][$resume['dir']]['lib'] as $l) {
538 if (!find_in_path($l['nom'], 'lib/')) {
539 $err[$p] = $resume;
540 $msg[$p][] = $l;
541 unset($plugin_valides[$p]);
542 }
543 }
544 }
545 }
546 if ($err) plugins_erreurs($err, '', $infos, $msg);
547
548 if (isset($GLOBALS['meta']['message_crash_plugins']))
549 effacer_meta('message_crash_plugins');
550 ecrire_meta('plugin',serialize($plugin_valides));
551 $liste = array_diff_key($liste,$plugin_valides);
552 ecrire_meta('plugin_attente',serialize($liste));
553 $header = strtolower(implode(",",$header));
554 ecrire_meta('plugin_header',substr($header,0,900));
555 if (!isset($GLOBALS['spip_header_silencieux']) OR !$GLOBALS['spip_header_silencieux'])
556 ecrire_fichier(_DIR_VAR."config.txt", (defined('_HEADER_COMPOSED_BY') ? _HEADER_COMPOSED_BY:"Composed-By: SPIP") . ' '. $GLOBALS['spip_version_affichee'] . " @ www.spip.net + " . $header);
557 else
558 @unlink(_DIR_VAR."config.txt");
559 // generer charger_plugins_chemin.php
560 plugins_precompile_chemin($plugin_valides, $ordre);
561 // generer les fichiers
562 // charger_plugins_options.php
563 // charger_plugins_fonctions.php
564 // et retourner les fichiers a verifier
565 plugins_precompile_xxxtions($plugin_valides, $ordre);
566 // mise a jour de la matrice des pipelines
567 pipeline_matrice_precompile($plugin_valides, $ordre, $pipe_recherche);
568 // generer le fichier _CACHE_PIPELINE
569 pipeline_precompile();
570
571 // attendre eventuellement l'invalidation du cache opcode
572 spip_attend_invalidation_opcode_cache();
573
574 if (spip_connect()) {
575 // lancer et initialiser les nouveaux crons !
576 include_spip('inc/genie');
577 genie_queue_watch_dist();
578 }
579
580 return ($GLOBALS['meta']['plugin'] != $actifs_avant);
581 }
582
583 function plugins_precompile_chemin($plugin_valides, $ordre)
584 {
585 $chemins = array();
586 $contenu = "";
587 foreach($ordre as $p => $info){
588 // $ordre peur contenir des plugins en attente et non valides pour ce hit
589 if (isset($plugin_valides[$p])){
590 $dir_type = $plugin_valides[$p]['dir_type'];
591 $plug = $plugin_valides[$p]['dir'];
592 // definir le plugin, donc le path avant l'include du fichier options
593 // permet de faire des include_spip pour attraper un inc_ du plugin
594
595 $dir = $dir_type.".'" . $plug ."/'";
596
597 $prefix = strtoupper(preg_replace(',\W,','_',$info['prefix']));
598 if ($prefix!=="SPIP"){
599 $contenu .= "define('_DIR_PLUGIN_$prefix',$dir);\n";
600 foreach($info['chemin'] as $chemin){
601 if (!isset($chemin['version']) OR plugin_version_compatible($chemin['version'],$GLOBALS['spip_version_branche'],'spip')){
602 $dir = $chemin['path'];
603 if (strlen($dir) AND $dir{0}=="/") $dir = substr($dir,1);
604 if (strlen($dir) AND $dir=="./") $dir = '';
605 if (strlen($dir)) $dir = rtrim($dir,'/').'/';
606 if (!isset($chemin['type']) OR $chemin['type']=='public')
607 $chemins['public'][]="_DIR_PLUGIN_$prefix".(strlen($dir)?".'$dir'":"");
608 if (!isset($chemin['type']) OR $chemin['type']=='prive')
609 $chemins['prive'][]="_DIR_PLUGIN_$prefix".(strlen($dir)?".'$dir'":"");
610 }
611 }
612 }
613 }
614 }
615 if (count($chemins)){
616 $contenu .= "if (_DIR_RESTREINT) _chemin(implode(':',array(".implode(',',array_reverse($chemins['public'])).")));\n"
617 . "else _chemin(implode(':',array(".implode(',',array_reverse($chemins['prive'])).")));\n";
618 }
619
620 ecrire_fichier_php(_CACHE_PLUGINS_PATH, $contenu);
621 }
622
623 function plugins_precompile_xxxtions($plugin_valides, $ordre)
624 {
625 $contenu = array('options' => '', 'fonctions' =>'');
626 $boutons = array();
627 $onglets = array();
628 $sign = "";
629
630 foreach($ordre as $p => $info){
631 // $ordre peur contenir des plugins en attente et non valides pour ce hit
632 if (isset($plugin_valides[$p])){
633 $dir_type = $plugin_valides[$p]['dir_type'];
634 $plug = $plugin_valides[$p]['dir'];
635 $dir = constant($dir_type);
636 $root_dir_type = str_replace('_DIR_','_ROOT_',$dir_type);
637 if ($info['menu'])
638 $boutons = array_merge($boutons,$info['menu']);
639 if ($info['onglet'])
640 $onglets = array_merge($onglets,$info['onglet']);
641 foreach($contenu as $charge => $v){
642 // si pas declare/detecte a la lecture du paquet.xml,
643 // detecer a nouveau ici puisque son ajout ne provoque pas une modif du paquet.xml
644 // donc ni sa relecture, ni sa detection
645 if (!isset($info[$charge])
646 AND $dir // exclure le cas du plugin "SPIP"
647 AND strpos($dir,":")===false // exclure le cas des procure:
648 AND file_exists("$dir$plug/paquet.xml") // uniquement pour les paquet.xml
649 ){
650 if (is_readable("$dir$plug/".($file=$info['prefix']."_".$charge.".php"))){
651 $info[$charge] = array($file);
652 }
653 }
654 if (isset($info[$charge])){
655 $files = $info[$charge];
656 foreach($files as $k=>$file){
657 // on genere un if file_exists devant chaque include
658 // pour pouvoir garder le meme niveau d'erreur general
659 $file = trim($file);
660 if (!is_readable("$dir$plug/$file")
661 // uniquement pour les paquet.xml
662 AND file_exists("$dir$plug/paquet.xml")){
663 unset($info[$charge][$k]);
664 }
665 else {
666 $_file = $root_dir_type . ".'$plug/$file'";
667 $contenu[$charge] .= "include_once_check($_file);\n";
668 }
669 }
670 }
671 }
672 $sign .= md5(serialize($info));
673 }
674 }
675
676 $contenu['options'] = "define('_PLUGINS_HASH','".md5($sign)."');\n" . $contenu['options'];
677 $contenu['fonctions'] .= plugin_ongletbouton("boutons_plugins", $boutons)
678 . plugin_ongletbouton("onglets_plugins", $onglets);
679
680 ecrire_fichier_php(_CACHE_PLUGINS_OPT, $contenu['options']);
681 ecrire_fichier_php(_CACHE_PLUGINS_FCT, $contenu['fonctions']);
682 }
683
684 function plugin_ongletbouton($nom, $val)
685 {
686 if (!$val) $val = array();
687 define("_UPDATED_$nom",$val = serialize($val));
688 define("_UPDATED_md5_$nom",$md5=md5($val));
689 $val = "unserialize('".str_replace("'","\'",$val)."')";
690 return
691 "if (!function_exists('$nom')) {\n"
692 ."function $nom(){return defined('_UPDATED_$nom')?unserialize(_UPDATED_$nom):$val;}\n"
693 ."function md5_$nom(){return defined('_UPDATED_md5_$nom')?_UPDATED_md5_$nom:'".$md5."';}\n"
694 ."}\n";
695 }
696
697 // creer le fichier CACHE_PLUGIN_VERIF a partir de
698 // $GLOBALS['spip_pipeline']
699 // $GLOBALS['spip_matrice']
700
701 function pipeline_matrice_precompile($plugin_valides, $ordre, $pipe_recherche)
702 {
703 static $liste_pipe_manquants=array();
704 if (($pipe_recherche)&&(!in_array($pipe_recherche,$liste_pipe_manquants)))
705 $liste_pipe_manquants[]=$pipe_recherche;
706
707 foreach($ordre as $p => $info){
708 // $ordre peur contenir des plugins en attente et non valides pour ce hit
709 if (isset($plugin_valides[$p])){
710 $dir_type = $plugin_valides[$p]['dir_type'];
711 $root_dir_type = str_replace('_DIR_','_ROOT_',$dir_type);
712 $plug = $plugin_valides[$p]['dir'];
713 $prefix = (($info['prefix']=="spip")?"":$info['prefix']."_");
714 if (isset($info['pipeline']) AND is_array($info['pipeline'])){
715 foreach($info['pipeline'] as $pipe){
716 $nom = $pipe['nom'];
717 if (isset($pipe['action']))
718 $action = $pipe['action'];
719 else
720 $action = $nom;
721 $nomlower = strtolower($nom);
722 if ($nomlower!=$nom
723 AND isset($GLOBALS['spip_pipeline'][$nom])
724 AND !isset($GLOBALS['spip_pipeline'][$nomlower])){
725 $GLOBALS['spip_pipeline'][$nomlower] = $GLOBALS['spip_pipeline'][$nom];
726 unset($GLOBALS['spip_pipeline'][$nom]);
727 }
728 $nom = $nomlower;
729 // une action vide est une declaration qui ne doit pas etre compilee !
730 if (!isset($GLOBALS['spip_pipeline'][$nom])) // creer le pipeline eventuel
731 $GLOBALS['spip_pipeline'][$nom]="";
732 if ($action){
733 if (strpos($GLOBALS['spip_pipeline'][$nom],"|$prefix$action")===FALSE)
734 $GLOBALS['spip_pipeline'][$nom] = preg_replace(",(\|\||$),","|$prefix$action\\1",$GLOBALS['spip_pipeline'][$nom],1);
735 if (isset($pipe['inclure'])){
736 $GLOBALS['spip_matrice']["$prefix$action"] =
737 "$root_dir_type:$plug/".$pipe['inclure'];
738 }
739 }
740 }
741 }
742 }
743 }
744
745 // on charge les fichiers d'options qui peuvent completer
746 // la globale spip_pipeline egalement
747 if (@is_readable(_CACHE_PLUGINS_PATH))
748 include_once(_CACHE_PLUGINS_PATH); // securite : a priori n'a pu etre fait plus tot
749 if (@is_readable(_CACHE_PLUGINS_OPT)) {
750 include_once(_CACHE_PLUGINS_OPT);
751 } else {
752 spip_log("pipelines desactives: impossible de produire " . _CACHE_PLUGINS_OPT);
753 }
754
755 // on ajoute les pipe qui ont ete recenses manquants
756 foreach($liste_pipe_manquants as $add_pipe)
757 if (!isset($GLOBALS['spip_pipeline'][$add_pipe]))
758 $GLOBALS['spip_pipeline'][$add_pipe]= '';
759 }
760
761 // precompilation des pipelines
762 // http://doc.spip.org/@pipeline_precompile
763 function pipeline_precompile(){
764 global $spip_pipeline, $spip_matrice;
765
766 $content = "";
767 foreach($spip_pipeline as $action=>$pipeline){
768 $s_inc = "";
769 $s_call = "";
770 $pipe = array_filter(explode('|',$pipeline));
771 // Eclater le pipeline en filtres et appliquer chaque filtre
772 foreach ($pipe as $fonc) {
773 $fonc = trim($fonc);
774 $s_call .= '$val = minipipe(\''.$fonc.'\', $val);'."\n";
775 if (isset($spip_matrice[$fonc])){
776 $file = $spip_matrice[$fonc];
777 $file = "'$file'";
778 // si un _DIR_XXX: est dans la chaine, on extrait la constante
779 if (preg_match(",(_(DIR|ROOT)_[A-Z_]+):,Ums",$file,$regs)){
780 $dir = $regs[1];
781 $root_dir = str_replace('_DIR_','_ROOT_',$dir);
782 if (defined($root_dir))
783 $dir = $root_dir;
784 $file = str_replace($regs[0],"'.".$dir.".'",$file);
785 $file = str_replace("''.","",$file);
786 $file = str_replace(constant($dir), '', $file);
787 }
788 $s_inc .= "include_once_check($file);\n";
789 }
790 }
791 if (strlen($s_inc))
792 $s_inc = "static \$inc=null;\nif (!\$inc){\n$s_inc\$inc=true;\n}\n";
793 $content .= "// Pipeline $action \n"
794 . "function execute_pipeline_$action(&\$val){\n"
795 . $s_inc
796 . $s_call
797 . "return \$val;\n}\n";
798 }
799 ecrire_fichier_php(_CACHE_PIPELINES, $content);
800 clear_path_cache();
801 }
802
803
804 // http://doc.spip.org/@plugin_est_installe
805 function plugin_est_installe($plug_path){
806 $plugin_installes = isset($GLOBALS['meta']['plugin_installes'])?unserialize($GLOBALS['meta']['plugin_installes']):array();
807 if (!$plugin_installes) return false;
808 return in_array($plug_path,$plugin_installes);
809 }
810
811
812 function plugin_installes_meta()
813 {
814 $installer_plugins = charger_fonction('installer', 'plugins');
815 $meta_plug_installes = array();
816 foreach (unserialize($GLOBALS['meta']['plugin']) as $prefix=>$resume) {
817 if ($plug = $resume['dir']){
818 $infos = $installer_plugins($plug, 'install', $resume['dir_type']);
819 if ($infos){
820 if (!is_array($infos) OR $infos['install_test'][0])
821 $meta_plug_installes[] = $plug;
822 if (is_array($infos)){
823 list($ok, $trace) = $infos['install_test'];
824 include_spip('inc/filtres_boites');
825 echo "<div class='install-plugins svp_retour'>"
826 .boite_ouvrir(_T('plugin_titre_installation', array('plugin' => typo($infos['nom']))), ($ok ? 'success' : 'error'))
827 .$trace
828 ."<div class='result'>"
829 .($ok ? ((isset($infos['upgrade']) && $infos['upgrade']) ? _T("plugin_info_upgrade_ok") : _T("plugin_info_install_ok")) : _T("avis_operation_echec"))
830 ."</div>"
831 .boite_fermer()
832 ."</div>";
833 }
834 }
835 }
836 }
837 ecrire_meta('plugin_installes',serialize($meta_plug_installes),'non');
838 }
839
840 function ecrire_fichier_php($nom, $contenu, $comment='')
841 {
842 ecrire_fichier($nom,
843 '<'.'?php' . "\n" . $comment ."\nif (defined('_ECRIRE_INC_VERSION')) {\n". $contenu . "}\n?".'>');
844 }
845