[SPIP] ~maj v2.1.25-->2.1.26
[velocampus/web/www.git] / www / ecrire / inc / charger_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
14 /*
15 * Ce fichier est extrait du plugin charge : action charger decompresser
16 *
17 * Auteur : bertrand@toggg.com
18 * © 2007 - Distribue sous licence LGPL
19 *
20 */
21
22 if (!defined('_ECRIRE_INC_VERSION')) return;
23
24 include_spip('inc/plugin');
25 include_spip('inc/actions');
26
27 // http://doc.spip.org/@formulaire_charger_plugin
28 function formulaire_charger_plugin($retour='') {
29 global $spip_lang_left, $spip_lang_right;
30
31 include_spip('inc/filtres');
32 include_spip('inc/presentation');
33
34 // Si defini comme non-existant
35 if (!_DIR_PLUGINS)
36 return '';
37
38 $auto = '';
39 if (_DIR_PLUGINS_AUTO) {
40 if (!@is_dir(_DIR_PLUGINS_AUTO)
41 OR !is_writeable(_DIR_PLUGINS_AUTO)) {
42 $auto = _T('plugin_info_automatique1')."\n"
43 .'<ol class="spip"><li>'._T('plugin_info_automatique2',array('rep'=>joli_repertoire(_DIR_PLUGINS_AUTO))).'</li>'
44 .'<li>'._T('plugin_info_automatique3').aide("install0")."</li></ol>"
45 ."\n<p>"._T('plugin_info_automatique_lib')."</p>";
46 }
47
48 if (!$auto)
49 $auto = interface_plugins_auto($retour);
50
51 }
52
53 $message = _T('plugin_info_automatique_ftp',array('rep'=>joli_repertoire(_DIR_PLUGINS)));
54 if (!@is_dir(_DIR_PLUGINS))
55 $message .= " &mdash; "._T('plugin_info_automatique_creer');
56
57 return debut_cadre_trait_couleur("spip-pack-24.png", true, "", _T('plugin_titre_automatique_ajouter'))
58 . "<h3>"._T('plugin_titre_automatique')."</h3>"
59 . "<p>".$message."</p>\n"
60 . $auto
61 . fin_cadre_trait_couleur(true);
62
63 }
64
65
66 // http://doc.spip.org/@interface_plugins_auto
67 function interface_plugins_auto($retour) {
68
69 $res = "<div class='verdana2'>";
70
71 if ($retour) {
72 $res .= "<div>$retour</div>\n";
73 }
74
75 $liste = liste_plugins_distants();
76
77 $message .= '<div class="explication">'._T('plugin_zip_adresse')
78 . '<br />'._T('plugin_info_automatique_exemples').'<ul class="spip">';
79
80 $les_urls = array('http://plugins.spip.net/rss-+-selection-2-1-+','http://www.spip-contrib.net/?page=rss-plugins-spip-2-1');
81 if (isset($GLOBALS['chargeur_urls_rss']) AND is_array($GLOBALS['chargeur_urls_rss']))
82 $les_urls = array_merge($les_urls,$GLOBALS['chargeur_urls_rss']);
83 foreach($les_urls as $url)
84 $message .= "<li><a href='$url' onclick=\"jQuery('#url_zip_plugin2').attr('value',jQuery(this).html()).focus();return false;\">"
85 .$url
86 ."</a></li>";
87 $message .= "</ul></div>";
88
89 $form = "";
90 $form .= "<ul><li class='editer_url_zip_plugin2 obligatoire'>";
91
92 $form .= "<label for='url_zip_plugin2'>"._T('plugin_zip_adresse_champ')."</label>";
93 $form .= $message;
94 $form .= "
95 <input type='text' class='text' id='url_zip_plugin2' name='url_zip_plugin2' value='' size='40' />";
96 $form .= "</li></ul>";
97 $form .= "<div class='boutons' id='loadrss'><input type='submit' value='"
98 . _T('bouton_valider')
99 . "'/>\n"
100 . "</div>\n";
101 $form = redirige_action_post('charger_plugin',
102 '', // arg = 'plugins' / 'lib', a priori
103 '',
104 '',
105 $form);
106
107 $res .= "<div class='formulaire_spip formulaire_editer'>";
108
109 $res .= $form;
110 $res .= "</div>\n";
111
112
113 $res .= "</div>\n";
114
115 $res .= afficher_liste_listes_plugins();
116
117 if ($liste) {
118 $res .= afficher_liste_plugins_distants($liste);
119
120 $menu = array();
121 $compte = 0;
122
123 $res .=
124 http_script("
125 jQuery(function(){
126 jQuery('.plugins li.item a[rel=info]').click(function(){
127 var li = jQuery(this).parents('li').eq(0);
128 if (!jQuery('div.details',li).html()) {
129 jQuery('div.details',li).prepend(ajax_image_searching).load(
130 jQuery(this).attr('href').replace(/admin_plugin|plugins|charger_plugin/, 'info_plugin_distant'), {}, function(){
131 li.addClass('on');
132 }
133 );
134 }
135 else {
136 if (jQuery('div.details',li).toggle().is(':visible'))
137 li.addClass('on');
138 else
139 li.removeClass('on');
140 }
141 return false;
142 });
143 });
144 ");
145
146 }
147 return $res;
148 }
149
150 function afficher_liste_plugins_distants($liste){
151 $res = "";
152 if (!$liste) return "";
153
154 $menu = array();
155 $compte = 0;
156
157 $afficher_plugin_distant = charger_fonction('afficher_plugin_distant','plugins');
158 $url_page = self();
159 foreach ($liste as $url => $info) {
160 $titre = $info[0];
161 $titre = strtoupper(trim(typo(translitteration(unicode2charset(html2unicode($titre))))));
162 $menu[$titre] = $afficher_plugin_distant($url_page, $url, $info, _request('plugin')==$url);
163 }
164 ksort($menu);
165
166 $res .=
167 "<h3>"._T('plugins_compte',array('count' => count($menu)))."</h3>"
168 . '<p>'._T('plugin_info_automatique_select',array('rep'=>joli_repertoire(_DIR_PLUGINS_AUTO))).'</p>'
169 . "<ul class='liste-items plugins distants'>".join("\n",$menu)."</ul>";
170
171 return $res;
172 }
173
174 // http://doc.spip.org/@chargeur_charger_zip
175 function chargeur_charger_zip($quoi = array())
176 {
177 if (!$quoi) {
178 return true;
179 }
180 if (is_scalar($quoi)) {
181 $quoi = array('zip' => $quoi);
182 }
183 if (isset($quoi['depot']) || isset($quoi['nom'])) {
184 $quoi['zip'] = $quoi['depot'] . $quoi['nom'] . '.zip';
185 }
186 foreach (array( 'remove' => 'spip',
187 'arg' => 'lib',
188 'plugin' => null,
189 'cache_cache' => null,
190 'rename' => array(),
191 'edit' => array(),
192 'root_extract' => false, # extraire a la racine de dest ?
193 'tmp' => sous_repertoire(_DIR_CACHE, 'chargeur')
194 )
195 as $opt=>$def) {
196 isset($quoi[$opt]) || ($quoi[$opt] = $def);
197 }
198
199
200 # destination finale des fichiers
201 switch($quoi['arg']) {
202 case 'lib':
203 $quoi['dest'] = _DIR_RACINE.'lib/';
204 break;
205 case 'plugins':
206 $quoi['dest'] = _DIR_PLUGINS_AUTO;
207 break;
208 default:
209 $quoi['dest'] = '';
210 break;
211 }
212
213
214 if (!@file_exists($fichier = $quoi['fichier']))
215 return 0;
216
217 include_spip('inc/pclzip');
218 $zip = new PclZip($fichier);
219 $list = $zip->listContent();
220
221 // on cherche la plus longue racine commune a tous les fichiers
222 $max_n = 999999;
223 foreach($list as $n) {
224 $p = array();
225 foreach(explode('/', $n['filename']) as $n => $x) {
226 if ($n>$max_n)
227 continue;
228 $sofar = join('/',$p);
229 $paths[$n][$sofar]++;
230 $p[] = $x;
231 }
232 $max_n = min($n,$max_n);
233 }
234
235 $total = $paths[0][''];
236 $i = 0;
237 while (isset($paths[$i])
238 AND count($paths[$i]) <= 1
239 AND array_values($paths[$i]) == array($total))
240 $i++;
241
242 $racine = '';
243 if ($i){
244 $racine = array_keys($paths[$i-1]);
245 $racine = array_pop($racine).'/';
246 }
247
248 $quoi['remove'] = $racine;
249
250 if (!strlen($nom = basename($racine)))
251 $nom = basename($fichier, '.zip');
252
253 $dir_export = $quoi['root_extract']
254 ? $quoi['dest']
255 : $quoi['dest'] . $nom.'/';
256
257 $tmpname = $quoi['tmp'].$nom.'/';
258
259 // On extrait, mais dans tmp/ si on ne veut pas vraiment le faire
260 $ok = $zip->extract(
261 PCLZIP_OPT_PATH,
262 $quoi['extract']
263 ? $dir_export
264 : $tmpname
265 ,
266 PCLZIP_OPT_SET_CHMOD, _SPIP_CHMOD,
267 PCLZIP_OPT_REPLACE_NEWER,
268 PCLZIP_OPT_REMOVE_PATH, $quoi['remove']
269 );
270 if ($zip->error_code < 0) {
271 spip_log('charger_decompresser erreur zip ' . $zip->error_code .
272 ' pour paquet: ' . $quoi['zip']);
273 return //$zip->error_code
274 $zip->errorName(true);
275 }
276
277 /*
278 * desactive pour l'instant
279 *
280 *
281 if (!$quoi['cache_cache']) {
282 chargeur_montre_tout($quoi);
283 }
284 if ($quoi['rename']) {
285 chargeur_rename($quoi);
286 }
287 if ($quoi['edit']) {
288 chargeur_edit($dir_export, $quoi['edit']);
289 }
290
291 if ($quoi['plugin']) {
292 chargeur_activer_plugin($quoi['plugin']);
293 }
294 */
295
296 spip_log('charger_decompresser OK pour paquet: ' . $quoi['zip']);
297
298
299
300 $size = $compressed_size = 0;
301 $removex = ',^'.preg_quote($quoi['remove'], ',').',';
302 foreach ($list as $a => $f) {
303 $size += $f['size'];
304 $compressed_size += $f['compressed_size'];
305 $list[$a] = preg_replace($removex,'',$f['filename']);
306 }
307
308 // Indiquer par un fichier install.log
309 // a la racine que c'est chargeur qui a installe ce plugin
310 ecrire_fichier($tmpname.'/install.log',
311 "installation: charger_plugin\n"
312 ."date: ".gmdate('Y-m-d\TH:i:s\Z', time())."\n"
313 ."source: ".$quoi['zip']."\n"
314 );
315
316
317
318 return array(
319 'files' => $list,
320 'size' => $size,
321 'compressed_size' => $compressed_size,
322 'dirname' => $dir_export,
323 'tmpname' => $tmpname
324 );
325 }
326
327 // pas de fichiers caches et preg_files() les ignore (*sigh*)
328 // http://doc.spip.org/@chargeur_montre_tout
329 function chargeur_montre_tout($quoi)
330 {
331 # echo($quoi['dest']);
332 if (!($d = @opendir($quoi['dest']))) {
333 return;
334 }
335 while (($f = readdir($d)) !== false) {
336 if ($f == '.' || $f == '..' || $f[0] != '.') {
337 continue;
338 }
339 rename($quoi['dest'] . '/' . $f, $quoi['dest'] . '/'. substr($f, 1));
340 }
341 }
342
343 // renommer des morceaux
344 // http://doc.spip.org/@chargeur_edit
345 function chargeur_edit($dir, $edit)
346 {
347 if (!($d = @opendir($dir))) {
348 return;
349 }
350 while (($f = readdir($d)) !== false) {
351 if ($f == '.' || $f == '..') {
352 continue;
353 }
354 if (is_dir($f = $dir . '/' . $f)) {
355 chargeur_edit($f, $edit);
356 }
357 $contenu = file_get_contents($f);
358 if (($change = preg_replace(
359 array_keys($edit), array_values($edit), $contenu)) == $contenu) {
360 continue;
361 }
362 $fw = fopen($f, 'w');
363 fwrite($fw, $change);
364 fclose($fw);
365 }
366 }
367
368 // renommer des morceaux
369 // http://doc.spip.org/@chargeur_rename
370 function chargeur_rename($quoi)
371 {
372 /*
373 preg_files() est deficiante pour les fichiers caches, ca aurait pu etre bien pourtant ...
374 */
375 spip_log($quoi);
376 foreach ($quoi['rename'] as $old => $new) {
377 !is_writable($file = $quoi['dest'] . '/' . $old) ||
378 rename($file, $quoi['dest'] . '/'. $new);
379 }
380 }
381
382 // juste activer le plugin du repertoire $plugin
383 // http://doc.spip.org/@chargeur_activer_plugin
384 function chargeur_activer_plugin($plugin)
385 {
386 spip_log('charger_decompresser activer plugin: ' . $plugin);
387 include_spip('inc/plugin');
388 ecrire_plugin_actifs(array($plugin), false, 'ajoute');
389 }
390
391
392 // http://doc.spip.org/@liste_fichiers_pclzip
393 function liste_fichiers_pclzip($status) {
394 $list = $status['files'];
395
396 $ret = '<b>'._T('plugin_zip_content',array('taille'=>taille_en_octets($status['size']), 'rep'=>$status['dirname'])).'</b>';
397
398 $l .= "<ul style='font-size:x-small;'>\n";
399 foreach ($list as $f) {
400 if (basename($f) == 'svn.revision')
401 lire_fichier($status['tmpname'].'/'.$f,$svn);
402 if ($joli = preg_replace(',^(.*/)([^/]+/?)$,', '<span style="visibility:hidden">\1</span>\2', $f)) {
403 if (!$vu[dirname($f.'x')]++)
404 $l .= "<li>".$f."</li>\n";
405 else
406 $l .= "<li>".$joli."</li>\n";
407 }
408 }
409 $l .= "</ul>\n";
410
411 include_spip('inc/filtres');
412 if (preg_match(',<revision>([^<]+)<,', $svn, $t))
413 $rev = '<div>revision '.$t[1].'</div>';
414 if (preg_match(',<commit>([^<]+),', $svn, $t))
415 $date = '<div>' . affdate($t[1]) .'</div>';
416
417 return $ret . $rev . $date . $l;
418 }
419
420 // Attention on ne sait pas ce que vaut cette URL
421 // http://doc.spip.org/@essaie_ajouter_liste_plugins
422 function essaie_ajouter_liste_plugins($url) {
423 if (!preg_match(',^https?://[^.]+\.[^.]+.*/.*[^/]$,', $url))
424 return;
425
426 include_spip('inc/distant');
427 if (!$rss = recuperer_page($url)
428 OR !preg_match(',<item,i', $rss))
429 return;
430
431 $liste = chercher_enclosures_zip($rss,true);
432 if (!$liste)
433 return;
434
435 // Ici c'est bon, on conserve l'url dans spip_meta
436 // et une copie du flux analise dans tmp/
437 ecrire_fichier(_DIR_TMP.'syndic_plug_'.md5($url).'.txt', serialize($liste));
438 $syndic_plug = @unserialize($GLOBALS['meta']['syndic_plug']);
439 $syndic_plug[$url] = count($liste);
440 ecrire_meta('syndic_plug', serialize($syndic_plug));
441 }
442
443 // Recherche les enclosures de type zip dans un flux rss ou atom
444 // les renvoie sous forme de tableau url => titre
445 // si $desc on ramene aussi le descriptif du paquet desc
446 // http://doc.spip.org/@chercher_enclosures_zip
447 function chercher_enclosures_zip($rss, $desc = '') {
448 $liste = array();
449 include_spip('inc/syndic');
450 foreach(analyser_backend($rss) as $item){
451 if ($item['enclosures']
452 AND $zips = extraire_balises($item['enclosures'], 'a')){
453 if ($img = extraire_balise($item['descriptif'], 'img')
454 AND $src = extraire_attribut($img, 'src')) {
455 $item['icon'] = $src;
456 }
457 foreach ($zips as $zip)
458 if (extraire_attribut($zip, 'type') == 'application/zip') {
459 if ($url = extraire_attribut($zip, 'href')) {
460 $liste[$url] = array($item['titre'], $item['url']);
461 if ($desc===true OR $desc == $url)
462 $liste[$url][] = $item;
463 }
464 }
465 }
466 }
467 spip_log(count($liste).' enclosures au format zip');
468 return $liste;
469 }
470
471
472 // Renvoie la liste des plugins distants (accessibles a travers
473 // l'une des listes de plugins)
474 // Si on passe desc = un url, ramener le descriptif de ce paquet
475 // http://doc.spip.org/@liste_plugins_distants
476 function liste_plugins_distants($desc = false) {
477 // TODO une liste multilingue a telecharger
478 $liste = array();
479
480 if (is_array($flux = @unserialize($GLOBALS['meta']['syndic_plug']))) {
481
482 foreach ($flux as $url => $c) {
483 if (file_exists($cache=_DIR_TMP.'syndic_plug_'.md5($url).'.txt')
484 AND lire_fichier($cache, $rss))
485 $liste = array_merge(unserialize($rss),$liste);
486 }
487 }
488
489 return $liste;
490 }
491
492 // http://doc.spip.org/@afficher_liste_listes_plugins
493 function afficher_liste_listes_plugins() {
494 if (!is_array($flux = @unserialize($GLOBALS['meta']['syndic_plug'])))
495 return '';
496
497 if (count($flux)){
498 $ret = '<h3>'._T('plugin_info_automatique_liste').'</h3><ul class="liste-items">';
499 //$ret .= '<li>'._T('plugin_info_automatique_liste_officielle').'</li>';
500 foreach ($flux as $url => $c) {
501 $a = '<div class="actions">[<a href="'.parametre_url(
502 generer_action_auteur('charger_plugin', 'supprimer_flux'),'supprimer_flux', $url).'">'._T('lien_supprimer').'</a>]</div>';
503 $time = @filemtime(_DIR_TMP.'syndic_plug_'.md5($url).'.txt');
504 $ret .= '<li class="item">'.inserer_attribut(PtoBR(propre("[->$url]")),'title',$url).' ('._T('plugins_compte',array('count' => $c)).') '
505 .($time?"<div class='small'>" . _T('info_derniere_syndication').' '.affdate(date('Y-m-d H:i:s',$time)) ."</div>":'')
506 . $a .'</li>';
507 }
508 $ret .= '</ul>';
509
510 $ret .= '<div style="text-align:'.$GLOBALS['spip_lang_right'].'"><a href="'.parametre_url(
511 generer_action_auteur('charger_plugin', 'update_flux'),'update_flux', 'oui').'">'._T('plugin_info_automatique_liste_update').'</a></div>';
512 }
513
514 return $ret;
515 }
516
517 // Si le chargement auto est autorise, un bouton
518 // sinon on donne l'url du zip
519 // http://doc.spip.org/@bouton_telechargement_plugin
520 function bouton_telechargement_plugin($url, $rep) {
521 // essayer de creer le repertoire lib/ si on en a le droit
522 if (($rep == 'lib') AND !is_dir(_DIR_RACINE . 'lib'))
523 sous_repertoire(_DIR_RACINE . 'lib','',false,true);
524
525 if (($rep == 'lib')?
526 is_dir(_DIR_RACINE . 'lib'):
527 (_DIR_PLUGINS_AUTO AND @is_dir(_DIR_PLUGINS_AUTO))
528 )
529 $bouton = redirige_action_post('charger_plugin',
530 $rep, // arg = 'lib' ou 'plugins'
531 '',
532 '',
533 "<input type='hidden' name='url_zip_plugin' value='$url' />"
534 ."<input type='submit' name='ok' value='"._T('bouton_telecharger')."' />",
535 'class="noajax"');
536 else if ($rep == 'lib'){
537 $bouton = "<div class='info_todo'>"._T('plugin_info_automatique1_lib')."\n"
538 .'<ol><li>'._T('plugin_info_automatique2',array('rep'=>joli_repertoire(_DIR_RACINE . 'lib/'))).'</li>'
539 .'<li>'._T('plugin_info_automatique3').aide("install0")."</li></ol></div>";
540 }
541
542 return _T('plugin_info_telecharger',array('url'=>$url,'rep'=>$rep.'/')).$bouton;
543
544 }
545
546 ?>