Completed
Push — spip-3.0 ( 5d8b58 )
by cam
53:01 queued 42:30
created

plugin.php ➔ ecrire_plugin_actifs()   F

Complexity

Conditions 22
Paths 7489

Size

Total Lines 93
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 22
eloc 54
c 2
b 0
f 0
nc 7489
nop 3
dl 0
loc 93
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 View Code Duplication
		while (($f = readdir($d)) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
	if (strlen($minimum)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
	if (strlen($maximum)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
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 View Code Duplication
	foreach ($liste_plug as $plug){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
		foreach ($liste_plug as $plug){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
			foreach($info1['necessite'] as $need){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
			foreach($info1['utilise'] as $need){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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.
0 ignored issues
show
Documentation introduced by
The doc-type string. could not be parsed: Unknown type name "string." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
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);
0 ignored issues
show
Bug Best Practice introduced by
The expression $err of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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");
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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 View Code Duplication
						if (!isset($chemin['type']) OR $chemin['type']=='public')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
607
							$chemins['public'][]="_DIR_PLUGIN_$prefix".(strlen($dir)?".'$dir'":"");
608 View Code Duplication
						if (!isset($chemin['type']) OR $chemin['type']=='prive')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
846