[SPIP] +2.1.12
[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-2011 *
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 = $i
243 ? array_pop(array_keys($paths[$i-1])).'/'
244 : '';
245
246 $quoi['remove'] = $racine;
247
248 if (!strlen($nom = basename($racine)))
249 $nom = basename($fichier, '.zip');
250
251 $dir_export = $quoi['root_extract']
252 ? $quoi['dest']
253 : $quoi['dest'] . $nom.'/';
254
255 $tmpname = $quoi['tmp'].$nom.'/';
256
257 // On extrait, mais dans tmp/ si on ne veut pas vraiment le faire
258 $ok = $zip->extract(
259 PCLZIP_OPT_PATH,
260 $quoi['extract']
261 ? $dir_export
262 : $tmpname
263 ,
264 PCLZIP_OPT_SET_CHMOD, _SPIP_CHMOD,
265 PCLZIP_OPT_REPLACE_NEWER,
266 PCLZIP_OPT_REMOVE_PATH, $quoi['remove']
267 );
268 if ($zip->error_code < 0) {
269 spip_log('charger_decompresser erreur zip ' . $zip->error_code .
270 ' pour paquet: ' . $quoi['zip']);
271 return //$zip->error_code
272 $zip->errorName(true);
273 }
274
275 /*
276 * desactive pour l'instant
277 *
278 *
279 if (!$quoi['cache_cache']) {
280 chargeur_montre_tout($quoi);
281 }
282 if ($quoi['rename']) {
283 chargeur_rename($quoi);
284 }
285 if ($quoi['edit']) {
286 chargeur_edit($dir_export, $quoi['edit']);
287 }
288
289 if ($quoi['plugin']) {
290 chargeur_activer_plugin($quoi['plugin']);
291 }
292 */
293
294 spip_log('charger_decompresser OK pour paquet: ' . $quoi['zip']);
295
296
297
298 $size = $compressed_size = 0;
299 $removex = ',^'.preg_quote($quoi['remove'], ',').',';
300 foreach ($list as $a => $f) {
301 $size += $f['size'];
302 $compressed_size += $f['compressed_size'];
303 $list[$a] = preg_replace($removex,'',$f['filename']);
304 }
305
306 // Indiquer par un fichier install.log
307 // a la racine que c'est chargeur qui a installe ce plugin
308 ecrire_fichier($tmpname.'/install.log',
309 "installation: charger_plugin\n"
310 ."date: ".gmdate('Y-m-d\TH:i:s\Z', time())."\n"
311 ."source: ".$quoi['zip']."\n"
312 );
313
314
315
316 return array(
317 'files' => $list,
318 'size' => $size,
319 'compressed_size' => $compressed_size,
320 'dirname' => $dir_export,
321 'tmpname' => $tmpname
322 );
323 }
324
325 // pas de fichiers caches et preg_files() les ignore (*sigh*)
326 // http://doc.spip.org/@chargeur_montre_tout
327 function chargeur_montre_tout($quoi)
328 {
329 # echo($quoi['dest']);
330 if (!($d = @opendir($quoi['dest']))) {
331 return;
332 }
333 while (($f = readdir($d)) !== false) {
334 if ($f == '.' || $f == '..' || $f[0] != '.') {
335 continue;
336 }
337 rename($quoi['dest'] . '/' . $f, $quoi['dest'] . '/'. substr($f, 1));
338 }
339 }
340
341 // renommer des morceaux
342 // http://doc.spip.org/@chargeur_edit
343 function chargeur_edit($dir, $edit)
344 {
345 if (!($d = @opendir($dir))) {
346 return;
347 }
348 while (($f = readdir($d)) !== false) {
349 if ($f == '.' || $f == '..') {
350 continue;
351 }
352 if (is_dir($f = $dir . '/' . $f)) {
353 chargeur_edit($f, $edit);
354 }
355 $contenu = file_get_contents($f);
356 if (($change = preg_replace(
357 array_keys($edit), array_values($edit), $contenu)) == $contenu) {
358 continue;
359 }
360 $fw = fopen($f, 'w');
361 fwrite($fw, $change);
362 fclose($fw);
363 }
364 }
365
366 // renommer des morceaux
367 // http://doc.spip.org/@chargeur_rename
368 function chargeur_rename($quoi)
369 {
370 /*
371 preg_files() est deficiante pour les fichiers caches, ca aurait pu etre bien pourtant ...
372 */
373 spip_log($quoi);
374 foreach ($quoi['rename'] as $old => $new) {
375 !is_writable($file = $quoi['dest'] . '/' . $old) ||
376 rename($file, $quoi['dest'] . '/'. $new);
377 }
378 }
379
380 // juste activer le plugin du repertoire $plugin
381 // http://doc.spip.org/@chargeur_activer_plugin
382 function chargeur_activer_plugin($plugin)
383 {
384 spip_log('charger_decompresser activer plugin: ' . $plugin);
385 include_spip('inc/plugin');
386 ecrire_plugin_actifs(array($plugin), false, 'ajoute');
387 }
388
389
390 // http://doc.spip.org/@liste_fichiers_pclzip
391 function liste_fichiers_pclzip($status) {
392 $list = $status['files'];
393
394 $ret = '<b>'._T('plugin_zip_content',array('taille'=>taille_en_octets($status['size']), 'rep'=>$status['dirname'])).'</b>';
395
396 $l .= "<ul style='font-size:x-small;'>\n";
397 foreach ($list as $f) {
398 if (basename($f) == 'svn.revision')
399 lire_fichier($status['tmpname'].'/'.$f,$svn);
400 if ($joli = preg_replace(',^(.*/)([^/]+/?)$,', '<span style="visibility:hidden">\1</span>\2', $f)) {
401 if (!$vu[dirname($f.'x')]++)
402 $l .= "<li>".$f."</li>\n";
403 else
404 $l .= "<li>".$joli."</li>\n";
405 }
406 }
407 $l .= "</ul>\n";
408
409 include_spip('inc/filtres');
410 if (preg_match(',<revision>([^<]+)<,', $svn, $t))
411 $rev = '<div>revision '.$t[1].'</div>';
412 if (preg_match(',<commit>([^<]+),', $svn, $t))
413 $date = '<div>' . affdate($t[1]) .'</div>';
414
415 return $ret . $rev . $date . $l;
416 }
417
418 // Attention on ne sait pas ce que vaut cette URL
419 // http://doc.spip.org/@essaie_ajouter_liste_plugins
420 function essaie_ajouter_liste_plugins($url) {
421 if (!preg_match(',^https?://[^.]+\.[^.]+.*/.*[^/]$,', $url))
422 return;
423
424 include_spip('inc/distant');
425 if (!$rss = recuperer_page($url)
426 OR !preg_match(',<item,i', $rss))
427 return;
428
429 $liste = chercher_enclosures_zip($rss,true);
430 if (!$liste)
431 return;
432
433 // Ici c'est bon, on conserve l'url dans spip_meta
434 // et une copie du flux analise dans tmp/
435 ecrire_fichier(_DIR_TMP.'syndic_plug_'.md5($url).'.txt', serialize($liste));
436 $syndic_plug = @unserialize($GLOBALS['meta']['syndic_plug']);
437 $syndic_plug[$url] = count($liste);
438 ecrire_meta('syndic_plug', serialize($syndic_plug));
439 }
440
441 // Recherche les enclosures de type zip dans un flux rss ou atom
442 // les renvoie sous forme de tableau url => titre
443 // si $desc on ramene aussi le descriptif du paquet desc
444 // http://doc.spip.org/@chercher_enclosures_zip
445 function chercher_enclosures_zip($rss, $desc = '') {
446 $liste = array();
447 include_spip('inc/syndic');
448 foreach(analyser_backend($rss) as $item){
449 if ($item['enclosures']
450 AND $zips = extraire_balises($item['enclosures'], 'a')){
451 if ($img = extraire_balise($item['descriptif'], 'img')
452 AND $src = extraire_attribut($img, 'src')) {
453 $item['icon'] = $src;
454 }
455 foreach ($zips as $zip)
456 if (extraire_attribut($zip, 'type') == 'application/zip') {
457 if ($url = extraire_attribut($zip, 'href')) {
458 $liste[$url] = array($item['titre'], $item['url']);
459 if ($desc===true OR $desc == $url)
460 $liste[$url][] = $item;
461 }
462 }
463 }
464 }
465 spip_log(count($liste).' enclosures au format zip');
466 return $liste;
467 }
468
469
470 // Renvoie la liste des plugins distants (accessibles a travers
471 // l'une des listes de plugins)
472 // Si on passe desc = un url, ramener le descriptif de ce paquet
473 // http://doc.spip.org/@liste_plugins_distants
474 function liste_plugins_distants($desc = false) {
475 // TODO une liste multilingue a telecharger
476 $liste = array();
477
478 if (is_array($flux = @unserialize($GLOBALS['meta']['syndic_plug']))) {
479
480 foreach ($flux as $url => $c) {
481 if (file_exists($cache=_DIR_TMP.'syndic_plug_'.md5($url).'.txt')
482 AND lire_fichier($cache, $rss))
483 $liste = array_merge(unserialize($rss),$liste);
484 }
485 }
486
487 return $liste;
488 }
489
490 // http://doc.spip.org/@afficher_liste_listes_plugins
491 function afficher_liste_listes_plugins() {
492 if (!is_array($flux = @unserialize($GLOBALS['meta']['syndic_plug'])))
493 return '';
494
495 if (count($flux)){
496 $ret = '<h3>'._T('plugin_info_automatique_liste').'</h3><ul class="liste-items">';
497 //$ret .= '<li>'._T('plugin_info_automatique_liste_officielle').'</li>';
498 foreach ($flux as $url => $c) {
499 $a = '<div class="actions">[<a href="'.parametre_url(
500 generer_action_auteur('charger_plugin', 'supprimer_flux'),'supprimer_flux', $url).'">'._T('lien_supprimer').'</a>]</div>';
501 $time = @filemtime(_DIR_TMP.'syndic_plug_'.md5($url).'.txt');
502 $ret .= '<li class="item">'.inserer_attribut(PtoBR(propre("[->$url]")),'title',$url).' ('._T('plugins_compte',array('count' => $c)).') '
503 .($time?"<div class='small'>" . _T('info_derniere_syndication').' '.affdate(date('Y-m-d H:i:s',$time)) ."</div>":'')
504 . $a .'</li>';
505 }
506 $ret .= '</ul>';
507
508 $ret .= '<div style="text-align:'.$GLOBALS['spip_lang_right'].'"><a href="'.parametre_url(
509 generer_action_auteur('charger_plugin', 'update_flux'),'update_flux', 'oui').'">'._T('plugin_info_automatique_liste_update').'</a></div>';
510 }
511
512 return $ret;
513 }
514
515 // Si le chargement auto est autorise, un bouton
516 // sinon on donne l'url du zip
517 // http://doc.spip.org/@bouton_telechargement_plugin
518 function bouton_telechargement_plugin($url, $rep) {
519 // essayer de creer le repertoire lib/ si on en a le droit
520 if (($rep == 'lib') AND !is_dir(_DIR_RACINE . 'lib'))
521 sous_repertoire(_DIR_RACINE . 'lib','',false,true);
522
523 if (($rep == 'lib')?
524 is_dir(_DIR_RACINE . 'lib'):
525 (_DIR_PLUGINS_AUTO AND @is_dir(_DIR_PLUGINS_AUTO))
526 )
527 $bouton = redirige_action_post('charger_plugin',
528 $rep, // arg = 'lib' ou 'plugins'
529 '',
530 '',
531 "<input type='hidden' name='url_zip_plugin' value='$url' />"
532 ."<input type='submit' name='ok' value='"._T('bouton_telecharger')."' />",
533 'class="noajax"');
534 else if ($rep == 'lib'){
535 $bouton = "<div class='info_todo'>"._T('plugin_info_automatique1_lib')."\n"
536 .'<ol><li>'._T('plugin_info_automatique2',array('rep'=>joli_repertoire(_DIR_RACINE . 'lib/'))).'</li>'
537 .'<li>'._T('plugin_info_automatique3').aide("install0")."</li></ol></div>";
538 }
539
540 return _T('plugin_info_telecharger',array('url'=>$url,'rep'=>$rep.'/')).$bouton;
541
542 }
543
544 ?>