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

phraser_html.php ➔ public_phraser_html_dist()   F

Complexity

Conditions 19
Paths 9218

Size

Total Lines 172
Code Lines 112

Duplication

Lines 13
Ratio 7.56 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 19
eloc 112
c 2
b 0
f 0
nc 9218
nop 5
dl 13
loc 172
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
14
if (!defined('_ECRIRE_INC_VERSION')) return;
15
16
# Ce fichier transforme un squelette en un tableau d'objets de classe Boucle
17
# il est charge par un include calcule 
18
# pour permettre differentes syntaxes en entree
19
20
define('BALISE_BOUCLE', '<BOUCLE');
21
define('BALISE_FIN_BOUCLE', '</BOUCLE');
22
define('BALISE_PRE_BOUCLE', '<B');
23
define('BALISE_POST_BOUCLE', '</B');
24
define('BALISE_ALT_BOUCLE', '<//B');
25
26
define('TYPE_RECURSIF', 'boucle');
27
define('SPEC_BOUCLE', '/\s*\(\s*([^\s?)]+)(\s*[^)?]*)([?]?)\)/');
28
define('NOM_DE_BOUCLE', "[0-9]+|[-_][-_.a-zA-Z0-9]*");
29
# ecriture alambiquee pour rester compatible avec les hexadecimaux des vieux squelettes
30
define('NOM_DE_CHAMP', "#((" . NOM_DE_BOUCLE . "):)?(([A-F]*[G-Z_][A-Z_0-9]*)|[A-Z_]+)(\*{0,2})");
31
define('CHAMP_ETENDU', '/\[([^]\[]*)\(' . NOM_DE_CHAMP . '([^[)]*\)[^]\[]*)\]/S');
32
33
define('BALISE_INCLURE', '/<INCLU[DR]E[[:space:]]*(\(([^)]*)\))?/S');
34
define('BALISE_POLYGLOTTE', ',<multi>(.*)</multi>,Uims');
35
define('BALISE_IDIOMES', ',<:(([a-z0-9_]+):)?([a-z0-9_]*)({([^\|=>]*=[^\|>]*)})?((\|[^>]*)?:>),iS');
36
define('BALISE_IDIOMES_ARGS', '@^\s*([^= ]*)\s*=\s*((' . NOM_DE_CHAMP . '[{][^}]*})?[^,]*)\s*,?\s*@s');
37
38
define('SQL_ARGS', '(\([^)]*\))');
39
define('CHAMP_SQL_PLUS_FONC', '`?([A-Z_\/][A-Z_\/0-9.]*)' . SQL_ARGS . '?`?');
40
41
// http://doc.spip.org/@phraser_inclure
42
function phraser_inclure($texte, $ligne, $result){
43
44
	while (preg_match(BALISE_INCLURE, $texte, $match)){
45
		$p = strpos($texte, $match[0]);
46
		$debut = substr($texte, 0, $p);
47
		if ($p) $result = phraser_idiomes($debut, $ligne, $result);
48
		$ligne += substr_count($debut, "\n");
49
		$champ = new Inclure;
50
		$champ->ligne = $ligne;
51
		$ligne += substr_count($match[0], "\n");
52
		$fichier = @$match[2];
53
		# assurer ici la migration .php3 => .php
54
		# et de l'ancienne syntaxe INCLURE(page.php3) devenue surperflue
55
		if (preg_match(',^(.*[.]php)3$,', $fichier, $r)){
56
			$fichier = $r[1];
57
		}
58
		$champ->texte = ($fichier!=='page.php') ? $fichier : '';
59
		$texte = substr($texte, $p+strlen($match[0]));
60
		// on assimile {var=val} a une liste de un argument sans fonction
61
		phraser_args($texte, "/>", "", $result, $champ);
62
		if (!$champ->texte OR count($champ->param)>1){
63
			if (!function_exists('normaliser_inclure'))
64
				include_spip('public/normaliser');
65
			normaliser_inclure($champ);
66
		}
67
		$texte = substr($champ->apres, strpos($champ->apres, '>')+1);
68
		$champ->apres = "";
69
		$texte = preg_replace(',^</INCLU[DR]E>,', '', $texte);
70
		$result[] = $champ;
71
	}
72
73
	return (($texte==="") ? $result : phraser_idiomes($texte, $ligne, $result));
74
}
75
76
// http://doc.spip.org/@phraser_polyglotte
77
function phraser_polyglotte($texte, $ligne, $result){
78
79
	if (preg_match_all(BALISE_POLYGLOTTE, $texte, $m, PREG_SET_ORDER))
80
		foreach ($m as $match){
81
			$p = strpos($texte, $match[0]);
82
			$debut = substr($texte, 0, $p);
83
			if ($p){
84
				$champ = new Texte;
85
				$champ->texte = $debut;
86
				$champ->ligne = $ligne;
87
				$result[] = $champ;
88
				$ligne += substr_count($champ->texte, "\n");
89
			}
90
91
			$champ = new Polyglotte;
92
			$champ->ligne = $ligne;
93
			$ligne += substr_count($match[0], "\n");
94
			$lang = '';
95
			$bloc = $match[1];
96
			$texte = substr($texte, $p+strlen($match[0]));
97
			while (preg_match("/^[[:space:]]*([^[{]*)[[:space:]]*[[{]([a-z_]+)[]}](.*)$/si", $bloc, $regs)){
98
				$trad = $regs[1];
99
				if ($trad OR $lang)
100
					$champ->traductions[$lang] = $trad;
101
				$lang = $regs[2];
102
				$bloc = $regs[3];
103
			}
104
			$champ->traductions[$lang] = $bloc;
105
			$result[] = $champ;
106
		}
107
	if ($texte!==""){
108
		$champ = new Texte;
109
		$champ->texte = $texte;
110
		$champ->ligne = $ligne;
111
		$result[] = $champ;
112
	}
113
114
	return $result;
115
}
116
117
118
// Reperer les balises de traduction
119
// <:module:chaine{arg1=texte1,arg2=#BALISE}|filtre1{texte2,#BALISE}|filtre2:>
120
// chaine peut etre vide si =texte1 est present et arg1 est vide
121
// sinon ce n'est pas un idiome
122
// http://doc.spip.org/@phraser_idiomes
123
function phraser_idiomes($texte, $ligne, $result){
124
	while (preg_match(BALISE_IDIOMES, $texte, $match)){
125
		$p = strpos($texte, $match[0]);
126
		$ko = (!$match[3] && ($match[5][0]!=='='));
127
		$debut = substr($texte, 0, $p+($ko ? strlen($match[0]) : 0));
128
		if ($debut) $result = phraser_champs($debut, $ligne, $result);
129
		$texte = substr($texte, $p+strlen($match[0]));
130
		$ligne += substr_count($debut, "\n");
131
		if ($ko) continue; // faux idiome
132
		$champ = new Idiome;
133
		$champ->ligne = $ligne;
134
		$ligne += substr_count($match[0], "\n");
135
		// Stocker les arguments de la balise de traduction
136
		$args = array();
137
		$largs = $match[5];
138
		while (preg_match(BALISE_IDIOMES_ARGS, $largs, $r)){
139
			$args[$r[1]] = phraser_champs($r[2], 0, array());
140
			$largs = substr($largs, strlen($r[0]));
141
		}
142
		$champ->arg = $args;
143
		$champ->nom_champ = strtolower($match[3]);
144
		$champ->module = $match[2];
145
		// pas d'imbrication pour les filtres sur langue
146
		phraser_args(@$match[7], ":", '', array(), $champ);
147
		$result[] = $champ;
148
	}
149
	if ($texte!=="") $result = phraser_champs($texte, $ligne, $result);
150
151
	return $result;
152
}
153
154
// http://doc.spip.org/@phraser_champs
155
function phraser_champs($texte, $ligne, $result){
156
	while (preg_match("/" . NOM_DE_CHAMP . "/S", $texte, $match)){
157
		$p = strpos($texte, $match[0]);
158
		$suite = substr($texte, $p+strlen($match[0]));
159
		if ($match[5] || (strpos($suite[0], "[0-9]")===false)){
160
			$debut = substr($texte, 0, $p);
161
			if ($p) $result = phraser_polyglotte($debut, $ligne, $result);
162
			$ligne += substr_count($debut, "\n");
163
			$champ = new Champ;
164
			$champ->ligne = $ligne;
165
			$ligne += substr_count($match[0], "\n");
166
			$champ->nom_boucle = $match[2];
167
			$champ->nom_champ = $match[3];
168
			$champ->etoile = $match[5];
169
170
			if ($suite[0]=='{'){
171
				phraser_arg($suite, '', array(), $champ);
172
				// ce ltrim est une ereur de conception
173
				// mais on le conserve par souci de compatibilite
174
				$texte = ltrim($suite);
175
				// Il faudrait le normaliser dans l'arbre de syntaxe abstraite
176
				// pour faire sauter ce cas particulier a la decompilation.
177
				/* Ce qui suit est malheureusement incomplet pour cela:
178
					if ($n = (strlen($suite) - strlen($texte))) {
179
						$champ->apres = array(new Texte);
180
						$champ->apres[0]->texte = substr($suite,0,$n);
181
					}
182
				*/
183
			} else $texte = $suite;
184
			phraser_vieux($champ);
185
			$result[] = $champ;
186
		} else {
187
			// faux champ
188
			$result = phraser_polyglotte(substr($texte, 0, $p+1), $ligne, $result);
189
			$texte = (substr($texte, $p+1));
190
		}
191
	}
192
	if ($texte!=="") $result = phraser_polyglotte($texte, $ligne, $result);
193
194
	return $result;
195
}
196
197
// Gestion des imbrications:
198
// on cherche les [..] les plus internes et on les remplace par une chaine
199
// %###N@ ou N indexe un tableau comportant le resultat de leur analyse
200
// on recommence tant qu'il y a des [...] en substituant a l'appel suivant
201
202
// http://doc.spip.org/@phraser_champs_etendus
203
function phraser_champs_etendus($texte, $ligne, $result){
204
	if ($texte==="") return $result;
205
	$sep = '##';
206
	while (strpos($texte, $sep)!==false)
207
		$sep .= '#';
208
209
	return array_merge($result, phraser_champs_interieurs($texte, $ligne, $sep, array()));
210
}
211
212
//  Analyse les filtres d'un champ etendu et affecte le resultat
213
// renvoie la liste des lexemes d'origine augmentee
214
// de ceux trouves dans les arguments des filtres (rare)
215
// sert aussi aux arguments des includes et aux criteres de boucles
216
// Tres chevelu
217
218
// http://doc.spip.org/@phraser_args
219
function phraser_args($texte, $fin, $sep, $result, &$pointeur_champ){
220
	$texte = ltrim($texte);
221
	while (($texte!=="") && strpos($fin, $texte[0])===false){
222
		$result = phraser_arg($texte, $sep, $result, $pointeur_champ);
223
		$texte = ltrim($texte);
224
	}
225
# mettre ici la suite du texte, 
226
# notamment pour que l'appelant vire le caractere fermant si besoin
227
	$pointeur_champ->apres = $texte;
228
229
	return $result;
230
}
231
232
// http://doc.spip.org/@phraser_arg
233
function phraser_arg(&$texte, $sep, $result, &$pointeur_champ){
234
	preg_match(",^(\|?[^}{)|]*)(.*)$,ms", $texte, $match);
235
	$suite = ltrim($match[2]);
236
	$fonc = trim($match[1]);
237
	if ($fonc && $fonc[0]=="|") $fonc = ltrim(substr($fonc, 1));
238
	$res = array($fonc);
239
	$err_f = '';
240
	// cas du filtre sans argument ou du critere /
241
	if (($suite && ($suite[0]!='{')) || ($fonc && $fonc[0]=='/')){
242
		// si pas d'argument, alors il faut une fonction ou un double |
243
		if (!$match[1]){
244
			$err_f = array('zbug_erreur_filtre', array('filtre' => $texte));
245
			erreur_squelette($err_f, $pointeur_champ);
246
			$texte = '';
247
		} else  $texte = $suite;
248 View Code Duplication
		if ($err_f) $pointeur_champ->param = 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...
249
		elseif ($fonc!=='') $pointeur_champ->param[] = $res;
250
		// pour les balises avec faux filtres qui boudent ce dur larbeur
251
		$pointeur_champ->fonctions[] = array($fonc, '');
252
253
		return $result;
254
	}
255
	$args = ltrim(substr($suite, 1)); // virer le '(' initial
256
	$collecte = array();
257
	while ($args && $args[0]!='}'){
258
		if ($args[0]=='"')
259
			preg_match('/^(")([^"]*)(")(.*)$/ms', $args, $regs);
260
		else if ($args[0]=="'")
261
			preg_match("/^(')([^']*)(')(.*)$/ms", $args, $regs);
262
		else {
263
			preg_match("/^([[:space:]]*)([^,([{}]*([(\[{][^])}]*[])}])?[^,}]*)([,}].*)$/ms", $args, $regs);
264
			if (!strlen($regs[2])){
265
				$err_f = array('zbug_erreur_filtre', array('filtre' => $args));
266
				erreur_squelette($err_f, $pointeur_champ);
267
				$champ = new Texte;
268
				$champ->apres = $champ->avant = $args = "";
269
				break;
270
			}
271
		}
272
		$arg = $regs[2];
273
		if (trim($regs[1])){
274
			$champ = new Texte;
275
			$champ->texte = $arg;
276
			$champ->apres = $champ->avant = $regs[1];
277
			$result[] = $champ;
278
			$collecte[] = $champ;
279
			$args = ltrim($regs[count($regs)-1]);
280
		} else {
281
			if (!preg_match("/" . NOM_DE_CHAMP . "([{|])/", $arg, $r)){
282
				// 0 est un aveu d'impuissance. A completer
283
				$arg = phraser_champs_exterieurs($arg, 0, $sep, $result);
284
285
				$args = ltrim($regs[count($regs)-1]);
286
				$collecte = array_merge($collecte, $arg);
287
				$result = array_merge($result, $arg);
288
			} else {
289
				$n = strpos($args, $r[0]);
290
				$pred = substr($args, 0, $n);
291
				$par = ',}';
292
				if (preg_match('/^(.*)\($/', $pred, $m)){
293
					$pred = $m[1];
294
					$par = ')';
295
				}
296
				if ($pred){
297
					$champ = new Texte;
298
					$champ->texte = $pred;
299
					$champ->apres = $champ->avant = "";
300
					$result[] = $champ;
301
					$collecte[] = $champ;
302
				}
303
				$rec = substr($args, $n+strlen($r[0])-1);
304
				$champ = new Champ;
305
				$champ->nom_boucle = $r[2];
306
				$champ->nom_champ = $r[3];
307
				$champ->etoile = $r[5];
308
				$next = $r[6];
309
				while ($next=='{'){
310
					phraser_arg($rec, $sep, array(), $champ);
311
					$args = ltrim($rec);
312
					$next = isset($args[0]) ? $args[0] : '';
313
				}
314
				while ($next=='|'){
315
					phraser_args($rec, $par, $sep, array(), $champ);
316
					$args = $champ->apres;
317
					$champ->apres = '';
318
					$next = isset($args[0]) ? $args[0] : '';
319
				}
320
				// Si erreur de syntaxe dans un sous-argument, propager.
321
				if ($champ->param===false)
322
					$err_f = true;
323
				else phraser_vieux($champ);
324
				if ($par==')') $args = substr($args, 1);
325
				$collecte[] = $champ;
326
				$result[] = $champ;
327
			}
328
		}
329
		if (isset($args[0]) AND $args[0]==','){
330
			$args = ltrim(substr($args, 1));
331
			if ($collecte){
0 ignored issues
show
Bug Best Practice introduced by
The expression $collecte 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...
332
				$res[] = $collecte;
333
				$collecte = array();
334
			}
335
		}
336
	}
337
	if ($collecte){
0 ignored issues
show
Bug Best Practice introduced by
The expression $collecte 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...
338
		$res[] = $collecte;
339
		$collecte = array();
0 ignored issues
show
Unused Code introduced by
$collecte 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...
340
	}
341
	$texte = substr($args, 1);
342
	$source = substr($suite, 0, strlen($suite)-strlen($texte));
343
	// propager les erreurs, et ignorer les param vides
344
	if ($pointeur_champ->param!==false){
345 View Code Duplication
		if ($err_f)
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...
346
			$pointeur_champ->param = false;
347
		elseif ($fonc!=='' || count($res)>1)
348
			$pointeur_champ->param[] = $res;
349
	}
350
	// pour les balises avec faux filtres qui boudent ce dur larbeur
351
	$pointeur_champ->fonctions[] = array($fonc, $source);
352
353
	return $result;
354
}
355
356
357
// http://doc.spip.org/@phraser_champs_exterieurs
358
function phraser_champs_exterieurs($texte, $ligne, $sep, $nested){
359
	$res = array();
360
	while (($p = strpos($texte, "%$sep"))!==false){
361
		if (!preg_match(',^%' . preg_quote($sep) . '([0-9]+)@,', substr($texte, $p), $m))
362
			break;
363
		$debut = substr($texte, 0, $p);
364
		$texte = substr($texte, $p+strlen($m[0]));
365
		if ($p)
366
			$res = phraser_inclure($debut, $ligne, $res);
367
		$ligne += substr_count($debut, "\n");
368
		$res[] = $nested[$m[1]];
369
	}
370
371
	return (($texte==='') ? $res : phraser_inclure($texte, $ligne, $res));
372
}
373
374
// http://doc.spip.org/@phraser_champs_interieurs
375
function phraser_champs_interieurs($texte, $ligne, $sep, $result){
376
	$i = 0; // en fait count($result)
377
	$x = "";
378
379
	while (true){
380
		$j = $i;
381
		$n = $ligne;
382
		while (preg_match(CHAMP_ETENDU, $texte, $match)){
383
			$p = strpos($texte, $match[0]);
384
			$debut = substr($texte, 0, $p);
385
			if ($p){
386
				$result[$i] = $debut;
387
				$i++;
388
			}
389
			$nom = $match[4];
390
			$champ = new Champ;
391
			// ca ne marche pas encore en cas de champ imbrique
392
			$champ->ligne = $x ? 0 : ($n+substr_count($debut, "\n"));
393
			$champ->nom_boucle = $match[3];
394
			$champ->nom_champ = $nom;
395
			$champ->etoile = $match[6];
396
			// phraser_args indiquera ou commence apres
397
			$result = phraser_args($match[7], ")", $sep, $result, $champ);
398
			phraser_vieux($champ);
399
			$champ->avant =
400
				phraser_champs_exterieurs($match[1], $n, $sep, $result);
401
			$debut = substr($champ->apres, 1);
402 View Code Duplication
			if (!empty($debut)){
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...
403
				$n += substr_count(substr($texte, 0, strpos($texte, $debut)), "\n");
404
			}
405
			$champ->apres = phraser_champs_exterieurs($debut, $n, $sep, $result);
406
407
			$result[$i] = $champ;
408
			$i++;
409
			$texte = substr($texte, $p+strlen($match[0]));
410
		}
411
		if ($texte!==""){
412
			$result[$i] = $texte;
413
			$i++;
414
		}
415
		$x = '';
416
417
		while ($j<$i){
418
			$z = $result[$j];
419
			// j'aurais besoin de connaitre le nombre de lignes...
420
			if (is_object($z))
421
				$x .= "%$sep$j@";
422
			else
423
				$x .= $z;
424
			$j++;
425
		}
426
		if (preg_match(CHAMP_ETENDU, $x))
427
			$texte = $x;
428
		else
429
			return phraser_champs_exterieurs($x, $ligne, $sep, $result);
430
	}
431
}
432
433
function phraser_vieux(&$champ){
434
	$nom = $champ->nom_champ;
435
	if ($nom=='EMBED_DOCUMENT'){
436
		if (!function_exists('phraser_vieux_emb'))
437
			include_spip('public/normaliser');
438
		phraser_vieux_emb($champ);
439
	} elseif ($nom=='EXPOSER') {
440
		if (!function_exists('phraser_vieux_exposer'))
441
			include_spip('public/normaliser');
442
		phraser_vieux_exposer($champ);
443
	} elseif ($champ->param) {
444
		if ($nom=='FORMULAIRE_RECHERCHE'){
445
			if (!function_exists('phraser_vieux_recherche'))
446
				include_spip('public/normaliser');
447
			phraser_vieux_recherche($champ);
448
		} elseif (preg_match(",^LOGO_[A-Z]+,", $nom)) {
449
			if (!function_exists('phraser_vieux_logos'))
450
				include_spip('public/normaliser');
451
			phraser_vieux_logos($champ);
452
		} elseif ($nom=='MODELE') {
453
			if (!function_exists('phraser_vieux_modele'))
454
				include_spip('public/normaliser');
455
			phraser_vieux_modele($champ);
456
		} elseif ($nom=='INCLURE' OR $nom=='INCLUDE') {
457
			if (!function_exists('phraser_vieux_inclu'))
458
				include_spip('public/normaliser');
459
			phraser_vieux_inclu($champ);
460
		}
461
	}
462
}
463
464
465
/**
466
 * Analyse les critères de boucle
467
 *
468
 * Chaque paramètre de la boucle (tel que {id_article>3}) est analysé
469
 * pour construire un critère (objet Critere) de boucle.
470
 *
471
 * Un critère a une description plus fine que le paramètre original
472
 * car on en extrait certaines informations tel que la n'égation et l'opérateur
473
 * utilisé s'il y a.
474
 *
475
 * La fonction en profite pour déclarer des modificateurs de boucles
476
 * en présence de certains critères (tout, plat) ou initialiser des
477
 * variables de compilation (doublons)...
478
 *
479
 * @param array $params
480
 *     Tableau de description des paramètres passés à la boucle.
481
 *     Chaque paramètre deviendra un critère
482
 * @param Boucle $result
483
 *     Description de la boucle
484
 *     Elle sera complété de la liste de ses critères
485
 * @return void
486
 **/
487
function phraser_criteres($params, &$result){
488
489
	$err_ci = ''; // indiquera s'il y a eu une erreur
490
	$args = array();
491
	$type = $result->type_requete;
492
	$doublons = array();
493
	foreach ($params as $v){
494
		$var = $v[1][0];
495
		$param = ($var->type!='texte') ? "" : $var->texte;
496
		if ((count($v)>2) && (!preg_match(",[^A-Za-z]IN[^A-Za-z],i", $param))){
497
// plus d'un argument et pas le critere IN:
498
// detecter comme on peut si c'est le critere implicite LIMIT debut, fin
499
500
			if ($var->type!='texte'
501
				OR preg_match("/^(n|n-|(n-)?\d+)$/S", $param)
502
			){
503
				$op = ',';
504
				$not = "";
505
			} else {
506
				// Le debut du premier argument est l'operateur
507
				preg_match("/^([!]?)([a-zA-Z][a-zA-Z0-9_]*)[[:space:]]*(\??)[[:space:]]*(.*)$/ms", $param, $m);
508
				$op = $m[2];
509
				$not = $m[1];
510
				$cond = $m[3];
511
				// virer le premier argument,
512
				// et mettre son reliquat eventuel
513
				// Recopier pour ne pas alterer le texte source
514
				// utile au debusqueur
515
				if ($m[4]){
516
					// une maniere tres sale de supprimer les "' autour de {critere "xxx","yyy"}
517
					if (preg_match(',^(["\'])(.*)\1$,', $m[4])){
518
						$c = null;
519
						eval ('$c = ' . $m[4] . ';');
520
						if (isset($c))
521
							$m[4] = $c;
522
					}
523
					$texte = new Texte;
524
					$texte->texte = $m[4];
525
					$v[1][0] = $texte;
526
				} else array_shift($v[1]);
527
			}
528
			array_shift($v); // $v[O] est vide
529
			$crit = new Critere;
530
			$crit->op = $op;
531
			$crit->not = $not;
532
			$crit->cond = $cond;
0 ignored issues
show
Bug introduced by
The property cond does not seem to exist in Critere.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The variable $cond 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...
533
			$crit->exclus = "";
534
			$crit->param = $v;
535
			$args[] = $crit;
536
		} else {
537
			if ($var->type!='texte'){
538
				// cas 1 seul arg ne commencant pas par du texte brut:
539
				// erreur ou critere infixe "/"
540
				if (($v[1][1]->type!='texte') || (trim($v[1][1]->texte)!='/')){
541
					$err_ci = array('zbug_critere_inconnu',
542
						array('critere' => $var->nom_champ));
543
					erreur_squelette($err_ci, $result);
544
				} else {
545
					$crit = new Critere;
546
					$crit->op = '/';
547
					$crit->not = "";
548
					$crit->exclus = "";
549
					$crit->param = array(array($v[1][0]), array($v[1][2]));
550
					$args[] = $crit;
551
				}
552
			} else {
553
				// traiter qq lexemes particuliers pour faciliter la suite
554
				// les separateurs
555
				if ($var->apres)
556
					$result->separateur[] = $param;
557
				elseif (($param=='tout') OR ($param=='tous'))
558
					$result->modificateur['tout'] = true;
559
				elseif ($param=='plat')
560
					$result->modificateur['plat'] = true;
561
562
				// Boucle hierarchie, analyser le critere id_rubrique
563
				// et les autres critères {id_x} pour forcer {tout} sur
564
				// ceux-ci pour avoir la rubrique mere...
565
				// Les autres critères de la boucle hierarchie doivent être
566
				// traités normalement.
567
				elseif (strcasecmp($type, 'hierarchie')==0
568
					AND !preg_match(",^id_rubrique\b,", $param)
569
					AND preg_match(",^id_\w+\s*$,", $param)
570
				) {
571
					$result->modificateur['tout'] = true;
572
				} elseif (strcasecmp($type, 'hierarchie')==0 AND $param=="id_rubrique") {
573
					// rien a faire sur {id_rubrique} tout seul
574
				} else {
575
					// pas d'emplacement statique, faut un dynamique
576
					/// mais il y a 2 cas qui ont les 2 !
577
					if (($param=='unique') || (preg_match(',^!?doublons *,', $param))){
578
						// cette variable sera inseree dans le code
579
						// et son nom sert d'indicateur des maintenant
580
						$result->doublons = '$doublons_index';
581
						if ($param=='unique') $param = 'doublons';
582
					} elseif ($param=='recherche')
583
						// meme chose (a cause de #nom_de_boucle:URL_*)
584
						$result->hash = ' ';
585
					if (preg_match(',^ *([0-9-]+) *(/) *(.+) *$,', $param, $m)){
586
						$crit = phraser_critere_infixe($m[1], $m[3], $v, '/', '', '');
587
					} elseif (preg_match(',^([!]?)(' . CHAMP_SQL_PLUS_FONC .
588
						')[[:space:]]*(\??)(!?)(<=?|>=?|==?|\b(?:IN|LIKE)\b)(.*)$,is', $param, $m)) {
589
						$a2 = trim($m[8]);
590
						if ($a2 AND ($a2[0]=="'" OR $a2[0]=='"') AND ($a2[0]==substr($a2, -1)))
591
							$a2 = substr($a2, 1, -1);
592
						$crit = phraser_critere_infixe($m[2], $a2, $v,
593
							(($m[2]=='lang_select') ? $m[2] : $m[7]),
594
							$m[6], $m[5]);
595
						$crit->exclus = $m[1];
596
					} elseif (preg_match("/^([!]?)\s*(" .
597
						CHAMP_SQL_PLUS_FONC .
598
						")\s*(\??)(.*)$/is", $param, $m)) {
599
						// contient aussi les comparaisons implicites !
600
						// Comme ci-dessus:
601
						// le premier arg contient l'operateur
602
						array_shift($v);
603
						if ($m[6]){
604
							$v[0][0] = new Texte;
605
							$v[0][0]->texte = $m[6];
606
						} else {
607
							array_shift($v[0]);
608
							if (!$v[0]) array_shift($v);
609
						}
610
						$crit = new Critere;
611
						$crit->op = $m[2];
612
						$crit->param = $v;
613
						$crit->not = $m[1];
614
						$crit->cond = $m[5];
615
					} else {
616
						$err_ci = array('zbug_critere_inconnu',
617
							array('critere' => $param));
618
						erreur_squelette($err_ci, $result);
619
					}
620
					if ((!preg_match(',^!?doublons *,', $param)) || $crit->not)
0 ignored issues
show
Bug Best Practice introduced by
The expression $crit->not of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
621
						$args[] = $crit;
0 ignored issues
show
Bug introduced by
The variable $crit 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...
622
					else
623
						$doublons[] = $crit;
624
				}
625
			}
626
		}
627
	}
628
	// les doublons non nies doivent etre le dernier critere
629
	// pour que la variable $doublon_index ait la bonne valeur
630
	// cf critere_doublon
631
	if ($doublons) $args = array_merge($args, $doublons);
0 ignored issues
show
Bug Best Practice introduced by
The expression $doublons 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...
632
	// Si erreur, laisser la chaine dans ce champ pour le HTTP 503
633
	if (!$err_ci) $result->criteres = $args;
0 ignored issues
show
Documentation Bug introduced by
It seems like $args of type array is incompatible with the declared type array<integer,object<Critere>> of property $criteres.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
634
}
635
636
// http://doc.spip.org/@phraser_critere_infixe
637
function phraser_critere_infixe($arg1, $arg2, $args, $op, $not, $cond){
638
	$args[0] = new Texte;
639
	$args[0]->texte = $arg1;
640
	$args[0] = array($args[0]);
641
	$args[1][0] = new Texte;
642
	$args[1][0]->texte = $arg2;
643
	$crit = new Critere;
644
	$crit->op = $op;
645
	$crit->not = $not;
646
	$crit->cond = $cond;
0 ignored issues
show
Bug introduced by
The property cond does not seem to exist in Critere.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
647
	$crit->param = $args;
648
649
	return $crit;
650
}
651
652
function public_phraser_html_dist($texte, $id_parent, &$boucles, $descr, $ligne = 1){
653
654
	$all_res = array();
655
656
	while (($pos_boucle = strpos($texte, BALISE_BOUCLE))!==false){
657
658
		$err_b = ''; // indiquera s'il y a eu une erreur
659
		$result = new Boucle;
660
		$result->id_parent = $id_parent;
661
		$result->descr = $descr;
662
# attention: reperer la premiere des 2 balises: pre_boucle ou boucle
663
664
		if (!preg_match("," . BALISE_PRE_BOUCLE . '[0-9_],', $texte, $r)
665
			OR ($n = strpos($texte, $r[0]))===false
666
			OR ($n>$pos_boucle)
667
		){
668
			$debut = substr($texte, 0, $pos_boucle);
669
			$milieu = substr($texte, $pos_boucle);
670
			$k = strpos($milieu, '(');
671
			$id_boucle = trim(substr($milieu,
672
				strlen(BALISE_BOUCLE),
673
				$k-strlen(BALISE_BOUCLE)));
674
			$milieu = substr($milieu, $k);
675
676
		} else {
677
			$debut = substr($texte, 0, $n);
678
			$milieu = substr($texte, $n);
679
			$k = strpos($milieu, '>');
680
			$id_boucle = substr($milieu,
681
				strlen(BALISE_PRE_BOUCLE),
682
				$k-strlen(BALISE_PRE_BOUCLE));
683
684
			if (!preg_match("," . BALISE_BOUCLE . $id_boucle . "[[:space:]]*\(,", $milieu, $r)){
685
				$err_b = array('zbug_erreur_boucle_syntaxe', array('id' => $id_boucle));
686
				erreur_squelette($err_b, $result);
687
				$texte = substr($texte, $n+1);
688
				continue;
689
			} else {
690
				$pos_boucle = $n;
0 ignored issues
show
Unused Code introduced by
$pos_boucle 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...
691
				$n = strpos($milieu, $r[0]);
692
				$result->avant = substr($milieu, $k+1, $n-$k-1);
693
				$milieu = substr($milieu, $n+strlen($id_boucle)+strlen(BALISE_BOUCLE));
694
			}
695
		}
696
		$result->id_boucle = $id_boucle;
697
698
		preg_match(SPEC_BOUCLE, $milieu, $match);
699
		$result->type_requete = $match[0];
700
		$milieu = substr($milieu, strlen($match[0]));
701
		$type = $match[1];
702
		$jointures = trim($match[2]);
703
		$table_optionnelle = ($match[3]);
704
		if ($jointures){
705
			// on affecte pas ici les jointures explicites, mais dans la compilation
706
			// ou elles seront completees des jointures declarees
707
			$result->jointures_explicites = $jointures;
708
		}
709
710
		if ($table_optionnelle){
711
			$result->table_optionnelle = $type;
0 ignored issues
show
Documentation Bug introduced by
The property $table_optionnelle was declared of type boolean, but $type is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
712
		}
713
714
		// 1ere passe sur les criteres, vu comme des arguments sans fct
715
		// Resultat mis dans result->param
716
		phraser_args($milieu, "/>", "", $all_res, $result);
717
718
		// En 2e passe result->criteres contiendra un tableau
719
		// pour l'instant on met le source (chaine) :
720
		// si elle reste ici au final, c'est qu'elle contient une erreur
721
		$result->criteres = substr($milieu, 0, @strpos($milieu, $result->apres));
722
		$milieu = $result->apres;
723
		$result->apres = "";
724
725
		//
726
		// Recuperer la fin :
727
		//
728
		if ($milieu[0]==='/'){
729
			$suite = substr($milieu, 2);
730
			$milieu = '';
731
		} else {
732
			$milieu = substr($milieu, 1);
733
			$s = BALISE_FIN_BOUCLE . $id_boucle . ">";
734
			$p = strpos($milieu, $s);
735
			if ($p===false){
736
				$err_b = array('zbug_erreur_boucle_fermant',
737
					array('id' => $id_boucle));
738
				erreur_squelette($err_b, $result);
739
			}
740
741
			$suite = substr($milieu, $p+strlen($s));
742
			$milieu = substr($milieu, 0, $p);
743
		}
744
745
		$result->milieu = $milieu;
746
747
		//
748
		// 1. Recuperer la partie conditionnelle apres
749
		//
750
		$s = BALISE_POST_BOUCLE . $id_boucle . ">";
751
		$p = strpos($suite, $s);
752 View Code Duplication
		if ($p!==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...
753
			$result->apres = substr($suite, 0, $p);
754
			$suite = substr($suite, $p+strlen($s));
755
		}
756
757
		//
758
		// 2. Recuperer la partie alternative
759
		//
760
		$s = BALISE_ALT_BOUCLE . $id_boucle . ">";
761
		$p = strpos($suite, $s);
762 View Code Duplication
		if ($p!==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...
763
			$result->altern = substr($suite, 0, $p);
764
			$suite = substr($suite, $p+strlen($s));
765
		}
766
		$result->ligne = $ligne+substr_count($debut, "\n");
767
		$m = substr_count($milieu, "\n");
768
		$b = substr_count($result->avant, "\n");
769
		$a = substr_count($result->apres, "\n");
770
771 View Code Duplication
		if ($p = strpos($type, ':')){
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...
772
			$result->sql_serveur = substr($type, 0, $p);
773
			$type = substr($type, $p+1);
774
		}
775
		$soustype = strtolower($type);
776
777
		if (!isset($GLOBALS["table_des_tables"][$soustype]))
778
			$soustype = $type;
779
780
		$result->type_requete = $soustype;
781
		// Lancer la 2e passe sur les criteres si la 1ere etait bonne
782
		if (!is_array($result->param))
783
			$err_b = true;
784
		else {
785
			phraser_criteres($result->param, $result);
786
			if (strncasecmp($soustype, TYPE_RECURSIF, strlen(TYPE_RECURSIF))==0){
787
				$result->type_requete = TYPE_RECURSIF;
788
				$args = $result->param;
789
				array_unshift($args,
790
					substr($type, strlen(TYPE_RECURSIF)));
791
				$result->param = $args;
792
			}
793
		}
794
795
		$result->avant = public_phraser_html_dist($result->avant, $id_parent, $boucles, $descr, $result->ligne);
796
		$result->apres = public_phraser_html_dist($result->apres, $id_parent, $boucles, $descr, $result->ligne+$b+$m);
797
		$result->altern = public_phraser_html_dist($result->altern, $id_parent, $boucles, $descr, $result->ligne+$a+$m+$b);
798
		$result->milieu = public_phraser_html_dist($milieu, $id_boucle, $boucles, $descr, $result->ligne+$b);
799
800
		// Prevenir le generateur de code que le squelette est faux
801
		if ($err_b) $result->type_requete = false;
802
803
		// Verifier qu'il n'y a pas double definition
804
		// apres analyse des sous-parties (pas avant).
805
806
		if (isset($boucles[$id_boucle])){
807
			$err_b_d = array('zbug_erreur_boucle_double',
808
				array('id' => $id_boucle));
809
			erreur_squelette($err_b_d, $result);
810
			// Prevenir le generateur de code que le squelette est faux
811
			$boucles[$id_boucle]->type_requete = false;
812
		} else
813
			$boucles[$id_boucle] = $result;
814
		$all_res = phraser_champs_etendus($debut, $ligne, $all_res);
815
		$all_res[] = &$boucles[$id_boucle];
816 View Code Duplication
		if (!empty($suite)){
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...
817
			$ligne += substr_count(substr($texte, 0, strpos($texte, $suite)), "\n");
818
		}
819
		$texte = $suite;
820
	}
821
822
	return phraser_champs_etendus($texte, $ligne, $all_res);
823
}
824
825
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
826