[SPIP] ~maj v3.0.14-->v3.0.17
[ptitvelo/web/www.git] / www / ecrire / inc / plugin.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2014 *
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://doc.spip.org/@liste_plugin_valides
156 function liste_plugin_valides($liste_plug, $force = false)
157 {
158 $liste_ext = liste_plugin_files(_DIR_PLUGINS_DIST);
159 $get_infos = charger_fonction('get_infos','plugins');
160 $infos = array(
161 // lister les extensions qui sont automatiquement actives
162 '_DIR_PLUGINS_DIST' => $get_infos($liste_ext, $force, _DIR_PLUGINS_DIST),
163 '_DIR_PLUGINS' => $get_infos($liste_plug, $force, _DIR_PLUGINS)
164 );
165
166 // creer une premiere liste non ordonnee mais qui ne retient
167 // que les plugins valides, et dans leur derniere version en cas de doublon
168 $infos['_DIR_RESTREINT'][''] = $get_infos('./',$force,_DIR_RESTREINT);
169 $infos['_DIR_RESTREINT']['SPIP']['version'] = $GLOBALS['spip_version_branche'];
170 $infos['_DIR_RESTREINT']['SPIP']['chemin'] = array();
171 $liste_non_classee = array('SPIP'=>array(
172 'nom' => 'SPIP',
173 'etat' => 'stable',
174 'version' => $GLOBALS['spip_version_branche'],
175 'dir_type' => '_DIR_RESTREINT',
176 'dir'=> '',
177 )
178 );
179
180 foreach($liste_ext as $plug){
181 if (isset($infos['_DIR_PLUGINS_DIST'][$plug]))
182 plugin_valide_resume($liste_non_classee, $plug, $infos, '_DIR_PLUGINS_DIST');
183 }
184 foreach($liste_plug as $plug) {
185 if (isset($infos['_DIR_PLUGINS'][$plug]))
186 plugin_valide_resume($liste_non_classee, $plug, $infos, '_DIR_PLUGINS');
187 }
188
189 if (defined('_DIR_PLUGINS_SUPPL') and _DIR_PLUGINS_SUPPL) {
190 $infos['_DIR_PLUGINS_SUPPL'] = $get_infos($liste_plug, false, _DIR_PLUGINS_SUPPL);
191 foreach($liste_plug as $plug) {
192 if (isset($infos['_DIR_PLUGINS_SUPPL'][$plug]))
193 plugin_valide_resume($liste_non_classee, $plug, $infos, '_DIR_PLUGINS_SUPPL');
194 }
195 }
196
197 // les procure de core.xml sont consideres comme des plugins proposes,
198 // mais surchargeables (on peut activer un plugin qui procure ca pour l'ameliorer,
199 // donc avec le meme prefixe)
200 foreach($infos['_DIR_RESTREINT']['']['procure'] as $procure) {
201 $p = strtoupper($procure['nom']);
202 if (!isset($liste_non_classee[$p])){
203 $procure['etat'] = '?';
204 $procure['dir_type'] = '_DIR_RESTREINT';
205 $procure['dir'] = '';
206 $liste_non_classee[$p] = $procure;
207 }
208 }
209
210 return array($infos, $liste_non_classee);
211 }
212
213 // Ne retenir un plugin que s'il est valide
214 // et dans leur plus recente version compatible
215 // avec la version presente de SPIP
216
217 function plugin_valide_resume(&$liste, $plug, $infos, $dir)
218 {
219 $i = $infos[$dir][$plug];
220 if (isset($i['erreur']) AND $i['erreur'])
221 return;
222 if (!plugin_version_compatible($i['compatibilite'], $GLOBALS['spip_version_branche'],'spip'))
223 return;
224 $p = strtoupper($i['prefix']);
225 if (!isset($liste[$p])
226 OR spip_version_compare($i['version'],$liste[$p]['version'],'>')) {
227 $liste[$p] = array(
228 'nom' => $i['nom'],
229 'etat' => $i['etat'],
230 'version'=> $i['version'],
231 'dir'=> $plug,
232 'dir_type' => $dir
233 );
234 }
235 }
236
237 /**
238 * extrait les chemins d'une liste de plugin
239 * selectionne au passage ceux qui sont dans $dir_plugins uniquement
240 * si valeur non vide
241 *
242 * @param array $liste
243 * @param string $dir_plugins
244 * @return array
245 */
246 function liste_chemin_plugin($liste, $dir_plugins=_DIR_PLUGINS){
247 foreach ($liste as $prefix=>$infos) {
248 if (!$dir_plugins
249 OR (
250 defined($infos['dir_type'])
251 AND constant($infos['dir_type'])==$dir_plugins))
252 $liste[$prefix] = $infos['dir'];
253 else
254 unset($liste[$prefix]);
255 }
256 return $liste;
257 }
258
259 /**
260 * Liste les chemins vers les plugins actifs du dossier fourni en argument
261 * a partir d'une liste d'elelements construits par plugin_valide_resume
262 *
263 * @return array
264 */
265 // http://doc.spip.org/@liste_chemin_plugin_actifs
266 function liste_chemin_plugin_actifs($dir_plugins=_DIR_PLUGINS){
267 include_spip('plugins/installer');
268 return liste_chemin_plugin(liste_plugin_actifs(), $dir_plugins);
269 }
270
271 // Pour tester utilise, il faut connaitre tous les plugins
272 // qui seront forcement pas la a la fin,
273 // car absent de la liste des plugins actifs.
274 // Il faut donc construire une liste ordonnee
275 // Cette fonction detecte des dependances circulaires,
276 // avec un doute sur un "utilise" qu'on peut ignorer.
277 // Mais ne pas inserer silencieusement et risquer un bug sournois latent
278
279 function plugin_trier($infos, $liste_non_classee)
280 {
281 $toute_la_liste = $liste_non_classee;
282 $liste = $ordre = array();
283 $count = 0;
284 while ($c=count($liste_non_classee) AND $c!=$count){ // tant qu'il reste des plugins a classer, et qu'on ne stagne pas
285 #echo "tour::";var_dump($liste_non_classee);
286 $count = $c;
287 foreach($liste_non_classee as $p=>$resume) {
288 $plug = $resume['dir'];
289 $dir_type = $resume['dir_type'];
290 $info1 = $infos[$dir_type][$plug];
291 // si des plugins sont necessaires,
292 // on ne peut inserer qu'apres eux
293 foreach($info1['necessite'] as $need){
294 $nom = strtoupper($need['nom']);
295 $compat = isset($need['compatibilite']) ? $need['compatibilite'] : '';
296 if (!isset($liste[$nom]) OR !plugin_version_compatible($compat,$liste[$nom]['version'])) {
297 $info1 = false;
298 break;
299 }
300 }
301 if (!$info1) continue;
302 // idem si des plugins sont utiles,
303 // sauf si ils sont de toute facon absents de la liste
304 foreach($info1['utilise'] as $need){
305 $nom = strtoupper($need['nom']);
306 $compat = isset($need['compatibilite']) ? $need['compatibilite'] : '';
307 if (isset($toute_la_liste[$nom])) {
308 if (!isset($liste[$nom]) OR
309 !plugin_version_compatible($compat, $liste[$nom]['version'])) {
310 $info1 = false;
311 break;
312 }
313 }
314 }
315 if ($info1) {
316 $ordre[$p] = $info1;
317 $liste[$p] = $liste_non_classee[$p];
318 unset($liste_non_classee[$p]);
319 }
320 }
321 }
322 return array($liste, $ordre, $liste_non_classee);
323 }
324
325 // Collecte les erreurs dans la meta
326
327 function plugins_erreurs($liste_non_classee, $liste, $infos, $msg=array())
328 {
329 static $erreurs = array();
330 foreach($liste_non_classee as $p=>$resume){
331 $dir_type = $resume['dir_type'];
332 $plug = $resume['dir'];
333 $k = $infos[$dir_type][$plug];
334 $plug = constant($dir_type) . $plug;
335 if (!isset($msg[$p])) {
336 if (!$msg[$p] = plugin_necessite($k['necessite'], $liste))
337 $msg[$p] = plugin_necessite($k['utilise'], $liste);
338 } else {
339 foreach($msg[$p] as $c => $l)
340 $msg[$p][$c] = plugin_controler_lib($l['nom'], $l['lien']);
341 }
342 $erreurs[$plug] = $msg[$p];
343 }
344 ecrire_meta('plugin_erreur_activation', serialize($erreurs));
345 }
346
347 function plugin_donne_erreurs($raw=false, $raz=true) {
348 if (!isset($GLOBALS['meta']['plugin_erreur_activation'])) return $raw?array():'';
349 $list = @unserialize($GLOBALS['meta']['plugin_erreur_activation']);
350 // Compat ancienne version
351 if (!$list)
352 $list = $raw?array():$GLOBALS['meta']['plugin_erreur_activation'];
353 elseif(!$raw) {
354 foreach($list as $plug => $msg)
355 $list[$plug] = "<li>" . _T('plugin_impossible_activer', array('plugin' => $plug))
356 . "<ul><li>" . implode("</li><li>", $msg) . "</li></ul></li>";
357 $list ="<ul>" . join("\n", $list) . "</ul>";
358 }
359 if ($raz)
360 effacer_meta('plugin_erreur_activation');
361 return $list;
362 }
363
364 /**
365 * Teste des dependances
366 * Et verifie que chaque dependance est presente
367 * dans la liste de plugins donnee
368 *
369 * @param array $n
370 * Tableau de dependances dont on souhaite verifier leur presence
371 * @param array $liste
372 * Tableau des plugins presents
373 * @return array
374 * Tableau des messages d'erreurs recus. Il sera vide si tout va bien.
375 *
376 **/
377 function plugin_necessite($n, $liste) {
378 $msg = array();
379 foreach($n as $need){
380 $id = strtoupper($need['nom']);
381 if ($r = plugin_controler_necessite($liste, $id, $need['compatibilite'])) {
382 $msg[] = $r;
383 }
384 }
385 return $msg;
386 }
387
388 /**
389 * Verifie qu'une dependance (plugin) est bien presente.
390 *
391 * @param $liste
392 * Liste de description des plugins
393 * @param $nom
394 * Le plugin donc on cherche la presence
395 * @param $version
396 * L'éventuelle intervalle de compatibilité de la dependance. ex: [1.1.0;]
397 * @return string.
398 * Vide si ok,
399 * Message d'erreur lorsque la dependance est absente.
400 **/
401 function plugin_controler_necessite($liste, $nom, $version)
402 {
403 if (isset($liste[$nom]) AND plugin_version_compatible($version,$liste[$nom]['version'])) {
404 return '';
405 }
406 // retrouver le minimum
407 if (preg_match(_EXTRAIRE_INTERVALLE, $version, $regs)) {
408 $minimum = $regs[1];
409 if ($minimum) {
410 return _T('plugin_necessite_plugin', array(
411 'plugin' => $nom,
412 'version' => $minimum));
413 }
414 }
415 return _T('plugin_necessite_plugin_sans_version', array('plugin' => $nom));
416 }
417
418 function plugin_controler_lib($lib, $url)
419 {
420 /* Feature sortie du core, voir STP
421 * if ($url) {
422 include_spip('inc/charger_plugin');
423 $url = '<br />' . bouton_telechargement_plugin($url, 'lib');
424 }*/
425 return _T('plugin_necessite_lib', array('lib'=>$lib)) . " <a href='$url'>$url</a>";
426 }
427
428 // Pour compatibilite et lisibilite du code
429 function actualise_plugins_actifs($pipe_recherche = false){
430 return ecrire_plugin_actifs('', $pipe_recherche, 'force');
431 }
432
433 // mise a jour du meta en fonction de l'etat du repertoire
434 // Les ecrire_meta() doivent en principe aussi initialiser la valeur a vide
435 // si elle n'existe pas
436 // risque de pb en php5 a cause du typage ou de null (verifier dans la doc php)
437 // @return true/false si il y a du nouveau
438 // http://doc.spip.org/@ecrire_plugin_actifs
439 function ecrire_plugin_actifs($plugin,$pipe_recherche=false,$operation='raz') {
440
441 // creer le repertoire cache/ si necessaire ! (installation notamment)
442 sous_repertoire(_DIR_CACHE, '', false,true);
443
444 if (!spip_connect()) return false;
445 if ($operation!='raz') {
446 $plugin_valides = liste_chemin_plugin_actifs();
447 $plugin_valides = is_plugin_dir($plugin_valides);
448 if(defined('_DIR_PLUGINS_SUPPL') && _DIR_PLUGINS_SUPPL){
449 $plugin_valides_supp = liste_chemin_plugin_actifs(_DIR_PLUGINS_SUPPL);
450 $plugin_valides_supp = is_plugin_dir($plugin_valides_supp,_DIR_PLUGINS_SUPPL);
451 $plugin_valides = array_merge($plugin_valides,$plugin_valides_supp);
452 }
453 // si des plugins sont en attentes (coches mais impossible a activer)
454 // on les reinjecte ici
455 if (isset($GLOBALS['meta']['plugin_attente'])
456 AND $a = unserialize($GLOBALS['meta']['plugin_attente']))
457 $plugin_valides = $plugin_valides + liste_chemin_plugin($a);
458
459 if ($operation=='ajoute')
460 $plugin = array_merge($plugin_valides,$plugin);
461 elseif ($operation=='enleve')
462 $plugin = array_diff($plugin_valides,$plugin);
463 else $plugin = $plugin_valides;
464 }
465 $actifs_avant = $GLOBALS['meta']['plugin'];
466
467 // si une fonction de gestion de dependances existe, l'appeler ici
468 if ($ajouter_dependances = charger_fonction("ajouter_dependances","plugins",true)){
469 $plugin = $ajouter_dependances($plugin);
470 }
471
472 // recharger le xml des plugins a activer
473 // on forcer le reload ici, meme si le fichier xml n'a pas change
474 // pour ne pas rater l'ajout ou la suppression d'un fichier fonctions/options/administrations
475 // pourra etre evite quand on ne supportera plus les plugin.xml
476 // en deplacant la detection de ces fichiers dans la compilation ci dessous
477 list($infos,$liste) = liste_plugin_valides($plugin,true);
478 // trouver l'ordre d'activation
479 list($plugin_valides,$ordre,$reste) = plugin_trier($infos, $liste);
480 if ($reste) plugins_erreurs($reste, $liste, $infos);
481 // Ignorer les plugins necessitant une lib absente
482 // et preparer la meta d'entete Http
483 $err = $msg = $header = array();
484 foreach($plugin_valides as $p => $resume) {
485 $header[]= $p.($resume['version']?"(".$resume['version'].")":"");
486 if ($resume['dir']){
487 foreach($infos[$resume['dir_type']][$resume['dir']]['lib'] as $l) {
488 if (!find_in_path($l['nom'], 'lib/')) {
489 $err[$p] = $resume;
490 $msg[$p][] = $l;
491 unset($plugin_valides[$p]);
492 }
493 }
494 }
495 }
496 if ($err) plugins_erreurs($err, '', $infos, $msg);
497
498 if (isset($GLOBALS['meta']['message_crash_plugins']))
499 effacer_meta('message_crash_plugins');
500 ecrire_meta('plugin',serialize($plugin_valides));
501 $liste = array_diff_key($liste,$plugin_valides);
502 ecrire_meta('plugin_attente',serialize($liste));
503 $header = strtolower(implode(",",$header));
504 ecrire_meta('plugin_header',substr($header,0,900));
505 if (!isset($GLOBALS['spip_header_silencieux']) OR !$GLOBALS['spip_header_silencieux'])
506 ecrire_fichier(_DIR_VAR."config.txt", (defined('_HEADER_COMPOSED_BY') ? _HEADER_COMPOSED_BY:"Composed-By: SPIP") . ' '. $GLOBALS['spip_version_affichee'] . " @ www.spip.net + " . $header);
507 else
508 @unlink(_DIR_VAR."config.txt");
509 // generer charger_plugins_chemin.php
510 plugins_precompile_chemin($plugin_valides, $ordre);
511 // generer les fichiers
512 // charger_plugins_options.php
513 // charger_plugins_fonctions.php
514 // et retourner les fichiers a verifier
515 plugins_precompile_xxxtions($plugin_valides, $ordre);
516 // mise a jour de la matrice des pipelines
517 pipeline_matrice_precompile($plugin_valides, $ordre, $pipe_recherche);
518 // generer le fichier _CACHE_PIPELINE
519 pipeline_precompile();
520
521 // lancer et initialiser les nouveaux crons !
522 include_spip('inc/genie');
523 genie_queue_watch_dist();
524
525 return ($GLOBALS['meta']['plugin'] != $actifs_avant);
526 }
527
528 function plugins_precompile_chemin($plugin_valides, $ordre)
529 {
530 $chemins = array();
531 $contenu = "";
532 foreach($ordre as $p => $info){
533 // $ordre peur contenir des plugins en attente et non valides pour ce hit
534 if (isset($plugin_valides[$p])){
535 $dir_type = $plugin_valides[$p]['dir_type'];
536 $plug = $plugin_valides[$p]['dir'];
537 // definir le plugin, donc le path avant l'include du fichier options
538 // permet de faire des include_spip pour attraper un inc_ du plugin
539
540 $dir = $dir_type.".'" . $plug ."/'";
541
542 $prefix = strtoupper(preg_replace(',\W,','_',$info['prefix']));
543 if ($prefix!=="SPIP"){
544 $contenu .= "define('_DIR_PLUGIN_$prefix',$dir);\n";
545 foreach($info['chemin'] as $chemin){
546 if (!isset($chemin['version']) OR plugin_version_compatible($chemin['version'],$GLOBALS['spip_version_branche'],'spip')){
547 $dir = $chemin['path'];
548 if (strlen($dir) AND $dir{0}=="/") $dir = substr($dir,1);
549 if (strlen($dir) AND $dir=="./") $dir = '';
550 if (strlen($dir)) $dir = rtrim($dir,'/').'/';
551 if (!isset($chemin['type']) OR $chemin['type']=='public')
552 $chemins['public'][]="_DIR_PLUGIN_$prefix".(strlen($dir)?".'$dir'":"");
553 if (!isset($chemin['type']) OR $chemin['type']=='prive')
554 $chemins['prive'][]="_DIR_PLUGIN_$prefix".(strlen($dir)?".'$dir'":"");
555 }
556 }
557 }
558 }
559 }
560 if (count($chemins)){
561 $contenu .= "if (_DIR_RESTREINT) _chemin(implode(':',array(".implode(',',array_reverse($chemins['public'])).")));\n"
562 . "else _chemin(implode(':',array(".implode(',',array_reverse($chemins['prive'])).")));\n";
563 }
564
565 ecrire_fichier_php(_CACHE_PLUGINS_PATH, $contenu);
566 }
567
568 function plugins_precompile_xxxtions($plugin_valides, $ordre)
569 {
570 $contenu = array('options' => '', 'fonctions' =>'');
571 $boutons = array();
572 $onglets = array();
573 $sign = "";
574
575 foreach($ordre as $p => $info){
576 // $ordre peur contenir des plugins en attente et non valides pour ce hit
577 if (isset($plugin_valides[$p])){
578 $dir_type = $plugin_valides[$p]['dir_type'];
579 $plug = $plugin_valides[$p]['dir'];
580 $dir = constant($dir_type);
581 $root_dir_type = str_replace('_DIR_','_ROOT_',$dir_type);
582 if ($info['menu'])
583 $boutons = array_merge($boutons,$info['menu']);
584 if ($info['onglet'])
585 $onglets = array_merge($onglets,$info['onglet']);
586 foreach($contenu as $charge => $v){
587 // si pas declare/detecte a la lecture du paquet.xml,
588 // detecer a nouveau ici puisque son ajout ne provoque pas une modif du paquet.xml
589 // donc ni sa relecture, ni sa detection
590 if (!isset($info[$charge])
591 AND $dir // exclure le cas du plugin "SPIP"
592 AND file_exists("$dir$plug/paquet.xml") // uniquement pour les paquet.xml
593 ){
594 if (is_readable("$dir$plug/".($file=$info['prefix']."_".$charge.".php"))){
595 $info[$charge] = array($file);
596 }
597 }
598 if (isset($info[$charge])){
599 $files = $info[$charge];
600 foreach($files as $k=>$file){
601 // on genere un if file_exists devant chaque include
602 // pour pouvoir garder le meme niveau d'erreur general
603 $file = trim($file);
604 if (!is_readable("$dir$plug/$file")
605 // uniquement pour les paquet.xml
606 AND file_exists("$dir$plug/paquet.xml")){
607 unset($info[$charge][$k]);
608 }
609 else {
610 $_file = $root_dir_type . ".'$plug/$file'";
611 $contenu[$charge] .= "include_once_check($_file);\n";
612 }
613 }
614 }
615 }
616 $sign .= md5(serialize($info));
617 }
618 }
619
620 $contenu['options'] = "define('_PLUGINS_HASH','".md5($sign)."');\n" . $contenu['options'];
621 $contenu['fonctions'] .= plugin_ongletbouton("boutons_plugins", $boutons)
622 . plugin_ongletbouton("onglets_plugins", $onglets);
623
624 ecrire_fichier_php(_CACHE_PLUGINS_OPT, $contenu['options']);
625 ecrire_fichier_php(_CACHE_PLUGINS_FCT, $contenu['fonctions']);
626 }
627
628 function plugin_ongletbouton($nom, $val)
629 {
630 if (!$val) $val = array();
631 define("_UPDATED_$nom",$val = serialize($val));
632 define("_UPDATED_md5_$nom",$md5=md5($val));
633 $val = "unserialize('".str_replace("'","\'",$val)."')";
634 return
635 "if (!function_exists('$nom')) {\n"
636 ."function $nom(){return defined('_UPDATED_$nom')?unserialize(_UPDATED_$nom):$val;}\n"
637 ."function md5_$nom(){return defined('_UPDATED_md5_$nom')?_UPDATED_md5_$nom:'".$md5."';}\n"
638 ."}\n";
639 }
640
641 // creer le fichier CACHE_PLUGIN_VERIF a partir de
642 // $GLOBALS['spip_pipeline']
643 // $GLOBALS['spip_matrice']
644
645 function pipeline_matrice_precompile($plugin_valides, $ordre, $pipe_recherche)
646 {
647 static $liste_pipe_manquants=array();
648 if (($pipe_recherche)&&(!in_array($pipe_recherche,$liste_pipe_manquants)))
649 $liste_pipe_manquants[]=$pipe_recherche;
650
651 foreach($ordre as $p => $info){
652 // $ordre peur contenir des plugins en attente et non valides pour ce hit
653 if (isset($plugin_valides[$p])){
654 $dir_type = $plugin_valides[$p]['dir_type'];
655 $root_dir_type = str_replace('_DIR_','_ROOT_',$dir_type);
656 $plug = $plugin_valides[$p]['dir'];
657 $prefix = (($info['prefix']=="spip")?"":$info['prefix']."_");
658 if (isset($info['pipeline']) AND is_array($info['pipeline'])){
659 foreach($info['pipeline'] as $pipe){
660 $nom = $pipe['nom'];
661 if (isset($pipe['action']))
662 $action = $pipe['action'];
663 else
664 $action = $nom;
665 $nomlower = strtolower($nom);
666 if ($nomlower!=$nom
667 AND isset($GLOBALS['spip_pipeline'][$nom])
668 AND !isset($GLOBALS['spip_pipeline'][$nomlower])){
669 $GLOBALS['spip_pipeline'][$nomlower] = $GLOBALS['spip_pipeline'][$nom];
670 unset($GLOBALS['spip_pipeline'][$nom]);
671 }
672 $nom = $nomlower;
673 // une action vide est une declaration qui ne doit pas etre compilee !
674 if (!isset($GLOBALS['spip_pipeline'][$nom])) // creer le pipeline eventuel
675 $GLOBALS['spip_pipeline'][$nom]="";
676 if ($action){
677 if (strpos($GLOBALS['spip_pipeline'][$nom],"|$prefix$action")===FALSE)
678 $GLOBALS['spip_pipeline'][$nom] = preg_replace(",(\|\||$),","|$prefix$action\\1",$GLOBALS['spip_pipeline'][$nom],1);
679 if (isset($pipe['inclure'])){
680 $GLOBALS['spip_matrice']["$prefix$action"] =
681 "$root_dir_type:$plug/".$pipe['inclure'];
682 }
683 }
684 }
685 }
686 }
687 }
688
689 // on charge les fichiers d'options qui peuvent completer
690 // la globale spip_pipeline egalement
691 if (@is_readable(_CACHE_PLUGINS_PATH))
692 include_once(_CACHE_PLUGINS_PATH); // securite : a priori n'a pu etre fait plus tot
693 if (@is_readable(_CACHE_PLUGINS_OPT)) {
694 include_once(_CACHE_PLUGINS_OPT);
695 } else {
696 spip_log("pipelines desactives: impossible de produire " . _CACHE_PLUGINS_OPT);
697 }
698
699 // on ajoute les pipe qui ont ete recenses manquants
700 foreach($liste_pipe_manquants as $add_pipe)
701 if (!isset($GLOBALS['spip_pipeline'][$add_pipe]))
702 $GLOBALS['spip_pipeline'][$add_pipe]= '';
703 }
704
705 // precompilation des pipelines
706 // http://doc.spip.org/@pipeline_precompile
707 function pipeline_precompile(){
708 global $spip_pipeline, $spip_matrice;
709
710 $content = "";
711 foreach($spip_pipeline as $action=>$pipeline){
712 $s_inc = "";
713 $s_call = "";
714 $pipe = array_filter(explode('|',$pipeline));
715 // Eclater le pipeline en filtres et appliquer chaque filtre
716 foreach ($pipe as $fonc) {
717 $fonc = trim($fonc);
718 $s_call .= '$val = minipipe(\''.$fonc.'\', $val);'."\n";
719 if (isset($spip_matrice[$fonc])){
720 $file = $spip_matrice[$fonc];
721 $file = "'$file'";
722 // si un _DIR_XXX: est dans la chaine, on extrait la constante
723 if (preg_match(",(_(DIR|ROOT)_[A-Z_]+):,Ums",$file,$regs)){
724 $dir = $regs[1];
725 $root_dir = str_replace('_DIR_','_ROOT_',$dir);
726 if (defined($root_dir))
727 $dir = $root_dir;
728 $file = str_replace($regs[0],"'.".$dir.".'",$file);
729 $file = str_replace("''.","",$file);
730 $file = str_replace(constant($dir), '', $file);
731 }
732 $s_inc .= "include_once_check($file);\n";
733 }
734 }
735 if (strlen($s_inc))
736 $s_inc = "static \$inc=null;\nif (!\$inc){\n$s_inc\$inc=true;\n}\n";
737 $content .= "// Pipeline $action \n"
738 . "function execute_pipeline_$action(&\$val){\n"
739 . $s_inc
740 . $s_call
741 . "return \$val;\n}\n";
742 }
743 ecrire_fichier_php(_CACHE_PIPELINES, $content);
744 clear_path_cache();
745 }
746
747
748 // http://doc.spip.org/@plugin_est_installe
749 function plugin_est_installe($plug_path){
750 $plugin_installes = isset($GLOBALS['meta']['plugin_installes'])?unserialize($GLOBALS['meta']['plugin_installes']):array();
751 if (!$plugin_installes) return false;
752 return in_array($plug_path,$plugin_installes);
753 }
754
755
756 function plugin_installes_meta()
757 {
758 $installer_plugins = charger_fonction('installer', 'plugins');
759 $meta_plug_installes = array();
760 foreach (unserialize($GLOBALS['meta']['plugin']) as $prefix=>$resume) {
761 if ($plug = $resume['dir']){
762 $infos = $installer_plugins($plug, 'install', $resume['dir_type']);
763 if ($infos){
764 if (!is_array($infos) OR $infos['install_test'][0])
765 $meta_plug_installes[] = $plug;
766 if (is_array($infos)){
767 list($ok, $trace) = $infos['install_test'];
768 include_spip('inc/filtres_boites');
769 echo "<div class='install-plugins svp_retour'>"
770 .boite_ouvrir(_T('plugin_titre_installation', array('plugin' => typo($infos['nom']))), ($ok ? 'success' : 'error'))
771 .$trace
772 ."<div class='result'>"
773 .($ok ? ((isset($infos['upgrade']) && $infos['upgrade']) ? _T("plugin_info_upgrade_ok") : _T("plugin_info_install_ok")) : _T("avis_operation_echec"))
774 ."</div>"
775 .boite_fermer()
776 ."</div>";
777 }
778 }
779 }
780 }
781 ecrire_meta('plugin_installes',serialize($meta_plug_installes),'non');
782 }
783
784 function ecrire_fichier_php($nom, $contenu, $comment='')
785 {
786 ecrire_fichier($nom,
787 '<'.'?php' . "\n" . $comment ."\nif (defined('_ECRIRE_INC_VERSION')) {\n". $contenu . "}\n?".'>');
788 }
789 ?>