Completed
Push — master ( 9507f8...0c925c )
by cam
08:29
created

composer.php ➔ filtre_introduction_dist()   C

Complexity

Conditions 14
Paths 193

Size

Total Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
nc 193
nop 5
dl 0
loc 71
rs 5.026
c 0
b 0
f 0

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-2018                                                *
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
 * Compose un squelette : compile le squelette au besoin et vérifie
15
 * la validité du code compilé
16
 *
17
 * @package SPIP\Core\Compilateur\Composer
18
 **/
19
20
if (!defined('_ECRIRE_INC_VERSION')) {
21
	return;
22
}
23
24
include_spip('inc/texte');
25
include_spip('inc/documents');
26
include_spip('inc/distant');
27
include_spip('inc/rubriques'); # pour calcul_branche (cf critere branche)
28
include_spip('inc/acces'); // Gestion des acces pour ical
29
include_spip('inc/actions');
30
include_spip('public/iterateur');
31
include_spip('public/interfaces');
32
include_spip('public/quete');
33
34
# Charge et retourne un composeur ou '' s'il est inconnu. Le compile au besoin
35
# Charge egalement un fichier homonyme de celui du squelette
36
# mais de suffixe '_fonctions.php' pouvant contenir:
37
# 1. des filtres
38
# 2. des fonctions de traduction de balise, de critere et de boucle
39
# 3. des declaration de tables SQL supplementaires
40
# Toutefois pour 2. et 3. preferer la technique de la surcharge
41
42
// http://code.spip.net/@public_composer_dist
43
function public_composer_dist($squelette, $mime_type, $gram, $source, $connect = '') {
44
45
	$nom = calculer_nom_fonction_squel($squelette, $mime_type, $connect);
46
47
	//  si deja en memoire (INCLURE  a repetition) c'est bon.
48
	if (function_exists($nom)) {
49
		return $nom;
50
	}
51
52
	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
53
		$GLOBALS['debug_objets']['courant'] = $nom;
54
	}
55
56
	$phpfile = sous_repertoire(_DIR_SKELS, '', false, true) . $nom . '.php';
57
58
	// si squelette est deja compile et perenne, le charger
59
	if (!squelette_obsolete($phpfile, $source)) {
60
		include_once $phpfile;
61
		#if (!squelette_obsolete($phpfile, $source)
62
		#  AND lire_fichier ($phpfile, $skel_code,
63
		#  array('critique' => 'oui', 'phpcheck' => 'oui'))){
64
		## eval('?'.'>'.$skel_code);
65
		#	 spip_log($skel_code, 'comp')
66
		#}
67
	}
68
69
	if (file_exists($lib = $squelette . '_fonctions' . '.php')) {
70
		include_once $lib;
71
	}
72
73
	// tester si le eval ci-dessus a mis le squelette en memoire
74
75
	if (function_exists($nom)) {
76
		return $nom;
77
	}
78
79
	// charger le source, si possible, et compiler 
80
	if (lire_fichier($source, $skel)) {
81
		$compiler = charger_fonction('compiler', 'public');
82
		$skel_code = $compiler($skel, $nom, $gram, $source, $connect);
83
	}
84
85
	// Ne plus rien faire si le compilateur n'a pas pu operer.
86
	if (!$skel_code) {
0 ignored issues
show
Bug introduced by
The variable $skel_code does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
87
		return false;
88
	}
89
90
	foreach ($skel_code as $id => $boucle) {
91
		$f = $boucle->return;
92
		if (@eval("return true; $f ;") === false) {
93
			// Code syntaxiquement faux (critere etc mal programme')
94
			$msg = _T('zbug_erreur_compilation');
95
			erreur_squelette($msg, $boucle);
96
			// continuer pour trouver d'autres fautes eventuelles
97
			// mais prevenir que c'est mort
98
			$nom = '';
99
		}
100
		// Contexte de compil inutile a present
101
		// (mais la derniere valeur de $boucle est utilisee ci-dessous)
102
		$skel_code[$id] = $f;
103
	}
104
105
	$code = '';
106
	if ($nom) {
107
		// Si le code est bon, concatener et mettre en cache
108
		if (function_exists($nom)) {
109
			$code = squelette_traduit($skel, $source, $phpfile, $skel_code);
110
		} else {
111
			// code semantiquement faux: bug du compilateur
112
			// $boucle est en fait ici la fct principale du squelette
113
			$msg = _T('zbug_erreur_compilation');
114
			erreur_squelette($msg, $boucle);
0 ignored issues
show
Bug introduced by
The variable $boucle seems to be defined by a foreach iteration on line 90. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
115
			$nom = '';
116
		}
117
	}
118
119
	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
120
121
		// Tracer ce qui vient d'etre compile
122
		$GLOBALS['debug_objets']['code'][$nom . 'tout'] = $code;
123
124
		// si c'est ce que demande le debusqueur, lui passer la main
125 View Code Duplication
		if ($GLOBALS['debug_objets']['sourcefile']
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...
126
			and (_request('var_mode_objet') == $nom)
127
			and (_request('var_mode_affiche') == 'code')
128
		) {
129
			erreur_squelette();
130
		}
131
	}
132
133
	return $nom ? $nom : false;
134
}
135
136
function squelette_traduit($squelette, $sourcefile, $phpfile, $boucles) {
0 ignored issues
show
Unused Code introduced by
The parameter $squelette is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
137
138
	// Le dernier index est '' (fonction principale)
139
	$noms = substr(join(', ', array_keys($boucles)), 0, -2);
140
	if (CODE_COMMENTE) {
141
		$code = "
142
/*
143
 * Squelette : $sourcefile
144
 * Date :      " . gmdate("D, d M Y H:i:s", @filemtime($sourcefile)) . " GMT
145
 * Compile :   " . gmdate("D, d M Y H:i:s", time()) . " GMT
146
 * " . (!$boucles ? "Pas de boucle" : ("Boucles :   " . $noms)) . "
147
 */ ";
148
	}
149
150
	$code = '<' . "?php\n" . $code . join('', $boucles) . "\n?" . '>';
0 ignored issues
show
Bug introduced by
The variable $code does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
151
	if (!defined('_VAR_NOCACHE') or !_VAR_NOCACHE) {
152
		ecrire_fichier($phpfile, $code);
153
	}
154
155
	return $code;
156
}
157
158
// Le squelette compile est-il trop vieux ?
159
// http://code.spip.net/@squelette_obsolete
160
function squelette_obsolete($skel, $squelette) {
161
	static $date_change = null;
162
	// ne verifier la date de mes_fonctions et mes_options qu'une seule fois
163
	// par hit
164
	if (is_null($date_change)) {
165
		if (@file_exists($fonc = 'mes_fonctions.php')) {
166
			$date_change = @filemtime($fonc);
167
		} # compatibilite
168
		if (defined('_FILE_OPTIONS')) {
169
			$date_change = max($date_change, @filemtime(_FILE_OPTIONS));
170
		}
171
	}
172
173
	return (
174
		(defined('_VAR_MODE') and in_array(_VAR_MODE, array('recalcul', 'preview', 'debug')))
175
		or !@file_exists($skel)
176
		or ((@file_exists($squelette) ? @filemtime($squelette) : 0)
177
			> ($date = @filemtime($skel)))
178
		or ($date_change > $date)
179
	);
180
}
181
182
// Activer l'invalideur de session
183
// http://code.spip.net/@invalideur_session
184
function invalideur_session(&$Cache, $code = null) {
185
	$Cache['session'] = spip_session();
186
187
	return $code;
188
}
189
190
191
// http://code.spip.net/@analyse_resultat_skel
192
function analyse_resultat_skel($nom, $cache, $corps, $source = '') {
193
	static $filtres = array();
194
	$headers = array();
195
196
	// Recupere les < ?php header('Xx: y'); ? > pour $page['headers']
197
	// note: on essaie d'attrapper aussi certains de ces entetes codes
198
	// "a la main" dans les squelettes, mais evidemment sans exhaustivite
199
	if (stripos($corps, 'header') !== false
200
		and preg_match_all(
201
			'/(<[?]php\s+)@?header\s*\(\s*.([^:\'"]*):?\s*([^)]*)[^)]\s*\)\s*[;]?\s*[?]>/ims',
202
			$corps, $regs, PREG_SET_ORDER)
203
	) {
204
		foreach ($regs as $r) {
205
			$corps = str_replace($r[0], '', $corps);
206
			# $j = Content-Type, et pas content-TYPE.
207
			$j = join('-', array_map('ucwords', explode('-', strtolower($r[2]))));
208
209
			if ($j == 'X-Spip-Filtre' and isset($headers[$j])) {
210
				$headers[$j] .= "|" . $r[3];
211
			} else {
212
				$headers[$j] = $r[3];
213
			}
214
		}
215
	}
216
	// S'agit-il d'un resultat constant ou contenant du code php
217
	$process_ins = (
218
		strpos($corps, '<' . '?') === false
219
		or
220
		(strpos($corps, '<' . '?xml') !== false and
221
			strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
222
	)
223
		? 'html'
224
		: 'php';
225
226
	$skel = array(
227
		'squelette' => $nom,
228
		'source' => $source,
229
		'process_ins' => $process_ins,
230
		'invalideurs' => $cache,
231
		'entetes' => $headers,
232
		'duree' => isset($headers['X-Spip-Cache']) ? intval($headers['X-Spip-Cache']) : 0
233
	);
234
235
	// traiter #FILTRE{} et filtres
236
	if (!isset($filtres[$nom])) {
237
		$filtres[$nom] = pipeline('declarer_filtres_squelettes', array('args' => $skel, 'data' => array()));
238
	}
239
	if (count($filtres[$nom]) or (isset($headers['X-Spip-Filtre']) and strlen($headers['X-Spip-Filtre']))) {
240
		include_spip('public/sandbox');
241
		$corps = sandbox_filtrer_squelette($skel, $corps,
242
			strlen($headers['X-Spip-Filtre']) ? explode('|', $headers['X-Spip-Filtre']) : array(), $filtres[$nom]);
243
		unset($headers['X-Spip-Filtre']);
244
245
		if ($process_ins == 'html') {
246
			$skel['process_ins'] = (
247
				strpos($corps, '<' . '?') === false
248
				or
249
				(strpos($corps, '<' . '?xml') !== false and
250
					strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
251
			)
252
				? 'html'
253
				: 'php';
254
		}
255
	}
256
257
	$skel['entetes'] = $headers;
258
	$skel['texte'] = $corps;
259
260
	return $skel;
261
}
262
263
//
264
// Des fonctions diverses utilisees lors du calcul d'une page ; ces fonctions
265
// bien pratiques n'ont guere de logique organisationnelle ; elles sont
266
// appelees par certaines balises au moment du calcul des pages. (Peut-on
267
// trouver un modele de donnees qui les associe physiquement au fichier
268
// definissant leur balise ???
269
//
270
271
272
/**
273
 * Calcul d'une introduction
274
 *
275
 * L'introduction est prise dans le descriptif s'il est renseigné,
276
 * sinon elle est calculée depuis le texte : à ce moment là,
277
 * l'introduction est prise dans le contenu entre les balises
278
 * `<intro>` et `</intro>` si présentes, sinon en coupant le
279
 * texte à la taille indiquée.
280
 *
281
 * Cette fonction est utilisée par la balise #INTRODUCTION
282
 *
283
 * @param string $descriptif
284
 *     Descriptif de l'introduction
285
 * @param string $texte
286
 *     Texte à utiliser en absence de descriptif
287
 * @param string $longueur
288
 *     Longueur de l'introduction
289
 * @param string $connect
290
 *     Nom du connecteur à la base de données
291
 * @param string $suite
0 ignored issues
show
Documentation introduced by
Should the type for parameter $suite not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
292
 *     points de suite si on coupe (par defaut _INTRODUCTION_SUITE et sinon &nbsp;(...)
293
 * @return string
294
 *     Introduction calculée
295
 **/
296
function filtre_introduction_dist($descriptif, $texte, $longueur, $connect, $suite = null) {
297
	// Si un descriptif est envoye, on l'utilise directement
298
	if (strlen($descriptif)) {
299
		return appliquer_traitement_champ($descriptif, 'introduction', '', array(), $connect);
300
	}
301
302
	// De preference ce qui est marque <intro>...</intro>
303
	$intro = '';
304
	$texte = preg_replace(",(</?)intro>,i", "\\1intro>", $texte); // minuscules
305
	while ($fin = strpos($texte, "</intro>")) {
306
		$zone = substr($texte, 0, $fin);
307
		$texte = substr($texte, $fin + strlen("</intro>"));
308
		if ($deb = strpos($zone, "<intro>") or substr($zone, 0, 7) == "<intro>") {
309
			$zone = substr($zone, $deb + 7);
310
		}
311
		$intro .= $zone;
312
	}
313
314
	// [12025] On ne *PEUT* pas couper simplement ici car c'est du texte brut,
315
	// qui inclus raccourcis et modeles
316
	// un simple <articlexx> peut etre ensuite transforme en 1000 lignes ...
317
	// par ailleurs le nettoyage des raccourcis ne tient pas compte
318
	// des surcharges et enrichissement de propre
319
	// couper doit se faire apres propre
320
	//$texte = nettoyer_raccourcis_typo($intro ? $intro : $texte, $connect);
321
322
	// Cependant pour des questions de perfs on coupe quand meme, en prenant
323
	// large et en se mefiant des tableaux #1323
324
325
	if (strlen($intro)) {
326
		$texte = $intro;
327
	} else {
328
		if (strpos("\n" . $texte, "\n|") === false
329
			and strlen($texte) > 2.5 * $longueur
330
		) {
331
			if (strpos($texte, "<multi") !== false) {
332
				$texte = extraire_multi($texte);
333
			}
334
			$texte = couper($texte, 2 * $longueur);
335
		}
336
	}
337
338
	// ne pas tenir compte des notes
339
	if ($notes = charger_fonction('notes', 'inc', true)) {
340
		$notes('', 'empiler');
341
	}
342
	// Supprimer les modèles avant le propre afin d'éviter qu'ils n'ajoutent du texte indésirable
343
	// dans l'introduction.
344
	$texte = supprime_img($texte, '');
345
	$texte = appliquer_traitement_champ($texte, 'introduction', '', array(), $connect);
346
347
	if ($notes) {
348
		$notes('', 'depiler');
349
	}
350
351
	if (is_null($suite) and defined('_INTRODUCTION_SUITE')) {
352
		$suite = _INTRODUCTION_SUITE;
353
	}
354
	$texte = couper($texte, $longueur, $suite);
355
	// comme on a coupe il faut repasser la typo (on a perdu les insecables)
356
	$texte = typo($texte, true, $connect, array());
357
358
	// et reparagrapher si necessaire (coherence avec le cas descriptif)
359
	// une introduction a tojours un <p>
360
	if ($GLOBALS['toujours_paragrapher']) // Fermer les paragraphes
361
	{
362
		$texte = paragrapher($texte, $GLOBALS['toujours_paragrapher']);
363
	}
364
365
	return $texte;
366
}
367
368
//
369
// Balises dynamiques
370
//
371
372
/** Code PHP pour inclure une balise dynamique à l'exécution d'une page */
373
define('CODE_INCLURE_BALISE', '<' . '?php 
374
include_once("%s");
375
if ($lang_select = "%s") $lang_select = lang_select($lang_select);
376
inserer_balise_dynamique(balise_%s_dyn(%s), array(%s));
377
if ($lang_select) lang_select();
378
?'
379
	. '>');
380
381
/**
382
 * Synthétise une balise dynamique : crée l'appel à l'inclusion
383
 * en transmettant les arguments calculés et le contexte de compilation.
384
 *
385
 * @uses argumenter_squelette() Pour calculer les arguments de l'inclusion
386
 *
387
 * @param string $nom
388
 *     Nom de la balise dynamique
389
 * @param array $args
390
 *     Liste des arguments calculés
391
 * @param string $file
392
 *     Chemin du fichier de squelette à inclure
393
 * @param array $context_compil
394
 *     Tableau d'informations sur la compilation
395
 * @return string
396
 *     Code PHP pour inclure le squelette de la balise dynamique
397
 **/
398
function synthetiser_balise_dynamique($nom, $args, $file, $context_compil) {
399
	if (strncmp($file, "/", 1) !== 0) {
400
		$file = './" . _DIR_RACINE . "' . $file;
401
	}
402
	$r = sprintf(CODE_INCLURE_BALISE,
403
		$file,
404
		$context_compil[4] ? $context_compil[4] : '',
405
		$nom,
406
		join(', ', array_map('argumenter_squelette', $args)),
407
		join(', ', array_map('_q', $context_compil)));
408
409
	return $r;
410
}
411
412
/**
413
 * Crée le code PHP pour transmettre des arguments (généralement pour une inclusion)
414
 *
415
 * @param array|string $v
416
 *     Arguments à transmettre :
417
 *
418
 *    - string : un simple texte à faire écrire
419
 *    - array : couples ('nom' => 'valeur') liste des arguments et leur valeur
420
 * @return string
421
 *
422
 *    - Code PHP créant le tableau des arguments à transmettre,
423
 *    - ou texte entre quote `'` (si `$v` était une chaîne)
424
 **/
425
function argumenter_squelette($v) {
426
427 View Code Duplication
	if (!is_array($v)) {
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...
428
		return "'" . texte_script($v) . "'";
429
	} else {
430
		$out = array();
431
		foreach ($v as $k => $val) {
432
			$out [] = argumenter_squelette($k) . '=>' . argumenter_squelette($val);
433
		}
434
435
		return 'array(' . join(", ", $out) . ')';
436
	}
437
}
438
439
440
/**
441
 * Calcule et retourne le code PHP retourné par l'exécution d'une balise
442
 * dynamique.
443
 *
444
 * Vérifier les arguments et filtres et calcule le code PHP à inclure.
445
 *
446
 * - charge le fichier PHP de la balise dynamique dans le répertoire
447
 *   `balise/`, soit du nom complet de la balise, soit d'un nom générique
448
 *    (comme 'formulaire_.php'). Dans ce dernier cas, le nom de la balise
449
 *    est ajouté en premier argument.
450
 * - appelle une éventuelle fonction de traitement des arguments `balise_NOM_stat()`
451
 * - crée le code PHP de la balise si une fonction `balise_NOM_dyn()` (ou variantes)
452
 *   est effectivement trouvée.
453
 *
454
 * @uses synthetiser_balise_dynamique()
455
 *     Pour calculer le code PHP d'inclusion produit
456
 *
457
 * @param string $nom
458
 *     Nom de la balise dynamique
459
 * @param array $args
460
 *     Liste des arguments calculés de la balise
461
 * @param array $context_compil
462
 *     Tableau d'informations sur la compilation
463
 * @return string
464
 *     Code PHP d'exécutant l'inclusion du squelette (ou texte) de la balise dynamique
465
 **/
466
function executer_balise_dynamique($nom, $args, $context_compil) {
467
	$nomfonction = $nom;
468
	$nomfonction_generique = "";
469
470
	// Calculer un nom générique (ie. 'formulaire_' dans 'formulaire_editer_article')
471
	if (false !== ($p = strpos($nom, "_"))) {
472
		$nomfonction_generique = substr($nom, 0, $p + 1);
473
	}
474
475
	if (!$fonction_balise = charger_fonction($nomfonction, 'balise', true)) {
476
		if ($nomfonction_generique and $fonction_balise = charger_fonction($nomfonction_generique, 'balise', true)) {
477
			// et injecter en premier arg le nom de la balise 
478
			array_unshift($args, $nom);
479
			$nomfonction = $nomfonction_generique;
480
		}
481
	}
482
483 View Code Duplication
	if (!$fonction_balise) {
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...
484
		$msg = array('zbug_balise_inexistante', array('from' => 'CVT', 'balise' => $nom));
485
		erreur_squelette($msg, $context_compil);
486
487
		return '';
488
	}
489
490
	// retrouver le fichier qui a déclaré la fonction
491
	// même si la fonction dynamique est déclarée dans un fichier de fonctions.
492
	// Attention sous windows, getFileName() retourne un antislash. 
493
	$reflector = new ReflectionFunction($fonction_balise);
494
	$file = str_replace('\\', '/', $reflector->getFileName());
495 View Code Duplication
	if (strncmp($file, str_replace('\\', '/', _ROOT_RACINE), strlen(_ROOT_RACINE)) === 0) {
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...
496
		$file = substr($file, strlen(_ROOT_RACINE));
497
	}
498
499
	// Y a-t-il une fonction de traitement des arguments ?
500
	$f = 'balise_' . $nomfonction . '_stat';
501
502
	$r = !function_exists($f) ? $args : $f($args, $context_compil);
503
504
	if (!is_array($r)) {
505
		return $r;
506
	}
507
508
	// verifier que la fonction dyn est la, 
509
	// sinon se replier sur la generique si elle existe
510
	if (!function_exists('balise_' . $nomfonction . '_dyn')) {
511
		if ($nomfonction_generique
512
			and $file = include_spip("balise/" . strtolower($nomfonction_generique))
513
			and function_exists('balise_' . $nomfonction_generique . '_dyn')
514
		) {
515
			// et lui injecter en premier arg le nom de la balise 
516
			array_unshift($r, $nom);
517
			$nomfonction = $nomfonction_generique;
518
			if (!_DIR_RESTREINT) {
519
				$file = _DIR_RESTREINT_ABS . $file;
520
			}
521 View Code Duplication
		} else {
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...
522
			$msg = array('zbug_balise_inexistante', array('from' => 'CVT', 'balise' => $nom));
523
			erreur_squelette($msg, $context_compil);
524
525
			return '';
526
		}
527
	}
528
529
	return synthetiser_balise_dynamique($nomfonction, $r, $file, $context_compil);
0 ignored issues
show
Bug introduced by
It seems like $file defined by include_spip('balise/' ....nomfonction_generique)) on line 512 can also be of type boolean; however, synthetiser_balise_dynamique() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
530
531
}
532
533
/**
534
 * Retourne pour une clé primaire d'objet donnée les identifiants ayant un logo
535
 *
536
 * @uses type_du_logo() Pour calculer le nom du logo
537
 *
538
 * @param string $type
539
 *     Nom de la clé primaire de l'objet
540
 * @return string
541
 *     Liste des identifiants ayant un logo (séparés par une virgule)
542
 **/
543
function lister_objets_avec_logos($type) {
544
545
	$logos = array();
546
	$chercher_logo = charger_fonction('chercher_logo', 'inc');
0 ignored issues
show
Unused Code introduced by
$chercher_logo is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
547
	$type = '/'
548
		. type_du_logo($type)
549
		. "on(\d+)\.("
550
		. join('|', $GLOBALS['formats_logos'])
551
		. ")$/";
552
553
	if ($d = opendir(_DIR_LOGOS)) {
554
		while (($f = readdir($d)) !== false) {
555
			if (preg_match($type, $f, $r)) {
556
				$logos[] = $r[1];
557
			}
558
		}
559
	}
560
	@closedir($d);
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...
561
562
	return join(',', $logos);
563
}
564
565
566
/**
567
 * Renvoie l'état courant des notes, le purge et en prépare un nouveau
568
 *
569
 * Fonction appelée par la balise `#NOTES`
570
 *
571
 * @see  balise_NOTES_dist()
572
 * @uses inc_notes_dist()
573
 *
574
 * @return string
575
 *     Code HTML des notes
576
 **/
577
function calculer_notes() {
578
	$r = '';
579
	if ($notes = charger_fonction('notes', 'inc', true)) {
580
		$r = $notes(array());
581
		$notes('', 'depiler');
582
		$notes('', 'empiler');
583
	}
584
585
	return $r;
586
}
587
588
/**
589
 * Selectionner la langue de l'objet dans la boucle
590
 *
591
 * Applique sur un item de boucle la langue de l'élément qui est parcourru.
592
 * Sauf dans les cas ou il ne le faut pas !
593
 *
594
 * La langue n'est pas modifiée lorsque :
595
 * - la globale 'forcer_lang' est définie à true
596
 * - l'objet ne définit pas de langue
597
 * - le titre contient une balise multi.
598
 *
599
 * @param string $lang
600
 *     Langue de l'objet
601
 * @param string $lang_select
602
 *     'oui' si critère lang_select est présent, '' sinon.
603
 * @param null|string $titre
604
 *     Titre de l'objet
605
 * @return null;
0 ignored issues
show
Documentation introduced by
The doc-type null; could not be parsed: Expected "|" or "end of type", but got ";" at position 4. (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...
606
 **/
607
function lang_select_public($lang, $lang_select, $titre = null) {
608
	// Cas 1. forcer_lang = true et pas de critere {lang_select}
609
	if (isset($GLOBALS['forcer_lang']) and $GLOBALS['forcer_lang']
610
		and $lang_select !== 'oui'
611
	) {
612
		$lang = $GLOBALS['spip_lang'];
613
	} // Cas 2. l'objet n'a pas de langue definie (ou definie a '')
614
	elseif (!strlen($lang)) {
615
		$lang = $GLOBALS['spip_lang'];
616
	} // Cas 3. l'objet est multilingue !
617
	elseif ($lang_select !== 'oui'
618
		and strlen($titre) > 10
619
		and strpos($titre, '<multi>') !== false
620
		and strpos(echappe_html($titre), '<multi>') !== false
621
	) {
622
		$lang = $GLOBALS['spip_lang'];
623
	}
624
625
	// faire un lang_select() eventuellement sur la langue inchangee
626
	lang_select($lang);
627
628
	return;
629
}
630
631
632
// Si un tableau &doublons[articles] est passe en parametre,
633
// il faut le nettoyer car il pourrait etre injecte en SQL
634
// http://code.spip.net/@nettoyer_env_doublons
635
function nettoyer_env_doublons($envd) {
636
	foreach ($envd as $table => $liste) {
637
		$n = '';
638
		foreach (explode(',', $liste) as $val) {
639
			if ($a = intval($val) and $val === strval($a)) {
640
				$n .= ',' . $val;
641
			}
642
		}
643
		if (strlen($n)) {
644
			$envd[$table] = $n;
645
		} else {
646
			unset($envd[$table]);
647
		}
648
	}
649
650
	return $envd;
651
}
652
653
/**
654
 * Cherche la présence d'un opérateur SELF ou SUBSELECT
655
 *
656
 * Cherche dans l'index 0 d'un tableau, la valeur SELF ou SUBSELECT
657
 * indiquant pour une expression WHERE de boucle que nous sommes
658
 * face à une sous-requête.
659
 *
660
 * Cherche de manière récursive également dans les autres valeurs si celles-ci
661
 * sont des tableaux
662
 *
663
 * @param string|array $w
664
 *     Description d'une condition WHERE de boucle (ou une partie de cette description)
665
 * @return string|bool
666
 *     Opérateur trouvé (SELF ou SUBSELECT) sinon false.
667
 **/
668
function match_self($w) {
669
	if (is_string($w)) {
670
		return false;
671
	}
672
	if (is_array($w)) {
673
		if (in_array(reset($w), array("SELF", "SUBSELECT"))) {
674
			return $w;
675
		}
676
		foreach (array_filter($w, 'is_array') as $sw) {
677
			if ($m = match_self($sw)) {
678
				return $m;
679
			}
680
		}
681
	}
682
683
	return false;
684
}
685
686
/**
687
 * Remplace une condition décrivant une sous requête par son code
688
 *
689
 * @param array|string $w
690
 *     Description d'une condition WHERE de boucle (ou une partie de cette description)
691
 *     qui possède une description de sous-requête
692
 * @param string $sousrequete
693
 *     Code PHP de la sous requête (qui doit remplacer la description)
694
 * @return array|string
695
 *     Tableau de description du WHERE dont la description de sous-requête
696
 *     est remplacée par son code.
697
 **/
698
function remplace_sous_requete($w, $sousrequete) {
699
	if (is_array($w)) {
700
		if (in_array(reset($w), array("SELF", "SUBSELECT"))) {
701
			return $sousrequete;
702
		}
703
		foreach ($w as $k => $sw) {
704
			$w[$k] = remplace_sous_requete($sw, $sousrequete);
705
		}
706
	}
707
708
	return $w;
709
}
710
711
/**
712
 * Sépare les conditions de boucles simples de celles possédant des sous-requêtes.
713
 *
714
 * @param array $where
715
 *     Description d'une condition WHERE de boucle
716
 * @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...
717
 *     Liste de 2 tableaux :
718
 *     - Conditions simples (ne possédant pas de sous requêtes)
719
 *     - Conditions avec des sous requêtes
720
 **/
721
function trouver_sous_requetes($where) {
722
	$where_simples = array();
723
	$where_sous = array();
724
	foreach ($where as $k => $w) {
725
		if (match_self($w)) {
726
			$where_sous[$k] = $w;
727
		} else {
728
			$where_simples[$k] = $w;
729
		}
730
	}
731
732
	return array($where_simples, $where_sous);
733
}
734
735
736
/**
737
 * Calcule une requête et l’exécute
738
 *
739
 * Cette fonction est présente dans les squelettes compilés.
740
 * Elle peut permettre de générer des requêtes avec jointure.
741
 *
742
 * @param array $select
743
 * @param array $from
744
 * @param array $from_type
745
 * @param array $where
746
 * @param array $join
747
 * @param array $groupby
748
 * @param array $orderby
749
 * @param string $limit
750
 * @param array $having
751
 * @param string $table
752
 * @param string $id
753
 * @param string $serveur
754
 * @param bool $requeter
755
 * @return resource
756
 */
757
function calculer_select(
758
	$select = array(),
759
	$from = array(),
760
	$from_type = array(),
761
	$where = array(),
762
	$join = array(),
763
	$groupby = array(),
764
	$orderby = array(),
765
	$limit = '',
766
	$having = array(),
767
	$table = '',
768
	$id = '',
769
	$serveur = '',
770
	$requeter = true
771
) {
772
773
	// retirer les criteres vides:
774
	// {X ?} avec X absent de l'URL
775
	// {par #ENV{X}} avec X absent de l'URL
776
	// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
777
	$menage = false;
778
	foreach ($where as $k => $v) {
779 View Code Duplication
		if (is_array($v)) {
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...
780
			if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
781
				$op = false;
782
			} elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
783
				$op = false;
784
			} else {
785
				$op = $v[0] ? $v[0] : $v;
786
			}
787
		} else {
788
			$op = $v;
789
		}
790
		if ((!$op) or ($op == 1) or ($op == '0=0')) {
791
			unset($where[$k]);
792
			$menage = true;
793
		}
794
	}
795
796
	// evacuer les eventuels groupby vide issus d'un calcul dynamique
797
	$groupby = array_diff($groupby, array(''));
798
799
	// remplacer les sous requetes recursives au calcul
800
	list($where_simples, $where_sous) = trouver_sous_requetes($where);
801
	foreach ($where_sous as $k => $w) {
802
		$menage = true;
803
		// on recupere la sous requete 
804
		$sous = match_self($w);
805
		if ($sous[0] == 'SELF') {
806
			// c'est une sous requete identique a elle meme sous la forme (SELF,$select,$where)
807
			array_push($where_simples, $sous[2]);
808
			$wheresub = array(
809
				$sous[2],
810
				'0=0'
811
			); // pour accepter une string et forcer a faire le menage car on a surement simplifie select et where
812
			$jsub = $join;
813
			// trouver les jointures utiles a
814
			// reinjecter dans le where de la sous requete les conditions supplementaires des jointures qui y sont mentionnees
815
			// ie L1.objet='article'
816
			// on construit le where une fois, puis on ajoute les where complentaires si besoin, et on reconstruit le where en fonction
817
			$i = 0;
818
			do {
819
				$where[$k] = remplace_sous_requete($w, "(" . calculer_select(
820
						array($sous[1] . " AS id"),
821
						$from,
822
						$from_type,
823
						$wheresub,
824
						$jsub,
825
						array(), array(), '',
826
						$having, $table, $id, $serveur, false) . ")");
827
				if (!$i) {
828
					$i = 1;
829
					$wherestring = calculer_where_to_string($where[$k]);
830
					foreach ($join as $cle => $wj) {
831
						if (count($wj) == 4
832
							and strpos($wherestring, "{$cle}.") !== false
833
						) {
834
							$i = 0;
835
							$wheresub[] = $wj[3];
836
							unset($jsub[$cle][3]);
837
						}
838
					}
839
				}
840
			} while ($i++ < 1);
841
		}
842
		if ($sous[0] == 'SUBSELECT') {
843
			// c'est une sous requete explicite sous la forme identique a sql_select : (SUBSELECT,$select,$from,$where,$groupby,$orderby,$limit,$having)
844
			array_push($where_simples, $sous[3]); // est-ce utile dans ce cas ?
845
			$where[$k] = remplace_sous_requete($w, "(" . calculer_select(
846
					$sous[1], # select
847
					$sous[2], #from
848
					array(), #from_type
849
					$sous[3] ? (is_array($sous[3]) ? $sous[3] : array($sous[3])) : array(),
850
					#where, qui peut etre de la forme string comme dans sql_select
851
					array(), #join
852
					$sous[4] ? $sous[4] : array(), #groupby
853
					$sous[5] ? $sous[5] : array(), #orderby
854
					$sous[6], #limit
855
					$sous[7] ? $sous[7] : array(), #having
856
					$table, $id, $serveur, false
857
				) . ")");
858
		}
859
		array_pop($where_simples);
860
	}
861
862
	foreach ($having as $k => $v) {
863
		if ((!$v) or ($v == 1) or ($v == '0=0')) {
864
			unset($having[$k]);
865
		}
866
	}
867
868
	// Installer les jointures.
869
	// Retirer celles seulement utiles aux criteres finalement absents mais
870
	// parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
871
	// si elle est seulement utile a Ln+1 elle meme inutile
872
873
	$afrom = array();
874
	$equiv = array();
875
	$k = count($join);
876
	foreach (array_reverse($join, true) as $cledef => $j) {
877
		$cle = $cledef;
878
		// le format de join est :
879
		// array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
880
		$join[$cle] = array_values($join[$cle]); // recalculer les cles car des unset ont pu perturber
881
		if (count($join[$cle]) == 2) {
882
			$join[$cle][] = $join[$cle][1];
883
		}
884
		if (count($join[$cle]) == 3) {
885
			$join[$cle][] = '';
886
		}
887
		list($t, $c, $carr, $and) = $join[$cle];
888
		// si le nom de la jointure n'a pas ete specifiee, on prend Lx avec x sont rang dans la liste
889
		// pour compat avec ancienne convention
890
		if (is_numeric($cle)) {
891
			$cle = "L$k";
892
		}
893
		if (!$menage
894
			or isset($afrom[$cle])
895
			or calculer_jointnul($cle, $select)
896
			or calculer_jointnul($cle, array_diff_key($join, array($cle => $join[$cle])))
897
			or calculer_jointnul($cle, $having)
898
			or calculer_jointnul($cle, $where_simples)
899
		) {
900
			// corriger les references non explicites dans select
901
			// ou groupby
902
			foreach ($select as $i => $s) {
903
				if ($s == $c) {
904
					$select[$i] = "$cle.$c AS $c";
905
					break;
906
				}
907
			}
908
			foreach ($groupby as $i => $g) {
909
				if ($g == $c) {
910
					$groupby[$i] = "$cle.$c";
911
					break;
912
				}
913
			}
914
			// on garde une ecriture decomposee pour permettre une simplification ulterieure si besoin
915
			// sans recours a preg_match
916
			// un implode(' ',..) est fait dans reinjecte_joint un peu plus bas
917
			$afrom[$t][$cle] = array(
918
				"\n" .
919
				(isset($from_type[$cle]) ? $from_type[$cle] : "INNER") . " JOIN",
920
				$from[$cle],
921
				"AS $cle",
922
				"ON (",
923
				"$cle.$c",
924
				"=",
925
				"$t.$carr",
926
				($and ? "AND " . $and : "") .
927
				")"
928
			);
929
			if (isset($afrom[$cle])) {
930
				$afrom[$t] = $afrom[$t] + $afrom[$cle];
931
				unset($afrom[$cle]);
932
			}
933
			$equiv[] = $carr;
934
		} else {
935
			unset($join[$cledef]);
936
		}
937
		unset($from[$cle]);
938
		$k--;
939
	}
940
941
	if (count($afrom)) {
942
		// Regarder si la table principale ne sert finalement a rien comme dans
943
		//<BOUCLE3(MOTS){id_article}{id_mot}> class='on'</BOUCLE3>
944
		//<BOUCLE2(MOTS){id_article} />#TOTAL_BOUCLE<//B2>
945
		//<BOUCLE5(RUBRIQUES){id_mot}{tout} />#TOTAL_BOUCLE<//B5>
946
		// ou dans
947
		//<BOUCLE8(HIERARCHIE){id_rubrique}{tout}{type='Squelette'}{inverse}{0,1}{lang_select=non} />#TOTAL_BOUCLE<//B8>
948
		// qui comporte plusieurs jointures
949
		// ou dans
950
		// <BOUCLE6(ARTICLES){id_mot=2}{statut==.*} />#TOTAL_BOUCLE<//B6>
951
		// <BOUCLE7(ARTICLES){id_mot>0}{statut?} />#TOTAL_BOUCLE<//B7>
952
		// penser a regarder aussi la clause orderby pour ne pas simplifier abusivement
953
		// <BOUCLE9(ARTICLES){recherche truc}{par titre}>#ID_ARTICLE</BOUCLE9>
954
		// penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
955
		// <BOUCLE10(EVENEMENTS){id_rubrique} />#TOTAL_BOUCLE<//B10>
956
957
		$t = key($from);
958
		$c = current($from);
0 ignored issues
show
Unused Code introduced by
$c is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
959
		reset($from);
960
		$e = '/\b(' . "$t\\." . join("|" . $t . '\.', $equiv) . ')\b/';
961
		if (!(strpos($t, ' ') or // jointure des le depart cf boucle_doc
962
				calculer_jointnul($t, $select, $e) or
963
				calculer_jointnul($t, $join, $e) or
964
				calculer_jointnul($t, $where, $e) or
965
				calculer_jointnul($t, $orderby, $e) or
966
				calculer_jointnul($t, $groupby, $e) or
967
				calculer_jointnul($t, $having, $e))
968
			&& count($afrom[$t])
969
		) {
970
			$nfrom = reset($afrom[$t]);
971
			$nt = key($afrom[$t]);
972
			unset($from[$t]);
973
			$from[$nt] = $nfrom[1];
974
			unset($afrom[$t][$nt]);
975
			$afrom[$nt] = $afrom[$t];
976
			unset($afrom[$t]);
977
			$e = '/\b' . preg_quote($nfrom[6]) . '\b/';
978
			$t = $nfrom[4];
979
			$alias = "";
980
			// verifier que les deux cles sont homonymes, sinon installer un alias dans le select
981
			$oldcle = explode('.', $nfrom[6]);
982
			$oldcle = end($oldcle);
983
			$newcle = explode('.', $nfrom[4]);
984
			$newcle = end($newcle);
985
			if ($newcle != $oldcle) {
986
				// si l'ancienne cle etait deja dans le select avec un AS
987
				// reprendre simplement ce AS
988
				$as = '/\b' . preg_quote($nfrom[6]) . '\s+(AS\s+\w+)\b/';
989
				if (preg_match($as, implode(',', $select), $m)) {
990
					$alias = "";
991
				} else {
992
					$alias = ", " . $nfrom[4] . " AS $oldcle";
993
				}
994
			}
995
			$select = remplacer_jointnul($t . $alias, $select, $e);
996
			$join = remplacer_jointnul($t, $join, $e);
0 ignored issues
show
Unused Code introduced by
$join is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
997
			$where = remplacer_jointnul($t, $where, $e);
998
			$having = remplacer_jointnul($t, $having, $e);
999
			$groupby = remplacer_jointnul($t, $groupby, $e);
1000
			$orderby = remplacer_jointnul($t, $orderby, $e);
1001
		}
1002
		$from = reinjecte_joint($afrom, $from);
1003
	}
1004
	$GLOBALS['debug']['aucasou'] = array($table, $id, $serveur, $requeter);
1005
	$r = sql_select($select, $from, $where,
1006
		$groupby, array_filter($orderby), $limit, $having, $serveur, $requeter);
1007
	unset($GLOBALS['debug']['aucasou']);
1008
1009
	return $r;
1010
}
1011
1012
/**
1013
 * Analogue a calculer_mysql_expression et autre (a unifier ?)
1014
 *
1015
 * @param string|array $v
1016
 * @param string $join
1017
 * @return string
1018
 */
1019 View Code Duplication
function calculer_where_to_string($v, $join = 'AND') {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in 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...
1020
	if (empty($v)) {
1021
		return '';
1022
	}
1023
1024
	if (!is_array($v)) {
1025
		return $v;
1026
	} else {
1027
		$exp = "";
1028
		if (strtoupper($join) === 'AND') {
1029
			return $exp . join(" $join ", array_map('calculer_where_to_string', $v));
1030
		} else {
1031
			return $exp . join($join, $v);
1032
		}
1033
	}
1034
}
1035
1036
1037
//condition suffisante (mais non necessaire) pour qu'une table soit utile
1038
1039
// http://code.spip.net/@calculer_jointnul
1040
function calculer_jointnul($cle, $exp, $equiv = '') {
1041
	if (!is_array($exp)) {
1042
		if ($equiv) {
1043
			$exp = preg_replace($equiv, '', $exp);
1044
		}
1045
1046
		return preg_match("/\\b$cle\\./", $exp);
1047
	} else {
1048
		foreach ($exp as $v) {
1049
			if (calculer_jointnul($cle, $v, $equiv)) {
1050
				return true;
1051
			}
1052
		}
1053
1054
		return false;
1055
	}
1056
}
1057
1058
// http://code.spip.net/@reinjecte_joint
1059
function reinjecte_joint($afrom, $from) {
1060
	$from_synth = array();
1061
	foreach ($from as $k => $v) {
1062
		$from_synth[$k] = $from[$k];
1063
		if (isset($afrom[$k])) {
1064
			foreach ($afrom[$k] as $kk => $vv) {
1065
				$afrom[$k][$kk] = implode(' ', $afrom[$k][$kk]);
1066
			}
1067
			$from_synth["$k@"] = implode(' ', $afrom[$k]);
1068
			unset($afrom[$k]);
1069
		}
1070
	}
1071
1072
	return $from_synth;
1073
}
1074
1075
// http://code.spip.net/@remplacer_jointnul
1076
function remplacer_jointnul($cle, $exp, $equiv = '') {
1077
	if (!is_array($exp)) {
1078
		return preg_replace($equiv, $cle, $exp);
1079
	} else {
1080
		foreach ($exp as $k => $v) {
1081
			$exp[$k] = remplacer_jointnul($cle, $v, $equiv);
1082
		}
1083
1084
		return $exp;
1085
	}
1086
}
1087
1088
// calcul du nom du squelette
1089
// http://code.spip.net/@calculer_nom_fonction_squel
1090
function calculer_nom_fonction_squel($skel, $mime_type = 'html', $connect = '') {
1091
	// ne pas doublonner les squelette selon qu'ils sont calcules depuis ecrire/ ou depuis la racine
1092 View Code Duplication
	if ($l = strlen(_DIR_RACINE) and strncmp($skel, _DIR_RACINE, $l) == 0) {
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...
1093
		$skel = substr($skel, strlen(_DIR_RACINE));
1094
	}
1095
1096
	return $mime_type
1097
	. (!$connect ? '' : preg_replace('/\W/', "_", $connect)) . '_'
1098
	. md5($GLOBALS['spip_version_code'] . ' * ' . $skel . (isset($GLOBALS['marqueur_skel']) ? '*' . $GLOBALS['marqueur_skel'] : ''));
1099
}
1100