Mise en route du suivi.
[aidenligne_francais_universite.git] / ecrire / inc / plugin.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2007 *
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 // librairie pour parametrage plugin
16 //
17 define('_FILE_PLUGIN_CONFIG', "plugin.xml");
18
19 // besoin de inc_meta
20 include_spip('inc/meta');
21
22 // lecture des sous repertoire plugin existants
23 // http://doc.spip.org/@liste_plugin_files
24 function liste_plugin_files(){
25 static $plugin_files=array();
26 if (!count($plugin_files)){
27 foreach (preg_files(_DIR_PLUGINS, '/plugin[.]xml$') as $plugin) {
28 $plugin_files[]=substr(dirname($plugin), strlen(_DIR_PLUGINS));
29 }
30 sort($plugin_files);
31 }
32 return $plugin_files;
33 }
34
35 // http://doc.spip.org/@liste_plugin_valides
36 function liste_plugin_valides($liste_plug,&$infos){
37 $liste = array();
38 $infos = array();
39 if (is_array($liste_plug))
40 foreach($liste_plug as $plug){
41 $infos[$plug] = plugin_get_infos($plug);
42 if (!isset($infos[$plug]['erreur']) && !isset($plugin_valides[$p=strtoupper($infos[$plug]['prefix'])]))
43 $liste[$p] = array('dir'=>$plug,'version'=>isset($infos[$plug]['version'])?$infos[$plug]['version']:NULL);
44 }
45 return $liste;
46 }
47
48 // A utiliser pour initialiser ma variable globale $plugin
49 // http://doc.spip.org/@liste_plugin_actifs
50 function liste_plugin_actifs(){
51 $meta_plugin = isset($GLOBALS['meta']['plugin'])?$GLOBALS['meta']['plugin']:'';
52 if (strlen($meta_plugin)>0){
53 if (is_array($t=unserialize($meta_plugin)))
54 return $t;
55 else{ // compatibilite pre 1.9.2, mettre a jour la meta
56 $t = explode(",",$meta_plugin);
57 $liste = liste_plugin_valides($t,$infos);
58 ecrire_meta('plugin',serialize($liste));
59 ecrire_metas();
60 return $liste;
61 }
62 }
63 else
64 return array();
65 }
66 // http://doc.spip.org/@liste_chemin_plugin_actifs
67 function liste_chemin_plugin_actifs(){
68 $liste = liste_plugin_actifs();
69 foreach ($liste as $prefix=>$infos) {
70 $liste[$prefix] = $infos['dir'];
71 }
72 return $liste;
73 }
74
75 // http://doc.spip.org/@ecrire_plugin_actifs
76 function ecrire_plugin_actifs($plugin,$pipe_recherche=false,$operation='raz'){
77 static $liste_pipe_manquants=array();
78 $liste_fichier_verif = array();
79 if (($pipe_recherche)&&(!in_array($pipe_recherche,$liste_pipe_manquants)))
80 $liste_pipe_manquants[]=$pipe_recherche;
81
82 if ($operation!='raz'){
83 $plugin_actifs = liste_chemin_plugin_actifs();
84 $plugin_liste = liste_plugin_files();
85 $plugin_valides = array_intersect($plugin_actifs,$plugin_liste);
86 if ($operation=='ajoute')
87 $plugin = array_merge($plugin_valides,$plugin);
88 if ($operation=='enleve')
89 $plugin = array_diff($plugin_valides,$plugin);
90 }
91
92 $plugin_valides = liste_plugin_valides($plugin,$infos);
93 ecrire_meta('plugin',serialize($plugin_valides));
94 $plugin_header_info = array();
95 foreach($plugin_valides as $p=>$info){
96 $plugin_header_info[]= $p.($info['version']?"(".$info['version'].")":"");
97 }
98 ecrire_meta('plugin_header',substr(strtolower(implode(",",$plugin_header_info)),0,900));
99
100 $start_file = "<"."?php\nif (!defined('_ECRIRE_INC_VERSION')) return;\n";
101 $end_file = "\n?".">";
102
103 // generer les fichier
104 // charger_plugins_options.php
105 // charger_plugins_fonctions.php
106 foreach(array('options','fonctions') as $charge){
107 $s = "";
108 $splugs = "";
109 if (is_array($infos)){
110 foreach($infos as $plug=>$info){
111 // definir le plugin, donc le path avant l'include du fichier options
112 // permet de faire des include_ecrire pour attraper un inc_ du plugin
113 if ($charge=='options'){
114 $prefix = strtoupper($info['prefix']);
115 $splugs .= '$GLOBALS[\'plugins\'][]=\''.$plug.'\';';
116 $splugs .= "define('_DIR_PLUGIN_$prefix',_DIR_PLUGINS.'$plug/');";
117 $splugs .= "\n";
118 }
119 if (isset($info[$charge])){
120 foreach($info[$charge] as $file){
121 $s .= "@include_once _DIR_PLUGINS.'$plug/".trim($file)."';\n";
122 $liste_fichier_verif[] = "_DIR_PLUGINS.'$plug/".trim($file)."'";
123 }
124 }
125 }
126 }
127 ecrire_fichier(_DIR_TMP."charger_plugins_$charge.php",
128 $start_file . $splugs . $s . $end_file);
129 }
130
131 if (is_array($infos)){
132 // construire tableaux de pipelines et matrices
133 // $GLOBALS['spip_pipeline']
134 // $GLOBALS['spip_matrice']
135 foreach($infos as $plug=>$info){
136 $prefix = "";
137 $prefix = $info['prefix']."_";
138 if (isset($info['pipeline']) AND is_array($info['pipeline'])){
139 foreach($info['pipeline'] as $pipe){
140 $nom = trim(array_pop($pipe['nom']));
141 if (isset($pipe['action']))
142 $action = trim(array_pop($pipe['action']));
143 else
144 $action = $nom;
145 if (strpos($GLOBALS['spip_pipeline'][$nom],"|$prefix$action")===FALSE)
146 $GLOBALS['spip_pipeline'][$nom] .= "|$prefix$action";
147 if (isset($pipe['inclure'])){
148 $GLOBALS['spip_matrice']["$prefix$action"] =
149 "_DIR_PLUGINS$plug/".array_pop($pipe['inclure']);
150 }
151 }
152 }
153 }
154 }
155 // on ajoute les pipe qui ont ete recenses manquants
156 foreach($liste_pipe_manquants as $add_pipe)
157 if (!isset($GLOBALS['spip_pipeline'][$add_pipe]))
158 $GLOBALS['spip_pipeline'][$add_pipe]= '';
159
160 $liste_fichier_verif2 = pipeline_precompile();
161 $liste_fichier_verif = array_merge($liste_fichier_verif,$liste_fichier_verif2);
162
163 // horrible !
164 foreach ($liste_fichier_verif as $k => $f)
165 $liste_fichier_verif[$k] = _DIR_PLUGINS.preg_replace(",(_DIR_PLUGINS\.)?',", "", $f);
166 ecrire_fichier(_DIR_TMP.'verifier_plugins.txt',
167 serialize($liste_fichier_verif));
168 }
169
170 // precompilation des pipelines
171 // http://doc.spip.org/@pipeline_precompile
172 function pipeline_precompile(){
173 global $spip_pipeline, $spip_matrice;
174 $liste_fichier_verif = array();
175
176 $start_file = "<"."?php\nif (!defined('_ECRIRE_INC_VERSION')) return;\n";
177 $end_file = "\n?".">";
178 $content = "";
179 foreach($spip_pipeline as $action=>$pipeline){
180 $s_inc = "";
181 $s_call = "";
182 $pipe = array_filter(explode('|',$pipeline));
183 // Eclater le pipeline en filtres et appliquer chaque filtre
184 foreach ($pipe as $fonc) {
185 $s_call .= '$val = minipipe(\''.$fonc.'\', $val);'."\n";
186 if (isset($spip_matrice[$fonc])){
187 $file = $spip_matrice[$fonc];
188 $s_inc .= '@include_once(';
189 // si _DIR_PLUGINS est dans la chaine, on extrait la constante
190 if (($p = strpos($file,'_DIR_PLUGINS'))!==FALSE){
191 $f = "";
192 if ($p)
193 $f .= "'".substr($file,0,$p)."'.";
194 $f .= "_DIR_PLUGINS.";
195 $f .= "'".substr($file,$p+12)."'";
196 $s_inc .= $f;
197 $liste_fichier_verif[] = $f;
198 }
199 else{
200 $s_inc .= "'$file'";
201 $liste_fichier_verif[] = "'$file'";
202 }
203 $s_inc .= ');'."\n";
204 }
205 }
206 $content .= "// Pipeline $action \n";
207 $content .= "function execute_pipeline_$action(\$val){\n";
208 $content .= $s_inc;
209 $content .= $s_call;
210 $content .= "return \$val;\n}\n\n";
211 }
212 ecrire_fichier(_DIR_TMP."charger_pipelines.php",
213 $start_file . $content . $end_file);
214 return $liste_fichier_verif;
215 }
216
217 // pas sur que ca serve...
218 // http://doc.spip.org/@liste_plugin_inactifs
219 function liste_plugin_inactifs(){
220 return array_diff (liste_plugin_files(),liste_chemin_plugin_actifs());
221 }
222
223 // mise a jour du meta en fonction de l'etat du repertoire
224 // penser a faire une maj du cache => ecrire_meta()
225 // en principe cela doit aussi initialiser la valeur a vide si elle n'esite pas
226 // risque de pb en php5 a cause du typage ou de null (verifier dans la doc php)
227 // http://doc.spip.org/@verif_plugin
228 function verif_plugin($pipe_recherche = false){
229 $plugin_actifs = liste_chemin_plugin_actifs();
230 $plugin_liste = liste_plugin_files();
231 $plugin_new = array_intersect($plugin_actifs,$plugin_liste);
232 ecrire_plugin_actifs($plugin_new,$pipe_recherche);
233 ecrire_metas();
234 }
235
236 // http://doc.spip.org/@ordonne_plugin
237 function ordonne_plugin(){
238 $liste = liste_chemin_plugin_actifs();
239 $liste_triee = array();
240 $i=2;
241 foreach($liste as $plug){
242 $index = $i;
243 $i = $i+2;
244 if (rawurldecode($_GET['monter'])==$plug) $index = $index-3;
245 if (rawurldecode($_GET['descendre'])==$plug) $index = $index+3;
246 $liste_triee[$index] = $plug;
247 }
248 ksort($liste_triee);
249 ecrire_plugin_actifs($liste_triee);
250 ecrire_metas();
251 }
252
253 // http://doc.spip.org/@spip_plugin_install
254 function spip_plugin_install($action,$prefix,$version_cible){
255 $nom_meta_base_version = $prefix."_base_version";
256 switch ($action){
257 case 'test':
258 return (isset($GLOBALS['meta'][$nom_meta_base_version]) AND ($GLOBALS['meta'][$nom_meta_base_version]>=$version_cible));
259 break;
260 case 'install':
261 if (function_exists($upgrade = $prefix."_upgrade"))
262 $upgrade($nom_meta_base_version,$version_cible);
263 break;
264 case 'uninstall':
265 if (function_exists($vider_tables = $prefix."_vider_tables"))
266 $vider_tables($nom_meta_base_version);
267 break;
268 }
269 }
270
271 // http://doc.spip.org/@desinstalle_un_plugin
272 function desinstalle_un_plugin($plug,$infos){
273 // faire les include qui vont bien
274 foreach($infos['install'] as $file){
275 $file = trim($file);
276 @include_once(_DIR_PLUGINS."$plug/$file");
277 }
278 $prefix_install = $infos['prefix']."_install";
279 if (function_exists($prefix_install)){
280 $prefix_install('uninstall');
281 $ok = $prefix_install('test');
282 return $ok;
283 }
284 if (isset($infos['version_base'])){
285 spip_plugin_install('uninstall',$infos['prefix'],$infos['version_base']);
286 $ok = spip_plugin_install('test',$infos['prefix'],$infos['version_base']);
287 return $ok;
288 }
289
290 return false;
291 }
292
293 // http://doc.spip.org/@installe_un_plugin
294 function installe_un_plugin($plug,$infos){
295 // faire les include qui vont bien
296 foreach($infos['install'] as $file){
297 $file = trim($file);
298 @include_once(_DIR_PLUGINS."$plug/$file");
299 }
300 $prefix_install = $infos['prefix']."_install";
301 // cas de la fonction install fournie par le plugin
302 if (function_exists($prefix_install)){
303 // voir si on a besoin de faire l'install
304 $ok = $prefix_install('test');
305 if (!$ok) {
306 $prefix_install('install');
307 $ok = $prefix_install('test');
308 }
309 return $ok; // le plugin est deja installe et ok
310 }
311 // pas de fonction instal fournie, mais une version_base dans le plugin
312 // on utilise la fonction par defaut
313 if (isset($infos['version_base'])){
314 $ok = spip_plugin_install('test',$infos['prefix'],$infos['version_base']);
315 if (!$ok) {
316 spip_plugin_install('install',$infos['prefix'],$infos['version_base']);
317 $ok = spip_plugin_install('test',$infos['prefix'],$infos['version_base']);
318 }
319 return $ok; // le plugin est deja installe et ok
320 }
321 return false;
322 }
323
324 // http://doc.spip.org/@installe_plugins
325 function installe_plugins(){
326 $meta_plug_installes = array();
327 $liste = liste_chemin_plugin_actifs();
328 foreach($liste as $plug){
329 $infos = plugin_get_infos($plug);
330 if (isset($infos['install'])){
331 $ok = installe_un_plugin($plug,$infos);
332 // on peut enregistrer le chemin ici car il est mis a jour juste avant l'affichage
333 // du panneau -> cela suivra si le plugin demenage
334 if ($ok)
335 $meta_plug_installes[] = $plug;
336 }
337 }
338 ecrire_meta('plugin_installes',serialize($meta_plug_installes),'non');
339 ecrire_metas();
340 }
341 // http://doc.spip.org/@plugin_est_installe
342 function plugin_est_installe($plug_path){
343 $plugin_installes = isset($GLOBALS['meta']['plugin_installes'])?unserialize($GLOBALS['meta']['plugin_installes']):array();
344 if (!$plugin_installes) return false;
345 return in_array($plug_path,$plugin_installes);
346 }
347
348 // lecture du fichier de configuration d'un plugin
349 // http://doc.spip.org/@plugin_get_infos
350 function plugin_get_infos($plug){
351 include_spip('inc/xml');
352 static $infos=array();
353 static $plugin_xml_cache=NULL;
354 if (!isset($infos[$plug])){
355 if ($plugin_xml_cache==NULL){
356 $plugin_xml_cache = array();
357 if (is_file($f=_DIR_TMP."plugin_xml.cache")){
358 lire_fichier($f,$contenu);
359 $plugin_xml_cache = unserialize($contenu);
360 if (!is_array($plugin_xml_cache)) $plugin_xml_cache = array();
361 }
362 }
363 $ret = array();
364 if (isset($plugin_xml_cache[$plug])){
365 $info = $plugin_xml_cache[$plug];
366 if (isset($info['filemtime']) && (@filemtime(_DIR_PLUGINS."$plug/plugin.xml")<=$info['filemtime']))
367 $ret = $info;
368 }
369 if (!count($ret)){
370 if ((@file_exists(_DIR_PLUGINS))&&(is_dir(_DIR_PLUGINS))){
371 if (@file_exists($f = _DIR_PLUGINS."$plug/plugin.xml")) {
372 $arbre = spip_xml_load($f);
373 if (!$arbre OR !isset($arbre['plugin']) OR !is_array($arbre['plugin']))
374 $arbre = array('erreur' => array(_T('erreur_plugin_fichier_def_incorrect')." : $plug/plugin.xml"));
375 }
376 else {
377 // pour arriver ici on l'a vraiment cherche...
378 $arbre = array('erreur' => array(_T('erreur_plugin_fichier_def_absent')." : $plug/plugin.xml"));
379 }
380 plugin_verifie_conformite($plug,$arbre);
381 $ret['nom'] = spip_xml_aplatit($arbre['nom']);
382 $ret['version'] = trim(end($arbre['version']));
383 if (isset($arbre['auteur']))
384 $ret['auteur'] = spip_xml_aplatit($arbre['auteur']);
385 if (isset($arbre['icon']))
386 $ret['icon'] = spip_xml_aplatit($arbre['icon']);
387 if (isset($arbre['description']))
388 $ret['description'] = spip_xml_aplatit($arbre['description']);
389 if (isset($arbre['lien']))
390 $ret['lien'] = join(' ',$arbre['lien']);
391 if (isset($arbre['etat']))
392 $ret['etat'] = trim(end($arbre['etat']));
393 if (isset($arbre['options']))
394 $ret['options'] = $arbre['options'];
395 if (isset($arbre['install']))
396 $ret['install'] = $arbre['install'];
397 if (isset($arbre['fonctions']))
398 $ret['fonctions'] = $arbre['fonctions'];
399 $ret['prefix'] = trim(array_pop($arbre['prefix']));
400 if (isset($arbre['pipeline']))
401 $ret['pipeline'] = $arbre['pipeline'];
402 if (isset($arbre['erreur']))
403 $ret['erreur'] = $arbre['erreur'];
404 if (isset($arbre['version_base']))
405 $ret['version_base'] = trim(end($arbre['version_base']));
406
407 if ($t=@filemtime($f)){
408 $ret['filemtime'] = $t;
409 $plugin_xml_cache[$plug]=$ret;
410 ecrire_fichier(_DIR_TMP."plugin_xml.cache",serialize($plugin_xml_cache));
411 }
412 }
413 }
414 $infos[$plug] = $ret;
415 }
416 return $infos[$plug];
417 }
418
419 // http://doc.spip.org/@plugin_verifie_conformite
420 function plugin_verifie_conformite($plug,&$arbre){
421 $silence = false;
422 if (isset($arbre['plugin'])&&is_array($arbre['plugin']))
423 $arbre = end($arbre['plugin']); // derniere def plugin
424 else{
425 $arbre = array('erreur' => array(_T('erreur_plugin_tag_plugin_absent')." : $plug/plugin.xml"));
426 $silence = true;
427 }
428 // verification de la conformite du plugin avec quelques
429 // precautions elementaires
430 if (!isset($arbre['nom'])){
431 if (!$silence)
432 $arbre['erreur'][] = _T('erreur_plugin_nom_manquant');
433 $arbre['nom'] = array("");
434 }
435 if (!isset($arbre['version'])){
436 if (!$silence)
437 $arbre['erreur'][] = _T('erreur_plugin_version_manquant');
438 $arbre['version'] = array("");
439 }
440 if (!isset($arbre['prefix'])){
441 if (!$silence)
442 $arbre['erreur'][] = _T('erreur_plugin_prefix_manquant');
443 $arbre['prefix'] = array("");
444 }
445 else{
446 $prefix = "";
447 $prefix = trim(end($arbre['prefix']));
448 if (isset($arbre['etat'])){
449 $etat = trim(end($arbre['etat']));
450 if (!in_array($etat,array('dev','experimental','test','stable')))
451 $arbre['erreur'][] = _T('erreur_plugin_etat_inconnu')." : $etat";
452 }
453 if (isset($arbre['options'])){
454 foreach($arbre['options'] as $optfile){
455 $optfile = trim($optfile);
456 if (!@is_readable(_DIR_PLUGINS."$plug/$optfile"))
457 if (!$silence)
458 $arbre['erreur'][] = _T('erreur_plugin_fichier_absent')." : $optfile";
459 }
460 }
461 if (isset($arbre['fonctions'])){
462 foreach($arbre['fonctions'] as $optfile){
463 $optfile = trim($optfile);
464 if (!@is_readable(_DIR_PLUGINS."$plug/$optfile"))
465 if (!$silence)
466 $arbre['erreur'][] = _T('erreur_plugin_fichier_absent')." : $optfile";
467 }
468 }
469 $fonctions = array();
470 if (isset($arbre['fonctions']))
471 $fonctions = $arbre['fonctions'];
472 $liste_methodes_reservees = array('__construct','__destruct','plugin','install','uninstall',strtolower($prefix));
473 if (is_array($arbre['pipeline'])){
474 foreach($arbre['pipeline'] as $pipe){
475 $nom = trim(end($pipe['nom']));
476 if (isset($pipe['action']))
477 $action = trim(end($pipe['action']));
478 else
479 $action = $nom;
480 // verif que la methode a un nom autorise
481 if (in_array(strtolower($action),$liste_methodes_reservees)){
482 if (!$silence)
483 $arbre['erreur'][] = _T("erreur_plugin_nom_fonction_interdit")." : $action";
484 }
485 else{
486 // verif que le fichier de def est bien present
487 if (isset($pipe['inclure'])){
488 $inclure = _DIR_PLUGINS."$plug/".end($pipe['inclure']);
489 if (!@is_readable($inclure))
490 if (!$silence)
491 $arbre['erreur'][] = _T('erreur_plugin_fichier_absent')." : $inclure";
492 }
493 }
494 }
495 }
496 }
497 }
498
499 // http://doc.spip.org/@verifie_include_plugins
500 function verifie_include_plugins() {
501 if (_request('exec')!="admin_plugin"
502 AND $_SERVER['X-Requested-With'] != 'XMLHttpRequest'){
503 if (@is_readable(_DIR_PLUGINS)) {
504 include_spip('inc/headers');
505 redirige_par_entete(generer_url_ecrire("admin_plugin"));
506 }
507 // plus de repertoire plugin existant, le menu n'existe plus
508 // on fait une mise a jour silencieuse
509 // generer les fichiers php precompiles
510 // de chargement des plugins et des pipelines
511 verif_plugin();
512 spip_log("desactivation des plugins suite a suppression du repertoire");
513 }
514 }
515
516 // http://doc.spip.org/@affiche_bloc_plugin
517 function affiche_bloc_plugin($plug_file, $info) {
518 global $spip_lang_right;
519
520 // puce d'etat du plugin
521 // <etat>dev|experimental|test|stable</etat>
522 $etat = 'dev';
523 if (isset($info['etat']))
524 $etat = $info['etat'];
525 switch ($etat) {
526 case 'experimental':
527 $puce = 'puce-rouge.gif';
528 $titre_etat = _T('plugin_etat_experimental');
529 break;
530 case 'test':
531 $puce = 'puce-orange.gif';
532 $titre_etat = _T('plugin_etat_test');
533 break;
534 case 'stable':
535 $puce = 'puce-verte.gif';
536 $titre_etat = _T('plugin_etat_stable');
537 break;
538 default:
539 $puce = 'puce-poubelle.gif';
540 $titre_etat = _T('plugin_etat_developpement');
541 break;
542 }
543
544 $s .= "<div class='detailplugin verdana2'>";
545
546 if (isset($info['icon']))
547 $s .= "<img src='". _DIR_PLUGINS.$plug_file.'/'.trim($info['icon'])."' style='float:$spip_lang_right;' alt=' ' />\n";
548
549 $s .= _T('version') .' '. $info['version'] . " | <strong>$titre_etat</strong><br/>";
550 $s .= _T('repertoire_plugins') .' '. $plug_file . "<br/>";
551
552 if (isset($info['description']))
553 $s .= "<hr/>" . propre($info['description']) . "<br/>";
554
555 if (isset($info['auteur']))
556 $s .= "<hr/>" . _T('auteur') .' '. propre($info['auteur']) . "<br/>";
557
558 if (trim($info['lien'])) {
559 if (preg_match(',^https?://,iS', $info['lien']))
560 $s .= "<hr/>" . _T('info_url') .' '. propre("[->".$info['lien']."]") . "<br/>";
561 else
562 $s .= "<hr/>" . _T('info_url') .' '. propre($info['lien']) . "<br/>";
563 }
564 $s .= "</div>";
565
566 return $s;
567 }
568
569 ?>