Completed
Push — spip-2.1 ( b6b097 )
by cam
42:28 queued 30:44
created

criteres.php ➔ critere_parinverse()   F

Complexity

Conditions 28
Paths 2316

Size

Total Lines 98
Code Lines 72

Duplication

Lines 13
Ratio 13.27 %

Importance

Changes 0
Metric Value
cc 28
eloc 72
nc 2316
nop 4
dl 13
loc 98
rs 2
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-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
// Definition des {criteres} d'une boucle
15
//
16
17
// Une Regexp reperant une chaine produite par le compilateur,
18
// souvent utilisee pour faire de la concatenation lors de la compilation
19
// plutot qu'a l'execution, i.e. pour remplacer 'x'.'y' par 'xy'
20
21
define('_CODE_QUOTE', ",^(\n//[^\n]*\n)? *'(.*)' *$,");
22
23
if (!defined('_ECRIRE_INC_VERSION')) return;
24
25
// {racine}
26
// http://www.spip.net/@racine
27
// http://doc.spip.org/@critere_racine_dist
28
function critere_racine_dist($idb, &$boucles, $crit) {
29
	global $exceptions_des_tables;
30
	$not = $crit->not;
31
	$boucle = &$boucles[$idb];
32
	$id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
33
		$exceptions_des_tables[$boucle->id_table]['id_parent'] :
34
		'id_parent';
35
36
	if ($not)
37
		return (array('zbug_critere_inconnu', array('critere' => $not . $crit->op)));
38
39
	$boucle->where[]= array("'='", "'$boucle->id_table." . "$id_parent'", 0);
40
}
41
42
// {exclus}
43
// http://www.spip.net/@exclus
44
// http://doc.spip.org/@critere_exclus_dist
45
function critere_exclus_dist($idb, &$boucles, $crit) {
46
	$not = $crit->not;
47
	$boucle = &$boucles[$idb];
48
	$id = $boucle->primary;
49
50 View Code Duplication
	if ($not OR !$id)
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...
51
		return (array('zbug_critere_inconnu', array('critere' => $not . $crit->op)));
52
	$arg = kwote(calculer_argument_precedent($idb, $id, $boucles));
53
	$boucle->where[]= array("'!='", "'$boucle->id_table." . "$id'", $arg);
54
}
55
56
// {doublons} ou {unique}
57
// http://www.spip.net/@doublons
58
// attention: boucle->doublons designe une variable qu'on affecte
59
// http://doc.spip.org/@critere_doublons_dist
60
function critere_doublons_dist($idb, &$boucles, $crit) {
61
	$boucle = &$boucles[$idb];
62
	$primary = $boucle->primary;
63
	$type = $boucle->type_requete;
64
	// Dans le cas NOT, la table du doublon peut etre indiquee
65
	// si la table courante a un champ homonyme de sa cle primaire.
66
	// Tres utile pour la table des forums.
67
	if (isset($crit->param[1])) {
68
	  $primary = '';
69
	  $x = !$crit->not ? '' : calculer_liste($crit->param[1], array(), $boucles, $boucle->id_parent);
70
	  # attention au commentaire "// x signes" qui precede
71
	  if (preg_match(",^(?:\s*//[^\n]*\n)?'([^']+)'*$,ms", $x, $m))  {
72
	    $x = id_table_objet($type = $m[1]);
73
	    if (isset($boucle->show['field'][$x]))
74
	      $primary = $x; // sinon erreur declenchee ci-dessous
75
	  }
76
	}
77
78
	if (!$primary OR strpos($primary,',')) {
79
		return (array('zbug_doublon_sur_table_sans_cle_primaire'));
80
	}
81
	$not = ($crit->not ? '' : 'NOT');
82
	$nom = !isset($crit->param[0]) ? "''" : calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
83
	// mettre un tableau pour que ce ne soit pas vu comme une constante
84
85
	$nom = "'" . $type .  "'" .  ($nom == "''" ? '' : " . $nom");
86
87
	$debutdoub = '$doublons['
88
	.  (!$not ? '' : ($boucle->doublons . "[]= "));
89
90
	$findoub = "($nom)]"; 
91
92
	$debin = "sql_in('" . $boucle->id_table . '.' . $primary . "', ";
93
94
	$suitin = $debin . $debutdoub;
95
96
	// si autre critere doublon, fusionner pour avoir un seul In
97
	foreach ($boucle->where as $k => $w) {
98
		if (strpos($w[0], $suitin) ===0) {
99
			$boucle->where[$k][0] = $debin . $debutdoub . $findoub . ' . ' . substr($w[0],strlen($debin));
100
			return;
101
		}
102
	}
103
	$boucle->where[]= array($suitin . $findoub . ", '" . $not . "')");
104
105
# la ligne suivante avait l'intention d'eviter une collecte deja faite
106
# mais elle fait planter une boucle a 2 critere doublons:
107
# {!doublons A}{doublons B}
108
# (de http://article.gmane.org/gmane.comp.web.spip.devel/31034)
109
#	if ($crit->not) $boucle->doublons = "";
110
}
111
112
// {lang_select}
113
// http://www.spip.net/@lang_select
114
// http://doc.spip.org/@critere_lang_select_dist
115
function critere_lang_select_dist($idb, &$boucles, $crit) {
116
	if (!($param = $crit->param[1][0]->texte)) $param = 'oui';
117
	if ($crit->not)	$param = ($param=='oui') ? 'non' : 'oui';
118
	$boucle = &$boucles[$idb];
119
	$boucle->lang_select = $param;
120
}
121
122
// {debut_xxx}
123
// http://www.spip.net/@debut_
124
// http://doc.spip.org/@critere_debut_dist
125
function critere_debut_dist($idb, &$boucles, $crit) {
126
	list($un, $deux) = $crit->param;
127
	$un = $un[0]->texte;
128
	$deux = $deux[0]->texte;
129
	if ($deux) {
130
		$boucles[$idb]->limit = 'intval($Pile[0]["debut' .
131
		  $un .
132
		  '"]) . ",' .
133
		  $deux .
134
		  '"' ;
135
	} else calculer_critere_DEFAUT_dist($idb, $boucles, $crit);
136
}
137
138
// {pagination}
139
// {pagination 20}
140
// {pagination #ENV{pages,5}} etc
141
// {pagination 20 #ENV{truc,chose}} pour utiliser la variable debut_#ENV{truc,chose}
142
// http://www.spip.net/@pagination
143
// http://doc.spip.org/@critere_pagination_dist
144
function critere_pagination_dist($idb, &$boucles, $crit) {
145
146
	$boucle = &$boucles[$idb];
147
	// definition de la taille de la page
148
	$pas = !isset($crit->param[0][0]) ? "''" : calculer_liste(array($crit->param[0][0]), array(), $boucles, $boucle->id_parent);
149
150
	if (!preg_match(_CODE_QUOTE, $pas, $r)) {
151
		$pas = "((\$a = intval($pas)) ? \$a : 10)";
152
	} else {
153
		$r = intval($r[2]);
154
		$pas = strval($r ? $r : 10);
155
	}
156
	$type = !isset($crit->param[0][1]) ? "'$idb'" : calculer_liste(array($crit->param[0][1]), array(), $boucles, $boucle->id_parent);
157
	$debut = ($type[0]!=="'") ? "'debut'.$type" 
158
	  : ("'debut" .substr($type,1));
159
160
	$boucle->modificateur['debut_nom'] = $type;
161
	$partie =
162
		 // tester si le numero de page demande est de la forme '@yyy'
163
		 'isset($Pile[0]['.$debut.']) ? $Pile[0]['.$debut.'] : _request('.$debut.");\n"
164
		."\tif(substr(\$debut_boucle,0,1)=='@'){\n"
165
		."\t\t".'$debut_boucle = $Pile[0]['. $debut.'] = quete_debut_pagination(\''.$boucle->primary.'\',$Pile[0][\'@'.$boucle->primary.'\'] = substr($debut_boucle,1),'.$pas.',$result,'._q($boucle->sql_serveur).');'."\n"
166
		."\t\t".'if (!sql_seek($result,0,'._q($boucle->sql_serveur).")){\n"
167
		."\t\t\t".'@sql_free($result,'._q($boucle->sql_serveur).");\n"
168
		."\t\t\t".'$result = calculer_select($select, $from, $type, $where, $join, $groupby, $orderby, $limit, $having, $table, $id, $connect);'."\n"
169
		."\t\t}\n"
170
		."\t}\n"
171
		."\t".'$debut_boucle = intval($debut_boucle)';
172
173
174
	$boucle->total_parties = $pas;
175
	calculer_parties($boucles, $idb, $partie, 'p+');
176
	// ajouter la cle primaire dans le select pour pouvoir gerer la pagination referencee par @id
177
	// sauf si pas de primaire, ou si primaire composee
178
	// dans ce cas, on ne sait pas gerer une pagination indirecte
179
	$t = $boucle->id_table . '.' . $boucle->primary;
180
	if ($boucle->primary
181
		AND !preg_match('/[,\s]/',$boucle->primary)
182
		AND !in_array($t, $boucle->select))
183
	  $boucle->select[]= $t;
184
}
185
186
187
// {recherche} ou {recherche susan}
188
// http://www.spip.net/@recherche
189
// http://doc.spip.org/@critere_recherche_dist
190
function critere_recherche_dist($idb, &$boucles, $crit) {
191
192
	$boucle = &$boucles[$idb];
193
194 View Code Duplication
	if (isset($crit->param[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...
195
		$quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
196
	else
197
		$quoi = '@$Pile[0]["recherche"]';
198
199
	// indiquer si l'on est dans une boucle forum avec le critère {plat} ou {tout}
200
	$plat = "false" ;
201
	if (isset($boucle->modificateur['tout']) OR isset($boucle->modificateur['plat'])) {
202
		$plat = "true" ;
203
	}	
204
		
205
	$boucle->hash .= '
206
	// RECHERCHE
207
	$prepare_recherche = charger_fonction(\'prepare_recherche\', \'inc\');
208
	list($rech_select, $rech_where) = $prepare_recherche('.$quoi.', "'.$boucle->id_table.'", "'.$crit->cond.'","' . $boucle->sql_serveur . '", "'.$plat.'");
209
	';
210
211
	$t = $boucle->id_table . '.' . $boucle->primary;
212
	if (!in_array($t, $boucles[$idb]->select))
213
	  $boucle->select[]= $t; # pour postgres, neuneu ici
214
	$boucle->join['resultats']=array("'".$boucle->id_table."'","'id'","'".$boucle->primary."'");
215
	$boucle->from['resultats']='spip_resultats';
216
	$boucle->select[]= '$rech_select';
217
	//$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";
218
219
	// et la recherche trouve
220
	$boucle->where[]= '$rech_where?$rech_where:\'\'';
221
}
222
223
// {traduction}
224
// http://www.spip.net/@traduction
225
//   (id_trad>0 AND id_trad=id_trad(precedent))
226
//    OR id_article=id_article(precedent)
227
// http://doc.spip.org/@critere_traduction_dist
228
function critere_traduction_dist($idb, &$boucles, $crit) {
0 ignored issues
show
Unused Code introduced by
The parameter $crit 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...
229
	$boucle = &$boucles[$idb];
230
	$prim = $boucle->primary;
231
	$table = $boucle->id_table;
232
	$arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles));
233
	$dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles));
234
	$boucle->where[]=
235
		array("'OR'",
236
			array("'AND'",
237
				array("'='", "'$table.id_trad'", 0),
238
				array("'='", "'$table.$prim'", $dprim)
239
			),
240
			array("'AND'",
241
				array("'>'", "'$table.id_trad'", 0),
242
				array("'='", "'$table.id_trad'", $arg)
243
			)
244
		);
245
}
246
247
// {origine_traduction}
248
//   (id_trad>0 AND id_article=id_trad) OR (id_trad=0)
249
// http://www.spip.net/@origine_traduction
250
// http://doc.spip.org/@critere_origine_traduction_dist
251
function critere_origine_traduction_dist($idb, &$boucles, $crit) {
252
	$boucle = &$boucles[$idb];
253
	$prim = $boucle->primary;
254
	$table = $boucle->id_table;
255
256
	$c =
257
	array("'OR'",
258
		array("'='", "'$table." . "id_trad'", "'$table.$prim'"),
259
		array("'='", "'$table.id_trad'", "'0'")
260
	);
261
	$boucle->where[]= ($crit->not ? array("'NOT'", $c) : $c);
262
}
263
264
// {meme_parent}
265
// http://www.spip.net/@meme_parent
266
// http://doc.spip.org/@critere_meme_parent_dist
267
function critere_meme_parent_dist($idb, &$boucles, $crit) {
0 ignored issues
show
Unused Code introduced by
The parameter $crit 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...
268
	global $exceptions_des_tables;
269
	$boucle = &$boucles[$idb];
270
	$arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
271
	$id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
272
		$exceptions_des_tables[$boucle->id_table]['id_parent'] :
273
		'id_parent';
274
	$mparent = $boucle->id_table . '.' . $id_parent;
275
276
	if ($boucle->type_requete == 'rubriques' OR isset($exceptions_des_tables[$boucle->id_table]['id_parent'])) {
277
		$boucle->where[]= array("'='", "'$mparent'", $arg);
278
279
	} else if ($boucle->type_requete == 'forums') {
280
			$boucle->where[]= array("'='", "'$mparent'", $arg);
281
			$boucle->where[]= array("'>'", "'$mparent'", 0);
282
			$boucle->modificateur['plat'] = true;
283
	} else erreur_squelette(_T('zbug_info_erreur_squelette'), "{meme_parent} BOUCLE$idb");
284
}
285
286
// {branche ?}
287
// http://www.spip.net/@branche
288
// http://doc.spip.org/@critere_branche_dist
289
function critere_branche_dist($idb, &$boucles, $crit) {
290
291
	$not = $crit->not;
292
	$boucle = &$boucles[$idb];
293
	$arg = calculer_argument_precedent($idb, 'id_rubrique', $boucles);
294
295
	//Trouver une jointure
296
	$desc = $boucle->show;
297
	//Seulement si necessaire
298
	if (!array_key_exists('id_rubrique', $desc['field'])) {
299
		$cle = trouver_jointure_champ('id_rubrique', $boucle);
300
	} else $cle = $boucle->id_table;
301
302
	$c = "sql_in('$cle" . ".id_rubrique', calcul_branche_in($arg)"
303
	  . ($not ? ", 'NOT'" : '') . ")";
304
	$boucle->where[]= !$crit->cond ? $c :
305
	  ("($arg ? $c : " . ($not ? "'0=1'" : "'1=1'") .')');
306
}
307
308
// {logo} liste les objets qui ont un logo
309
// http://doc.spip.org/@critere_logo_dist
310
function critere_logo_dist($idb, &$boucles, $crit) {
311
312
	$not = $crit->not;
313
	$boucle = &$boucles[$idb];
314
315
	$c = "sql_in('" .
316
	  $boucle->id_table . '.' . $boucle->primary
317
	  . "', lister_objets_avec_logos('". $boucle->primary ."'), '')";
318
	if ($crit->cond) $c = "($arg ? $c : 1)";
0 ignored issues
show
Bug introduced by
The variable $arg does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
319
320
	if ($not)
321
		$boucle->where[]= array("'NOT'", $c);
322
	else
323
		$boucle->where[]= $c;
324
}
325
326
// c'est la commande SQL "GROUP BY"
327
// par exemple <boucle(articles){fusion lang}>
328
// http://doc.spip.org/@critere_fusion_dist
329
function critere_fusion_dist($idb,&$boucles, $crit) {
330
	if ($t = isset($crit->param[0])) {
331
		$t = $crit->param[0];
332
		if ($t[0]->type == 'texte') {
333
			$t = $t[0]->texte;
334 View Code Duplication
			if (preg_match("/^(.*)\.(.*)$/", $t, $r)) {
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...
335
				$t = table_objet_sql($r[1]);
336
				$t = array_search($t, $boucles[$idb]->from);
337
				if ($t) $t .= '.' . $r[2];
338
			}
339
		} else { $t = '".'
340
		    . calculer_critere_arg_dynamique($idb, $boucles, $t)
341
		    . '."';
342
		}
343
	}
344
	if ($t) {
345
		$boucles[$idb]->group[] = $t; 
346 View Code Duplication
		if (!in_array($t, $boucles[$idb]->select))
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...
347
		    $boucles[$idb]->select[] = $t;
348
	} else 
349
		return (array('zbug_critere_inconnu', array('critere' => $crit->op . ' ?')));
350
}
351
352
// c'est la commande SQL "COLLATE"
353
// qui peut etre appliquee sur les order by, group by, where like ...
354
// http://doc.spip.org/@critere_collecte_dist
355
function critere_collecte_dist($idb,&$boucles, $crit) {
356
	if (isset($crit->param[0])) {
357
		$_coll = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
358
		$boucle = $boucles[$idb];
359
		$boucle->modificateur['collate'] = "($_coll ?' COLLATE '.$_coll:'')";
360
    $n = count($boucle->order);
361
    if ($n && (strpos($boucle->order[$n-1],'COLLATE')===false))
362
    	$boucle->order[$n-1] .= " . " . $boucle->modificateur['collate'];
363
	} else
364
		return (array('zbug_critere_inconnu', array('critere' => $crit->op . " $n")));
0 ignored issues
show
Bug introduced by
The variable $n seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
365
}
366
367
// http://doc.spip.org/@calculer_critere_arg_dynamique
368
function calculer_critere_arg_dynamique($idb, &$boucles, $crit, $suffix='')
369
{
370
	$boucle = $boucles[$idb];
371
	$alt = "('" . $boucle->id_table . '.\' . $x' . $suffix . ')';
372
	$var = '$champs_' . $idb;
373
	$desc = (strpos($boucle->in, "static $var =") !== false);
374
	if (!$desc) {
375
		$desc = $boucle->show['field'];
376
		$desc = implode(',',array_map('_q',array_keys($desc)));
377
		$boucles[$idb]->in .= "\n\tstatic $var = array(" . $desc .");";
378
	}
379
	if ($desc) $alt = "(in_array(\$x, $var)  ? $alt :(\$x$suffix))";
380
	$arg = calculer_liste($crit, array(), $boucles, $boucle->id_parent);
381
	return	"((\$x = preg_replace(\"/\\W/\",'', $arg)) ? $alt : '')";
382
}
383
// Tri : {par xxxx}
384
// http://www.spip.net/@par
385
// http://doc.spip.org/@critere_par_dist
386
function critere_par_dist($idb, &$boucles, $crit) {
387
	return critere_parinverse($idb, $boucles, $crit) ;
388
}
389
390
// http://doc.spip.org/@critere_parinverse
391
function critere_parinverse($idb, &$boucles, $crit, $sens='') {
392
	global $exceptions_des_jointures;
393
	$boucle = &$boucles[$idb];
394
	if ($crit->not) $sens = $sens ? "" : " . ' DESC'";
395
	$collecte = (isset($boucle->modificateur['collecte']))?" . ".$boucle->modificateur['collecte']:"";
396
397
	foreach ($crit->param as $tri) {
398
399
	  $order = $fct = ""; // en cas de fonction SQL
0 ignored issues
show
Unused Code introduced by
$order 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...
400
	// tris specifies dynamiquement
401
	  if ($tri[0]->type != 'texte') {
402
	  	// calculer le order dynamique qui verifie les champs
403
			$order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
404
			// et si ce n'est fait, ajouter un champ 'hasard' 
405
			// pour supporter 'hasard' comme tri dynamique
406
			$par = "rand()";
407
			$parha = $par . " AS hasard";
408
			if (!in_array($parha, $boucle->select))
409
				$boucle->select[]= $parha;
410
	  } else {
411
	      $par = array_shift($tri);
412
	      $par = $par->texte;
413
    // par multi champ
414
	      if (preg_match(",^multi[\s]*(.*)$,",$par, $m)) {
415
		  $texte = $boucle->id_table . '.' . trim($m[1]);
416
		  $boucle->select[] =  "\".sql_multi('".$texte."', \$GLOBALS['spip_lang']).\"" ;
417
		  $order = "'multi'";
418
	// par num champ(, suite)
419
	      }	else if (preg_match(",^num (.*)$,m",$par, $m)) {
420
		  $texte = '0+' . $boucle->id_table . '.' . trim($m[1]);
421
		  $suite = calculer_liste($tri, array(), $boucles, $boucle->id_parent);
422
		  if ($suite !== "''")
423
		    $texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . " . \"";
424
		  $as = 'num' .($boucle->order ? count($boucle->order) : "");
425
		  $boucle->select[] = $texte . " AS $as";
426
		  $order = "'$as'";
427
	      } else {
428
		if (!preg_match(",^" . CHAMP_SQL_PLUS_FONC . '$,is', $par, $match)) {
429
			return (array('zbug_critere_inconnu', array('critere' => $crit->op . " $par")));
430
		} else {
431
		if (count($match)>2) { $par = substr($match[2],1,-1); $fct = $match[1]; }
432
	// par hasard
433
		if ($par == 'hasard') {
434
			$par = "rand()";
435
			$boucle->select[]= $par . " AS alea";
436
			$order = "'alea'";
437
		}
438
	// par titre_mot ou type_mot voire d'autres
439
		else if (isset($exceptions_des_jointures[$par])) {
440
			list($table, $champ) =  $exceptions_des_jointures[$par];
441
			$order = critere_par_joint($table, $champ, $boucle, $idb);
442 View Code Duplication
			if (!$order)
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...
443
				return (array('zbug_critere_inconnu', array('critere' => $crit->op . " $par")));
444
		}
445
		else if ($par == 'date'
446
		AND isset($GLOBALS['table_date'][$boucle->type_requete])) {
447
			$m = $GLOBALS['table_date'][$boucle->type_requete];
448
			$order = "'".$boucle->id_table ."." . $m . "'";
449
		}
450
		// par champ. Verifier qu'ils sont presents.
451
		elseif (preg_match("/^([^,]*)\.(.*)$/", $par, $r)) {
452
		  // cas du tri sur champ de jointure explicite
453
			$t = array_search($r[1], $boucle->from);
454
			if (!$t) {
455
				$t = trouver_champ_exterieur($r[2], array($r[1]), $boucle);
456
				$t = array_search(@$t[0], $boucle->from);
457
			}
458
			if (!$t) {
459
				return (array('zbug_critere_inconnu', array('critere' => $crit->op . " $par")));
460
			} else 	$order = "'" . $t . '.' . $r[2] . "'";
461
		} else {
462
			$desc = $boucle->show;
463
			if ($desc['field'][$par])
464
				$par = $boucle->id_table.".".$par;
465
		  // sinon tant pis, ca doit etre un champ synthetise (cf points)
466
			$order = "'$par'";
467
		}
468
	      }
469
	      }
470
	  }
471 View Code Duplication
	  if (preg_match('/^\'([^"]*)\'$/', $order, $m)) {
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...
472
	      $t = $m[1];
473
	      if (strpos($t,'.') AND !in_array($t, $boucle->select)) {
474
		$boucle->select[] = $t;
475
	      }
476
	  } else $sens ='';
477
478 View Code Duplication
	  if ($fct) {
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...
479
	    if (preg_match("/^\s*'(.*)'\s*$/", $order, $r))
480
	      $order = "'$fct(" . $r[1] . ")'";
481
	    else $order = "'$fct(' . $order . ')'";
482
	  }
483
	  $t = $order . $collecte . $sens;
484
	  if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r))
485
	      $t = $r[1] . $r[2];
486
	  $boucle->order[] = $t;
487
	}
488
}
489
490
// http://doc.spip.org/@critere_par_joint
491
function critere_par_joint($table, $champ, &$boucle, $idb)
0 ignored issues
show
Unused Code introduced by
The parameter $idb 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...
492
{
493
	$t = array_search($table, $boucle->from);
494
	if (!$t) $t = trouver_jointure_champ($champ, $boucle);
495
	return !$t ? '' : ("'" . $t . '.' . $champ . "'");
496
}
497
498
// {inverse}
499
// http://www.spip.net/@inverse
500
501
// http://doc.spip.org/@critere_inverse_dist
502
function critere_inverse_dist($idb, &$boucles, $crit) {
503
504
	$boucle = &$boucles[$idb];
505
	// Classement par ordre inverse
506
	if ($crit->not)
507
		critere_parinverse($idb, $boucles, $crit);
508
	else
509
	  {
510
	  	$order = "' DESC'";
511
	// Classement par ordre inverse fonction eventuelle de #ENV{...}
512 View Code Duplication
		if (isset($crit->param[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...
513
			$critere = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
514
			$order = "(($critere)?' DESC':'')";
515
		}
516
517
		$n = count($boucle->order);
518
		if (!$n) {
519
		  if (isset($boucle->default_order[0]))
520
			$boucle->default_order[0] .=  ' . " DESC"';
521
		  else
522
			$boucle->default_order[] =  ' DESC';
523
		}
524
		else {
525
			$t = $boucle->order[$n-1] . " . $order";
526
			if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r))
527
				$t = $r[1] . $r[2];
528
			$boucle->order[$n-1] = $t;
529
		}
530
	  }
531
}
532
533
// http://doc.spip.org/@critere_agenda_dist
534
function critere_agenda_dist($idb, &$boucles, $crit)
535
{
536
	$params = $crit->param;
537
538
	if (count($params) < 1)
539
		return array('zbug_critere_inconnu', array('critere' => $crit->op . " ?"));
540
541
	$boucle = &$boucles[$idb];
542
	$parent = $boucle->id_parent;
543
	$fields = $boucle->show['field'];
544
545
	$date = array_shift($params);
546
	$type = array_shift($params);
547
548
	// la valeur $type doit etre connue a la compilation
549
	// donc etre forcement reduite a un litteral unique dans le source
550
551
	$type = $type[0]->texte;
552
553
	// La valeur date doit designer un champ de la table SQL.
554
	// Si c'est un litteral unique dans le source, verifier a la compil,
555
	// sinon synthetiser le test de verif pour execution ulterieure
556
	// On prendra arbitrairement le premier champ si test negatif.
557
558
	if ((count($date) == 1)  AND ($date[0]->type == 'texte')) {
559
		$date = $date[0]->texte;
560
		if (!isset($fields[$date]))
561
		  return array('zbug_critere_inconnu', array('critere' => $crit->op . " " . $date));
562
	} else  {
563
		$a = calculer_liste($date, array(), $boucles, $parent);
564
		$noms = array_keys($fields);
565
		$defaut = $noms[0];
566
		$noms = join(" ", $noms);
567
		# bien laisser 2 espaces avant $nom pour que strpos<>0
568
		$cond = "(\$a=strval($a))AND\nstrpos(\"  $noms \",\" \$a \")";
569
		$date = "'.(($cond)\n?\$a:\"$defaut\").'";
570
	}
571
	$annee = $params ? array_shift($params) : "";
572
	$annee = "\n" . 'sprintf("%04d", ($x = ' .
573
		calculer_liste($annee, array(), $boucles, $parent) .
574
		') ? $x : date("Y"))';
575
576
	$mois =  $params ? array_shift($params) : "";
577
	$mois = "\n" . 'sprintf("%02d", ($x = ' .
578
		calculer_liste($mois, array(), $boucles, $parent) .
579
		') ? $x : date("m"))';
580
581
	$jour =  $params ? array_shift($params) : "";
582
	$jour = "\n" . 'sprintf("%02d", ($x = ' .
583
		calculer_liste($jour, array(), $boucles, $parent) .
584
		') ? $x : date("d"))';
585
586
	$annee2 = $params ? array_shift($params) : "";
587
	$annee2 = "\n" . 'sprintf("%04d", ($x = ' .
588
		calculer_liste($annee2, array(), $boucles, $parent) .
589
		') ? $x : date("Y"))';
590
591
	$mois2 =  $params ? array_shift($params) : "";
592
	$mois2 = "\n" . 'sprintf("%02d", ($x = ' .
593
		calculer_liste($mois2, array(), $boucles, $parent) .
594
		') ? $x : date("m"))';
595
596
	$jour2 =  $params ? array_shift($params) : "";
597
	$jour2 = "\n" .  'sprintf("%02d", ($x = ' .
598
		calculer_liste($jour2, array(), $boucles, $parent) .
599
		') ? $x : date("d"))';
600
601
	$date = $boucle->id_table . ".$date";
602
603
	if ($type == 'jour')
604
		$boucle->where[]= array("'='", "'DATE_FORMAT($date, \'%Y%m%d\')'",
605
					("$annee . $mois . $jour"));
606
	elseif ($type == 'mois')
607
		$boucle->where[]= array("'='", "'DATE_FORMAT($date, \'%Y%m\')'",
608
					("$annee . $mois"));
609 View Code Duplication
	elseif ($type == 'semaine')
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...
610
		$boucle->where[]= array("'AND'", 
611
					array("'>='",
612
					     "'DATE_FORMAT($date, \'%Y%m%d\')'", 
613
					      ("date_debut_semaine($annee, $mois, $jour)")),
614
					array("'<='",
615
					      "'DATE_FORMAT($date, \'%Y%m%d\')'",
616
					      ("date_fin_semaine($annee, $mois, $jour)")));
617 View Code Duplication
	elseif (count($crit->param) > 2) 
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...
618
		$boucle->where[]= array("'AND'",
619
					array("'>='",
620
					      "'DATE_FORMAT($date, \'%Y%m%d\')'",
621
					      ("$annee . $mois . $jour")),
622
					array("'<='", "'DATE_FORMAT($date, \'%Y%m%d\')'", ("$annee2 . $mois2 . $jour2")));
623
	// sinon on prend tout
624
}
625
626
// http://doc.spip.org/@calculer_critere_parties
627
function calculer_critere_parties($idb, &$boucles, $crit) {
628
	$boucle = &$boucles[$idb];
629
	$a1 = $crit->param[0];
630
	$a2 = $crit->param[1];
631
	$op = $crit->op;
632
633
	list($a11,$a12) = calculer_critere_parties_aux($idb, $boucles, $a1);
634
	list($a21,$a22) = calculer_critere_parties_aux($idb, $boucles, $a2);
635
	if (($op== ',')&&(is_numeric($a11) && (is_numeric($a21))))
636
	    $boucle->limit = $a11 .',' . $a21;
637
	else {
638
		$boucle->total_parties =  ($a21 != 'n') ? $a21 : $a22;
639
		$partie = ($a11 != 'n') ? $a11 : $a12;
640
		$mode = (($op == '/') ? '/' :
641
			(($a11=='n') ? '-' : '+').(($a21=='n') ? '-' : '+'));
642
		calculer_parties($boucles, $idb, $partie,  $mode);
643
	}
644
}
645
646
//
647
// Code specifique aux criteres {pagination}, {1,n} {n/m} etc
648
//
649
650
function calculer_parties(&$boucles, $id_boucle, $debut, $mode) {
651
652
	$total_parties = $boucles[$id_boucle]->total_parties;
653
	preg_match(",([+-/p])([+-/])?,", $mode, $regs);
654
	list(,$op1,$op2) = $regs;
655
	$nombre_boucle = "\$Numrows['$id_boucle']['total']";
656
	// {1/3}
657
	if ($op1 == '/') {
658
		$pmoins1 = is_numeric($debut) ? ($debut-1) : "($debut-1)";
659
		$totpos = is_numeric($total_parties) ? ($total_parties) :
660
		  "($total_parties ? $total_parties : 1)";
661
		$fin = "ceil(($nombre_boucle * $debut )/$totpos) - 1";
662
		$debut = !$pmoins1 ? 0 : "ceil(($nombre_boucle * $pmoins1)/$totpos);";
663
	} else {
664
		// cas {n-1,x}
665
		if ($op1 == '-') $debut = "$nombre_boucle - $debut;";
666
667
		// cas {x,n-1}
668
		if ($op2 == '-') {
669
			$fin = '$debut_boucle + '.$nombre_boucle.' - '
670
			. (is_numeric($total_parties) ? ($total_parties+1) :
671
			   ($total_parties . ' - 1'));
672
		} else {
673
			// {x,1} ou {pagination}
674
			$fin = '$debut_boucle'
675
			. (is_numeric($total_parties) ?
676
			     (($total_parties==1) ? "" :(' + ' . ($total_parties-1))):
677
			     ('+' . $total_parties . ' - 1'));
678
		}
679
		
680
		// {pagination}, gerer le debut_xx=-1 pour tout voir
681
		if ($op1 == 'p') {
682
			$debut .= ";\n	\$debut_boucle = ((\$tout=(\$debut_boucle == -1))?0:(\$debut_boucle))";
683
			$debut .= ";\n	\$debut_boucle = max(0,min(\$debut_boucle,floor(($nombre_boucle-1)/($total_parties))*($total_parties)))";
684
			$fin = "(\$tout ? $nombre_boucle : $fin)";
685
		}
686
	}
687
688
	// Notes :
689
	// $debut_boucle et $fin_boucle sont les indices SQL du premier
690
	// et du dernier demandes dans la boucle : 0 pour le premier,
691
	// n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
692
	// Utiliser min pour rabattre $fin_boucle sur total_boucle.
693
694
	$boucles[$id_boucle]->mode_partie = "\n\t"
695
	. '$debut_boucle = ' . $debut .   ";\n	"
696
	. '$fin_boucle = min(' . $fin . ", \$Numrows['$id_boucle']['total'] - 1);\n	"
697
	. '$Numrows[\''.$id_boucle. "']['grand_total'] = \$Numrows['$id_boucle']['total'];\n	"
698
	. '$Numrows[\''.$id_boucle.'\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);'
699
	. "\n\tif (\$debut_boucle>0 AND \$debut_boucle < \$Numrows['$id_boucle']['grand_total'] AND sql_seek(\$result,\$debut_boucle,"._q($boucles[$id_boucle]->sql_serveur).",'continue'))\n\t\t\$Numrows['$id_boucle']['compteur_boucle'] = \$debut_boucle;\n\t";
700
701
	$boucles[$id_boucle]->partie = "
702
		if (\$Numrows['$id_boucle']['compteur_boucle'] <= \$debut_boucle) continue;
703
		if (\$Numrows['$id_boucle']['compteur_boucle']-1 > \$fin_boucle) break;";
704
}
705
706
// http://doc.spip.org/@calculer_critere_parties_aux
707
function calculer_critere_parties_aux($idb, &$boucles, $param) {
708
	if ($param[0]->type != 'texte')
709
	  {
710
	    $a1 = calculer_liste(array($param[0]), array('id_mere' => $idb), $boucles, $boucles[$idb]->id_parent);
711
	  preg_match(',^ *(-([0-9]+))? *$,', $param[1]->texte, $m);
712
	  return array("intval($a1)", ($m[2] ? $m[2] : 0));
713
	  } else {
714
	    preg_match(',^ *(([0-9]+)|n) *(- *([0-9]+)? *)?$,', $param[0]->texte, $m);
715
	    $a1 = $m[1];
716
	    if (!@$m[3])
717
	      return array($a1, 0);
718
	    elseif ($m[4])
719
	      return array($a1, $m[4]);
720
	    else return array($a1, 
721
			      calculer_liste(array($param[1]), array(), $boucles[$idb]->id_parent, $boucles));
722
	}
723
}
724
725
//
726
// La fonction d'aiguillage sur le nom du critere dans leur liste
727
// Si l'une au moins des fonctions associees retourne une erreur 
728
// (i.e. un tableau), on propage l'information
729
// Sinon, ne retourne rien (affectation directe dans l'arbre)
730
731
// http://doc.spip.org/@calculer_criteres
732
function calculer_criteres ($idb, &$boucles)
733
{
734
	$msg = '';
735
	$boucle = $boucles[$idb];
736
	$table = strtoupper($boucle->id_table);
737
	$defaut = charger_fonction('DEFAUT', 'calculer_critere');
738
	// s'il y avait une erreur de syntaxe, propager cette info
739
	if (!is_array($boucle->criteres)) return array(); 
740
	foreach($boucle->criteres as $crit) {
741
		$critere = $crit->op;
742
		// critere personnalise ?
743
		if ((!function_exists($f="critere_".$table."_".$critere))
744
		AND (!function_exists($f=$f."_dist"))
745
		AND (!function_exists($f="critere_".$critere))
746
		AND (!function_exists($f=$f."_dist"))	) {
747
			// fonction critere standard 
748
			$f = $defaut;
749
		}
750
		// compile le critere
751
		$res = $f($idb, $boucles, $crit);
752
753
		// Gestion centralisee des erreurs pour pouvoir propager
754
		if (is_array($res)) {
755
			$msg = $res;
756
			erreur_squelette($msg, $boucle);
757
		}
758
	}
759
	return $msg;
760
}
761
762
// Madeleine de Proust, revision MIT-1958 sqq, revision CERN-1989
763
// hum, c'est kwoi cette fonxion ?
764
// http://doc.spip.org/@kwote
765
function kwote($lisp)
766
{
767
	if (preg_match(_CODE_QUOTE, $lisp, $r))
768
		return $r[1] . "\"" . sql_quote(str_replace(array("\\'","\\\\"),array("'","\\"),$r[2])) . "\"" ;
769
	else
770
		return "sql_quote($lisp)"; 
771
}
772
773
// Si on a une liste de valeurs dans #ENV{x}, utiliser la double etoile
774
// pour faire par exemple {id_article IN #ENV**{liste_articles}}
775
// http://doc.spip.org/@critere_IN_dist
776
function critere_IN_dist ($idb, &$boucles, $crit)
777
{
778
	$r = calculer_critere_infixe($idb, $boucles, $crit);
779
	if (!$r) {
780
		return (array('zbug_critere_inconnu', array('critere' => $crit->op . " ?")));
781
	}
782
	list($arg, $op, $val, $col, $where_complement) = $r;
783
784
	$in = critere_IN_cas($idb, $boucles, $crit->not ? 'NOT' : ($crit->exclus? 'exclus' :  ''), $arg, $op, $val, $col);
785
//	inserer la condition; exemple: {id_mot ?IN (66, 62, 64)}
786
	$where = $in;
787
	if ($crit->cond) {
788
		$pred = calculer_argument_precedent($idb, $col, $boucles);
789
		$where = array("'?'",$pred,	$where,"''");
790
		if ($where_complement) // condition annexe du type "AND (objet='article')"
791
			$where_complement = array("'?'",$pred,	$where_complement,"''");
792
	}
793 View Code Duplication
	if ($crit->exclus)
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...
794
		if (!preg_match(",^L[0-9]+[.],",$arg))
795
			$where = array("'NOT'", $where);
796
		else
797
			// un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
798
			$where = array("'NOT'",array("'IN'","'".$boucles[$idb]->id_table.".".$boucles[$idb]->primary."'" ,array("'SELF'","'".$boucles[$idb]->id_table.".".$boucles[$idb]->primary."'",$where)));
799
800
	$boucles[$idb]->where[] = $where;
801
	if ($where_complement) // condition annexe du type "AND (objet='article')"
802
		$boucles[$idb]->where[]= $where_complement;
803
}
804
805
// http://doc.spip.org/@critere_IN_cas
806
function critere_IN_cas ($idb, &$boucles, $crit2, $arg, $op, $val, $col)
0 ignored issues
show
Unused Code introduced by
The parameter $op 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...
Unused Code introduced by
The parameter $col 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...
807
{
808
	static $num = array();
809
	$descr = $boucles[$idb]->descr;
810
	$cpt = &$num[$descr['nom']][$descr['gram']][$idb];
811
812
	$var = '$in' . $cpt++;
813
	$x= "\n\t$var = array();";
814
	foreach ($val as $k => $v) {
815
		if (preg_match(",^(\n//.*\n)?'(.*)'$,", $v, $r)) {
816
		  // optimiser le traitement des constantes
817
			if (is_numeric($r[2]))
818
				$x .= "\n\t$var" . "[]= $r[2];";
819
			else
820
				$x .= "\n\t$var" . "[]= " . sql_quote($r[2]) . ";";
821
		} else {
822
		  // Pour permettre de passer des tableaux de valeurs
823
		  // on repere l'utilisation brute de #ENV**{X}, 
824
		  // c'est-a-dire sa  traduction en ($PILE[0][X]).
825
		  // et on deballe mais en rajoutant l'anti XSS
826
		  $x .= "\n\tif (!(is_array(\$a = ($v))))\n\t\t$var" ."[]= \$a;\n\telse $var = array_merge($var, \$a);";
827
		}
828
	}
829
	
830
	$boucles[$idb]->in .= $x;
831
	
832
	// inserer le tri par defaut selon les ordres du IN ... 
833
	// avec une ecriture de type FIELD qui degrade les performances (du meme ordre qu'un rexgexp)
834
	// et que l'on limite donc strictement aux cas necessaires :
835
	// si ce n'est pas un !IN, et si il n'y a pas d'autre order dans la boucle
836
	if (!$crit2){
837
		$boucles[$idb]->default_order[] = "((!sql_quote($var) OR sql_quote($var)===\"''\") ? 0 : ('FIELD($arg,' . sql_quote($var) . ')'))";
838
	}
839
	
840
	return "sql_in('$arg',sql_quote($var)".($crit2=='NOT'?",'NOT'":"").")";
841
}
842
843
# Criteres de comparaison
844
845
// http://doc.spip.org/@calculer_critere_DEFAUT
846
function calculer_critere_DEFAUT_dist($idb, &$boucles, $crit)
847
{
848
	// double cas particulier {0,1} et {1/2} repere a l'analyse lexicale
849
	if (($crit->op == ",") OR ($crit->op == '/'))
850
		return calculer_critere_parties($idb, $boucles, $crit);
851
852
	$r = calculer_critere_infixe($idb, $boucles, $crit);
853
854
	if (!$r) {
855
		return (array('zbug_critere_inconnu', array('critere' => $crit->op )));
856
	} else calculer_critere_DEFAUT_args($idb, $boucles, $crit, $r);
857
}
858
859
function calculer_critere_DEFAUT_args($idb, &$boucles, $crit, $args)
860
{
861
	list($arg, $op, $val, $col, $where_complement) = $args;
862
863
	$where = array("'$op'", "'$arg'", $val[0]);
864
865
	// inserer la negation (cf !...)
866
867
	if ($crit->not) $where = array("'NOT'", $where);
868 View Code Duplication
	if ($crit->exclus) 
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...
869
		if (!preg_match(",^L[0-9]+[.],",$arg))
870
			$where = array("'NOT'", $where);
871
		else
872
			// un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
873
			$where = array("'NOT'",array("'IN'","'".$boucles[$idb]->id_table.".".$boucles[$idb]->primary."'" ,array("'SELF'","'".$boucles[$idb]->id_table.".".$boucles[$idb]->primary."'",$where)));
874
875
	// inserer la condition (cf {lang?})
876
	// traiter a part la date, elle est mise d'office par SPIP,
877
	if ($crit->cond) {
878
		$pred = calculer_argument_precedent($idb, $col, $boucles);
879 View Code Duplication
		if ($col == "date" OR $col == "date_redac") {
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...
880
			if($pred == "\$Pile[0]['".$col."']") {
881
			  $pred = "(\$Pile[0]['{$col}_default']?'':$pred)";
882
			}
883
		}
884
		
885
		if ($op == '=' AND !$crit->not)
886
		  $where = array("'?'", "(is_array($pred))", 
887
				 critere_IN_cas ($idb, $boucles, 'COND', $arg, $op, array($pred), $col), 
888
				 $where);
889
		$where = array("'?'", "!(is_array($pred)?count($pred):strlen($pred))","''", $where);
890
		if ($where_complement) // condition annexe du type "AND (objet='article')"
891
			$where_complement = array("'?'", "!$pred","''", $where_complement);
892
	}
893
894
	$boucles[$idb]->where[]= $where;
895
	if ($where_complement) // condition annexe du type "AND (objet='article')"
896
		$boucles[$idb]->where[]= $where_complement;
897
}
898
899
// http://doc.spip.org/@calculer_critere_infixe
900
function calculer_critere_infixe($idb, &$boucles, $crit) {
901
902
	global $table_criteres_infixes;
903
	global $exceptions_des_jointures, $exceptions_des_tables;
904
905
	$boucle = &$boucles[$idb];
906
	$type = $boucle->type_requete;
907
	$table = $boucle->id_table;
908
	$desc = $boucle->show;
909
	$date = array();
910
911
	list($fct, $col, $op, $val, $args_sql) =
912
	  calculer_critere_infixe_ops($idb, $boucles, $crit);
913
914
	$col_alias = $col;
915
	$where_complement =false;
916
917
	// Cas particulier : id_enfant => utiliser la colonne id_objet
918
	if ($col == 'id_enfant')
919
	  $col = $boucle->primary;
920
921
	// Cas particulier : id_parent => verifier les exceptions de tables
922
	if ($col == 'id_parent')
923
	  $col = isset($exceptions_des_tables[$table]['id_parent']) ?
924
		$exceptions_des_tables[$table]['id_parent'] :
925
		'id_parent';
926
927
	// Cas particulier : id_secteur pour certaines tables
928
	else if (($col == 'id_secteur')&&($type == 'breves')) {
929
		$col = 'id_rubrique';
930
	}
931
	// et possibilite de gerer un critere secteur sur des tables de plugins (ie forums)
932
	else if (($col == 'id_secteur') AND ($critere_secteur = charger_fonction("critere_secteur_$type","public",true))) {
933
		$table = $critere_secteur($idb, $boucles, $val, $crit);
934
	}
935
	
936
	// cas id_article=xx qui se mappe en id_objet=xx AND objet=article
937
	else if (count(trouver_champs_decomposes($col,$desc))>1){
938
		$e = decompose_champ_id_objet($col);
939
		$col = array_shift($e);
940
		$where_complement = primary_doublee($e, $table);
941
942
	}
943
	// Cas particulier : expressions de date
944
	else if ($date = tester_param_date($boucle->type_requete, $col)) {
945
		$col = calculer_critere_infixe_date($idb, $boucles, $date);
946
		$table = '';
947
	}
948
	else if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
949
		  list(,$table, $col) = $r;
950
		  $col_alias = $col;
951
		  $table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op !='='), true);
952
		  if (!$table) return '';
953
	}
954
	elseif (@!array_key_exists($col, $desc['field'])) {
955
		$r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table);
956
		if (!$r) return '';
957
		list($col, $col_alias, $table, $where_complement) = $r;
958
	}
959
	// Si la colonne SQL est numerique ou le critere est une date relative
960
	// virer les guillemets eventuels qui sont refuses par certains SQL
961
	// Ne pas utiliser intval, PHP tronquant les Bigint de SQL
962
963
	if (($op == '=' OR in_array($op, $table_criteres_infixes))
964
	AND (($desc AND isset($desc['field'][$col]) AND sql_test_int($desc['field'][$col]))
965
	     OR ($date AND strpos($date[0], '_relatif')))) {
966
		if (preg_match("/^\"'(-?\d+)'\"$/", $val[0], $r))
967
			$val[0] = $r[1];
968
		elseif (preg_match('/^sql_quote[(](.*?)(,[^)]*)?[)]\s*$/', $val[0], $r)) {
969
		  $r = $r[1] . ($r[2] ? $r[2] : ",''") . ",'int'";
970
		  $val[0] = "sql_quote($r)";
971
		}
972
	}
973
	// Indicateur pour permettre aux fonctionx boucle_X de modifier 
974
	// leurs requetes par defaut, notamment le champ statut
975
	// Ne pas confondre champs de la table principale et des jointures
976
	if ($table === $boucle->id_table) {
977
		$boucles[$idb]->modificateur['criteres'][$col] = true;
978
		if ($col_alias!=$col)
979
			$boucles[$idb]->modificateur['criteres'][$col_alias] = true;
980
	}
981
	
982
	// ajout pour le cas special d'une condition sur le champ statut:
983
	// il faut alors interdire a la fonction de boucle
984
	// de mettre ses propres criteres de statut
985
	// http://www.spip.net/@statut (a documenter)
986
	// garde pour compatibilite avec code des plugins anterieurs, mais redondant avec la ligne precedente
987
	if ($col == 'statut') $boucles[$idb]->statut = true;
988
989
	// ajout pour le cas special des forums
990
	// il faut alors interdire a la fonction de boucle sur forum
991
	// de selectionner uniquement les forums sans pere
992
993
	elseif ($boucles[$idb]->type_requete == 'forums' AND
994
		($col == 'id_parent' OR $col == 'id_forum'))
995
		$boucles[$idb]->modificateur['plat'] = true;
996
	// inserer le nom de la table SQL devant le nom du champ
997
	if ($table) {
998
		if ($col[0] == "`") 
999
		  $arg = "$table." . substr($col,1,-1);
1000
		else $arg = "$table.$col";
1001
	} else $arg = $col;
1002
1003
	// inserer la fonction SQL
1004
	if ($fct) $arg = "$fct($arg$args_sql)";
1005
1006
	return array($arg, $op, $val, $col_alias, $where_complement);
1007
}
1008
1009
function calculer_critere_infixe_externe(&$boucle, $crit, $op, $desc, $col, $col_alias, $table)
1010
{
1011
	global $exceptions_des_jointures;
1012
	$where = '';
1013
1014
	$calculer_critere_externe = 'calculer_critere_externe_init';
1015
	// gestion par les plugins des jointures tordues 
1016
	// pas automatiques mais necessaires
1017
	if (is_array($exceptions_des_jointures[$table])) {
1018
1019
		$t = $exceptions_des_jointures[$table];
1020
		$index = isset($t[$col])
1021
		?  $t[$col] : (isset($t['']) ? $t[''] : array());
1022
		
1023
		if (count($index)==3)
1024
			list($t, $col, $calculer_critere_externe) = $index;
1025
		elseif (count($index)==2)
1026
			list($t, $col) = $t[$col];
1027
		elseif (count($index)==1){
1028
			list($calculer_critere_externe) = $index;
1029
			$t = $table;
1030
		}
1031
		else
1032
			$t=''; // jointure non declaree. La trouver.
1033
	}
1034
	elseif (isset($exceptions_des_jointures[$col]))
1035
		list($t, $col) = $exceptions_des_jointures[$col];
1036
	else $t =''; // jointure non declaree. La trouver.
1037
1038
	$table = $calculer_critere_externe($boucle, $boucle->jointures, $col, $desc, ($crit->cond OR $op !='='), $t);
1039
1040
	if (!$table) return '';
1041
1042
	list($nom, $desc) = trouver_champ_exterieur($col, $boucle->jointures, $boucle);
0 ignored issues
show
Unused Code introduced by
The assignment to $nom is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1043
	if (count(trouver_champs_decomposes($col,$desc))>1){
1044
		$col_alias = $col; // id_article devient juste le nom d'origine
1045
		$e = decompose_champ_id_objet($col);
1046
		$col = array_shift($e);
1047
		$where = primary_doublee($e, $table);
1048
	}
1049
1050
	return array($col, $col_alias, $table, $where);
1051
}
1052
1053
// Ne pas appliquer sql_quote lors de la compilation,
1054
// car on ne connait pas le serveur SQL, donc s'il faut \' ou ''
1055
1056
// http://doc.spip.org/@primary_doublee
1057
function primary_doublee($decompose, $table)
1058
{
1059
	$e1 = reset($decompose);
1060
	$e2 = "sql_quote('" . end($decompose) ."')";
1061
	return array("'='","'$table.". $e1 ."'",$e2);
1062
}
1063
1064
// Faute de copie du champ id_secteur dans la table des forums,
1065
// faut le retrouver par jointure
1066
// Pour chaque Row il faudrait tester si le forum est 
1067
// d'article, de breve, de rubrique, ou de syndication.
1068
// Pour le moment on ne traite que les articles,
1069
// les 3 autres cas ne marcheront donc pas: ca ferait 4 jointures
1070
// qu'il faut traiter optimalement ou alors pas du tout.
1071
1072
// http://doc.spip.org/@critere_secteur_forum
1073
function critere_secteur_forum($idb, &$boucles, $val, $crit)
0 ignored issues
show
Unused Code introduced by
The parameter $val 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...
1074
{
1075
	static $trouver_table;
1076
	if (!$trouver_table)
1077
		$trouver_table = charger_fonction('trouver_table', 'base');
1078
1079
	$desc = $trouver_table('articles', $boucles[$idb]->sql_serveur);
1080
	return calculer_critere_externe_init($boucles[$idb], array($desc['table']), 'id_secteur', $desc, $crit->cond, true);
1081
}
1082
1083
// Champ hors table, ca ne peut etre qu'une jointure.
1084
// On cherche la table du champ et on regarde si elle est deja jointe
1085
// Si oui et qu'on y cherche un champ nouveau, pas de jointure supplementaire
1086
// Exemple: criteres {titre_mot=...}{type_mot=...}
1087
// Dans les 2 autres cas ==> jointure 
1088
// (Exemple: criteres {type_mot=...}{type_mot=...} donne 2 jointures
1089
// pour selectioner ce qui a exactement ces 2 mots-cles.
1090
1091
// http://doc.spip.org/@calculer_critere_externe_init
1092
function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $eg, $checkarrivee = false)
1093
{
1094
	$cle = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee);
1095
	if (!$cle) return '';
1096
	$t = array_search($cle[0], $boucle->from);
1097
	// transformer eventuellement id_xx en (id_objet,objet)
1098
	$cols = trouver_champs_decomposes($col,$cle[1]); 
1099
	if ($t) {
1100
			$joindre = false;
1101
			foreach($cols as $col){
1102
			  $c = '/\b' . $t  . ".$col" . '\b/';
1103
			  if (trouver_champ($c, $boucle->where)) $joindre = true;
1104
			  else {
1105
			    // mais ca peut etre dans le FIELD pour le Having
1106
			    $c = "/FIELD.$t" .".$col,/";
1107
			    if (trouver_champ($c, $boucle->select)) $joindre = true;
1108
			  }
1109
			}
1110
		  if (!$joindre) return $t;
1111
	}
1112
	return calculer_jointure($boucle, array($boucle->id_table, $desc), $cle, $cols, $eg);
1113
1114
}
1115
1116
// http://doc.spip.org/@trouver_champ
1117
function trouver_champ($champ, $where)
1118
{
1119
  if (!is_array($where))
1120
 	return preg_match($champ,$where);
1121
  else {
1122
   	 foreach ($where as $clause) {
1123
	   if (trouver_champ($champ, $clause)) return true;
1124
	 }
1125
	 return false;
1126
  }
1127
}
1128
1129
1130
// determine l'operateur et les operandes
1131
1132
// http://doc.spip.org/@calculer_critere_infixe_ops
1133
function calculer_critere_infixe_ops($idb, &$boucles, $crit)
1134
{
1135
	// cas d'une valeur comparee a elle-meme ou son referent
1136
	if (count($crit->param) == 0)
1137
	  { $op = '=';
1138
	    $col = $val = $crit->op;
1139
	    if (preg_match('/^(.*)\.(.*)$/', $col, $r)) $val = $r[2];
1140
	    // Cas special {lang} : aller chercher $GLOBALS['spip_lang']
1141
	    if ($val == 'lang')
1142
	      $val = array(kwote('$GLOBALS[\'spip_lang\']'));
1143
	    else {
1144
	    // Si id_parent, comparer l'id_parent avec l'id_objet
1145
	    // de la boucle superieure.... faudrait verifier qu'il existe
1146
	      // pour eviter l'erreur SQL
1147
	      if ($val == 'id_parent')
1148
		$val = $boucles[$idb]->primary;
1149
	      // Si id_enfant, comparer l'id_objet avec l'id_parent
1150
	      // de la boucle superieure
1151
	      else if ($val == 'id_enfant')
1152
		$val = 'id_parent';
1153
	// un critere conditionnel sur date est traite a part
1154
	// car la date est mise d'office par SPIP, 
1155
	      $val = calculer_argument_precedent($idb, $val, $boucles);
1156 View Code Duplication
	      if ($crit->cond AND ($col == "date" OR $col == "date_redac")) {
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...
1157
		      if($val == "\$Pile[0]['".$col."']") {
1158
			$val = "(\$Pile[0]['{$col}_default']?'':$val)";
1159
		      }
1160
	      }
1161
	      $val = array(kwote($val));
1162
	    }
1163
	  } else {
1164
	    // comparaison explicite
1165
	    // le phraseur impose que le premier param soit du texte
1166
		$params = $crit->param;
1167
		$op = $crit->op;
1168
		if ($op == '==') $op = 'REGEXP';
1169
		$col = array_shift($params);
1170
		$col = $col[0]->texte;
1171
1172
		$val = array();
1173
		$desc = array('id_mere' => $idb);
1174
		$parent = $boucles[$idb]->id_parent;
1175
1176
		// Dans le cas {x=='#DATE'} etc, defaire le travail du phraseur,
1177
		// celui ne sachant pas ce qu'est un critere infixe
1178
		// et a fortiori son 2e operande qu'entoure " ou '
1179
		if (count($params)==1
1180
		AND count($params[0]==3)
1181
		AND $params[0][0]->type == 'texte' 
1182
		AND @$params[0][2]->type == 'texte' 
1183
		AND ($p=$params[0][0]->texte) == $params[0][2]->texte
1184
		AND (($p == "'") OR ($p == '"'))
1185
		AND $params[0][1]->type == 'champ' ) {
1186
			$val[]= "$p\\$p#" . $params[0][1]->nom_champ . "\\$p$p";
1187
		} else 
1188
			foreach ((($op != 'IN') ? $params : calculer_vieux_in($params)) as $p) {
1189
				$a = calculer_liste($p, $desc, $boucles, $parent);
1190
				if ($op == 'IN') $val[]= $a;
1191
				else $val[]=kwote($a);
1192
			}
1193
	}
1194
1195
	$fct = $args_sql = '';
1196
	// fonction SQL ?
1197
	if (preg_match('/^(.*)' . SQL_ARGS . '$/', $col, $m)) {
1198
	  $fct = $m[1];
1199
	  preg_match('/^\(([^,]*)(.*)\)$/', $m[2], $a);
1200
	  $col = $a[1];
1201
	  if (preg_match('/^(\S*)(\s+AS\s+.*)$/i', $col, $m)) {
1202
	    $col=$m[1];
1203
	    $args_sql = $m[2];
1204
	  }
1205
	  $args_sql .= $a[2];;
1206
	}
1207
1208
	return array($fct, $col, $op, $val, $args_sql);
1209
}
1210
1211
// compatibilite ancienne version
1212
1213
// http://doc.spip.org/@calculer_vieux_in
1214
function calculer_vieux_in($params)
1215
{
1216
	      $deb = $params[0][0];
1217
	      $k = count($params)-1;
1218
	      $last = $params[$k];
1219
	      $j = count($last)-1;
1220
	      $last = $last[$j];
1221
	      $n = strlen($last->texte);
1222
1223
	      if (!(($deb->texte[0] == '(') && ($last->texte[$n-1] == ')')))
1224
		return $params;
1225
	      $params[0][0]->texte = substr($deb->texte,1);
1226
	      // attention, on peut avoir k=0,j=0 ==> recalculer
1227
	      $last = $params[$k][$j];
1228
	      $n = strlen($last->texte);
1229
	      $params[$k][$j]->texte = substr($last->texte,0,$n-1);
1230
	      $newp = array();
1231
	      foreach($params as $v) {
1232
		    if ($v[0]->type != 'texte')
1233
		      $newp[] = $v;
1234
		    else {
1235
		      foreach(explode(',', $v[0]->texte) as $x) {
1236
			$t = new Texte;
1237
			$t->texte = $x;
1238
			$newp[] = array($t);
1239
		      }
1240
		    }
1241
	      }
1242
	      return  $newp;
1243
}
1244
1245
// http://doc.spip.org/@calculer_critere_infixe_date
1246
function calculer_critere_infixe_date($idb, &$boucles, $regs)
1247
{
1248
	global $table_date; 
1249
	$boucle = $boucles[$idb];
1250
	$col = $regs[1];
1251
	$date_orig = $pred = isset($table_date[$boucle->type_requete])?$table_date[$boucle->type_requete]:'date';
1252
	if (isset($regs[3]) AND $suite=$regs[3]) {
1253
	# Recherche de l'existence du champ date_xxxx,
1254
	# si oui choisir ce champ, sinon choisir xxxx
1255
		$t = $boucle->show;
1256
		if ($t['field']["date$suite"])
1257
			$date_orig = 'date'.$suite;
1258
		else
1259
			$date_orig = substr($suite, 1);
1260
		$pred = $date_orig;
1261
	} 
1262
	else 
1263
	  if (isset($regs[2]) AND $rel=$regs[2]) $pred = 'date';
1264
1265
	$date_compare = "\"' . normaliser_date(" .
1266
	      calculer_argument_precedent($idb, $pred, $boucles) .
1267
	      ") . '\"";
1268
	$date_orig = $boucle->id_table . '.' . $date_orig;
1269
1270
	switch ($col) {
1271
		case 'date':
1272
			$col = $date_orig;
1273
			break;
1274
		case 'jour':
1275
			$col = "DAYOFMONTH($date_orig)";
1276
			break;
1277
		case 'mois':
1278
			$col = "MONTH($date_orig)";
1279
			break;
1280
		case 'annee':
1281
			$col = "YEAR($date_orig)";
1282
			break;
1283
		case 'heure':
1284
			$col = "DATE_FORMAT($date_orig, '%H:%i')";
1285
			break;
1286
		case 'age':
1287
			$col = calculer_param_date("NOW()", $date_orig);
1288
			break;
1289
		case 'age_relatif':
1290
			$col = calculer_param_date($date_compare, $date_orig);
1291
			break;
1292
		case 'jour_relatif':
1293
			$col = "LEAST(TO_DAYS(" .$date_compare . ")-TO_DAYS(" .
1294
			$date_orig . "), DAYOFMONTH(" . $date_compare .
1295
			")-DAYOFMONTH(" . $date_orig . ")+30.4368*(MONTH(" .
1296
			$date_compare . ")-MONTH(" . $date_orig .
1297
			"))+365.2422*(YEAR(" . $date_compare . ")-YEAR(" .
1298
			$date_orig . ")))";
1299
			break;
1300
		case 'mois_relatif':
1301
			$col = "MONTH(" . $date_compare . ")-MONTH(" .
1302
			$date_orig . ")+12*(YEAR(" . $date_compare .
1303
			")-YEAR(" . $date_orig . "))";
1304
			break;
1305
		case 'annee_relatif':
1306
			$col = "YEAR(" . $date_compare . ")-YEAR(" .
1307
			$date_orig . ")";
1308
			break;
1309
	}
1310
	return $col;
1311
}
1312
1313
// http://doc.spip.org/@calculer_param_date
1314
function calculer_param_date($date_compare, $date_orig) {
1315
	if (preg_match(",'\" *\.(.*)\. *\"',", $date_compare, $r)) {
1316
	  $init = "'\" . (\$x = $r[1]) . \"'";
1317
	  $date_compare = '\'$x\'';
1318
	}
1319
	else
1320
	  $init = $date_compare;
1321
1322
	return
1323
	"LEAST((UNIX_TIMESTAMP(" .
1324
	$init .
1325
	")-UNIX_TIMESTAMP(" .
1326
	$date_orig .
1327
	"))/86400,\n\tTO_DAYS(" .
1328
	$date_compare .
1329
	")-TO_DAYS(" .
1330
	$date_orig .
1331
	"),\n\tDAYOFMONTH(" .
1332
	$date_compare .
1333
	")-DAYOFMONTH(" .
1334
	$date_orig .
1335
	")+30.4368*(MONTH(" .
1336
	$date_compare .
1337
	")-MONTH(" .
1338
	$date_orig .
1339
	"))+365.2422*(YEAR(" .
1340
	$date_compare .
1341
	")-YEAR(" .
1342
	$date_orig .
1343
	")))";
1344
}
1345
1346
// http://doc.spip.org/@tester_param_date
1347
function tester_param_date($type, $col)
1348
{
1349
	global $table_date;
1350
	if (isset($table_date[$type]) 
1351
	AND preg_match(",^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z]+)?$,", $col, $regs))
1352
	  return $regs;
1353
	else return false;
1354
}
1355
1356
?>
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...
1357