Completed
Push — master ( a90d7c...b74a87 )
by cam
01:35
created
ecrire/public/criteres.php 1 patch
Indentation   +1718 added lines, -1718 removed lines patch added patch discarded remove patch
@@ -20,7 +20,7 @@  discard block
 block discarded – undo
20 20
  **/
21 21
 
22 22
 if (!defined('_ECRIRE_INC_VERSION')) {
23
-	return;
23
+    return;
24 24
 }
25 25
 
26 26
 /**
@@ -46,12 +46,12 @@  discard block
 block discarded – undo
46 46
  **/
47 47
 function critere_racine_dist($idb, &$boucles, $crit) {
48 48
 
49
-	$not = $crit->not;
50
-	$boucle = &$boucles[$idb];
51
-	$id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
49
+    $not = $crit->not;
50
+    $boucle = &$boucles[$idb];
51
+    $id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
52 52
 
53
-	$c = ["'='", "'$boucle->id_table." . "$id_parent'", 0];
54
-	$boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
53
+    $c = ["'='", "'$boucle->id_table." . "$id_parent'", 0];
54
+    $boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
55 55
 }
56 56
 
57 57
 
@@ -68,15 +68,15 @@  discard block
 block discarded – undo
68 68
  * @return void|array
69 69
  **/
70 70
 function critere_exclus_dist($idb, &$boucles, $crit) {
71
-	$not = $crit->not;
72
-	$boucle = &$boucles[$idb];
73
-	$id = $boucle->primary;
74
-
75
-	if ($not or !$id) {
76
-		return ['zbug_critere_inconnu', ['critere' => $not . $crit->op]];
77
-	}
78
-	$arg = kwote(calculer_argument_precedent($idb, $id, $boucles));
79
-	$boucle->where[] = ["'!='", "'$boucle->id_table." . "$id'", $arg];
71
+    $not = $crit->not;
72
+    $boucle = &$boucles[$idb];
73
+    $id = $boucle->primary;
74
+
75
+    if ($not or !$id) {
76
+        return ['zbug_critere_inconnu', ['critere' => $not . $crit->op]];
77
+    }
78
+    $arg = kwote(calculer_argument_precedent($idb, $id, $boucles));
79
+    $boucle->where[] = ["'!='", "'$boucle->id_table." . "$id'", $arg];
80 80
 }
81 81
 
82 82
 
@@ -96,73 +96,73 @@  discard block
 block discarded – undo
96 96
  * @return void|array
97 97
  **/
98 98
 function critere_doublons_dist($idb, &$boucles, $crit) {
99
-	$boucle = &$boucles[$idb];
100
-	$primary = $boucle->primary;
101
-
102
-	// la table nécessite une clé primaire, non composée
103
-	if (!$primary or strpos($primary, ',')) {
104
-		return ['zbug_doublon_sur_table_sans_cle_primaire'];
105
-	}
106
-
107
-	$not = ($crit->not ? '' : 'NOT');
108
-
109
-	// le doublon s'applique sur un type de boucle (article)
110
-	$nom = "'" . $boucle->type_requete . "'";
111
-
112
-	// compléter le nom avec un nom précisé {doublons nom}
113
-	// on obtient $nom = "'article' . 'nom'"
114
-	if (isset($crit->param[0])) {
115
-		$nom .= '.' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
116
-	}
117
-
118
-	// code qui déclarera l'index du stockage de nos doublons (pour éviter une notice PHP)
119
-	$init_comment = "\n\n\t// Initialise le(s) critère(s) doublons\n";
120
-	$init_code = "\tif (!isset(\$doublons[\$d = $nom])) { \$doublons[\$d] = ''; }\n";
121
-
122
-	// on crée un sql_in avec la clé primaire de la table
123
-	// et la collection des doublons déjà emmagasinés dans le tableau
124
-	// $doublons et son index, ici $nom
125
-
126
-	// debut du code "sql_in('articles.id_article', "
127
-	$debut_in = "sql_in('" . $boucle->id_table . '.' . $primary . "', ";
128
-	// lecture des données du doublon "$doublons[$doublon_index[] = "
129
-	// Attention : boucle->doublons désigne une variable qu'on affecte
130
-	$debut_doub = '$doublons[' . (!$not ? '' : ($boucle->doublons . '[]= '));
131
-
132
-	// le debut complet du code des doublons
133
-	$debut_doub = $debut_in . $debut_doub;
134
-
135
-	// nom du doublon "('article' . 'nom')]"
136
-	$fin_doub = "($nom)]";
137
-
138
-	// si on trouve un autre critère doublon,
139
-	// on fusionne pour avoir un seul IN, et on s'en va !
140
-	foreach ($boucle->where as $k => $w) {
141
-		if (strpos($w[0], $debut_doub) === 0) {
142
-			// fusionner le sql_in (du where)
143
-			$boucle->where[$k][0] = $debut_doub . $fin_doub . ' . ' . substr($w[0], strlen($debut_in));
144
-			// fusionner l'initialisation (du hash) pour faire plus joli
145
-			$x = strpos($boucle->hash, $init_comment);
146
-			$len = strlen($init_comment);
147
-			$boucle->hash =
148
-				substr($boucle->hash, 0, $x + $len) . $init_code . substr($boucle->hash, $x + $len);
149
-
150
-			return;
151
-		}
152
-	}
153
-
154
-	// mettre l'ensemble dans un tableau pour que ce ne soit pas vu comme une constante
155
-	$boucle->where[] = [$debut_doub . $fin_doub . ", '" . $not . "')"];
156
-
157
-	// déclarer le doublon s'il n'existe pas encore
158
-	$boucle->hash .= $init_comment . $init_code;
159
-
160
-
161
-	# la ligne suivante avait l'intention d'eviter une collecte deja faite
162
-	# mais elle fait planter une boucle a 2 critere doublons:
163
-	# {!doublons A}{doublons B}
164
-	# (de http://article.gmane.org/gmane.comp.web.spip.devel/31034)
165
-	#	if ($crit->not) $boucle->doublons = "";
99
+    $boucle = &$boucles[$idb];
100
+    $primary = $boucle->primary;
101
+
102
+    // la table nécessite une clé primaire, non composée
103
+    if (!$primary or strpos($primary, ',')) {
104
+        return ['zbug_doublon_sur_table_sans_cle_primaire'];
105
+    }
106
+
107
+    $not = ($crit->not ? '' : 'NOT');
108
+
109
+    // le doublon s'applique sur un type de boucle (article)
110
+    $nom = "'" . $boucle->type_requete . "'";
111
+
112
+    // compléter le nom avec un nom précisé {doublons nom}
113
+    // on obtient $nom = "'article' . 'nom'"
114
+    if (isset($crit->param[0])) {
115
+        $nom .= '.' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
116
+    }
117
+
118
+    // code qui déclarera l'index du stockage de nos doublons (pour éviter une notice PHP)
119
+    $init_comment = "\n\n\t// Initialise le(s) critère(s) doublons\n";
120
+    $init_code = "\tif (!isset(\$doublons[\$d = $nom])) { \$doublons[\$d] = ''; }\n";
121
+
122
+    // on crée un sql_in avec la clé primaire de la table
123
+    // et la collection des doublons déjà emmagasinés dans le tableau
124
+    // $doublons et son index, ici $nom
125
+
126
+    // debut du code "sql_in('articles.id_article', "
127
+    $debut_in = "sql_in('" . $boucle->id_table . '.' . $primary . "', ";
128
+    // lecture des données du doublon "$doublons[$doublon_index[] = "
129
+    // Attention : boucle->doublons désigne une variable qu'on affecte
130
+    $debut_doub = '$doublons[' . (!$not ? '' : ($boucle->doublons . '[]= '));
131
+
132
+    // le debut complet du code des doublons
133
+    $debut_doub = $debut_in . $debut_doub;
134
+
135
+    // nom du doublon "('article' . 'nom')]"
136
+    $fin_doub = "($nom)]";
137
+
138
+    // si on trouve un autre critère doublon,
139
+    // on fusionne pour avoir un seul IN, et on s'en va !
140
+    foreach ($boucle->where as $k => $w) {
141
+        if (strpos($w[0], $debut_doub) === 0) {
142
+            // fusionner le sql_in (du where)
143
+            $boucle->where[$k][0] = $debut_doub . $fin_doub . ' . ' . substr($w[0], strlen($debut_in));
144
+            // fusionner l'initialisation (du hash) pour faire plus joli
145
+            $x = strpos($boucle->hash, $init_comment);
146
+            $len = strlen($init_comment);
147
+            $boucle->hash =
148
+                substr($boucle->hash, 0, $x + $len) . $init_code . substr($boucle->hash, $x + $len);
149
+
150
+            return;
151
+        }
152
+    }
153
+
154
+    // mettre l'ensemble dans un tableau pour que ce ne soit pas vu comme une constante
155
+    $boucle->where[] = [$debut_doub . $fin_doub . ", '" . $not . "')"];
156
+
157
+    // déclarer le doublon s'il n'existe pas encore
158
+    $boucle->hash .= $init_comment . $init_code;
159
+
160
+
161
+    # la ligne suivante avait l'intention d'eviter une collecte deja faite
162
+    # mais elle fait planter une boucle a 2 critere doublons:
163
+    # {!doublons A}{doublons B}
164
+    # (de http://article.gmane.org/gmane.comp.web.spip.devel/31034)
165
+    #	if ($crit->not) $boucle->doublons = "";
166 166
 }
167 167
 
168 168
 
@@ -183,14 +183,14 @@  discard block
 block discarded – undo
183 183
  * @return void
184 184
  **/
185 185
 function critere_lang_select_dist($idb, &$boucles, $crit) {
186
-	if (!isset($crit->param[1][0]) or !($param = $crit->param[1][0]->texte)) {
187
-		$param = 'oui';
188
-	}
189
-	if ($crit->not) {
190
-		$param = ($param == 'oui') ? 'non' : 'oui';
191
-	}
192
-	$boucle = &$boucles[$idb];
193
-	$boucle->lang_select = $param;
186
+    if (!isset($crit->param[1][0]) or !($param = $crit->param[1][0]->texte)) {
187
+        $param = 'oui';
188
+    }
189
+    if ($crit->not) {
190
+        $param = ($param == 'oui') ? 'non' : 'oui';
191
+    }
192
+    $boucle = &$boucles[$idb];
193
+    $boucle->lang_select = $param;
194 194
 }
195 195
 
196 196
 
@@ -212,15 +212,15 @@  discard block
 block discarded – undo
212 212
  * @return void
213 213
  **/
214 214
 function critere_debut_dist($idb, &$boucles, $crit) {
215
-	[$un, $deux] = $crit->param;
216
-	$un = $un[0]->texte;
217
-	$deux = $deux[0]->texte;
218
-	if ($deux) {
219
-		$boucles[$idb]->limit =
220
-			'intval($Pile[0]["debut' . $un . '"]) . ",' . $deux . '"';
221
-	} else {
222
-		calculer_critere_DEFAUT_dist($idb, $boucles, $crit);
223
-	}
215
+    [$un, $deux] = $crit->param;
216
+    $un = $un[0]->texte;
217
+    $deux = $deux[0]->texte;
218
+    if ($deux) {
219
+        $boucles[$idb]->limit =
220
+            'intval($Pile[0]["debut' . $un . '"]) . ",' . $deux . '"';
221
+    } else {
222
+        calculer_critere_DEFAUT_dist($idb, $boucles, $crit);
223
+    }
224 224
 }
225 225
 
226 226
 
@@ -254,58 +254,58 @@  discard block
 block discarded – undo
254 254
  **/
255 255
 function critere_pagination_dist($idb, &$boucles, $crit) {
256 256
 
257
-	$boucle = &$boucles[$idb];
258
-	// definition de la taille de la page
259
-	$pas = !isset($crit->param[0][0]) ? "''"
260
-		: calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
261
-
262
-	if (!preg_match(_CODE_QUOTE, $pas, $r)) {
263
-		$pas = "((\$a = intval($pas)) ? \$a : 10)";
264
-	} else {
265
-		$r = intval($r[2]);
266
-		$pas = strval($r ?: 10);
267
-	}
268
-
269
-	// Calcul du nommage de la pagination si il existe.
270
-	// La nouvelle syntaxe {pagination 20, nom} est prise en compte et privilégiée mais on reste
271
-	// compatible avec l'ancienne car certains cas fonctionnent correctement
272
-	$type = "'$idb'";
273
-	// Calcul d'un nommage spécifique de la pagination si précisé.
274
-	// Syntaxe {pagination 20, nom}
275
-	if (isset($crit->param[0][1])) {
276
-		$type = calculer_liste([$crit->param[0][1]], $idb, $boucles, $boucle->id_parent);
277
-	} // Ancienne syntaxe {pagination 20 nom} pour compatibilité
278
-	elseif (isset($crit->param[1][0])) {
279
-		$type = calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
280
-	}
281
-
282
-	$debut = ($type[0] !== "'") ? "'debut'.$type" : ("'debut" . substr($type, 1));
283
-	$boucle->modificateur['debut_nom'] = $type;
284
-	$partie =
285
-		// tester si le numero de page demande est de la forme '@yyy'
286
-		'isset($Pile[0][' . $debut . ']) ? $Pile[0][' . $debut . '] : _request(' . $debut . ");\n"
287
-		. "\tif (\$debut_boucle && \$debut_boucle[0] === '@') {\n"
288
-		. "\t\t" . '$debut_boucle = $Pile[0][' . $debut . '] = quete_debut_pagination(\'' . $boucle->primary . '\',$Pile[0][\'@' . $boucle->primary . '\'] = substr($debut_boucle,1),' . $pas . ',$iter);' . "\n"
289
-		. "\t\t" . '$iter->seek(0);' . "\n"
290
-		. "\t}\n"
291
-		. "\t" . '$debut_boucle = intval($debut_boucle)';
292
-
293
-	$boucle->hash .= '
257
+    $boucle = &$boucles[$idb];
258
+    // definition de la taille de la page
259
+    $pas = !isset($crit->param[0][0]) ? "''"
260
+        : calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
261
+
262
+    if (!preg_match(_CODE_QUOTE, $pas, $r)) {
263
+        $pas = "((\$a = intval($pas)) ? \$a : 10)";
264
+    } else {
265
+        $r = intval($r[2]);
266
+        $pas = strval($r ?: 10);
267
+    }
268
+
269
+    // Calcul du nommage de la pagination si il existe.
270
+    // La nouvelle syntaxe {pagination 20, nom} est prise en compte et privilégiée mais on reste
271
+    // compatible avec l'ancienne car certains cas fonctionnent correctement
272
+    $type = "'$idb'";
273
+    // Calcul d'un nommage spécifique de la pagination si précisé.
274
+    // Syntaxe {pagination 20, nom}
275
+    if (isset($crit->param[0][1])) {
276
+        $type = calculer_liste([$crit->param[0][1]], $idb, $boucles, $boucle->id_parent);
277
+    } // Ancienne syntaxe {pagination 20 nom} pour compatibilité
278
+    elseif (isset($crit->param[1][0])) {
279
+        $type = calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
280
+    }
281
+
282
+    $debut = ($type[0] !== "'") ? "'debut'.$type" : ("'debut" . substr($type, 1));
283
+    $boucle->modificateur['debut_nom'] = $type;
284
+    $partie =
285
+        // tester si le numero de page demande est de la forme '@yyy'
286
+        'isset($Pile[0][' . $debut . ']) ? $Pile[0][' . $debut . '] : _request(' . $debut . ");\n"
287
+        . "\tif (\$debut_boucle && \$debut_boucle[0] === '@') {\n"
288
+        . "\t\t" . '$debut_boucle = $Pile[0][' . $debut . '] = quete_debut_pagination(\'' . $boucle->primary . '\',$Pile[0][\'@' . $boucle->primary . '\'] = substr($debut_boucle,1),' . $pas . ',$iter);' . "\n"
289
+        . "\t\t" . '$iter->seek(0);' . "\n"
290
+        . "\t}\n"
291
+        . "\t" . '$debut_boucle = intval($debut_boucle)';
292
+
293
+    $boucle->hash .= '
294 294
 	$command[\'pagination\'] = array((isset($Pile[0][' . $debut . ']) ? $Pile[0][' . $debut . '] : null), ' . $pas . ');';
295 295
 
296
-	$boucle->total_parties = $pas;
297
-	calculer_parties($boucles, $idb, $partie, 'p+');
298
-	// ajouter la cle primaire dans le select pour pouvoir gerer la pagination referencee par @id
299
-	// sauf si pas de primaire, ou si primaire composee
300
-	// dans ce cas, on ne sait pas gerer une pagination indirecte
301
-	$t = $boucle->id_table . '.' . $boucle->primary;
302
-	if (
303
-		$boucle->primary
304
-		and !preg_match('/[,\s]/', $boucle->primary)
305
-		and !in_array($t, $boucle->select)
306
-	) {
307
-		$boucle->select[] = $t;
308
-	}
296
+    $boucle->total_parties = $pas;
297
+    calculer_parties($boucles, $idb, $partie, 'p+');
298
+    // ajouter la cle primaire dans le select pour pouvoir gerer la pagination referencee par @id
299
+    // sauf si pas de primaire, ou si primaire composee
300
+    // dans ce cas, on ne sait pas gerer une pagination indirecte
301
+    $t = $boucle->id_table . '.' . $boucle->primary;
302
+    if (
303
+        $boucle->primary
304
+        and !preg_match('/[,\s]/', $boucle->primary)
305
+        and !in_array($t, $boucle->select)
306
+    ) {
307
+        $boucle->select[] = $t;
308
+    }
309 309
 }
310 310
 
311 311
 
@@ -327,24 +327,24 @@  discard block
 block discarded – undo
327 327
  **/
328 328
 function critere_recherche_dist($idb, &$boucles, $crit) {
329 329
 
330
-	$boucle = &$boucles[$idb];
330
+    $boucle = &$boucles[$idb];
331 331
 
332
-	if (!$boucle->primary or strpos($boucle->primary, ',')) {
333
-		erreur_squelette(_T('zbug_critere_sur_table_sans_cle_primaire', ['critere' => 'recherche']), $boucle);
332
+    if (!$boucle->primary or strpos($boucle->primary, ',')) {
333
+        erreur_squelette(_T('zbug_critere_sur_table_sans_cle_primaire', ['critere' => 'recherche']), $boucle);
334 334
 
335
-		return;
336
-	}
335
+        return;
336
+    }
337 337
 
338
-	if (isset($crit->param[0])) {
339
-		$quoi = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
340
-	} else {
341
-		$quoi = '(isset($Pile[0]["recherche"])?$Pile[0]["recherche"]:(isset($GLOBALS["recherche"])?$GLOBALS["recherche"]:""))';
342
-	}
338
+    if (isset($crit->param[0])) {
339
+        $quoi = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
340
+    } else {
341
+        $quoi = '(isset($Pile[0]["recherche"])?$Pile[0]["recherche"]:(isset($GLOBALS["recherche"])?$GLOBALS["recherche"]:""))';
342
+    }
343 343
 
344
-	$_modificateur = var_export($boucle->modificateur, true);
345
-	$boucle->hash .= '
344
+    $_modificateur = var_export($boucle->modificateur, true);
345
+    $boucle->hash .= '
346 346
 	// RECHERCHE'
347
-		. ($crit->cond ? '
347
+        . ($crit->cond ? '
348 348
 	if (!strlen(' . $quoi . ')){
349 349
 		list($rech_select, $rech_where) = array("0 as points","");
350 350
 	} else' : '') . '
@@ -355,21 +355,21 @@  discard block
 block discarded – undo
355 355
 	';
356 356
 
357 357
 
358
-	$t = $boucle->id_table . '.' . $boucle->primary;
359
-	if (!in_array($t, $boucles[$idb]->select)) {
360
-		$boucle->select[] = $t;
361
-	} # pour postgres, neuneu ici
362
-	// jointure uniquement sur le serveur principal
363
-	// (on ne peut joindre une table d'un serveur distant avec la table des resultats du serveur principal)
364
-	if (!$boucle->sql_serveur) {
365
-		$boucle->join['resultats'] = ["'" . $boucle->id_table . "'", "'id'", "'" . $boucle->primary . "'"];
366
-		$boucle->from['resultats'] = 'spip_resultats';
367
-	}
368
-	$boucle->select[] = '$rech_select';
369
-	//$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";
370
-
371
-	// et la recherche trouve
372
-	$boucle->where[] = '$rech_where?$rech_where:\'\'';
358
+    $t = $boucle->id_table . '.' . $boucle->primary;
359
+    if (!in_array($t, $boucles[$idb]->select)) {
360
+        $boucle->select[] = $t;
361
+    } # pour postgres, neuneu ici
362
+    // jointure uniquement sur le serveur principal
363
+    // (on ne peut joindre une table d'un serveur distant avec la table des resultats du serveur principal)
364
+    if (!$boucle->sql_serveur) {
365
+        $boucle->join['resultats'] = ["'" . $boucle->id_table . "'", "'id'", "'" . $boucle->primary . "'"];
366
+        $boucle->from['resultats'] = 'spip_resultats';
367
+    }
368
+    $boucle->select[] = '$rech_select';
369
+    //$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";
370
+
371
+    // et la recherche trouve
372
+    $boucle->where[] = '$rech_where?$rech_where:\'\'';
373 373
 }
374 374
 
375 375
 /**
@@ -386,25 +386,25 @@  discard block
 block discarded – undo
386 386
  * @return void
387 387
  **/
388 388
 function critere_traduction_dist($idb, &$boucles, $crit) {
389
-	$boucle = &$boucles[$idb];
390
-	$prim = $boucle->primary;
391
-	$table = $boucle->id_table;
392
-	$arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles));
393
-	$dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles));
394
-	$boucle->where[] =
395
-		[
396
-			"'OR'",
397
-			[
398
-				"'AND'",
399
-				["'='", "'$table.id_trad'", 0],
400
-				["'='", "'$table.$prim'", $dprim]
401
-			],
402
-			[
403
-				"'AND'",
404
-				["'>'", "'$table.id_trad'", 0],
405
-				["'='", "'$table.id_trad'", $arg]
406
-			]
407
-		];
389
+    $boucle = &$boucles[$idb];
390
+    $prim = $boucle->primary;
391
+    $table = $boucle->id_table;
392
+    $arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles));
393
+    $dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles));
394
+    $boucle->where[] =
395
+        [
396
+            "'OR'",
397
+            [
398
+                "'AND'",
399
+                ["'='", "'$table.id_trad'", 0],
400
+                ["'='", "'$table.$prim'", $dprim]
401
+            ],
402
+            [
403
+                "'AND'",
404
+                ["'>'", "'$table.id_trad'", 0],
405
+                ["'='", "'$table.id_trad'", $arg]
406
+            ]
407
+        ];
408 408
 }
409 409
 
410 410
 
@@ -422,17 +422,17 @@  discard block
 block discarded – undo
422 422
  * @return void
423 423
  **/
424 424
 function critere_origine_traduction_dist($idb, &$boucles, $crit) {
425
-	$boucle = &$boucles[$idb];
426
-	$prim = $boucle->primary;
427
-	$table = $boucle->id_table;
428
-
429
-	$c =
430
-		[
431
-			"'OR'",
432
-			["'='", "'$table." . "id_trad'", "'$table.$prim'"],
433
-			["'='", "'$table.id_trad'", "'0'"]
434
-		];
435
-	$boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
425
+    $boucle = &$boucles[$idb];
426
+    $prim = $boucle->primary;
427
+    $table = $boucle->id_table;
428
+
429
+    $c =
430
+        [
431
+            "'OR'",
432
+            ["'='", "'$table." . "id_trad'", "'$table.$prim'"],
433
+            ["'='", "'$table.id_trad'", "'0'"]
434
+        ];
435
+    $boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
436 436
 }
437 437
 
438 438
 
@@ -449,17 +449,17 @@  discard block
 block discarded – undo
449 449
  **/
450 450
 function critere_meme_parent_dist($idb, &$boucles, $crit) {
451 451
 
452
-	$boucle = &$boucles[$idb];
453
-	$arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
454
-	$id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
455
-	$mparent = $boucle->id_table . '.' . $id_parent;
456
-
457
-	if ($boucle->type_requete == 'rubriques' or isset($GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'])) {
458
-		$boucle->where[] = ["'='", "'$mparent'", $arg];
459
-	} // le cas FORUMS est gere dans le plugin forum, dans la fonction critere_FORUMS_meme_parent_dist()
460
-	else {
461
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $boucle->type_requete]];
462
-	}
452
+    $boucle = &$boucles[$idb];
453
+    $arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
454
+    $id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
455
+    $mparent = $boucle->id_table . '.' . $id_parent;
456
+
457
+    if ($boucle->type_requete == 'rubriques' or isset($GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'])) {
458
+        $boucle->where[] = ["'='", "'$mparent'", $arg];
459
+    } // le cas FORUMS est gere dans le plugin forum, dans la fonction critere_FORUMS_meme_parent_dist()
460
+    else {
461
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $boucle->type_requete]];
462
+    }
463 463
 }
464 464
 
465 465
 
@@ -490,37 +490,37 @@  discard block
 block discarded – undo
490 490
  **/
491 491
 function critere_branche_dist($idb, &$boucles, $crit) {
492 492
 
493
-	$not = $crit->not;
494
-	$boucle = &$boucles[$idb];
495
-	// prendre en priorite un identifiant en parametre {branche XX}
496
-	if (isset($crit->param[0])) {
497
-		$arg = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
498
-		// sinon on le prend chez une boucle parente
499
-	} else {
500
-		$arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles), $boucle->sql_serveur, 'int NOT NULL');
501
-	}
502
-
503
-	//Trouver une jointure
504
-	$champ = 'id_rubrique';
505
-	$desc = $boucle->show;
506
-	//Seulement si necessaire
507
-	if (!array_key_exists($champ, $desc['field'])) {
508
-		$cle = trouver_jointure_champ($champ, $boucle);
509
-		$trouver_table = charger_fonction('trouver_table', 'base');
510
-		$desc = $trouver_table($boucle->from[$cle]);
511
-		if (count(trouver_champs_decomposes($champ, $desc)) > 1) {
512
-			$decompose = decompose_champ_id_objet($champ);
513
-			$champ = array_shift($decompose);
514
-			$boucle->where[] = ["'='", _q($cle . '.' . reset($decompose)), '"' . sql_quote(end($decompose)) . '"'];
515
-		}
516
-	} else {
517
-		$cle = $boucle->id_table;
518
-	}
519
-
520
-	$c = "sql_in('$cle" . ".$champ', calcul_branche_in($arg)"
521
-		. ($not ? ", 'NOT'" : '') . ')';
522
-	$boucle->where[] = !$crit->cond ? $c :
523
-		("($arg ? $c : " . ($not ? "'0=1'" : "'1=1'") . ')');
493
+    $not = $crit->not;
494
+    $boucle = &$boucles[$idb];
495
+    // prendre en priorite un identifiant en parametre {branche XX}
496
+    if (isset($crit->param[0])) {
497
+        $arg = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
498
+        // sinon on le prend chez une boucle parente
499
+    } else {
500
+        $arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles), $boucle->sql_serveur, 'int NOT NULL');
501
+    }
502
+
503
+    //Trouver une jointure
504
+    $champ = 'id_rubrique';
505
+    $desc = $boucle->show;
506
+    //Seulement si necessaire
507
+    if (!array_key_exists($champ, $desc['field'])) {
508
+        $cle = trouver_jointure_champ($champ, $boucle);
509
+        $trouver_table = charger_fonction('trouver_table', 'base');
510
+        $desc = $trouver_table($boucle->from[$cle]);
511
+        if (count(trouver_champs_decomposes($champ, $desc)) > 1) {
512
+            $decompose = decompose_champ_id_objet($champ);
513
+            $champ = array_shift($decompose);
514
+            $boucle->where[] = ["'='", _q($cle . '.' . reset($decompose)), '"' . sql_quote(end($decompose)) . '"'];
515
+        }
516
+    } else {
517
+        $cle = $boucle->id_table;
518
+    }
519
+
520
+    $c = "sql_in('$cle" . ".$champ', calcul_branche_in($arg)"
521
+        . ($not ? ", 'NOT'" : '') . ')';
522
+    $boucle->where[] = !$crit->cond ? $c :
523
+        ("($arg ? $c : " . ($not ? "'0=1'" : "'1=1'") . ')');
524 524
 }
525 525
 
526 526
 /**
@@ -536,15 +536,15 @@  discard block
 block discarded – undo
536 536
  **/
537 537
 function critere_logo_dist($idb, &$boucles, $crit) {
538 538
 
539
-	$boucle = &$boucles[$idb];
540
-	$not = ($crit->not ? 'NOT' : '');
541
-	$serveur = $boucle->sql_serveur;
539
+    $boucle = &$boucles[$idb];
540
+    $not = ($crit->not ? 'NOT' : '');
541
+    $serveur = $boucle->sql_serveur;
542 542
 
543
-	$c = "sql_in('" .
544
-		$boucle->id_table . '.' . $boucle->primary
545
-		. "', lister_objets_avec_logos('" . $boucle->primary . "'), '$not', '$serveur')";
543
+    $c = "sql_in('" .
544
+        $boucle->id_table . '.' . $boucle->primary
545
+        . "', lister_objets_avec_logos('" . $boucle->primary . "'), '$not', '$serveur')";
546 546
 
547
-	$boucle->where[] = $c;
547
+    $boucle->where[] = $c;
548 548
 }
549 549
 
550 550
 
@@ -566,31 +566,31 @@  discard block
 block discarded – undo
566 566
  * @return void|array
567 567
  **/
568 568
 function critere_fusion_dist($idb, &$boucles, $crit) {
569
-	if ($t = isset($crit->param[0])) {
570
-		$t = $crit->param[0];
571
-		if ($t[0]->type == 'texte') {
572
-			$t = $t[0]->texte;
573
-			if (preg_match('/^(.*)\.(.*)$/', $t, $r)) {
574
-				$t = table_objet_sql($r[1]);
575
-				$t = array_search($t, $boucles[$idb]->from);
576
-				if ($t) {
577
-					$t .= '.' . $r[2];
578
-				}
579
-			}
580
-		} else {
581
-			$t = '".'
582
-				. calculer_critere_arg_dynamique($idb, $boucles, $t)
583
-				. '."';
584
-		}
585
-	}
586
-	if ($t) {
587
-		$boucles[$idb]->group[] = $t;
588
-		if (!in_array($t, $boucles[$idb]->select)) {
589
-			$boucles[$idb]->select[] = $t;
590
-		}
591
-	} else {
592
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
593
-	}
569
+    if ($t = isset($crit->param[0])) {
570
+        $t = $crit->param[0];
571
+        if ($t[0]->type == 'texte') {
572
+            $t = $t[0]->texte;
573
+            if (preg_match('/^(.*)\.(.*)$/', $t, $r)) {
574
+                $t = table_objet_sql($r[1]);
575
+                $t = array_search($t, $boucles[$idb]->from);
576
+                if ($t) {
577
+                    $t .= '.' . $r[2];
578
+                }
579
+            }
580
+        } else {
581
+            $t = '".'
582
+                . calculer_critere_arg_dynamique($idb, $boucles, $t)
583
+                . '."';
584
+        }
585
+    }
586
+    if ($t) {
587
+        $boucles[$idb]->group[] = $t;
588
+        if (!in_array($t, $boucles[$idb]->select)) {
589
+            $boucles[$idb]->select[] = $t;
590
+        }
591
+    } else {
592
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
593
+    }
594 594
 }
595 595
 
596 596
 /**
@@ -610,7 +610,7 @@  discard block
 block discarded – undo
610 610
  * @return void
611 611
  **/
612 612
 function critere_fusion_supprimer_dist($idb, &$boucles, $crit) {
613
-	$boucles[$idb]->group = [];
613
+    $boucles[$idb]->group = [];
614 614
 }
615 615
 
616 616
 /**
@@ -647,44 +647,44 @@  discard block
 block discarded – undo
647 647
  * @param Critere $crit Paramètres du critère dans cette boucle
648 648
  */
649 649
 function critere_collecte_dist($idb, &$boucles, $crit) {
650
-	if (isset($crit->param[0])) {
651
-		$_coll = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
652
-		$boucle = $boucles[$idb];
653
-		$boucle->modificateur['collate'] = "($_coll ?' COLLATE '.$_coll:'')";
654
-		$n = is_countable($boucle->order) ? count($boucle->order) : 0;
655
-		if ($n && (strpos($boucle->order[$n - 1], 'COLLATE') === false)) {
656
-			// l'instruction COLLATE doit être placée avant ASC ou DESC
657
-			// notamment lors de l'utilisation `{!par xxx}{collate yyy}`
658
-			if (
659
-				(false !== $i = strpos($boucle->order[$n - 1], 'ASC'))
660
-				or (false !== $i = strpos($boucle->order[$n - 1], 'DESC'))
661
-			) {
662
-				$boucle->order[$n - 1] = substr_replace($boucle->order[$n - 1], "' . " . $boucle->modificateur['collate'] . " . ' ", $i, 0);
663
-			} else {
664
-				$boucle->order[$n - 1] .= ' . ' . $boucle->modificateur['collate'];
665
-			}
666
-		}
667
-	} else {
668
-		return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . (is_countable($boucles[$idb]->order) ? count($boucles[$idb]->order) : 0)]]);
669
-	}
650
+    if (isset($crit->param[0])) {
651
+        $_coll = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
652
+        $boucle = $boucles[$idb];
653
+        $boucle->modificateur['collate'] = "($_coll ?' COLLATE '.$_coll:'')";
654
+        $n = is_countable($boucle->order) ? count($boucle->order) : 0;
655
+        if ($n && (strpos($boucle->order[$n - 1], 'COLLATE') === false)) {
656
+            // l'instruction COLLATE doit être placée avant ASC ou DESC
657
+            // notamment lors de l'utilisation `{!par xxx}{collate yyy}`
658
+            if (
659
+                (false !== $i = strpos($boucle->order[$n - 1], 'ASC'))
660
+                or (false !== $i = strpos($boucle->order[$n - 1], 'DESC'))
661
+            ) {
662
+                $boucle->order[$n - 1] = substr_replace($boucle->order[$n - 1], "' . " . $boucle->modificateur['collate'] . " . ' ", $i, 0);
663
+            } else {
664
+                $boucle->order[$n - 1] .= ' . ' . $boucle->modificateur['collate'];
665
+            }
666
+        }
667
+    } else {
668
+        return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . (is_countable($boucles[$idb]->order) ? count($boucles[$idb]->order) : 0)]]);
669
+    }
670 670
 }
671 671
 
672 672
 function calculer_critere_arg_dynamique($idb, &$boucles, $crit, $suffix = '') {
673
-	$boucle = $boucles[$idb];
674
-	$alt = "('" . $boucle->id_table . '.\' . $x' . $suffix . ')';
675
-	$var = '$champs_' . $idb;
676
-	$desc = (strpos($boucle->in, (string) "static $var =") !== false);
677
-	if (!$desc) {
678
-		$desc = $boucle->show['field'];
679
-		$desc = implode(',', array_map('_q', array_keys($desc)));
680
-		$boucles[$idb]->in .= "\n\tstatic $var = array(" . $desc . ');';
681
-	}
682
-	if ($desc) {
683
-		$alt = "(in_array(\$x, $var)  ? $alt :(\$x$suffix))";
684
-	}
685
-	$arg = calculer_liste($crit, $idb, $boucles, $boucle->id_parent);
686
-
687
-	return "((\$x = preg_replace(\"/\\W/\",'', $arg)) ? $alt : '')";
673
+    $boucle = $boucles[$idb];
674
+    $alt = "('" . $boucle->id_table . '.\' . $x' . $suffix . ')';
675
+    $var = '$champs_' . $idb;
676
+    $desc = (strpos($boucle->in, (string) "static $var =") !== false);
677
+    if (!$desc) {
678
+        $desc = $boucle->show['field'];
679
+        $desc = implode(',', array_map('_q', array_keys($desc)));
680
+        $boucles[$idb]->in .= "\n\tstatic $var = array(" . $desc . ');';
681
+    }
682
+    if ($desc) {
683
+        $alt = "(in_array(\$x, $var)  ? $alt :(\$x$suffix))";
684
+    }
685
+    $arg = calculer_liste($crit, $idb, $boucles, $boucle->id_parent);
686
+
687
+    return "((\$x = preg_replace(\"/\\W/\",'', $arg)) ? $alt : '')";
688 688
 }
689 689
 
690 690
 /**
@@ -723,7 +723,7 @@  discard block
 block discarded – undo
723 723
  * @param Critere $crit Paramètres du critère dans cette boucle
724 724
  */
725 725
 function critere_par_dist($idb, &$boucles, $crit) {
726
-	return critere_parinverse($idb, $boucles, $crit);
726
+    return critere_parinverse($idb, $boucles, $crit);
727 727
 }
728 728
 
729 729
 /**
@@ -745,93 +745,93 @@  discard block
 block discarded – undo
745 745
  * @param Critere $crit Paramètres du critère dans cette boucle
746 746
  */
747 747
 function critere_parinverse($idb, &$boucles, $crit) {
748
-	$boucle = &$boucles[$idb];
749
-
750
-	$sens = $collecte = '';
751
-	if ($crit->not) {
752
-		$sens = " . ' DESC'";
753
-	}
754
-	if (isset($boucle->modificateur['collate'])) {
755
-		$collecte = ' . ' . $boucle->modificateur['collate'];
756
-	}
757
-
758
-	// Pour chaque paramètre du critère
759
-	foreach ($crit->param as $tri) {
760
-		$order = $fct = '';
761
-		// tris specifiés dynamiquement {par #ENV{tri}}
762
-		if ($tri[0]->type != 'texte') {
763
-			// calculer le order dynamique qui verifie les champs
764
-			$order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
765
-			// ajouter 'hasard' comme possibilité de tri dynamique
766
-			calculer_critere_par_hasard($idb, $boucles, $crit);
767
-		}
768
-		// tris textuels {par titre}
769
-		else {
770
-			$par = array_shift($tri);
771
-			$par = $par->texte;
772
-
773
-			// tris de la forme {par expression champ} tel que {par num titre} ou {par multi titre}
774
-			if (preg_match(',^(\w+)[\s]+(.*)$,', $par, $m)) {
775
-				$expression = trim($m[1]);
776
-				$champ = trim($m[2]);
777
-				if (function_exists($f = 'calculer_critere_par_expression_' . $expression)) {
778
-					$order = $f($idb, $boucles, $crit, $tri, $champ);
779
-				} else {
780
-					return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
781
-				}
782
-
783
-			// tris de la forme {par champ} ou {par FONCTION(champ)}
784
-			} elseif ($boucle->type_requete == 'DATA' or preg_match(',^' . CHAMP_SQL_PLUS_FONC . '$,is', $par, $match)) {
785
-				// {par FONCTION(champ)}
786
-				if (isset($match) and count($match) > 2) {
787
-					$par = substr($match[2], 1, -1);
788
-					$fct = $match[1];
789
-				}
790
-				// quelques cas spécifiques {par hasard}, {par date}
791
-				if ($par == 'hasard') {
792
-					$order = calculer_critere_par_hasard($idb, $boucles, $crit);
793
-				} elseif ($par == 'date' and !empty($boucle->show['date'])) {
794
-					$order = "'" . $boucle->id_table . '.' . $boucle->show['date'] . "'";
795
-				} else {
796
-					// cas général {par champ}, {par table.champ}, ...
797
-					$order = calculer_critere_par_champ($idb, $boucles, $crit, $par);
798
-				}
799
-			}
800
-
801
-			// on ne sait pas traiter…
802
-			else {
803
-				return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
804
-			}
805
-
806
-			// En cas d'erreur de squelette retournée par une fonction
807
-			if (is_array($order)) {
808
-				return $order;
809
-			}
810
-		}
811
-
812
-		if (preg_match('/^\'([^"]*)\'$/', $order, $m)) {
813
-			$t = $m[1];
814
-			if (strpos($t, '.') and !in_array($t, $boucle->select)) {
815
-				$boucle->select[] = $t;
816
-			}
817
-		} else {
818
-			$sens = '';
819
-		}
820
-
821
-		if ($fct) {
822
-			if (preg_match("/^\s*'(.*)'\s*$/", $order, $r)) {
823
-				$order = "'$fct(" . $r[1] . ")'";
824
-			} else {
825
-				$order = "'$fct(' . $order . ')'";
826
-			}
827
-		}
828
-		$t = $order . $collecte . $sens;
829
-		if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
830
-			$t = $r[1] . $r[2];
831
-		}
832
-
833
-		$boucle->order[] = $t;
834
-	}
748
+    $boucle = &$boucles[$idb];
749
+
750
+    $sens = $collecte = '';
751
+    if ($crit->not) {
752
+        $sens = " . ' DESC'";
753
+    }
754
+    if (isset($boucle->modificateur['collate'])) {
755
+        $collecte = ' . ' . $boucle->modificateur['collate'];
756
+    }
757
+
758
+    // Pour chaque paramètre du critère
759
+    foreach ($crit->param as $tri) {
760
+        $order = $fct = '';
761
+        // tris specifiés dynamiquement {par #ENV{tri}}
762
+        if ($tri[0]->type != 'texte') {
763
+            // calculer le order dynamique qui verifie les champs
764
+            $order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
765
+            // ajouter 'hasard' comme possibilité de tri dynamique
766
+            calculer_critere_par_hasard($idb, $boucles, $crit);
767
+        }
768
+        // tris textuels {par titre}
769
+        else {
770
+            $par = array_shift($tri);
771
+            $par = $par->texte;
772
+
773
+            // tris de la forme {par expression champ} tel que {par num titre} ou {par multi titre}
774
+            if (preg_match(',^(\w+)[\s]+(.*)$,', $par, $m)) {
775
+                $expression = trim($m[1]);
776
+                $champ = trim($m[2]);
777
+                if (function_exists($f = 'calculer_critere_par_expression_' . $expression)) {
778
+                    $order = $f($idb, $boucles, $crit, $tri, $champ);
779
+                } else {
780
+                    return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
781
+                }
782
+
783
+            // tris de la forme {par champ} ou {par FONCTION(champ)}
784
+            } elseif ($boucle->type_requete == 'DATA' or preg_match(',^' . CHAMP_SQL_PLUS_FONC . '$,is', $par, $match)) {
785
+                // {par FONCTION(champ)}
786
+                if (isset($match) and count($match) > 2) {
787
+                    $par = substr($match[2], 1, -1);
788
+                    $fct = $match[1];
789
+                }
790
+                // quelques cas spécifiques {par hasard}, {par date}
791
+                if ($par == 'hasard') {
792
+                    $order = calculer_critere_par_hasard($idb, $boucles, $crit);
793
+                } elseif ($par == 'date' and !empty($boucle->show['date'])) {
794
+                    $order = "'" . $boucle->id_table . '.' . $boucle->show['date'] . "'";
795
+                } else {
796
+                    // cas général {par champ}, {par table.champ}, ...
797
+                    $order = calculer_critere_par_champ($idb, $boucles, $crit, $par);
798
+                }
799
+            }
800
+
801
+            // on ne sait pas traiter…
802
+            else {
803
+                return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
804
+            }
805
+
806
+            // En cas d'erreur de squelette retournée par une fonction
807
+            if (is_array($order)) {
808
+                return $order;
809
+            }
810
+        }
811
+
812
+        if (preg_match('/^\'([^"]*)\'$/', $order, $m)) {
813
+            $t = $m[1];
814
+            if (strpos($t, '.') and !in_array($t, $boucle->select)) {
815
+                $boucle->select[] = $t;
816
+            }
817
+        } else {
818
+            $sens = '';
819
+        }
820
+
821
+        if ($fct) {
822
+            if (preg_match("/^\s*'(.*)'\s*$/", $order, $r)) {
823
+                $order = "'$fct(" . $r[1] . ")'";
824
+            } else {
825
+                $order = "'$fct(' . $order . ')'";
826
+            }
827
+        }
828
+        $t = $order . $collecte . $sens;
829
+        if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
830
+            $t = $r[1] . $r[2];
831
+        }
832
+
833
+        $boucle->order[] = $t;
834
+    }
835 835
 }
836 836
 
837 837
 /**
@@ -845,13 +845,13 @@  discard block
 block discarded – undo
845 845
  * @return string Clause pour le Order by
846 846
  */
847 847
 function calculer_critere_par_hasard($idb, &$boucles, $crit) {
848
-	$boucle = &$boucles[$idb];
849
-	// Si ce n'est fait, ajouter un champ 'hasard' dans le select
850
-	$parha = 'rand() AS hasard';
851
-	if (!in_array($parha, $boucle->select)) {
852
-		$boucle->select[] = $parha;
853
-	}
854
-	return "'hasard'";
848
+    $boucle = &$boucles[$idb];
849
+    // Si ce n'est fait, ajouter un champ 'hasard' dans le select
850
+    $parha = 'rand() AS hasard';
851
+    if (!in_array($parha, $boucle->select)) {
852
+        $boucle->select[] = $parha;
853
+    }
854
+    return "'hasard'";
855 855
 }
856 856
 
857 857
 /**
@@ -875,24 +875,24 @@  discard block
 block discarded – undo
875 875
  * @return string|array Clause pour le Order by (array si erreur)
876 876
  */
877 877
 function calculer_critere_par_expression_num($idb, &$boucles, $crit, $tri, $champ) {
878
-	$_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
879
-	if (is_array($_champ)) {
880
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . " num $champ"]];
881
-	}
882
-	$boucle = &$boucles[$idb];
883
-	$texte = '0+' . $_champ;
884
-	$suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
885
-	if ($suite !== "''") {
886
-		$texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
887
-	}
888
-	$asnum = 'num' . ($boucle->order ? count($boucle->order) : '');
889
-	$boucle->select[] = $texte . " AS $asnum";
890
-
891
-	$orderassinum = calculer_critere_par_expression_sinum($idb, $boucles, $crit, $tri, $champ);
892
-	$orderassinum = trim($orderassinum, "'");
893
-
894
-	$order = "'$orderassinum, $asnum'";
895
-	return $order;
878
+    $_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
879
+    if (is_array($_champ)) {
880
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . " num $champ"]];
881
+    }
882
+    $boucle = &$boucles[$idb];
883
+    $texte = '0+' . $_champ;
884
+    $suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
885
+    if ($suite !== "''") {
886
+        $texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
887
+    }
888
+    $asnum = 'num' . ($boucle->order ? count($boucle->order) : '');
889
+    $boucle->select[] = $texte . " AS $asnum";
890
+
891
+    $orderassinum = calculer_critere_par_expression_sinum($idb, $boucles, $crit, $tri, $champ);
892
+    $orderassinum = trim($orderassinum, "'");
893
+
894
+    $order = "'$orderassinum, $asnum'";
895
+    return $order;
896 896
 }
897 897
 
898 898
 /**
@@ -913,35 +913,35 @@  discard block
 block discarded – undo
913 913
  * @return string|array Clause pour le Order by (array si erreur)
914 914
  */
915 915
 function calculer_critere_par_expression_sinum($idb, &$boucles, $crit, $tri, $champ) {
916
-	$_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
917
-	if (is_array($_champ)) {
918
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . " sinum $champ"]];
919
-	}
920
-	$boucle = &$boucles[$idb];
921
-	$texte = '0+' . $_champ;
922
-	$suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
923
-	if ($suite !== "''") {
924
-		$texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
925
-	}
926
-
927
-	$as = false;
928
-	$select = "CASE ( $texte ) WHEN 0 THEN 1 ELSE 0 END AS ";
929
-	foreach ($boucle->select as $s) {
930
-		if (strpos($s, $select) === 0) {
931
-			$as = trim(substr($s, strlen($select)));
932
-			if (!preg_match(',\W,', $as)) {
933
-				break;
934
-			}
935
-			$as = false;
936
-		}
937
-	}
938
-
939
-	if (!$as) {
940
-		$as = 'sinum' . ($boucle->order ? count($boucle->order) : '');
941
-		$boucle->select[] = $select . $as;
942
-	}
943
-	$order = "'$as'";
944
-	return $order;
916
+    $_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
917
+    if (is_array($_champ)) {
918
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . " sinum $champ"]];
919
+    }
920
+    $boucle = &$boucles[$idb];
921
+    $texte = '0+' . $_champ;
922
+    $suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
923
+    if ($suite !== "''") {
924
+        $texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
925
+    }
926
+
927
+    $as = false;
928
+    $select = "CASE ( $texte ) WHEN 0 THEN 1 ELSE 0 END AS ";
929
+    foreach ($boucle->select as $s) {
930
+        if (strpos($s, $select) === 0) {
931
+            $as = trim(substr($s, strlen($select)));
932
+            if (!preg_match(',\W,', $as)) {
933
+                break;
934
+            }
935
+            $as = false;
936
+        }
937
+    }
938
+
939
+    if (!$as) {
940
+        $as = 'sinum' . ($boucle->order ? count($boucle->order) : '');
941
+        $boucle->select[] = $select . $as;
942
+    }
943
+    $order = "'$as'";
944
+    return $order;
945 945
 }
946 946
 
947 947
 
@@ -961,14 +961,14 @@  discard block
 block discarded – undo
961 961
  * @return string|array Clause pour le Order by (array si erreur)
962 962
  */
963 963
 function calculer_critere_par_expression_multi($idb, &$boucles, $crit, $tri, $champ) {
964
-	$_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
965
-	if (is_array($_champ)) {
966
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . " multi $champ"]];
967
-	}
968
-	$boucle = &$boucles[$idb];
969
-	$boucle->select[] = "\".sql_multi('" . $_champ . "', \$GLOBALS['spip_lang']).\"";
970
-	$order = "'multi'";
971
-	return $order;
964
+    $_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
965
+    if (is_array($_champ)) {
966
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . " multi $champ"]];
967
+    }
968
+    $boucle = &$boucles[$idb];
969
+    $boucle->select[] = "\".sql_multi('" . $_champ . "', \$GLOBALS['spip_lang']).\"";
970
+    $order = "'multi'";
971
+    return $order;
972 972
 }
973 973
 
974 974
 /**
@@ -987,56 +987,56 @@  discard block
 block discarded – undo
987 987
  * @return array|string
988 988
  */
989 989
 function calculer_critere_par_champ($idb, &$boucles, $crit, $par, $raw = false) {
990
-	$boucle = &$boucles[$idb];
991
-	$desc = $boucle->show;
992
-
993
-	// le champ existe dans la table, pas de souci (le plus commun)
994
-	if (isset($desc['field'][$par])) {
995
-		$par = $boucle->id_table . '.' . $par;
996
-	}
997
-	// le champ est peut être une jointure
998
-	else {
999
-		$table = $table_alias = false; // toutes les tables de jointure possibles
1000
-		$champ = $par;
1001
-
1002
-		// le champ demandé est une exception de jointure {par titre_mot}
1003
-		if (isset($GLOBALS['exceptions_des_jointures'][$par])) {
1004
-			[$table, $champ] = $GLOBALS['exceptions_des_jointures'][$par];
1005
-		} // la table de jointure est explicitement indiquée {par truc.muche}
1006
-		elseif (preg_match('/^([^,]*)\.(.*)$/', $par, $r)) {
1007
-			[, $table, $champ] = $r;
1008
-			$table_alias = $table; // c'est peut-être un alias de table {par L1.titre}
1009
-			$table = table_objet_sql($table);
1010
-		}
1011
-
1012
-		// Si on connait la table d'arrivée, on la demande donc explicitement
1013
-		// Sinon on cherche le champ dans les tables possibles de jointures
1014
-		// Si la table est déjà dans le from, on la réutilise.
1015
-		if ($infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $table)) {
1016
-			$par = $infos['alias'] . '.' . $champ;
1017
-		} elseif (
1018
-			$boucle->jointures_explicites
1019
-			and $alias = trouver_jointure_champ($champ, $boucle, explode(' ', $boucle->jointures_explicites), false, $table)
1020
-		) {
1021
-			$par = $alias . '.' . $champ;
1022
-		} elseif ($alias = trouver_jointure_champ($champ, $boucle, $boucle->jointures, false, $table)) {
1023
-			$par = $alias . '.' . $champ;
1024
-		// en spécifiant directement l'alias {par L2.titre} (situation hasardeuse tout de même)
1025
-		} elseif (
1026
-			$table_alias
1027
-			and isset($boucle->from[$table_alias])
1028
-			and $infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $boucle->from[$table_alias])
1029
-		) {
1030
-			$par = $infos['alias'] . '.' . $champ;
1031
-		} elseif ($table) {
1032
-			// On avait table + champ, mais on ne les a pas trouvés
1033
-			return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
1034
-		} else {
1035
-			// Sinon tant pis, ca doit etre un champ synthetise (cf points)
1036
-		}
1037
-	}
1038
-
1039
-	return $raw ? $par : "'$par'";
990
+    $boucle = &$boucles[$idb];
991
+    $desc = $boucle->show;
992
+
993
+    // le champ existe dans la table, pas de souci (le plus commun)
994
+    if (isset($desc['field'][$par])) {
995
+        $par = $boucle->id_table . '.' . $par;
996
+    }
997
+    // le champ est peut être une jointure
998
+    else {
999
+        $table = $table_alias = false; // toutes les tables de jointure possibles
1000
+        $champ = $par;
1001
+
1002
+        // le champ demandé est une exception de jointure {par titre_mot}
1003
+        if (isset($GLOBALS['exceptions_des_jointures'][$par])) {
1004
+            [$table, $champ] = $GLOBALS['exceptions_des_jointures'][$par];
1005
+        } // la table de jointure est explicitement indiquée {par truc.muche}
1006
+        elseif (preg_match('/^([^,]*)\.(.*)$/', $par, $r)) {
1007
+            [, $table, $champ] = $r;
1008
+            $table_alias = $table; // c'est peut-être un alias de table {par L1.titre}
1009
+            $table = table_objet_sql($table);
1010
+        }
1011
+
1012
+        // Si on connait la table d'arrivée, on la demande donc explicitement
1013
+        // Sinon on cherche le champ dans les tables possibles de jointures
1014
+        // Si la table est déjà dans le from, on la réutilise.
1015
+        if ($infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $table)) {
1016
+            $par = $infos['alias'] . '.' . $champ;
1017
+        } elseif (
1018
+            $boucle->jointures_explicites
1019
+            and $alias = trouver_jointure_champ($champ, $boucle, explode(' ', $boucle->jointures_explicites), false, $table)
1020
+        ) {
1021
+            $par = $alias . '.' . $champ;
1022
+        } elseif ($alias = trouver_jointure_champ($champ, $boucle, $boucle->jointures, false, $table)) {
1023
+            $par = $alias . '.' . $champ;
1024
+        // en spécifiant directement l'alias {par L2.titre} (situation hasardeuse tout de même)
1025
+        } elseif (
1026
+            $table_alias
1027
+            and isset($boucle->from[$table_alias])
1028
+            and $infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $boucle->from[$table_alias])
1029
+        ) {
1030
+            $par = $infos['alias'] . '.' . $champ;
1031
+        } elseif ($table) {
1032
+            // On avait table + champ, mais on ne les a pas trouvés
1033
+            return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
1034
+        } else {
1035
+            // Sinon tant pis, ca doit etre un champ synthetise (cf points)
1036
+        }
1037
+    }
1038
+
1039
+    return $raw ? $par : "'$par'";
1040 1040
 }
1041 1041
 
1042 1042
 /**
@@ -1050,11 +1050,11 @@  discard block
 block discarded – undo
1050 1050
  * @return string Champ pour le compilateur si trouvé, tel que "'alias.champ'", sinon vide.
1051 1051
  */
1052 1052
 function critere_par_joint($table, $champ, &$boucle) {
1053
-	$t = array_search($table, $boucle->from);
1054
-	if (!$t) {
1055
-		$t = trouver_jointure_champ($champ, $boucle);
1056
-	}
1057
-	return !$t ? '' : ("'" . $t . '.' . $champ . "'");
1053
+    $t = array_search($table, $boucle->from);
1054
+    if (!$t) {
1055
+        $t = trouver_jointure_champ($champ, $boucle);
1056
+    }
1057
+    return !$t ? '' : ("'" . $t . '.' . $champ . "'");
1058 1058
 }
1059 1059
 
1060 1060
 /**
@@ -1079,33 +1079,33 @@  discard block
 block discarded – undo
1079 1079
  */
1080 1080
 function critere_inverse_dist($idb, &$boucles, $crit) {
1081 1081
 
1082
-	$boucle = &$boucles[$idb];
1083
-	// Classement par ordre inverse
1084
-	if ($crit->not) {
1085
-		critere_parinverse($idb, $boucles, $crit);
1086
-	} else {
1087
-		$order = "' DESC'";
1088
-		// Classement par ordre inverse fonction eventuelle de #ENV{...}
1089
-		if (isset($crit->param[0])) {
1090
-			$critere = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
1091
-			$order = "(($critere)?' DESC':'')";
1092
-		}
1093
-
1094
-		$n = is_countable($boucle->order) ? count($boucle->order) : 0;
1095
-		if (!$n) {
1096
-			if (isset($boucle->default_order[0])) {
1097
-				$boucle->default_order[0] .= ' . " DESC"';
1098
-			} else {
1099
-				$boucle->default_order[] = ' DESC';
1100
-			}
1101
-		} else {
1102
-			$t = $boucle->order[$n - 1] . " . $order";
1103
-			if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
1104
-				$t = $r[1] . $r[2];
1105
-			}
1106
-			$boucle->order[$n - 1] = $t;
1107
-		}
1108
-	}
1082
+    $boucle = &$boucles[$idb];
1083
+    // Classement par ordre inverse
1084
+    if ($crit->not) {
1085
+        critere_parinverse($idb, $boucles, $crit);
1086
+    } else {
1087
+        $order = "' DESC'";
1088
+        // Classement par ordre inverse fonction eventuelle de #ENV{...}
1089
+        if (isset($crit->param[0])) {
1090
+            $critere = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
1091
+            $order = "(($critere)?' DESC':'')";
1092
+        }
1093
+
1094
+        $n = is_countable($boucle->order) ? count($boucle->order) : 0;
1095
+        if (!$n) {
1096
+            if (isset($boucle->default_order[0])) {
1097
+                $boucle->default_order[0] .= ' . " DESC"';
1098
+            } else {
1099
+                $boucle->default_order[] = ' DESC';
1100
+            }
1101
+        } else {
1102
+            $t = $boucle->order[$n - 1] . " . $order";
1103
+            if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
1104
+                $t = $r[1] . $r[2];
1105
+            }
1106
+            $boucle->order[$n - 1] = $t;
1107
+        }
1108
+    }
1109 1109
 }
1110 1110
 
1111 1111
 /**
@@ -1117,139 +1117,139 @@  discard block
 block discarded – undo
1117 1117
  * @return void|array
1118 1118
  */
1119 1119
 function critere_par_ordre_liste_dist($idb, &$boucles, $crit) {
1120
-	$boucle = &$boucles[$idb];
1120
+    $boucle = &$boucles[$idb];
1121 1121
 
1122
-	$sens = $collecte = '';
1123
-	if ($crit->not) {
1124
-		$sens = " . ' DESC'";
1125
-	}
1122
+    $sens = $collecte = '';
1123
+    if ($crit->not) {
1124
+        $sens = " . ' DESC'";
1125
+    }
1126 1126
 
1127
-	$crit2 = clone $crit;
1128
-	$crit2->not = false;
1129
-	$crit2->param = [reset($crit->param)];
1130
-	$res = critere_parinverse($idb, $boucles, $crit2);
1127
+    $crit2 = clone $crit;
1128
+    $crit2->not = false;
1129
+    $crit2->param = [reset($crit->param)];
1130
+    $res = critere_parinverse($idb, $boucles, $crit2);
1131 1131
 
1132
-	// erreur ?
1133
-	if (is_array($res)) {
1134
-		return $res;
1135
-	}
1132
+    // erreur ?
1133
+    if (is_array($res)) {
1134
+        return $res;
1135
+    }
1136 1136
 
1137
-	$_order = array_pop($boucle->order);
1137
+    $_order = array_pop($boucle->order);
1138 1138
 
1139
-	$_liste = calculer_liste($crit->param[1], [], $boucles, $boucles[$idb]->id_parent);
1139
+    $_liste = calculer_liste($crit->param[1], [], $boucles, $boucles[$idb]->id_parent);
1140 1140
 
1141
-	$order = "'-FIELD(' . $_order . ',' . ((\$zl=formate_liste_critere_par_ordre_liste(array_reverse($_liste),'" . $boucle->sql_serveur . "')) ? \$zl : '0').')'$sens";
1142
-	$boucle->order[] = $order;
1141
+    $order = "'-FIELD(' . $_order . ',' . ((\$zl=formate_liste_critere_par_ordre_liste(array_reverse($_liste),'" . $boucle->sql_serveur . "')) ? \$zl : '0').')'$sens";
1142
+    $boucle->order[] = $order;
1143 1143
 }
1144 1144
 
1145 1145
 
1146 1146
 function critere_agenda_dist($idb, &$boucles, $crit) {
1147
-	$params = $crit->param;
1148
-
1149
-	if ((is_countable($params) ? count($params) : 0) < 1) {
1150
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
1151
-	}
1152
-
1153
-	$boucle = &$boucles[$idb];
1154
-	$parent = $boucle->id_parent;
1155
-	$fields = $boucle->show['field'];
1156
-
1157
-	$date = array_shift($params);
1158
-	$type = array_shift($params);
1159
-
1160
-	// la valeur $type doit etre connue a la compilation
1161
-	// donc etre forcement reduite a un litteral unique dans le source
1162
-	$type = is_object($type[0]) ? $type[0]->texte : null;
1163
-
1164
-	// La valeur date doit designer un champ de la table SQL.
1165
-	// Si c'est un litteral unique dans le source, verifier a la compil,
1166
-	// sinon synthetiser le test de verif pour execution ulterieure
1167
-	// On prendra arbitrairement le premier champ si test negatif.
1168
-	if (((is_countable($date) ? count($date) : 0) == 1) and ($date[0]->type == 'texte')) {
1169
-		$date = $date[0]->texte;
1170
-		if (!isset($fields[$date])) {
1171
-			return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $date]];
1172
-		}
1173
-	} else {
1174
-		$a = calculer_liste($date, $idb, $boucles, $parent);
1175
-		$noms = array_keys($fields);
1176
-		$defaut = $noms[0];
1177
-		$noms = join(' ', $noms);
1178
-		# bien laisser 2 espaces avant $nom pour que strpos<>0
1179
-		$cond = "(\$a=strval($a))AND\nstrpos(\"  $noms \",\" \$a \")";
1180
-		$date = "'.(($cond)\n?\$a:\"$defaut\").'";
1181
-	}
1182
-	$annee = $params ? array_shift($params) : '';
1183
-	$annee = "\n" . 'sprintf("%04d", ($x = ' .
1184
-		calculer_liste($annee, $idb, $boucles, $parent) .
1185
-		') ? $x : date("Y"))';
1186
-
1187
-	$mois = $params ? array_shift($params) : '';
1188
-	$mois = "\n" . 'sprintf("%02d", ($x = ' .
1189
-		calculer_liste($mois, $idb, $boucles, $parent) .
1190
-		') ? $x : date("m"))';
1191
-
1192
-	$jour = $params ? array_shift($params) : '';
1193
-	$jour = "\n" . 'sprintf("%02d", ($x = ' .
1194
-		calculer_liste($jour, $idb, $boucles, $parent) .
1195
-		') ? $x : date("d"))';
1196
-
1197
-	$annee2 = $params ? array_shift($params) : '';
1198
-	$annee2 = "\n" . 'sprintf("%04d", ($x = ' .
1199
-		calculer_liste($annee2, $idb, $boucles, $parent) .
1200
-		') ? $x : date("Y"))';
1201
-
1202
-	$mois2 = $params ? array_shift($params) : '';
1203
-	$mois2 = "\n" . 'sprintf("%02d", ($x = ' .
1204
-		calculer_liste($mois2, $idb, $boucles, $parent) .
1205
-		') ? $x : date("m"))';
1206
-
1207
-	$jour2 = $params ? array_shift($params) : '';
1208
-	$jour2 = "\n" . 'sprintf("%02d", ($x = ' .
1209
-		calculer_liste($jour2, $idb, $boucles, $parent) .
1210
-		') ? $x : date("d"))';
1211
-
1212
-	$date = $boucle->id_table . ".$date";
1213
-
1214
-	$quote_end = ",'" . $boucle->sql_serveur . "','text'";
1215
-	if ($type == 'jour') {
1216
-		$boucle->where[] = [
1217
-			"'='",
1218
-			"'DATE_FORMAT($date, \'%Y%m%d\')'",
1219
-			("sql_quote($annee . $mois . $jour$quote_end)")
1220
-		];
1221
-	} elseif ($type == 'mois') {
1222
-		$boucle->where[] = [
1223
-			"'='",
1224
-			"'DATE_FORMAT($date, \'%Y%m\')'",
1225
-			("sql_quote($annee . $mois$quote_end)")
1226
-		];
1227
-	} elseif ($type == 'semaine') {
1228
-		$boucle->where[] = [
1229
-			"'AND'",
1230
-			[
1231
-				"'>='",
1232
-				"'DATE_FORMAT($date, \'%Y%m%d\')'",
1233
-				("date_debut_semaine($annee, $mois, $jour)")
1234
-			],
1235
-			[
1236
-				"'<='",
1237
-				"'DATE_FORMAT($date, \'%Y%m%d\')'",
1238
-				("date_fin_semaine($annee, $mois, $jour)")
1239
-			]
1240
-		];
1241
-	} elseif ((is_countable($crit->param) ? count($crit->param) : 0) > 2) {
1242
-		$boucle->where[] = [
1243
-			"'AND'",
1244
-			[
1245
-				"'>='",
1246
-				"'DATE_FORMAT($date, \'%Y%m%d\')'",
1247
-				("sql_quote($annee . $mois . $jour$quote_end)")
1248
-			],
1249
-			["'<='", "'DATE_FORMAT($date, \'%Y%m%d\')'", ("sql_quote($annee2 . $mois2 . $jour2$quote_end)")]
1250
-		];
1251
-	}
1252
-	// sinon on prend tout
1147
+    $params = $crit->param;
1148
+
1149
+    if ((is_countable($params) ? count($params) : 0) < 1) {
1150
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
1151
+    }
1152
+
1153
+    $boucle = &$boucles[$idb];
1154
+    $parent = $boucle->id_parent;
1155
+    $fields = $boucle->show['field'];
1156
+
1157
+    $date = array_shift($params);
1158
+    $type = array_shift($params);
1159
+
1160
+    // la valeur $type doit etre connue a la compilation
1161
+    // donc etre forcement reduite a un litteral unique dans le source
1162
+    $type = is_object($type[0]) ? $type[0]->texte : null;
1163
+
1164
+    // La valeur date doit designer un champ de la table SQL.
1165
+    // Si c'est un litteral unique dans le source, verifier a la compil,
1166
+    // sinon synthetiser le test de verif pour execution ulterieure
1167
+    // On prendra arbitrairement le premier champ si test negatif.
1168
+    if (((is_countable($date) ? count($date) : 0) == 1) and ($date[0]->type == 'texte')) {
1169
+        $date = $date[0]->texte;
1170
+        if (!isset($fields[$date])) {
1171
+            return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $date]];
1172
+        }
1173
+    } else {
1174
+        $a = calculer_liste($date, $idb, $boucles, $parent);
1175
+        $noms = array_keys($fields);
1176
+        $defaut = $noms[0];
1177
+        $noms = join(' ', $noms);
1178
+        # bien laisser 2 espaces avant $nom pour que strpos<>0
1179
+        $cond = "(\$a=strval($a))AND\nstrpos(\"  $noms \",\" \$a \")";
1180
+        $date = "'.(($cond)\n?\$a:\"$defaut\").'";
1181
+    }
1182
+    $annee = $params ? array_shift($params) : '';
1183
+    $annee = "\n" . 'sprintf("%04d", ($x = ' .
1184
+        calculer_liste($annee, $idb, $boucles, $parent) .
1185
+        ') ? $x : date("Y"))';
1186
+
1187
+    $mois = $params ? array_shift($params) : '';
1188
+    $mois = "\n" . 'sprintf("%02d", ($x = ' .
1189
+        calculer_liste($mois, $idb, $boucles, $parent) .
1190
+        ') ? $x : date("m"))';
1191
+
1192
+    $jour = $params ? array_shift($params) : '';
1193
+    $jour = "\n" . 'sprintf("%02d", ($x = ' .
1194
+        calculer_liste($jour, $idb, $boucles, $parent) .
1195
+        ') ? $x : date("d"))';
1196
+
1197
+    $annee2 = $params ? array_shift($params) : '';
1198
+    $annee2 = "\n" . 'sprintf("%04d", ($x = ' .
1199
+        calculer_liste($annee2, $idb, $boucles, $parent) .
1200
+        ') ? $x : date("Y"))';
1201
+
1202
+    $mois2 = $params ? array_shift($params) : '';
1203
+    $mois2 = "\n" . 'sprintf("%02d", ($x = ' .
1204
+        calculer_liste($mois2, $idb, $boucles, $parent) .
1205
+        ') ? $x : date("m"))';
1206
+
1207
+    $jour2 = $params ? array_shift($params) : '';
1208
+    $jour2 = "\n" . 'sprintf("%02d", ($x = ' .
1209
+        calculer_liste($jour2, $idb, $boucles, $parent) .
1210
+        ') ? $x : date("d"))';
1211
+
1212
+    $date = $boucle->id_table . ".$date";
1213
+
1214
+    $quote_end = ",'" . $boucle->sql_serveur . "','text'";
1215
+    if ($type == 'jour') {
1216
+        $boucle->where[] = [
1217
+            "'='",
1218
+            "'DATE_FORMAT($date, \'%Y%m%d\')'",
1219
+            ("sql_quote($annee . $mois . $jour$quote_end)")
1220
+        ];
1221
+    } elseif ($type == 'mois') {
1222
+        $boucle->where[] = [
1223
+            "'='",
1224
+            "'DATE_FORMAT($date, \'%Y%m\')'",
1225
+            ("sql_quote($annee . $mois$quote_end)")
1226
+        ];
1227
+    } elseif ($type == 'semaine') {
1228
+        $boucle->where[] = [
1229
+            "'AND'",
1230
+            [
1231
+                "'>='",
1232
+                "'DATE_FORMAT($date, \'%Y%m%d\')'",
1233
+                ("date_debut_semaine($annee, $mois, $jour)")
1234
+            ],
1235
+            [
1236
+                "'<='",
1237
+                "'DATE_FORMAT($date, \'%Y%m%d\')'",
1238
+                ("date_fin_semaine($annee, $mois, $jour)")
1239
+            ]
1240
+        ];
1241
+    } elseif ((is_countable($crit->param) ? count($crit->param) : 0) > 2) {
1242
+        $boucle->where[] = [
1243
+            "'AND'",
1244
+            [
1245
+                "'>='",
1246
+                "'DATE_FORMAT($date, \'%Y%m%d\')'",
1247
+                ("sql_quote($annee . $mois . $jour$quote_end)")
1248
+            ],
1249
+            ["'<='", "'DATE_FORMAT($date, \'%Y%m%d\')'", ("sql_quote($annee2 . $mois2 . $jour2$quote_end)")]
1250
+        ];
1251
+    }
1252
+    // sinon on prend tout
1253 1253
 }
1254 1254
 
1255 1255
 
@@ -1274,33 +1274,33 @@  discard block
 block discarded – undo
1274 1274
  * @return void
1275 1275
  **/
1276 1276
 function calculer_critere_parties($idb, &$boucles, $crit) {
1277
-	$boucle = &$boucles[$idb];
1278
-	$a1 = $crit->param[0];
1279
-	$a2 = $crit->param[1];
1280
-	$op = $crit->op;
1281
-
1282
-	[$a11, $a12] = calculer_critere_parties_aux($idb, $boucles, $a1);
1283
-	[$a21, $a22] = calculer_critere_parties_aux($idb, $boucles, $a2);
1284
-
1285
-	if (($op == ',') && (is_numeric($a11) && (is_numeric($a21)))) {
1286
-		$boucle->limit = $a11 . ',' . $a21;
1287
-	} else {
1288
-		// 3 dans {1/3}, {2,3} ou {1,n-3}
1289
-		$boucle->total_parties = ($a21 != 'n') ? $a21 : $a22;
1290
-		// 2 dans {2/3}, {2,5}, {n-2,1}
1291
-		$partie = ($a11 != 'n') ? $a11 : $a12;
1292
-		$mode = (($op == '/') ? '/' :
1293
-			(($a11 == 'n') ? '-' : '+') . (($a21 == 'n') ? '-' : '+'));
1294
-		// cas simple {0,#ENV{truc}} compilons le en LIMIT :
1295
-		if ($a11 !== 'n' and $a21 !== 'n' and $mode == '++' and $op == ',') {
1296
-			$boucle->limit =
1297
-				(is_numeric($a11) ? "'$a11'" : $a11)
1298
-				. ".','."
1299
-				. (is_numeric($a21) ? "'$a21'" : $a21);
1300
-		} else {
1301
-			calculer_parties($boucles, $idb, $partie, $mode);
1302
-		}
1303
-	}
1277
+    $boucle = &$boucles[$idb];
1278
+    $a1 = $crit->param[0];
1279
+    $a2 = $crit->param[1];
1280
+    $op = $crit->op;
1281
+
1282
+    [$a11, $a12] = calculer_critere_parties_aux($idb, $boucles, $a1);
1283
+    [$a21, $a22] = calculer_critere_parties_aux($idb, $boucles, $a2);
1284
+
1285
+    if (($op == ',') && (is_numeric($a11) && (is_numeric($a21)))) {
1286
+        $boucle->limit = $a11 . ',' . $a21;
1287
+    } else {
1288
+        // 3 dans {1/3}, {2,3} ou {1,n-3}
1289
+        $boucle->total_parties = ($a21 != 'n') ? $a21 : $a22;
1290
+        // 2 dans {2/3}, {2,5}, {n-2,1}
1291
+        $partie = ($a11 != 'n') ? $a11 : $a12;
1292
+        $mode = (($op == '/') ? '/' :
1293
+            (($a11 == 'n') ? '-' : '+') . (($a21 == 'n') ? '-' : '+'));
1294
+        // cas simple {0,#ENV{truc}} compilons le en LIMIT :
1295
+        if ($a11 !== 'n' and $a21 !== 'n' and $mode == '++' and $op == ',') {
1296
+            $boucle->limit =
1297
+                (is_numeric($a11) ? "'$a11'" : $a11)
1298
+                . ".','."
1299
+                . (is_numeric($a21) ? "'$a21'" : $a21);
1300
+        } else {
1301
+            calculer_parties($boucles, $idb, $partie, $mode);
1302
+        }
1303
+    }
1304 1304
 }
1305 1305
 
1306 1306
 /**
@@ -1328,63 +1328,63 @@  discard block
 block discarded – undo
1328 1328
  * @return void
1329 1329
  **/
1330 1330
 function calculer_parties(&$boucles, $id_boucle, $debut, $mode) {
1331
-	$total_parties = $boucles[$id_boucle]->total_parties;
1332
-
1333
-	preg_match(',([+-/p])([+-/])?,', $mode, $regs);
1334
-	[, $op1, $op2] = array_pad($regs, 3, null);
1335
-	$nombre_boucle = "\$Numrows['$id_boucle']['total']";
1336
-	// {1/3}
1337
-	if ($op1 == '/') {
1338
-		$pmoins1 = is_numeric($debut) ? ($debut - 1) : "($debut-1)";
1339
-		$totpos = is_numeric($total_parties) ? ($total_parties) :
1340
-			"($total_parties ? $total_parties : 1)";
1341
-		$fin = "ceil(($nombre_boucle * $debut )/$totpos) - 1";
1342
-		$debut = !$pmoins1 ? 0 : "ceil(($nombre_boucle * $pmoins1)/$totpos);";
1343
-	} else {
1344
-		// cas {n-1,x}
1345
-		if ($op1 == '-') {
1346
-			$debut = "$nombre_boucle - $debut;";
1347
-		}
1348
-
1349
-		// cas {x,n-1}
1350
-		if ($op2 == '-') {
1351
-			$fin = '$debut_boucle + ' . $nombre_boucle . ' - '
1352
-				. (is_numeric($total_parties) ? ($total_parties + 1) :
1353
-					($total_parties . ' - 1'));
1354
-		} else {
1355
-			// {x,1} ou {pagination}
1356
-			$fin = '$debut_boucle'
1357
-				. (is_numeric($total_parties) ?
1358
-					(($total_parties == 1) ? '' : (' + ' . ($total_parties - 1))) :
1359
-					('+' . $total_parties . ' - 1'));
1360
-		}
1361
-
1362
-		// {pagination}, gerer le debut_xx=-1 pour tout voir
1363
-		if ($op1 == 'p') {
1364
-			$debut .= ";\n	\$debut_boucle = ((\$tout=(\$debut_boucle == -1))?0:(\$debut_boucle))";
1365
-			$debut .= ";\n	\$debut_boucle = max(0,min(\$debut_boucle,floor(($nombre_boucle-1)/($total_parties))*($total_parties)))";
1366
-			$fin = "(\$tout ? $nombre_boucle : $fin)";
1367
-		}
1368
-	}
1369
-
1370
-	// Notes :
1371
-	// $debut_boucle et $fin_boucle sont les indices SQL du premier
1372
-	// et du dernier demandes dans la boucle : 0 pour le premier,
1373
-	// n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
1374
-	// Utiliser min pour rabattre $fin_boucle sur total_boucle.
1375
-
1376
-	$boucles[$id_boucle]->mode_partie = "\n\t"
1377
-		. '$debut_boucle = ' . $debut . ";\n	"
1378
-		. "\$debut_boucle = intval(\$debut_boucle);\n	"
1379
-		. '$fin_boucle = min(' . $fin . ", \$Numrows['$id_boucle']['total'] - 1);\n	"
1380
-		. '$Numrows[\'' . $id_boucle . "']['grand_total'] = \$Numrows['$id_boucle']['total'];\n	"
1381
-		. '$Numrows[\'' . $id_boucle . '\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);'
1382
-		. "\n\tif (\$debut_boucle>0"
1383
-		. " AND \$debut_boucle < \$Numrows['$id_boucle']['grand_total']"
1384
-		. " AND \$iter->seek(\$debut_boucle,'continue'))"
1385
-		. "\n\t\t\$Numrows['$id_boucle']['compteur_boucle'] = \$debut_boucle;\n\t";
1386
-
1387
-	$boucles[$id_boucle]->partie = "
1331
+    $total_parties = $boucles[$id_boucle]->total_parties;
1332
+
1333
+    preg_match(',([+-/p])([+-/])?,', $mode, $regs);
1334
+    [, $op1, $op2] = array_pad($regs, 3, null);
1335
+    $nombre_boucle = "\$Numrows['$id_boucle']['total']";
1336
+    // {1/3}
1337
+    if ($op1 == '/') {
1338
+        $pmoins1 = is_numeric($debut) ? ($debut - 1) : "($debut-1)";
1339
+        $totpos = is_numeric($total_parties) ? ($total_parties) :
1340
+            "($total_parties ? $total_parties : 1)";
1341
+        $fin = "ceil(($nombre_boucle * $debut )/$totpos) - 1";
1342
+        $debut = !$pmoins1 ? 0 : "ceil(($nombre_boucle * $pmoins1)/$totpos);";
1343
+    } else {
1344
+        // cas {n-1,x}
1345
+        if ($op1 == '-') {
1346
+            $debut = "$nombre_boucle - $debut;";
1347
+        }
1348
+
1349
+        // cas {x,n-1}
1350
+        if ($op2 == '-') {
1351
+            $fin = '$debut_boucle + ' . $nombre_boucle . ' - '
1352
+                . (is_numeric($total_parties) ? ($total_parties + 1) :
1353
+                    ($total_parties . ' - 1'));
1354
+        } else {
1355
+            // {x,1} ou {pagination}
1356
+            $fin = '$debut_boucle'
1357
+                . (is_numeric($total_parties) ?
1358
+                    (($total_parties == 1) ? '' : (' + ' . ($total_parties - 1))) :
1359
+                    ('+' . $total_parties . ' - 1'));
1360
+        }
1361
+
1362
+        // {pagination}, gerer le debut_xx=-1 pour tout voir
1363
+        if ($op1 == 'p') {
1364
+            $debut .= ";\n	\$debut_boucle = ((\$tout=(\$debut_boucle == -1))?0:(\$debut_boucle))";
1365
+            $debut .= ";\n	\$debut_boucle = max(0,min(\$debut_boucle,floor(($nombre_boucle-1)/($total_parties))*($total_parties)))";
1366
+            $fin = "(\$tout ? $nombre_boucle : $fin)";
1367
+        }
1368
+    }
1369
+
1370
+    // Notes :
1371
+    // $debut_boucle et $fin_boucle sont les indices SQL du premier
1372
+    // et du dernier demandes dans la boucle : 0 pour le premier,
1373
+    // n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
1374
+    // Utiliser min pour rabattre $fin_boucle sur total_boucle.
1375
+
1376
+    $boucles[$id_boucle]->mode_partie = "\n\t"
1377
+        . '$debut_boucle = ' . $debut . ";\n	"
1378
+        . "\$debut_boucle = intval(\$debut_boucle);\n	"
1379
+        . '$fin_boucle = min(' . $fin . ", \$Numrows['$id_boucle']['total'] - 1);\n	"
1380
+        . '$Numrows[\'' . $id_boucle . "']['grand_total'] = \$Numrows['$id_boucle']['total'];\n	"
1381
+        . '$Numrows[\'' . $id_boucle . '\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);'
1382
+        . "\n\tif (\$debut_boucle>0"
1383
+        . " AND \$debut_boucle < \$Numrows['$id_boucle']['grand_total']"
1384
+        . " AND \$iter->seek(\$debut_boucle,'continue'))"
1385
+        . "\n\t\t\$Numrows['$id_boucle']['compteur_boucle'] = \$debut_boucle;\n\t";
1386
+
1387
+    $boucles[$id_boucle]->partie = "
1388 1388
 		if (\$Numrows['$id_boucle']['compteur_boucle'] <= \$debut_boucle) continue;
1389 1389
 		if (\$Numrows['$id_boucle']['compteur_boucle']-1 > \$fin_boucle) break;";
1390 1390
 }
@@ -1401,26 +1401,26 @@  discard block
 block discarded – undo
1401 1401
  * @return array          Valeur de l'élément (peut être une expression PHP), Nombre soustrait
1402 1402
  **/
1403 1403
 function calculer_critere_parties_aux($idb, &$boucles, $param) {
1404
-	if ($param[0]->type != 'texte') {
1405
-		$a1 = calculer_liste([$param[0]], $idb, $boucles, $boucles[$idb]->id_parent);
1406
-		if (isset($param[1]->texte)) {
1407
-			preg_match(',^\s*(-([0-9]+))?\s*$,', $param[1]->texte, $m);
1408
-
1409
-			return ["intval($a1)", ((isset($m[2]) and $m[2]) ? $m[2] : 0)];
1410
-		} else {
1411
-			return ["intval($a1)", 0];
1412
-		}
1413
-	} else {
1414
-		preg_match(',^\s*(([0-9]+)|n)\s*(-\s*([0-9]+)?\s*)?$,', $param[0]->texte, $m);
1415
-		$a1 = $m[1];
1416
-		if (empty($m[3])) {
1417
-			return [$a1, 0];
1418
-		} elseif (!empty($m[4])) {
1419
-			return [$a1, $m[4]];
1420
-		} else {
1421
-			return [$a1, calculer_liste([$param[1]], $idb, $boucles, $boucles[$idb]->id_parent)];
1422
-		}
1423
-	}
1404
+    if ($param[0]->type != 'texte') {
1405
+        $a1 = calculer_liste([$param[0]], $idb, $boucles, $boucles[$idb]->id_parent);
1406
+        if (isset($param[1]->texte)) {
1407
+            preg_match(',^\s*(-([0-9]+))?\s*$,', $param[1]->texte, $m);
1408
+
1409
+            return ["intval($a1)", ((isset($m[2]) and $m[2]) ? $m[2] : 0)];
1410
+        } else {
1411
+            return ["intval($a1)", 0];
1412
+        }
1413
+    } else {
1414
+        preg_match(',^\s*(([0-9]+)|n)\s*(-\s*([0-9]+)?\s*)?$,', $param[0]->texte, $m);
1415
+        $a1 = $m[1];
1416
+        if (empty($m[3])) {
1417
+            return [$a1, 0];
1418
+        } elseif (!empty($m[4])) {
1419
+            return [$a1, $m[4]];
1420
+        } else {
1421
+            return [$a1, calculer_liste([$param[1]], $idb, $boucles, $boucles[$idb]->id_parent)];
1422
+        }
1423
+    }
1424 1424
 }
1425 1425
 
1426 1426
 
@@ -1447,47 +1447,47 @@  discard block
 block discarded – undo
1447 1447
  *     array : Erreur sur un des critères
1448 1448
  **/
1449 1449
 function calculer_criteres($idb, &$boucles) {
1450
-	$msg = '';
1451
-	$boucle = $boucles[$idb];
1452
-	$table = strtoupper($boucle->type_requete);
1453
-	$serveur = strtolower($boucle->sql_serveur);
1454
-
1455
-	$defaut = charger_fonction('DEFAUT', 'calculer_critere');
1456
-	// s'il y avait une erreur de syntaxe, propager cette info
1457
-	if (!is_array($boucle->criteres)) {
1458
-		return [];
1459
-	}
1460
-
1461
-	foreach ($boucle->criteres as $crit) {
1462
-		$critere = $crit->op;
1463
-		// critere personnalise ?
1464
-		if (
1465
-			(!$serveur or
1466
-				((!function_exists($f = 'critere_' . $serveur . '_' . $table . '_' . $critere))
1467
-					and (!function_exists($f = $f . '_dist'))
1468
-					and (!function_exists($f = 'critere_' . $serveur . '_' . $critere))
1469
-					and (!function_exists($f = $f . '_dist'))
1470
-				)
1471
-			)
1472
-			and (!function_exists($f = 'critere_' . $table . '_' . $critere))
1473
-			and (!function_exists($f = $f . '_dist'))
1474
-			and (!function_exists($f = 'critere_' . $critere))
1475
-			and (!function_exists($f = $f . '_dist'))
1476
-		) {
1477
-			// fonction critere standard
1478
-			$f = $defaut;
1479
-		}
1480
-		// compile le critere
1481
-		$res = $f($idb, $boucles, $crit);
1482
-
1483
-		// Gestion centralisee des erreurs pour pouvoir propager
1484
-		if (is_array($res)) {
1485
-			$msg = $res;
1486
-			erreur_squelette($msg, $boucle);
1487
-		}
1488
-	}
1489
-
1490
-	return $msg;
1450
+    $msg = '';
1451
+    $boucle = $boucles[$idb];
1452
+    $table = strtoupper($boucle->type_requete);
1453
+    $serveur = strtolower($boucle->sql_serveur);
1454
+
1455
+    $defaut = charger_fonction('DEFAUT', 'calculer_critere');
1456
+    // s'il y avait une erreur de syntaxe, propager cette info
1457
+    if (!is_array($boucle->criteres)) {
1458
+        return [];
1459
+    }
1460
+
1461
+    foreach ($boucle->criteres as $crit) {
1462
+        $critere = $crit->op;
1463
+        // critere personnalise ?
1464
+        if (
1465
+            (!$serveur or
1466
+                ((!function_exists($f = 'critere_' . $serveur . '_' . $table . '_' . $critere))
1467
+                    and (!function_exists($f = $f . '_dist'))
1468
+                    and (!function_exists($f = 'critere_' . $serveur . '_' . $critere))
1469
+                    and (!function_exists($f = $f . '_dist'))
1470
+                )
1471
+            )
1472
+            and (!function_exists($f = 'critere_' . $table . '_' . $critere))
1473
+            and (!function_exists($f = $f . '_dist'))
1474
+            and (!function_exists($f = 'critere_' . $critere))
1475
+            and (!function_exists($f = $f . '_dist'))
1476
+        ) {
1477
+            // fonction critere standard
1478
+            $f = $defaut;
1479
+        }
1480
+        // compile le critere
1481
+        $res = $f($idb, $boucles, $crit);
1482
+
1483
+        // Gestion centralisee des erreurs pour pouvoir propager
1484
+        if (is_array($res)) {
1485
+            $msg = $res;
1486
+            erreur_squelette($msg, $boucle);
1487
+        }
1488
+    }
1489
+
1490
+    return $msg;
1491 1491
 }
1492 1492
 
1493 1493
 /**
@@ -1502,11 +1502,11 @@  discard block
 block discarded – undo
1502 1502
  * @return string         Code compilé rééchappé
1503 1503
  */
1504 1504
 function kwote($lisp, $serveur = '', $type = '') {
1505
-	if (preg_match(_CODE_QUOTE, $lisp, $r)) {
1506
-		return $r[1] . '"' . sql_quote(str_replace(["\\'", '\\\\'], ["'", '\\'], $r[2]), $serveur, $type) . '"';
1507
-	} else {
1508
-		return "sql_quote($lisp, '$serveur', '" . str_replace("'", "\\'", $type) . "')";
1509
-	}
1505
+    if (preg_match(_CODE_QUOTE, $lisp, $r)) {
1506
+        return $r[1] . '"' . sql_quote(str_replace(["\\'", '\\\\'], ["'", '\\'], $r[2]), $serveur, $type) . '"';
1507
+    } else {
1508
+        return "sql_quote($lisp, '$serveur', '" . str_replace("'", "\\'", $type) . "')";
1509
+    }
1510 1510
 }
1511 1511
 
1512 1512
 
@@ -1525,81 +1525,81 @@  discard block
 block discarded – undo
1525 1525
  * @return void|array
1526 1526
  **/
1527 1527
 function critere_IN_dist($idb, &$boucles, $crit) {
1528
-	$r = calculer_critere_infixe($idb, $boucles, $crit);
1529
-	if (!$r) {
1530
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
1531
-	}
1532
-	[$arg, $op, $val, $col, $where_complement] = $r;
1533
-
1534
-	$in = critere_IN_cas($idb, $boucles, $crit->not ? 'NOT' : ($crit->exclus ? 'exclus' : ''), $arg, $op, $val, $col);
1535
-
1536
-	//	inserer la condition; exemple: {id_mot ?IN (66, 62, 64)}
1537
-	$where = $in;
1538
-	if ($crit->cond) {
1539
-		$pred = calculer_argument_precedent($idb, $col, $boucles);
1540
-		$where = ["'?'", $pred, $where, "''"];
1541
-		if ($where_complement) { // condition annexe du type "AND (objet='article')"
1542
-		$where_complement = ["'?'", $pred, $where_complement, "''"];
1543
-		}
1544
-	}
1545
-	if ($crit->exclus) {
1546
-		if (!preg_match(',^L[0-9]+[.],', $arg)) {
1547
-			$where = ["'NOT'", $where];
1548
-		} else // un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1549
-			// c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1550
-		{
1551
-			$where = [
1552
-				"'NOT'",
1553
-				[
1554
-					"'IN'",
1555
-					"'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1556
-					["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1557
-				]
1558
-			];
1559
-		}
1560
-	}
1561
-
1562
-	$boucles[$idb]->where[] = $where;
1563
-	if ($where_complement) { // condition annexe du type "AND (objet='article')"
1564
-	$boucles[$idb]->where[] = $where_complement;
1565
-	}
1528
+    $r = calculer_critere_infixe($idb, $boucles, $crit);
1529
+    if (!$r) {
1530
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
1531
+    }
1532
+    [$arg, $op, $val, $col, $where_complement] = $r;
1533
+
1534
+    $in = critere_IN_cas($idb, $boucles, $crit->not ? 'NOT' : ($crit->exclus ? 'exclus' : ''), $arg, $op, $val, $col);
1535
+
1536
+    //	inserer la condition; exemple: {id_mot ?IN (66, 62, 64)}
1537
+    $where = $in;
1538
+    if ($crit->cond) {
1539
+        $pred = calculer_argument_precedent($idb, $col, $boucles);
1540
+        $where = ["'?'", $pred, $where, "''"];
1541
+        if ($where_complement) { // condition annexe du type "AND (objet='article')"
1542
+        $where_complement = ["'?'", $pred, $where_complement, "''"];
1543
+        }
1544
+    }
1545
+    if ($crit->exclus) {
1546
+        if (!preg_match(',^L[0-9]+[.],', $arg)) {
1547
+            $where = ["'NOT'", $where];
1548
+        } else // un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1549
+            // c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1550
+        {
1551
+            $where = [
1552
+                "'NOT'",
1553
+                [
1554
+                    "'IN'",
1555
+                    "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1556
+                    ["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1557
+                ]
1558
+            ];
1559
+        }
1560
+    }
1561
+
1562
+    $boucles[$idb]->where[] = $where;
1563
+    if ($where_complement) { // condition annexe du type "AND (objet='article')"
1564
+    $boucles[$idb]->where[] = $where_complement;
1565
+    }
1566 1566
 }
1567 1567
 
1568 1568
 function critere_IN_cas($idb, &$boucles, $crit2, $arg, $op, $val, $col) {
1569
-	static $num = [];
1570
-	$descr = $boucles[$idb]->descr;
1571
-	$cpt = &$num[$descr['nom']][$descr['gram']][$idb];
1572
-
1573
-	$var = '$in' . $cpt++;
1574
-	$x = "\n\t$var = array();";
1575
-	foreach ($val as $k => $v) {
1576
-		if (preg_match(",^(\n//.*\n)?'(.*)'$,", $v, $r)) {
1577
-			// optimiser le traitement des constantes
1578
-			if (is_numeric($r[2])) {
1579
-				$x .= "\n\t$var" . "[]= $r[2];";
1580
-			} else {
1581
-				$x .= "\n\t$var" . '[]= ' . sql_quote($r[2]) . ';';
1582
-			}
1583
-		} else {
1584
-			// Pour permettre de passer des tableaux de valeurs
1585
-			// on repere l'utilisation brute de #ENV**{X},
1586
-			// c'est-a-dire sa  traduction en ($PILE[0][X]).
1587
-			// et on deballe mais en rajoutant l'anti XSS
1588
-			$x .= "\n\tif (!(is_array(\$a = ($v))))\n\t\t$var" . "[]= \$a;\n\telse $var = array_merge($var, \$a);";
1589
-		}
1590
-	}
1591
-
1592
-	$boucles[$idb]->in .= $x;
1593
-
1594
-	// inserer le tri par defaut selon les ordres du IN ...
1595
-	// avec une ecriture de type FIELD qui degrade les performances (du meme ordre qu'un regexp)
1596
-	// et que l'on limite donc strictement aux cas necessaires :
1597
-	// si ce n'est pas un !IN, et si il n'y a pas d'autre order dans la boucle
1598
-	if (!$crit2) {
1599
-		$boucles[$idb]->default_order[] = "((!\$zqv=sql_quote($var) OR \$zqv===\"''\") ? 0 : ('FIELD($arg,' . \$zqv . ')'))";
1600
-	}
1601
-
1602
-	return "sql_in('$arg', $var" . ($crit2 == 'NOT' ? ",'NOT'" : '') . ')';
1569
+    static $num = [];
1570
+    $descr = $boucles[$idb]->descr;
1571
+    $cpt = &$num[$descr['nom']][$descr['gram']][$idb];
1572
+
1573
+    $var = '$in' . $cpt++;
1574
+    $x = "\n\t$var = array();";
1575
+    foreach ($val as $k => $v) {
1576
+        if (preg_match(",^(\n//.*\n)?'(.*)'$,", $v, $r)) {
1577
+            // optimiser le traitement des constantes
1578
+            if (is_numeric($r[2])) {
1579
+                $x .= "\n\t$var" . "[]= $r[2];";
1580
+            } else {
1581
+                $x .= "\n\t$var" . '[]= ' . sql_quote($r[2]) . ';';
1582
+            }
1583
+        } else {
1584
+            // Pour permettre de passer des tableaux de valeurs
1585
+            // on repere l'utilisation brute de #ENV**{X},
1586
+            // c'est-a-dire sa  traduction en ($PILE[0][X]).
1587
+            // et on deballe mais en rajoutant l'anti XSS
1588
+            $x .= "\n\tif (!(is_array(\$a = ($v))))\n\t\t$var" . "[]= \$a;\n\telse $var = array_merge($var, \$a);";
1589
+        }
1590
+    }
1591
+
1592
+    $boucles[$idb]->in .= $x;
1593
+
1594
+    // inserer le tri par defaut selon les ordres du IN ...
1595
+    // avec une ecriture de type FIELD qui degrade les performances (du meme ordre qu'un regexp)
1596
+    // et que l'on limite donc strictement aux cas necessaires :
1597
+    // si ce n'est pas un !IN, et si il n'y a pas d'autre order dans la boucle
1598
+    if (!$crit2) {
1599
+        $boucles[$idb]->default_order[] = "((!\$zqv=sql_quote($var) OR \$zqv===\"''\") ? 0 : ('FIELD($arg,' . \$zqv . ')'))";
1600
+    }
1601
+
1602
+    return "sql_in('$arg', $var" . ($crit2 == 'NOT' ? ",'NOT'" : '') . ')';
1603 1603
 }
1604 1604
 
1605 1605
 /**
@@ -1615,22 +1615,22 @@  discard block
 block discarded – undo
1615 1615
  * @return void
1616 1616
  */
1617 1617
 function critere_where_dist($idb, &$boucles, $crit) {
1618
-	$boucle = &$boucles[$idb];
1619
-	if (isset($crit->param[0])) {
1620
-		$_where = calculer_liste($crit->param[0], $idb, $boucles, $boucle->id_parent);
1621
-	} else {
1622
-		$_where = 'spip_sanitize_from_request(@$Pile[0]["where"],"where","vide")';
1623
-	}
1624
-
1625
-	if ($crit->cond) {
1626
-		$_where = "((\$zzw = $_where) ? \$zzw : '')";
1627
-	}
1628
-
1629
-	if ($crit->not) {
1630
-		$_where = "array('NOT',$_where)";
1631
-	}
1632
-
1633
-	$boucle->where[] = $_where;
1618
+    $boucle = &$boucles[$idb];
1619
+    if (isset($crit->param[0])) {
1620
+        $_where = calculer_liste($crit->param[0], $idb, $boucles, $boucle->id_parent);
1621
+    } else {
1622
+        $_where = 'spip_sanitize_from_request(@$Pile[0]["where"],"where","vide")';
1623
+    }
1624
+
1625
+    if ($crit->cond) {
1626
+        $_where = "((\$zzw = $_where) ? \$zzw : '')";
1627
+    }
1628
+
1629
+    if ($crit->not) {
1630
+        $_where = "array('NOT',$_where)";
1631
+    }
1632
+
1633
+    $boucle->where[] = $_where;
1634 1634
 }
1635 1635
 
1636 1636
 /**
@@ -1658,31 +1658,31 @@  discard block
 block discarded – undo
1658 1658
  * @return void
1659 1659
  */
1660 1660
 function critere_id__dist($idb, &$boucles, $crit) {
1661
-	/** @var Boucle $boucle */
1662
-	$boucle = $boucles[$idb];
1663
-
1664
-	$champs = lister_champs_id_conditionnel(
1665
-		$boucle->show['table'],
1666
-		$boucle->show,
1667
-		$boucle->sql_serveur
1668
-	);
1669
-
1670
-	// ne pas tenir compte des critères identiques déjà présents.
1671
-	if (!empty($boucle->modificateur['criteres'])) {
1672
-		$champs = array_diff($champs, array_keys($boucle->modificateur['criteres']));
1673
-	}
1674
-	// nous aider en mode debug.
1675
-	$boucle->debug[] = 'id_ : ' . implode(', ', $champs);
1676
-	$boucle->modificateur['id_'] = $champs;
1677
-
1678
-	// créer un critère {id_xxx?} de chaque champ retenu
1679
-	foreach ($champs as $champ) {
1680
-		$critere_id_table = new Critere();
1681
-		$critere_id_table->op = $champ;
1682
-		$critere_id_table->cond = true;
1683
-		$critere_id_table->ligne = $crit->ligne;
1684
-		calculer_critere_DEFAUT_dist($idb, $boucles, $critere_id_table);
1685
-	}
1661
+    /** @var Boucle $boucle */
1662
+    $boucle = $boucles[$idb];
1663
+
1664
+    $champs = lister_champs_id_conditionnel(
1665
+        $boucle->show['table'],
1666
+        $boucle->show,
1667
+        $boucle->sql_serveur
1668
+    );
1669
+
1670
+    // ne pas tenir compte des critères identiques déjà présents.
1671
+    if (!empty($boucle->modificateur['criteres'])) {
1672
+        $champs = array_diff($champs, array_keys($boucle->modificateur['criteres']));
1673
+    }
1674
+    // nous aider en mode debug.
1675
+    $boucle->debug[] = 'id_ : ' . implode(', ', $champs);
1676
+    $boucle->modificateur['id_'] = $champs;
1677
+
1678
+    // créer un critère {id_xxx?} de chaque champ retenu
1679
+    foreach ($champs as $champ) {
1680
+        $critere_id_table = new Critere();
1681
+        $critere_id_table->op = $champ;
1682
+        $critere_id_table->cond = true;
1683
+        $critere_id_table->ligne = $crit->ligne;
1684
+        calculer_critere_DEFAUT_dist($idb, $boucles, $critere_id_table);
1685
+    }
1686 1686
 }
1687 1687
 
1688 1688
 /**
@@ -1702,75 +1702,75 @@  discard block
 block discarded – undo
1702 1702
  * @return array Liste de nom de champs (tel que id_article, id_mot, id_parent ...)
1703 1703
  */
1704 1704
 function lister_champs_id_conditionnel($table, $desc = null, $serveur = '') {
1705
-	// calculer la description de la table
1706
-	if (!is_array($desc)) {
1707
-		$desc = description_table($table, $serveur);
1708
-	}
1709
-	if (!$desc) {
1710
-		return [];
1711
-	}
1712
-
1713
-	// Les champs id_xx de la table demandée
1714
-	$champs = array_filter(
1715
-		array_keys($desc['field']),
1716
-		fn($champ) => strpos($champ, 'id_') === 0 or (in_array($champ, ['objet']))
1717
-	);
1718
-
1719
-	// Si le champ id_rubrique appartient à la liste et si id_secteur n'est pas inclus on le rajoute.
1720
-	if (
1721
-		in_array('id_rubrique', $champs)
1722
-		and !in_array('id_secteur', $champs)
1723
-	) {
1724
-		$champs[] = 'id_secteur';
1725
-	}
1726
-
1727
-	// On ne fera pas mieux pour les tables d’un autre serveur
1728
-	if ($serveur) {
1729
-		return $champs;
1730
-	}
1731
-
1732
-	$primary = false;
1733
-	$associable = false;
1734
-	include_spip('action/editer_liens');
1735
-
1736
-	if (isset($desc['type'])) {
1737
-		$primary = id_table_objet($desc['type']);
1738
-		$associable = objet_associable($desc['type']);
1739
-	}
1740
-	if (isset($desc['field']['id_objet']) and isset($desc['field']['objet'])) {
1741
-		$associable = true;
1742
-	}
1743
-
1744
-	// liste de toutes les tables principales, sauf la notre
1745
-	$tables = lister_tables_objets_sql();
1746
-	unset($tables[$table]);
1747
-
1748
-	foreach ($tables as $_table => $_desc) {
1749
-		if (
1750
-			$associable
1751
-			or ($primary and in_array($primary, array_keys($_desc['field'])))
1752
-			or objet_associable($_desc['type'])
1753
-		) {
1754
-			$champs[] = id_table_objet($_table);
1755
-		}
1756
-	}
1757
-	$champs = array_values(array_unique($champs));
1758
-
1759
-	// Exclusions de certains id
1760
-	$exclusions = pipeline(
1761
-		'exclure_id_conditionnel',
1762
-		[
1763
-			'args' => [
1764
-				'table' => $table,
1765
-				'id_table_objet' => $primary,
1766
-				'associable' => $associable,
1767
-			],
1768
-			'data' => [],
1769
-		]
1770
-	);
1771
-	$champs = array_diff($champs, $exclusions);
1772
-
1773
-	return $champs;
1705
+    // calculer la description de la table
1706
+    if (!is_array($desc)) {
1707
+        $desc = description_table($table, $serveur);
1708
+    }
1709
+    if (!$desc) {
1710
+        return [];
1711
+    }
1712
+
1713
+    // Les champs id_xx de la table demandée
1714
+    $champs = array_filter(
1715
+        array_keys($desc['field']),
1716
+        fn($champ) => strpos($champ, 'id_') === 0 or (in_array($champ, ['objet']))
1717
+    );
1718
+
1719
+    // Si le champ id_rubrique appartient à la liste et si id_secteur n'est pas inclus on le rajoute.
1720
+    if (
1721
+        in_array('id_rubrique', $champs)
1722
+        and !in_array('id_secteur', $champs)
1723
+    ) {
1724
+        $champs[] = 'id_secteur';
1725
+    }
1726
+
1727
+    // On ne fera pas mieux pour les tables d’un autre serveur
1728
+    if ($serveur) {
1729
+        return $champs;
1730
+    }
1731
+
1732
+    $primary = false;
1733
+    $associable = false;
1734
+    include_spip('action/editer_liens');
1735
+
1736
+    if (isset($desc['type'])) {
1737
+        $primary = id_table_objet($desc['type']);
1738
+        $associable = objet_associable($desc['type']);
1739
+    }
1740
+    if (isset($desc['field']['id_objet']) and isset($desc['field']['objet'])) {
1741
+        $associable = true;
1742
+    }
1743
+
1744
+    // liste de toutes les tables principales, sauf la notre
1745
+    $tables = lister_tables_objets_sql();
1746
+    unset($tables[$table]);
1747
+
1748
+    foreach ($tables as $_table => $_desc) {
1749
+        if (
1750
+            $associable
1751
+            or ($primary and in_array($primary, array_keys($_desc['field'])))
1752
+            or objet_associable($_desc['type'])
1753
+        ) {
1754
+            $champs[] = id_table_objet($_table);
1755
+        }
1756
+    }
1757
+    $champs = array_values(array_unique($champs));
1758
+
1759
+    // Exclusions de certains id
1760
+    $exclusions = pipeline(
1761
+        'exclure_id_conditionnel',
1762
+        [
1763
+            'args' => [
1764
+                'table' => $table,
1765
+                'id_table_objet' => $primary,
1766
+                'associable' => $associable,
1767
+            ],
1768
+            'data' => [],
1769
+        ]
1770
+    );
1771
+    $champs = array_diff($champs, $exclusions);
1772
+
1773
+    return $champs;
1774 1774
 }
1775 1775
 
1776 1776
 /**
@@ -1825,28 +1825,28 @@  discard block
 block discarded – undo
1825 1825
  * @return void
1826 1826
  */
1827 1827
 function critere_tri_dist($idb, &$boucles, $crit) {
1828
-	$boucle = &$boucles[$idb];
1829
-
1830
-	// definition du champ par defaut
1831
-	$_champ_defaut = !isset($crit->param[0][0]) ? "''"
1832
-		: calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
1833
-	$_liste_sens_defaut = !isset($crit->param[1][0]) ? '1'
1834
-		: calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
1835
-	$_variable = !isset($crit->param[2][0]) ? "'$idb'"
1836
-		: calculer_liste([$crit->param[2][0]], $idb, $boucles, $boucle->id_parent);
1837
-
1838
-	$_tri = "((\$t=(isset(\$Pile[0]['tri'.$_variable]))?\$Pile[0]['tri'.$_variable]:((strncmp($_variable,'session',7)==0 AND session_get('tri'.$_variable))?session_get('tri'.$_variable):$_champ_defaut))?tri_protege_champ(\$t):'')";
1839
-
1840
-	$_sens_defaut = "(is_array(\$s=$_liste_sens_defaut)?(isset(\$s[\$st=$_tri])?\$s[\$st]:reset(\$s)):\$s)";
1841
-	$_sens = "((intval(\$t=(isset(\$Pile[0]['sens'.$_variable]))?\$Pile[0]['sens'.$_variable]:((strncmp($_variable,'session',7)==0 AND session_get('sens'.$_variable))?session_get('sens'.$_variable):$_sens_defaut))==-1 OR \$t=='inverse')?-1:1)";
1842
-
1843
-	$boucle->modificateur['tri_champ'] = $_tri;
1844
-	$boucle->modificateur['tri_sens'] = $_sens;
1845
-	$boucle->modificateur['tri_liste_sens_defaut'] = $_liste_sens_defaut;
1846
-	$boucle->modificateur['tri_nom'] = $_variable;
1847
-	// faut il inserer un test sur l'existence de $tri parmi les champs de la table ?
1848
-	// evite des erreurs sql, mais peut empecher des tri sur jointure ...
1849
-	$boucle->hash .= "
1828
+    $boucle = &$boucles[$idb];
1829
+
1830
+    // definition du champ par defaut
1831
+    $_champ_defaut = !isset($crit->param[0][0]) ? "''"
1832
+        : calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
1833
+    $_liste_sens_defaut = !isset($crit->param[1][0]) ? '1'
1834
+        : calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
1835
+    $_variable = !isset($crit->param[2][0]) ? "'$idb'"
1836
+        : calculer_liste([$crit->param[2][0]], $idb, $boucles, $boucle->id_parent);
1837
+
1838
+    $_tri = "((\$t=(isset(\$Pile[0]['tri'.$_variable]))?\$Pile[0]['tri'.$_variable]:((strncmp($_variable,'session',7)==0 AND session_get('tri'.$_variable))?session_get('tri'.$_variable):$_champ_defaut))?tri_protege_champ(\$t):'')";
1839
+
1840
+    $_sens_defaut = "(is_array(\$s=$_liste_sens_defaut)?(isset(\$s[\$st=$_tri])?\$s[\$st]:reset(\$s)):\$s)";
1841
+    $_sens = "((intval(\$t=(isset(\$Pile[0]['sens'.$_variable]))?\$Pile[0]['sens'.$_variable]:((strncmp($_variable,'session',7)==0 AND session_get('sens'.$_variable))?session_get('sens'.$_variable):$_sens_defaut))==-1 OR \$t=='inverse')?-1:1)";
1842
+
1843
+    $boucle->modificateur['tri_champ'] = $_tri;
1844
+    $boucle->modificateur['tri_sens'] = $_sens;
1845
+    $boucle->modificateur['tri_liste_sens_defaut'] = $_liste_sens_defaut;
1846
+    $boucle->modificateur['tri_nom'] = $_variable;
1847
+    // faut il inserer un test sur l'existence de $tri parmi les champs de la table ?
1848
+    // evite des erreurs sql, mais peut empecher des tri sur jointure ...
1849
+    $boucle->hash .= "
1850 1850
 	\$senstri = '';
1851 1851
 	\$tri = $_tri;
1852 1852
 	if (\$tri){
@@ -1854,8 +1854,8 @@  discard block
 block discarded – undo
1854 1854
 		\$senstri = (\$senstri<0)?' DESC':'';
1855 1855
 	};
1856 1856
 	";
1857
-	$boucle->select[] = '".tri_champ_select($tri)."';
1858
-	$boucle->order[] = "tri_champ_order(\$tri,\$command['from'],\$senstri)";
1857
+    $boucle->select[] = '".tri_champ_select($tri)."';
1858
+    $boucle->order[] = "tri_champ_order(\$tri,\$command['from'],\$senstri)";
1859 1859
 }
1860 1860
 
1861 1861
 # criteres de comparaison
@@ -1872,21 +1872,21 @@  discard block
 block discarded – undo
1872 1872
  * @return void|array
1873 1873
  **/
1874 1874
 function calculer_critere_DEFAUT_dist($idb, &$boucles, $crit) {
1875
-	// double cas particulier {0,1} et {1/2} repere a l'analyse lexicale
1876
-	if (($crit->op == ',') or ($crit->op == '/')) {
1877
-		calculer_critere_parties($idb, $boucles, $crit);
1878
-		return;
1879
-	}
1880
-
1881
-	$r = calculer_critere_infixe($idb, $boucles, $crit);
1882
-	if (!$r) {
1883
-		#	// on produit une erreur seulement si le critere n'a pas de '?'
1884
-		#	if (!$crit->cond) {
1885
-		return ['zbug_critere_inconnu', ['critere' => $crit->op]];
1886
-		#	}
1887
-	} else {
1888
-		calculer_critere_DEFAUT_args($idb, $boucles, $crit, $r);
1889
-	}
1875
+    // double cas particulier {0,1} et {1/2} repere a l'analyse lexicale
1876
+    if (($crit->op == ',') or ($crit->op == '/')) {
1877
+        calculer_critere_parties($idb, $boucles, $crit);
1878
+        return;
1879
+    }
1880
+
1881
+    $r = calculer_critere_infixe($idb, $boucles, $crit);
1882
+    if (!$r) {
1883
+        #	// on produit une erreur seulement si le critere n'a pas de '?'
1884
+        #	if (!$crit->cond) {
1885
+        return ['zbug_critere_inconnu', ['critere' => $crit->op]];
1886
+        #	}
1887
+    } else {
1888
+        calculer_critere_DEFAUT_args($idb, $boucles, $crit, $r);
1889
+    }
1890 1890
 }
1891 1891
 
1892 1892
 
@@ -1906,62 +1906,62 @@  discard block
 block discarded – undo
1906 1906
  * @return void
1907 1907
  **/
1908 1908
 function calculer_critere_DEFAUT_args($idb, &$boucles, $crit, $args) {
1909
-	[$arg, $op, $val, $col, $where_complement] = $args;
1910
-
1911
-	$where = ["'$op'", "'$arg'", $val[0]];
1912
-
1913
-	// inserer la negation (cf !...)
1914
-
1915
-	if ($crit->not) {
1916
-		$where = ["'NOT'", $where];
1917
-	}
1918
-	if ($crit->exclus) {
1919
-		if (!preg_match(',^L[0-9]+[.],', $arg)) {
1920
-			$where = ["'NOT'", $where];
1921
-		} else {
1922
-			// un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1923
-			// c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1924
-			$where = [
1925
-				"'NOT'",
1926
-				[
1927
-					"'IN'",
1928
-					"'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1929
-					["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1930
-				]
1931
-			];
1932
-		}
1933
-	}
1934
-
1935
-	// inserer la condition (cf {lang?})
1936
-	// traiter a part la date, elle est mise d'office par SPIP,
1937
-	if ($crit->cond) {
1938
-		$pred = calculer_argument_precedent($idb, $col, $boucles);
1939
-		if ($col === 'date' or $col === 'date_redac') {
1940
-			if ($pred === "\$Pile[0]['" . $col . "']") {
1941
-				$pred = "(\$Pile[0]['{$col}_default']?'':$pred)";
1942
-			}
1943
-		}
1944
-
1945
-		if ($op === '=' and !$crit->not) {
1946
-			$where = [
1947
-				"'?'",
1948
-				"(is_array($pred))",
1949
-				critere_IN_cas($idb, $boucles, 'COND', $arg, $op, [$pred], $col),
1950
-				$where
1951
-			];
1952
-		}
1953
-		$where = ["'?'", "!is_whereable($pred)", "''", $where];
1954
-		if ($where_complement) {
1955
-			// condition annexe du type "AND (objet='article')"
1956
-			$where_complement = ["'?'", "!is_whereable($pred)", "''", $where_complement];
1957
-		}
1958
-	}
1959
-
1960
-	$boucles[$idb]->where[] = $where;
1961
-	if ($where_complement) {
1962
-		// condition annexe du type "AND (objet='article')"
1963
-		$boucles[$idb]->where[] = $where_complement;
1964
-	}
1909
+    [$arg, $op, $val, $col, $where_complement] = $args;
1910
+
1911
+    $where = ["'$op'", "'$arg'", $val[0]];
1912
+
1913
+    // inserer la negation (cf !...)
1914
+
1915
+    if ($crit->not) {
1916
+        $where = ["'NOT'", $where];
1917
+    }
1918
+    if ($crit->exclus) {
1919
+        if (!preg_match(',^L[0-9]+[.],', $arg)) {
1920
+            $where = ["'NOT'", $where];
1921
+        } else {
1922
+            // un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1923
+            // c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1924
+            $where = [
1925
+                "'NOT'",
1926
+                [
1927
+                    "'IN'",
1928
+                    "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1929
+                    ["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1930
+                ]
1931
+            ];
1932
+        }
1933
+    }
1934
+
1935
+    // inserer la condition (cf {lang?})
1936
+    // traiter a part la date, elle est mise d'office par SPIP,
1937
+    if ($crit->cond) {
1938
+        $pred = calculer_argument_precedent($idb, $col, $boucles);
1939
+        if ($col === 'date' or $col === 'date_redac') {
1940
+            if ($pred === "\$Pile[0]['" . $col . "']") {
1941
+                $pred = "(\$Pile[0]['{$col}_default']?'':$pred)";
1942
+            }
1943
+        }
1944
+
1945
+        if ($op === '=' and !$crit->not) {
1946
+            $where = [
1947
+                "'?'",
1948
+                "(is_array($pred))",
1949
+                critere_IN_cas($idb, $boucles, 'COND', $arg, $op, [$pred], $col),
1950
+                $where
1951
+            ];
1952
+        }
1953
+        $where = ["'?'", "!is_whereable($pred)", "''", $where];
1954
+        if ($where_complement) {
1955
+            // condition annexe du type "AND (objet='article')"
1956
+            $where_complement = ["'?'", "!is_whereable($pred)", "''", $where_complement];
1957
+        }
1958
+    }
1959
+
1960
+    $boucles[$idb]->where[] = $where;
1961
+    if ($where_complement) {
1962
+        // condition annexe du type "AND (objet='article')"
1963
+        $boucles[$idb]->where[] = $where_complement;
1964
+    }
1965 1965
 }
1966 1966
 
1967 1967
 
@@ -2002,165 +2002,165 @@  discard block
 block discarded – undo
2002 2002
  **/
2003 2003
 function calculer_critere_infixe($idb, &$boucles, $crit) {
2004 2004
 
2005
-	$boucle = &$boucles[$idb];
2006
-	$type = $boucle->type_requete;
2007
-	$table = $boucle->id_table;
2008
-	$desc = $boucle->show;
2009
-	$col_vraie = null;
2010
-
2011
-	[$fct, $col, $op, $val, $args_sql] =
2012
-		calculer_critere_infixe_ops($idb, $boucles, $crit);
2013
-
2014
-	$col_alias = $col;
2015
-	$where_complement = false;
2016
-
2017
-	// Cas particulier : id_enfant => utiliser la colonne id_objet
2018
-	if ($col == 'id_enfant') {
2019
-		$col = $boucle->primary;
2020
-	}
2021
-
2022
-	// Cas particulier : id_parent => verifier les exceptions de tables
2023
-	if (
2024
-		(in_array($col, ['id_parent', 'id_secteur']) and isset($GLOBALS['exceptions_des_tables'][$table][$col]))
2025
-		or (isset($GLOBALS['exceptions_des_tables'][$table][$col]) and is_string($GLOBALS['exceptions_des_tables'][$table][$col]))
2026
-	) {
2027
-		$col = $GLOBALS['exceptions_des_tables'][$table][$col];
2028
-	} // et possibilite de gerer un critere secteur sur des tables de plugins (ie forums)
2029
-	else {
2030
-		if (($col == 'id_secteur') and ($critere_secteur = charger_fonction("critere_secteur_$type", 'public', true))) {
2031
-			$table = $critere_secteur($idb, $boucles, $val, $crit);
2032
-		}
2033
-
2034
-		// cas id_article=xx qui se mappe en id_objet=xx AND objet=article
2035
-		// sauf si exception declaree : sauter cette etape
2036
-		else {
2037
-			if (
2038
-				!isset($GLOBALS['exceptions_des_jointures'][table_objet_sql($table)][$col])
2039
-				and !isset($GLOBALS['exceptions_des_jointures'][$col])
2040
-				and count(trouver_champs_decomposes($col, $desc)) > 1
2041
-			) {
2042
-				$e = decompose_champ_id_objet($col);
2043
-				$col = array_shift($e);
2044
-				$where_complement = primary_doublee($e, $table);
2045
-			} // Cas particulier : expressions de date
2046
-			else {
2047
-				if ($c = calculer_critere_infixe_date($idb, $boucles, $col)) {
2048
-					[$col, $col_vraie] = $c;
2049
-					$table = '';
2050
-				} // table explicitée {mots.titre}
2051
-				else {
2052
-					if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2053
-						[, $table, $col] = $r;
2054
-						$col_alias = $col;
2055
-
2056
-						$trouver_table = charger_fonction('trouver_table', 'base');
2057
-						if (
2058
-							$desc = $trouver_table($table, $boucle->sql_serveur)
2059
-							and isset($desc['field'][$col])
2060
-							and $cle = array_search($desc['table'], $boucle->from)
2061
-						) {
2062
-							$table = $cle;
2063
-						} else {
2064
-							$table = trouver_jointure_champ($col, $boucle, [$table], ($crit->cond or $op != '='));
2065
-						}
2066
-						#$table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op!='='), true);
2067
-						if (!$table) {
2068
-							return '';
2069
-						}
2070
-					}
2071
-					// si le champ n'est pas trouvé dans la table,
2072
-					// on cherche si une jointure peut l'obtenir
2073
-					elseif (@!array_key_exists($col, $desc['field'])) {
2074
-						// Champ joker * des iterateurs DATA qui accepte tout
2075
-						if (@array_key_exists('*', $desc['field'])) {
2076
-							$desc['field'][$col_vraie ?: $col] = ''; // on veut pas de cast INT par defaut car le type peut etre n'importe quoi dans les boucles DATA
2077
-						}
2078
-						else {
2079
-							$r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table);
2080
-							if (!$r) {
2081
-								return '';
2082
-							}
2083
-							[$col, $col_alias, $table, $where_complement, $desc] = $r;
2084
-						}
2085
-					}
2086
-				}
2087
-			}
2088
-		}
2089
-	}
2090
-
2091
-	$col_vraie = ($col_vraie ?: $col);
2092
-	// Dans tous les cas,
2093
-	// virer les guillemets eventuels autour d'un int (qui sont refuses par certains SQL)
2094
-	// et passer dans sql_quote avec le type si connu
2095
-	// et int sinon si la valeur est numerique
2096
-	// sinon introduire le vrai type du champ si connu dans le sql_quote (ou int NOT NULL sinon)
2097
-	// Ne pas utiliser intval, PHP tronquant les Bigint de SQL
2098
-	if ($op == '=' or in_array($op, $GLOBALS['table_criteres_infixes'])) {
2099
-		$type_cast_quote = ($desc['field'][$col_vraie] ?? 'int NOT NULL');
2100
-		// defaire le quote des int et les passer dans sql_quote avec le bon type de champ si on le connait, int sinon
2101
-		// prendre en compte le debug ou la valeur arrive avec un commentaire PHP en debut
2102
-		if (preg_match(",^\\A(\s*//.*?$\s*)?\"'(-?\d+)'\"\\z,ms", $val[0], $r)) {
2103
-			$val[0] = $r[1] . '"' . sql_quote($r[2], $boucle->sql_serveur, $type_cast_quote) . '"';
2104
-		}
2105
-		// sinon expliciter les
2106
-		// sql_quote(truc) en sql_quote(truc,'',type)
2107
-		// sql_quote(truc,serveur) en sql_quote(truc,serveur,type)
2108
-		// sql_quote(truc,serveur,'') en sql_quote(truc,serveur,type)
2109
-		// sans toucher aux
2110
-		// sql_quote(truc,'','varchar(10) DEFAULT \'oui\' COLLATE NOCASE')
2111
-		// sql_quote(truc,'','varchar')
2112
-		elseif (
2113
-			preg_match('/\Asql_quote[(](.*?)(,[^)]*?)?(,[^)]*(?:\(\d+\)[^)]*)?)?[)]\s*\z/ms', $val[0], $r)
2114
-			// si pas deja un type
2115
-			and (!isset($r[3]) or !$r[3] or !trim($r[3], ", '"))
2116
-		) {
2117
-			$r = $r[1]
2118
-				. ((isset($r[2]) and $r[2]) ? $r[2] : ",''")
2119
-				. ",'" . addslashes($type_cast_quote) . "'";
2120
-			$val[0] = "sql_quote($r)";
2121
-		}
2122
-		elseif (
2123
-			strpos($val[0], '@@defaultcast@@') !== false
2124
-			and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2125
-		) {
2126
-			$val[0] = substr($val[0], 0, -strlen($r[0])) . "'" . addslashes($type_cast_quote) . "')";
2127
-		}
2128
-	}
2129
-
2130
-	if (
2131
-		strpos($val[0], '@@defaultcast@@') !== false
2132
-		and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2133
-	) {
2134
-		$val[0] = substr($val[0], 0, -strlen($r[0])) . "'char')";
2135
-	}
2136
-
2137
-	// Indicateur pour permettre aux fonctionx boucle_X de modifier
2138
-	// leurs requetes par defaut, notamment le champ statut
2139
-	// Ne pas confondre champs de la table principale et des jointures
2140
-	if ($table === $boucle->id_table) {
2141
-		$boucles[$idb]->modificateur['criteres'][$col_vraie] = true;
2142
-		if ($col_alias != $col_vraie) {
2143
-			$boucles[$idb]->modificateur['criteres'][$col_alias] = true;
2144
-		}
2145
-	}
2146
-
2147
-	// inserer le nom de la table SQL devant le nom du champ
2148
-	if ($table) {
2149
-		if ($col[0] == '`') {
2150
-			$arg = "$table." . substr($col, 1, -1);
2151
-		} else {
2152
-			$arg = "$table.$col";
2153
-		}
2154
-	} else {
2155
-		$arg = $col;
2156
-	}
2157
-
2158
-	// inserer la fonction SQL
2159
-	if ($fct) {
2160
-		$arg = "$fct($arg$args_sql)";
2161
-	}
2162
-
2163
-	return [$arg, $op, $val, $col_alias, $where_complement];
2005
+    $boucle = &$boucles[$idb];
2006
+    $type = $boucle->type_requete;
2007
+    $table = $boucle->id_table;
2008
+    $desc = $boucle->show;
2009
+    $col_vraie = null;
2010
+
2011
+    [$fct, $col, $op, $val, $args_sql] =
2012
+        calculer_critere_infixe_ops($idb, $boucles, $crit);
2013
+
2014
+    $col_alias = $col;
2015
+    $where_complement = false;
2016
+
2017
+    // Cas particulier : id_enfant => utiliser la colonne id_objet
2018
+    if ($col == 'id_enfant') {
2019
+        $col = $boucle->primary;
2020
+    }
2021
+
2022
+    // Cas particulier : id_parent => verifier les exceptions de tables
2023
+    if (
2024
+        (in_array($col, ['id_parent', 'id_secteur']) and isset($GLOBALS['exceptions_des_tables'][$table][$col]))
2025
+        or (isset($GLOBALS['exceptions_des_tables'][$table][$col]) and is_string($GLOBALS['exceptions_des_tables'][$table][$col]))
2026
+    ) {
2027
+        $col = $GLOBALS['exceptions_des_tables'][$table][$col];
2028
+    } // et possibilite de gerer un critere secteur sur des tables de plugins (ie forums)
2029
+    else {
2030
+        if (($col == 'id_secteur') and ($critere_secteur = charger_fonction("critere_secteur_$type", 'public', true))) {
2031
+            $table = $critere_secteur($idb, $boucles, $val, $crit);
2032
+        }
2033
+
2034
+        // cas id_article=xx qui se mappe en id_objet=xx AND objet=article
2035
+        // sauf si exception declaree : sauter cette etape
2036
+        else {
2037
+            if (
2038
+                !isset($GLOBALS['exceptions_des_jointures'][table_objet_sql($table)][$col])
2039
+                and !isset($GLOBALS['exceptions_des_jointures'][$col])
2040
+                and count(trouver_champs_decomposes($col, $desc)) > 1
2041
+            ) {
2042
+                $e = decompose_champ_id_objet($col);
2043
+                $col = array_shift($e);
2044
+                $where_complement = primary_doublee($e, $table);
2045
+            } // Cas particulier : expressions de date
2046
+            else {
2047
+                if ($c = calculer_critere_infixe_date($idb, $boucles, $col)) {
2048
+                    [$col, $col_vraie] = $c;
2049
+                    $table = '';
2050
+                } // table explicitée {mots.titre}
2051
+                else {
2052
+                    if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2053
+                        [, $table, $col] = $r;
2054
+                        $col_alias = $col;
2055
+
2056
+                        $trouver_table = charger_fonction('trouver_table', 'base');
2057
+                        if (
2058
+                            $desc = $trouver_table($table, $boucle->sql_serveur)
2059
+                            and isset($desc['field'][$col])
2060
+                            and $cle = array_search($desc['table'], $boucle->from)
2061
+                        ) {
2062
+                            $table = $cle;
2063
+                        } else {
2064
+                            $table = trouver_jointure_champ($col, $boucle, [$table], ($crit->cond or $op != '='));
2065
+                        }
2066
+                        #$table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op!='='), true);
2067
+                        if (!$table) {
2068
+                            return '';
2069
+                        }
2070
+                    }
2071
+                    // si le champ n'est pas trouvé dans la table,
2072
+                    // on cherche si une jointure peut l'obtenir
2073
+                    elseif (@!array_key_exists($col, $desc['field'])) {
2074
+                        // Champ joker * des iterateurs DATA qui accepte tout
2075
+                        if (@array_key_exists('*', $desc['field'])) {
2076
+                            $desc['field'][$col_vraie ?: $col] = ''; // on veut pas de cast INT par defaut car le type peut etre n'importe quoi dans les boucles DATA
2077
+                        }
2078
+                        else {
2079
+                            $r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table);
2080
+                            if (!$r) {
2081
+                                return '';
2082
+                            }
2083
+                            [$col, $col_alias, $table, $where_complement, $desc] = $r;
2084
+                        }
2085
+                    }
2086
+                }
2087
+            }
2088
+        }
2089
+    }
2090
+
2091
+    $col_vraie = ($col_vraie ?: $col);
2092
+    // Dans tous les cas,
2093
+    // virer les guillemets eventuels autour d'un int (qui sont refuses par certains SQL)
2094
+    // et passer dans sql_quote avec le type si connu
2095
+    // et int sinon si la valeur est numerique
2096
+    // sinon introduire le vrai type du champ si connu dans le sql_quote (ou int NOT NULL sinon)
2097
+    // Ne pas utiliser intval, PHP tronquant les Bigint de SQL
2098
+    if ($op == '=' or in_array($op, $GLOBALS['table_criteres_infixes'])) {
2099
+        $type_cast_quote = ($desc['field'][$col_vraie] ?? 'int NOT NULL');
2100
+        // defaire le quote des int et les passer dans sql_quote avec le bon type de champ si on le connait, int sinon
2101
+        // prendre en compte le debug ou la valeur arrive avec un commentaire PHP en debut
2102
+        if (preg_match(",^\\A(\s*//.*?$\s*)?\"'(-?\d+)'\"\\z,ms", $val[0], $r)) {
2103
+            $val[0] = $r[1] . '"' . sql_quote($r[2], $boucle->sql_serveur, $type_cast_quote) . '"';
2104
+        }
2105
+        // sinon expliciter les
2106
+        // sql_quote(truc) en sql_quote(truc,'',type)
2107
+        // sql_quote(truc,serveur) en sql_quote(truc,serveur,type)
2108
+        // sql_quote(truc,serveur,'') en sql_quote(truc,serveur,type)
2109
+        // sans toucher aux
2110
+        // sql_quote(truc,'','varchar(10) DEFAULT \'oui\' COLLATE NOCASE')
2111
+        // sql_quote(truc,'','varchar')
2112
+        elseif (
2113
+            preg_match('/\Asql_quote[(](.*?)(,[^)]*?)?(,[^)]*(?:\(\d+\)[^)]*)?)?[)]\s*\z/ms', $val[0], $r)
2114
+            // si pas deja un type
2115
+            and (!isset($r[3]) or !$r[3] or !trim($r[3], ", '"))
2116
+        ) {
2117
+            $r = $r[1]
2118
+                . ((isset($r[2]) and $r[2]) ? $r[2] : ",''")
2119
+                . ",'" . addslashes($type_cast_quote) . "'";
2120
+            $val[0] = "sql_quote($r)";
2121
+        }
2122
+        elseif (
2123
+            strpos($val[0], '@@defaultcast@@') !== false
2124
+            and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2125
+        ) {
2126
+            $val[0] = substr($val[0], 0, -strlen($r[0])) . "'" . addslashes($type_cast_quote) . "')";
2127
+        }
2128
+    }
2129
+
2130
+    if (
2131
+        strpos($val[0], '@@defaultcast@@') !== false
2132
+        and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2133
+    ) {
2134
+        $val[0] = substr($val[0], 0, -strlen($r[0])) . "'char')";
2135
+    }
2136
+
2137
+    // Indicateur pour permettre aux fonctionx boucle_X de modifier
2138
+    // leurs requetes par defaut, notamment le champ statut
2139
+    // Ne pas confondre champs de la table principale et des jointures
2140
+    if ($table === $boucle->id_table) {
2141
+        $boucles[$idb]->modificateur['criteres'][$col_vraie] = true;
2142
+        if ($col_alias != $col_vraie) {
2143
+            $boucles[$idb]->modificateur['criteres'][$col_alias] = true;
2144
+        }
2145
+    }
2146
+
2147
+    // inserer le nom de la table SQL devant le nom du champ
2148
+    if ($table) {
2149
+        if ($col[0] == '`') {
2150
+            $arg = "$table." . substr($col, 1, -1);
2151
+        } else {
2152
+            $arg = "$table.$col";
2153
+        }
2154
+    } else {
2155
+        $arg = $col;
2156
+    }
2157
+
2158
+    // inserer la fonction SQL
2159
+    if ($fct) {
2160
+        $arg = "$fct($arg$args_sql)";
2161
+    }
2162
+
2163
+    return [$arg, $op, $val, $col_alias, $where_complement];
2164 2164
 }
2165 2165
 
2166 2166
 
@@ -2189,77 +2189,77 @@  discard block
 block discarded – undo
2189 2189
  **/
2190 2190
 function calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table) {
2191 2191
 
2192
-	$where = '';
2193
-
2194
-	$calculer_critere_externe = 'calculer_critere_externe_init';
2195
-	// gestion par les plugins des jointures tordues
2196
-	// pas automatiques mais necessaires
2197
-	$table_sql = table_objet_sql($table);
2198
-	if (
2199
-		isset($GLOBALS['exceptions_des_jointures'][$table_sql])
2200
-		and is_array($GLOBALS['exceptions_des_jointures'][$table_sql])
2201
-		and
2202
-		(
2203
-			isset($GLOBALS['exceptions_des_jointures'][$table_sql][$col])
2204
-			or
2205
-			isset($GLOBALS['exceptions_des_jointures'][$table_sql][''])
2206
-		)
2207
-	) {
2208
-		$t = $GLOBALS['exceptions_des_jointures'][$table_sql];
2209
-		$index = $t[$col] ?? $t[''] ?? [];
2210
-
2211
-		if ((is_countable($index) ? count($index) : 0) == 3) {
2212
-			[$t, $col, $calculer_critere_externe] = $index;
2213
-		} elseif ((is_countable($index) ? count($index) : 0) == 2) {
2214
-			[$t, $col] = $t[$col];
2215
-		} elseif ((is_countable($index) ? count($index) : 0) == 1) {
2216
-			[$calculer_critere_externe] = $index;
2217
-			$t = $table;
2218
-		} else {
2219
-			$t = '';
2220
-		} // jointure non declaree. La trouver.
2221
-	} elseif (isset($GLOBALS['exceptions_des_jointures'][$col])) {
2222
-		[$t, $col] = $GLOBALS['exceptions_des_jointures'][$col];
2223
-	} else {
2224
-		$t = '';
2225
-	} // jointure non declaree. La trouver.
2226
-
2227
-	// ici on construit le from pour fournir $col en piochant dans les jointures
2228
-
2229
-	// si des jointures explicites sont fournies, on cherche d'abord dans celles ci
2230
-	// permet de forcer une table de lien quand il y a ambiguite
2231
-	// <BOUCLE_(DOCUMENTS documents_liens){id_mot}>
2232
-	// alors que <BOUCLE_(DOCUMENTS){id_mot}> produit la meme chose que <BOUCLE_(DOCUMENTS mots_liens){id_mot}>
2233
-	$table = '';
2234
-	if ($boucle->jointures_explicites) {
2235
-		$jointures_explicites = explode(' ', $boucle->jointures_explicites);
2236
-		$table = $calculer_critere_externe($boucle, $jointures_explicites, $col, $desc, ($crit->cond or $op != '='), $t);
2237
-	}
2238
-
2239
-	// et sinon on cherche parmi toutes les jointures declarees
2240
-	if (!$table) {
2241
-		$table = $calculer_critere_externe($boucle, $boucle->jointures, $col, $desc, ($crit->cond or $op != '='), $t);
2242
-	}
2243
-
2244
-	if (!$table) {
2245
-		return '';
2246
-	}
2247
-
2248
-	// il ne reste plus qu'a trouver le champ dans les from
2249
-	[$nom, $desc, $cle] = trouver_champ_exterieur($col, $boucle->from, $boucle);
2250
-
2251
-	if ((is_countable($cle) ? count($cle) : 0) > 1 or reset($cle) !== $col) {
2252
-		$col_alias = $col; // id_article devient juste le nom d'origine
2253
-		if ((is_countable($cle) ? count($cle) : 0) > 1 and reset($cle) == 'id_objet') {
2254
-			$e = decompose_champ_id_objet($col);
2255
-			$col = array_shift($e);
2256
-			$where = primary_doublee($e, $table);
2257
-		} else {
2258
-			$col = reset($cle);
2259
-		}
2260
-	}
2261
-
2262
-	return [$col, $col_alias, $table, $where, $desc];
2192
+    $where = '';
2193
+
2194
+    $calculer_critere_externe = 'calculer_critere_externe_init';
2195
+    // gestion par les plugins des jointures tordues
2196
+    // pas automatiques mais necessaires
2197
+    $table_sql = table_objet_sql($table);
2198
+    if (
2199
+        isset($GLOBALS['exceptions_des_jointures'][$table_sql])
2200
+        and is_array($GLOBALS['exceptions_des_jointures'][$table_sql])
2201
+        and
2202
+        (
2203
+            isset($GLOBALS['exceptions_des_jointures'][$table_sql][$col])
2204
+            or
2205
+            isset($GLOBALS['exceptions_des_jointures'][$table_sql][''])
2206
+        )
2207
+    ) {
2208
+        $t = $GLOBALS['exceptions_des_jointures'][$table_sql];
2209
+        $index = $t[$col] ?? $t[''] ?? [];
2210
+
2211
+        if ((is_countable($index) ? count($index) : 0) == 3) {
2212
+            [$t, $col, $calculer_critere_externe] = $index;
2213
+        } elseif ((is_countable($index) ? count($index) : 0) == 2) {
2214
+            [$t, $col] = $t[$col];
2215
+        } elseif ((is_countable($index) ? count($index) : 0) == 1) {
2216
+            [$calculer_critere_externe] = $index;
2217
+            $t = $table;
2218
+        } else {
2219
+            $t = '';
2220
+        } // jointure non declaree. La trouver.
2221
+    } elseif (isset($GLOBALS['exceptions_des_jointures'][$col])) {
2222
+        [$t, $col] = $GLOBALS['exceptions_des_jointures'][$col];
2223
+    } else {
2224
+        $t = '';
2225
+    } // jointure non declaree. La trouver.
2226
+
2227
+    // ici on construit le from pour fournir $col en piochant dans les jointures
2228
+
2229
+    // si des jointures explicites sont fournies, on cherche d'abord dans celles ci
2230
+    // permet de forcer une table de lien quand il y a ambiguite
2231
+    // <BOUCLE_(DOCUMENTS documents_liens){id_mot}>
2232
+    // alors que <BOUCLE_(DOCUMENTS){id_mot}> produit la meme chose que <BOUCLE_(DOCUMENTS mots_liens){id_mot}>
2233
+    $table = '';
2234
+    if ($boucle->jointures_explicites) {
2235
+        $jointures_explicites = explode(' ', $boucle->jointures_explicites);
2236
+        $table = $calculer_critere_externe($boucle, $jointures_explicites, $col, $desc, ($crit->cond or $op != '='), $t);
2237
+    }
2238
+
2239
+    // et sinon on cherche parmi toutes les jointures declarees
2240
+    if (!$table) {
2241
+        $table = $calculer_critere_externe($boucle, $boucle->jointures, $col, $desc, ($crit->cond or $op != '='), $t);
2242
+    }
2243
+
2244
+    if (!$table) {
2245
+        return '';
2246
+    }
2247
+
2248
+    // il ne reste plus qu'a trouver le champ dans les from
2249
+    [$nom, $desc, $cle] = trouver_champ_exterieur($col, $boucle->from, $boucle);
2250
+
2251
+    if ((is_countable($cle) ? count($cle) : 0) > 1 or reset($cle) !== $col) {
2252
+        $col_alias = $col; // id_article devient juste le nom d'origine
2253
+        if ((is_countable($cle) ? count($cle) : 0) > 1 and reset($cle) == 'id_objet') {
2254
+            $e = decompose_champ_id_objet($col);
2255
+            $col = array_shift($e);
2256
+            $where = primary_doublee($e, $table);
2257
+        } else {
2258
+            $col = reset($cle);
2259
+        }
2260
+    }
2261
+
2262
+    return [$col, $col_alias, $table, $where, $desc];
2263 2263
 }
2264 2264
 
2265 2265
 
@@ -2280,10 +2280,10 @@  discard block
 block discarded – undo
2280 2280
  *     - valeur
2281 2281
  **/
2282 2282
 function primary_doublee($decompose, $table) {
2283
-	$e1 = reset($decompose);
2284
-	$e2 = "sql_quote('" . end($decompose) . "')";
2283
+    $e1 = reset($decompose);
2284
+    $e2 = "sql_quote('" . end($decompose) . "')";
2285 2285
 
2286
-	return ["'='", "'$table." . $e1 . "'", $e2];
2286
+    return ["'='", "'$table." . $e1 . "'", $e2];
2287 2287
 }
2288 2288
 
2289 2289
 /**
@@ -2314,57 +2314,57 @@  discard block
 block discarded – undo
2314 2314
  *     Vide sinon.
2315 2315
  */
2316 2316
 function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $cond, $checkarrivee = false) {
2317
-	// si on demande un truc du genre spip_mots
2318
-	// avec aussi spip_mots_liens dans les jointures dispo
2319
-	// et qu'on est la
2320
-	// il faut privilegier la jointure directe en 2 etapes spip_mots_liens, spip_mots
2321
-	if (
2322
-		$checkarrivee
2323
-		and is_string($checkarrivee)
2324
-		and $a = table_objet($checkarrivee)
2325
-		and in_array($a . '_liens', $joints)
2326
-	) {
2327
-		if ($res = calculer_lien_externe_init($boucle, $joints, $col, $desc, $cond, $checkarrivee)) {
2328
-			return $res;
2329
-		}
2330
-	}
2331
-	foreach ($joints as $joint) {
2332
-		if ($arrivee = trouver_champ_exterieur($col, [$joint], $boucle, $checkarrivee)) {
2333
-			// alias de table dans le from
2334
-			$t = array_search($arrivee[0], $boucle->from);
2335
-			// recuperer la cle id_xx eventuellement decomposee en (id_objet,objet)
2336
-			$cols = $arrivee[2];
2337
-			// mais on ignore la 3eme cle si presente qui correspond alors au point de depart
2338
-			if ((is_countable($cols) ? count($cols) : 0) > 2) {
2339
-				array_pop($cols);
2340
-			}
2341
-			if ($t) {
2342
-				// la table est déjà dans le FROM, on vérifie si le champ est utilisé.
2343
-				$joindre = false;
2344
-				foreach ($cols as $col) {
2345
-					$c = '/\b' . $t . ".$col" . '\b/';
2346
-					if (trouver_champ($c, $boucle->where)) {
2347
-						$joindre = true;
2348
-					} else {
2349
-						// mais ca peut etre dans le FIELD pour le Having
2350
-						$c = "/FIELD.$t" . ".$col,/";
2351
-						if (trouver_champ($c, $boucle->select)) {
2352
-							$joindre = true;
2353
-						}
2354
-					}
2355
-				}
2356
-				if (!$joindre) {
2357
-					return $t;
2358
-				}
2359
-			}
2360
-			array_pop($arrivee);
2361
-			if ($res = calculer_jointure($boucle, [$boucle->id_table, $desc], $arrivee, $cols, $cond, 1)) {
2362
-				return $res;
2363
-			}
2364
-		}
2365
-	}
2366
-
2367
-	return '';
2317
+    // si on demande un truc du genre spip_mots
2318
+    // avec aussi spip_mots_liens dans les jointures dispo
2319
+    // et qu'on est la
2320
+    // il faut privilegier la jointure directe en 2 etapes spip_mots_liens, spip_mots
2321
+    if (
2322
+        $checkarrivee
2323
+        and is_string($checkarrivee)
2324
+        and $a = table_objet($checkarrivee)
2325
+        and in_array($a . '_liens', $joints)
2326
+    ) {
2327
+        if ($res = calculer_lien_externe_init($boucle, $joints, $col, $desc, $cond, $checkarrivee)) {
2328
+            return $res;
2329
+        }
2330
+    }
2331
+    foreach ($joints as $joint) {
2332
+        if ($arrivee = trouver_champ_exterieur($col, [$joint], $boucle, $checkarrivee)) {
2333
+            // alias de table dans le from
2334
+            $t = array_search($arrivee[0], $boucle->from);
2335
+            // recuperer la cle id_xx eventuellement decomposee en (id_objet,objet)
2336
+            $cols = $arrivee[2];
2337
+            // mais on ignore la 3eme cle si presente qui correspond alors au point de depart
2338
+            if ((is_countable($cols) ? count($cols) : 0) > 2) {
2339
+                array_pop($cols);
2340
+            }
2341
+            if ($t) {
2342
+                // la table est déjà dans le FROM, on vérifie si le champ est utilisé.
2343
+                $joindre = false;
2344
+                foreach ($cols as $col) {
2345
+                    $c = '/\b' . $t . ".$col" . '\b/';
2346
+                    if (trouver_champ($c, $boucle->where)) {
2347
+                        $joindre = true;
2348
+                    } else {
2349
+                        // mais ca peut etre dans le FIELD pour le Having
2350
+                        $c = "/FIELD.$t" . ".$col,/";
2351
+                        if (trouver_champ($c, $boucle->select)) {
2352
+                            $joindre = true;
2353
+                        }
2354
+                    }
2355
+                }
2356
+                if (!$joindre) {
2357
+                    return $t;
2358
+                }
2359
+            }
2360
+            array_pop($arrivee);
2361
+            if ($res = calculer_jointure($boucle, [$boucle->id_table, $desc], $arrivee, $cols, $cond, 1)) {
2362
+                return $res;
2363
+            }
2364
+        }
2365
+    }
2366
+
2367
+    return '';
2368 2368
 }
2369 2369
 
2370 2370
 /**
@@ -2390,35 +2390,35 @@  discard block
 block discarded – undo
2390 2390
  *     Alias de la table de jointure (Lx)
2391 2391
  */
2392 2392
 function calculer_lien_externe_init(&$boucle, $joints, $col, $desc, $cond, $checkarrivee = false) {
2393
-	$primary_arrivee = id_table_objet($checkarrivee);
2394
-
2395
-	// [FIXME] $checkarrivee peut-il arriver avec false ????
2396
-	$intermediaire = trouver_champ_exterieur($primary_arrivee, $joints, $boucle, $checkarrivee . '_liens');
2397
-	$arrivee = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee);
2398
-
2399
-	if (!$intermediaire or !$arrivee) {
2400
-		return '';
2401
-	}
2402
-	array_pop($intermediaire); // enlever la cle en 3eme argument
2403
-	array_pop($arrivee); // enlever la cle en 3eme argument
2404
-
2405
-	$res = fabrique_jointures(
2406
-		$boucle,
2407
-		[
2408
-			[
2409
-				$boucle->id_table,
2410
-				$intermediaire,
2411
-				[id_table_objet($desc['table_objet']), 'id_objet', 'objet', $desc['type']]
2412
-			],
2413
-			[reset($intermediaire), $arrivee, $primary_arrivee]
2414
-		],
2415
-		$cond,
2416
-		$desc,
2417
-		$boucle->id_table,
2418
-		[$col]
2419
-	);
2420
-
2421
-	return $res;
2393
+    $primary_arrivee = id_table_objet($checkarrivee);
2394
+
2395
+    // [FIXME] $checkarrivee peut-il arriver avec false ????
2396
+    $intermediaire = trouver_champ_exterieur($primary_arrivee, $joints, $boucle, $checkarrivee . '_liens');
2397
+    $arrivee = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee);
2398
+
2399
+    if (!$intermediaire or !$arrivee) {
2400
+        return '';
2401
+    }
2402
+    array_pop($intermediaire); // enlever la cle en 3eme argument
2403
+    array_pop($arrivee); // enlever la cle en 3eme argument
2404
+
2405
+    $res = fabrique_jointures(
2406
+        $boucle,
2407
+        [
2408
+            [
2409
+                $boucle->id_table,
2410
+                $intermediaire,
2411
+                [id_table_objet($desc['table_objet']), 'id_objet', 'objet', $desc['type']]
2412
+            ],
2413
+            [reset($intermediaire), $arrivee, $primary_arrivee]
2414
+        ],
2415
+        $cond,
2416
+        $desc,
2417
+        $boucle->id_table,
2418
+        [$col]
2419
+    );
2420
+
2421
+    return $res;
2422 2422
 }
2423 2423
 
2424 2424
 
@@ -2435,17 +2435,17 @@  discard block
 block discarded – undo
2435 2435
  *     false sinon.
2436 2436
  **/
2437 2437
 function trouver_champ($champ, $where) {
2438
-	if (!is_array($where)) {
2439
-		return preg_match($champ, $where);
2440
-	} else {
2441
-		foreach ($where as $clause) {
2442
-			if (trouver_champ($champ, $clause)) {
2443
-				return true;
2444
-			}
2445
-		}
2446
-
2447
-		return false;
2448
-	}
2438
+    if (!is_array($where)) {
2439
+        return preg_match($champ, $where);
2440
+    } else {
2441
+        foreach ($where as $clause) {
2442
+            if (trouver_champ($champ, $clause)) {
2443
+                return true;
2444
+            }
2445
+        }
2446
+
2447
+        return false;
2448
+    }
2449 2449
 }
2450 2450
 
2451 2451
 
@@ -2471,129 +2471,129 @@  discard block
 block discarded – undo
2471 2471
  *     - string $args_sql  Suite des arguments du critère. ?
2472 2472
  **/
2473 2473
 function calculer_critere_infixe_ops($idb, &$boucles, $crit) {
2474
-	// cas d'une valeur comparee a elle-meme ou son referent
2475
-	if (count($crit->param) == 0) {
2476
-		$op = '=';
2477
-		$col = $val = $crit->op;
2478
-		if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2479
-			$val = $r[2];
2480
-		}
2481
-		// Cas special {lang} : aller chercher $GLOBALS['spip_lang']
2482
-		if ($val == 'lang') {
2483
-			$val = [kwote('$GLOBALS[\'spip_lang\']')];
2484
-		} else {
2485
-			$defaut = null;
2486
-			if ($val == 'id_parent') {
2487
-				// Si id_parent, comparer l'id_parent avec l'id_objet
2488
-				// de la boucle superieure.... faudrait verifier qu'il existe
2489
-				// pour eviter l'erreur SQL
2490
-				$val = $boucles[$idb]->primary;
2491
-				// mais si pas de boucle superieure, prendre id_parent dans l'env
2492
-				$defaut = "(\$Pile[0]['id_parent'] ?? null)";
2493
-			} elseif ($val == 'id_enfant') {
2494
-				// Si id_enfant, comparer l'id_objet avec l'id_parent
2495
-				// de la boucle superieure
2496
-				$val = 'id_parent';
2497
-			} elseif ($crit->cond and ($col == 'date' or $col == 'date_redac')) {
2498
-				// un critere conditionnel sur date est traite a part
2499
-				// car la date est mise d'office par SPIP,
2500
-				$defaut = "(\$Pile[0]['{$col}_default']?'':\$Pile[0]['" . $col . "'])";
2501
-			}
2502
-
2503
-			$val = calculer_argument_precedent($idb, $val, $boucles, $defaut);
2504
-			$val = [kwote($val)];
2505
-		}
2506
-	} else {
2507
-		// comparaison explicite
2508
-		// le phraseur impose que le premier param soit du texte
2509
-		$params = $crit->param;
2510
-		$op = $crit->op;
2511
-		if ($op == '==') {
2512
-			$op = 'REGEXP';
2513
-		}
2514
-		$col = array_shift($params);
2515
-		$col = $col[0]->texte;
2516
-
2517
-		$val = [];
2518
-		$parent = $boucles[$idb]->id_parent;
2519
-
2520
-		// Dans le cas {x=='#DATE'} etc, defaire le travail du phraseur,
2521
-		// celui ne sachant pas ce qu'est un critere infixe
2522
-		// et a fortiori son 2e operande qu'entoure " ou '
2523
-		if (
2524
-			count($params) == 1
2525
-			and (is_countable($params[0]) ? count($params[0]) : 0) == 3
2526
-			and $params[0][0]->type == 'texte'
2527
-			and $params[0][2]->type == 'texte'
2528
-			and ($p = $params[0][0]->texte) == $params[0][2]->texte
2529
-			and (($p == "'") or ($p == '"'))
2530
-			and $params[0][1]->type == 'champ'
2531
-		) {
2532
-			$val[] = "$p\\$p#" . $params[0][1]->nom_champ . "\\$p$p";
2533
-		} else {
2534
-			foreach ((($op != 'IN') ? $params : calculer_vieux_in($params)) as $p) {
2535
-				$a = calculer_liste($p, $idb, $boucles, $parent);
2536
-				if (strcasecmp($op, 'IN') == 0) {
2537
-					$val[] = $a;
2538
-				} else {
2539
-					$val[] = kwote($a, $boucles[$idb]->sql_serveur, '@@defaultcast@@');
2540
-				} // toujours quoter en char ici
2541
-			}
2542
-		}
2543
-	}
2544
-
2545
-	$fct = $args_sql = '';
2546
-	// fonction SQL ?
2547
-	// chercher FONCTION(champ) tel que CONCAT(titre,descriptif)
2548
-	if (preg_match('/^(.*)' . SQL_ARGS . '$/', $col, $m)) {
2549
-		$fct = $m[1];
2550
-		preg_match('/^\(([^,]*)(.*)\)$/', $m[2], $a);
2551
-		$col = $a[1];
2552
-		if (preg_match('/^(\S*)(\s+AS\s+.*)$/i', $col, $m)) {
2553
-			$col = $m[1];
2554
-			$args_sql = $m[2];
2555
-		}
2556
-		$args_sql .= $a[2];
2557
-	}
2558
-
2559
-	return [$fct, $col, $op, $val, $args_sql];
2474
+    // cas d'une valeur comparee a elle-meme ou son referent
2475
+    if (count($crit->param) == 0) {
2476
+        $op = '=';
2477
+        $col = $val = $crit->op;
2478
+        if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2479
+            $val = $r[2];
2480
+        }
2481
+        // Cas special {lang} : aller chercher $GLOBALS['spip_lang']
2482
+        if ($val == 'lang') {
2483
+            $val = [kwote('$GLOBALS[\'spip_lang\']')];
2484
+        } else {
2485
+            $defaut = null;
2486
+            if ($val == 'id_parent') {
2487
+                // Si id_parent, comparer l'id_parent avec l'id_objet
2488
+                // de la boucle superieure.... faudrait verifier qu'il existe
2489
+                // pour eviter l'erreur SQL
2490
+                $val = $boucles[$idb]->primary;
2491
+                // mais si pas de boucle superieure, prendre id_parent dans l'env
2492
+                $defaut = "(\$Pile[0]['id_parent'] ?? null)";
2493
+            } elseif ($val == 'id_enfant') {
2494
+                // Si id_enfant, comparer l'id_objet avec l'id_parent
2495
+                // de la boucle superieure
2496
+                $val = 'id_parent';
2497
+            } elseif ($crit->cond and ($col == 'date' or $col == 'date_redac')) {
2498
+                // un critere conditionnel sur date est traite a part
2499
+                // car la date est mise d'office par SPIP,
2500
+                $defaut = "(\$Pile[0]['{$col}_default']?'':\$Pile[0]['" . $col . "'])";
2501
+            }
2502
+
2503
+            $val = calculer_argument_precedent($idb, $val, $boucles, $defaut);
2504
+            $val = [kwote($val)];
2505
+        }
2506
+    } else {
2507
+        // comparaison explicite
2508
+        // le phraseur impose que le premier param soit du texte
2509
+        $params = $crit->param;
2510
+        $op = $crit->op;
2511
+        if ($op == '==') {
2512
+            $op = 'REGEXP';
2513
+        }
2514
+        $col = array_shift($params);
2515
+        $col = $col[0]->texte;
2516
+
2517
+        $val = [];
2518
+        $parent = $boucles[$idb]->id_parent;
2519
+
2520
+        // Dans le cas {x=='#DATE'} etc, defaire le travail du phraseur,
2521
+        // celui ne sachant pas ce qu'est un critere infixe
2522
+        // et a fortiori son 2e operande qu'entoure " ou '
2523
+        if (
2524
+            count($params) == 1
2525
+            and (is_countable($params[0]) ? count($params[0]) : 0) == 3
2526
+            and $params[0][0]->type == 'texte'
2527
+            and $params[0][2]->type == 'texte'
2528
+            and ($p = $params[0][0]->texte) == $params[0][2]->texte
2529
+            and (($p == "'") or ($p == '"'))
2530
+            and $params[0][1]->type == 'champ'
2531
+        ) {
2532
+            $val[] = "$p\\$p#" . $params[0][1]->nom_champ . "\\$p$p";
2533
+        } else {
2534
+            foreach ((($op != 'IN') ? $params : calculer_vieux_in($params)) as $p) {
2535
+                $a = calculer_liste($p, $idb, $boucles, $parent);
2536
+                if (strcasecmp($op, 'IN') == 0) {
2537
+                    $val[] = $a;
2538
+                } else {
2539
+                    $val[] = kwote($a, $boucles[$idb]->sql_serveur, '@@defaultcast@@');
2540
+                } // toujours quoter en char ici
2541
+            }
2542
+        }
2543
+    }
2544
+
2545
+    $fct = $args_sql = '';
2546
+    // fonction SQL ?
2547
+    // chercher FONCTION(champ) tel que CONCAT(titre,descriptif)
2548
+    if (preg_match('/^(.*)' . SQL_ARGS . '$/', $col, $m)) {
2549
+        $fct = $m[1];
2550
+        preg_match('/^\(([^,]*)(.*)\)$/', $m[2], $a);
2551
+        $col = $a[1];
2552
+        if (preg_match('/^(\S*)(\s+AS\s+.*)$/i', $col, $m)) {
2553
+            $col = $m[1];
2554
+            $args_sql = $m[2];
2555
+        }
2556
+        $args_sql .= $a[2];
2557
+    }
2558
+
2559
+    return [$fct, $col, $op, $val, $args_sql];
2560 2560
 }
2561 2561
 
2562 2562
 // compatibilite ancienne version
2563 2563
 
2564 2564
 function calculer_vieux_in($params) {
2565
-	$deb = $params[0][0];
2566
-	$k = (is_countable($params) ? count($params) : 0) - 1;
2567
-	$last = $params[$k];
2568
-	$j = (is_countable($last) ? count($last) : 0) - 1;
2569
-	$last = $last[$j];
2570
-	$n = isset($last->texte) ? strlen($last->texte) : 0;
2571
-
2572
-	if (
2573
-		!((isset($deb->texte[0]) and $deb->texte[0] == '(')
2574
-		&& (isset($last->texte[$n - 1]) and $last->texte[$n - 1] == ')'))
2575
-	) {
2576
-		return $params;
2577
-	}
2578
-	$params[0][0]->texte = substr($deb->texte, 1);
2579
-	// attention, on peut avoir k=0,j=0 ==> recalculer
2580
-	$last = $params[$k][$j];
2581
-	$n = strlen($last->texte);
2582
-	$params[$k][$j]->texte = substr($last->texte, 0, $n - 1);
2583
-	$newp = [];
2584
-	foreach ($params as $v) {
2585
-		if ($v[0]->type != 'texte') {
2586
-			$newp[] = $v;
2587
-		} else {
2588
-			foreach (explode(',', $v[0]->texte) as $x) {
2589
-				$t = new Texte();
2590
-				$t->texte = $x;
2591
-				$newp[] = [$t];
2592
-			}
2593
-		}
2594
-	}
2595
-
2596
-	return $newp;
2565
+    $deb = $params[0][0];
2566
+    $k = (is_countable($params) ? count($params) : 0) - 1;
2567
+    $last = $params[$k];
2568
+    $j = (is_countable($last) ? count($last) : 0) - 1;
2569
+    $last = $last[$j];
2570
+    $n = isset($last->texte) ? strlen($last->texte) : 0;
2571
+
2572
+    if (
2573
+        !((isset($deb->texte[0]) and $deb->texte[0] == '(')
2574
+        && (isset($last->texte[$n - 1]) and $last->texte[$n - 1] == ')'))
2575
+    ) {
2576
+        return $params;
2577
+    }
2578
+    $params[0][0]->texte = substr($deb->texte, 1);
2579
+    // attention, on peut avoir k=0,j=0 ==> recalculer
2580
+    $last = $params[$k][$j];
2581
+    $n = strlen($last->texte);
2582
+    $params[$k][$j]->texte = substr($last->texte, 0, $n - 1);
2583
+    $newp = [];
2584
+    foreach ($params as $v) {
2585
+        if ($v[0]->type != 'texte') {
2586
+            $newp[] = $v;
2587
+        } else {
2588
+            foreach (explode(',', $v[0]->texte) as $x) {
2589
+                $t = new Texte();
2590
+                $t->texte = $x;
2591
+                $newp[] = [$t];
2592
+            }
2593
+        }
2594
+    }
2595
+
2596
+    return $newp;
2597 2597
 }
2598 2598
 
2599 2599
 /**
@@ -2612,95 +2612,95 @@  discard block
 block discarded – undo
2612 2612
  *     - nom de la colonne de date (si le calcul n'est pas relatif)
2613 2613
  **/
2614 2614
 function calculer_critere_infixe_date($idb, &$boucles, $col) {
2615
-	if (!preg_match(',^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z_]+)?$,', $col, $regs)) {
2616
-		return '';
2617
-	}
2618
-
2619
-	$boucle = $boucles[$idb];
2620
-	$table = $boucle->show;
2621
-
2622
-	// si c'est une colonne de la table, ne rien faire
2623
-	if (isset($table['field'][$col])) {
2624
-		return '';
2625
-	}
2626
-
2627
-	// Le type de critère à prendre en compte
2628
-	$col = $regs[1];
2629
-
2630
-	// Si on trouve un nom de champ date précis, on l'utilise, pas besoin de déclaration dans l'API objet
2631
-	if (isset($regs[3]) and $suite = $regs[3]) {
2632
-		# Recherche de l'existence du champ date_xxxx,
2633
-		# si oui choisir ce champ, sinon choisir xxxx
2634
-		if (isset($table['field']["date$suite"])) {
2635
-			$date_orig = 'date' . $suite;
2636
-		} else {
2637
-			$date_orig = substr($suite, 1);
2638
-		}
2639
-
2640
-		$pred = $date_orig;
2641
-	} else { // Sinon il FAUT avoir déclaré le champ date officiel dans l'API objet
2642
-		// Si aucune déclaration trouvée, on quitte
2643
-		if (!$table['date'] && !isset($GLOBALS['table_date'][$table['id_table']])) {
2644
-			return '';
2645
-		}
2646
-		// Par défaut, on prend le champ date déclaré dans l'API
2647
-		$pred = $date_orig = $GLOBALS['table_date'][$table['id_table']] ?? $table['date'];
2648
-
2649
-		// Si c'est pour du relatif
2650
-		if (isset($regs[2]) and $rel = $regs[2]) {
2651
-			$pred = 'date';
2652
-		}
2653
-	}
2654
-
2655
-	$date_compare = "\"' . normaliser_date(" .
2656
-		calculer_argument_precedent($idb, $pred, $boucles) .
2657
-		") . '\"";
2658
-
2659
-	$col_vraie = $date_orig;
2660
-	$date_orig = $boucle->id_table . '.' . $date_orig;
2661
-
2662
-	switch ($col) {
2663
-		case 'date':
2664
-			$col = $date_orig;
2665
-			break;
2666
-		case 'jour':
2667
-			$col = "DAYOFMONTH($date_orig)";
2668
-			break;
2669
-		case 'mois':
2670
-			$col = "MONTH($date_orig)";
2671
-			break;
2672
-		case 'annee':
2673
-			$col = "YEAR($date_orig)";
2674
-			break;
2675
-		case 'heure':
2676
-			$col = "DATE_FORMAT($date_orig, \\'%H:%i\\')";
2677
-			break;
2678
-		case 'age':
2679
-			$col = calculer_param_date("\'' . date('Y-m-d H:i:00') . '\'", $date_orig);
2680
-			$col_vraie = '';// comparer a un int (par defaut)
2681
-			break;
2682
-		case 'age_relatif':
2683
-			$col = calculer_param_date($date_compare, $date_orig);
2684
-			$col_vraie = '';// comparer a un int (par defaut)
2685
-			break;
2686
-		case 'jour_relatif':
2687
-			$col = '(TO_DAYS(' . $date_compare . ')-TO_DAYS(' . $date_orig . '))';
2688
-			$col_vraie = '';// comparer a un int (par defaut)
2689
-			break;
2690
-		case 'mois_relatif':
2691
-			$col = 'MONTH(' . $date_compare . ')-MONTH(' .
2692
-				$date_orig . ')+12*(YEAR(' . $date_compare .
2693
-				')-YEAR(' . $date_orig . '))';
2694
-			$col_vraie = '';// comparer a un int (par defaut)
2695
-			break;
2696
-		case 'annee_relatif':
2697
-			$col = 'YEAR(' . $date_compare . ')-YEAR(' .
2698
-				$date_orig . ')';
2699
-			$col_vraie = '';// comparer a un int (par defaut)
2700
-			break;
2701
-	}
2702
-
2703
-	return [$col, $col_vraie];
2615
+    if (!preg_match(',^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z_]+)?$,', $col, $regs)) {
2616
+        return '';
2617
+    }
2618
+
2619
+    $boucle = $boucles[$idb];
2620
+    $table = $boucle->show;
2621
+
2622
+    // si c'est une colonne de la table, ne rien faire
2623
+    if (isset($table['field'][$col])) {
2624
+        return '';
2625
+    }
2626
+
2627
+    // Le type de critère à prendre en compte
2628
+    $col = $regs[1];
2629
+
2630
+    // Si on trouve un nom de champ date précis, on l'utilise, pas besoin de déclaration dans l'API objet
2631
+    if (isset($regs[3]) and $suite = $regs[3]) {
2632
+        # Recherche de l'existence du champ date_xxxx,
2633
+        # si oui choisir ce champ, sinon choisir xxxx
2634
+        if (isset($table['field']["date$suite"])) {
2635
+            $date_orig = 'date' . $suite;
2636
+        } else {
2637
+            $date_orig = substr($suite, 1);
2638
+        }
2639
+
2640
+        $pred = $date_orig;
2641
+    } else { // Sinon il FAUT avoir déclaré le champ date officiel dans l'API objet
2642
+        // Si aucune déclaration trouvée, on quitte
2643
+        if (!$table['date'] && !isset($GLOBALS['table_date'][$table['id_table']])) {
2644
+            return '';
2645
+        }
2646
+        // Par défaut, on prend le champ date déclaré dans l'API
2647
+        $pred = $date_orig = $GLOBALS['table_date'][$table['id_table']] ?? $table['date'];
2648
+
2649
+        // Si c'est pour du relatif
2650
+        if (isset($regs[2]) and $rel = $regs[2]) {
2651
+            $pred = 'date';
2652
+        }
2653
+    }
2654
+
2655
+    $date_compare = "\"' . normaliser_date(" .
2656
+        calculer_argument_precedent($idb, $pred, $boucles) .
2657
+        ") . '\"";
2658
+
2659
+    $col_vraie = $date_orig;
2660
+    $date_orig = $boucle->id_table . '.' . $date_orig;
2661
+
2662
+    switch ($col) {
2663
+        case 'date':
2664
+            $col = $date_orig;
2665
+            break;
2666
+        case 'jour':
2667
+            $col = "DAYOFMONTH($date_orig)";
2668
+            break;
2669
+        case 'mois':
2670
+            $col = "MONTH($date_orig)";
2671
+            break;
2672
+        case 'annee':
2673
+            $col = "YEAR($date_orig)";
2674
+            break;
2675
+        case 'heure':
2676
+            $col = "DATE_FORMAT($date_orig, \\'%H:%i\\')";
2677
+            break;
2678
+        case 'age':
2679
+            $col = calculer_param_date("\'' . date('Y-m-d H:i:00') . '\'", $date_orig);
2680
+            $col_vraie = '';// comparer a un int (par defaut)
2681
+            break;
2682
+        case 'age_relatif':
2683
+            $col = calculer_param_date($date_compare, $date_orig);
2684
+            $col_vraie = '';// comparer a un int (par defaut)
2685
+            break;
2686
+        case 'jour_relatif':
2687
+            $col = '(TO_DAYS(' . $date_compare . ')-TO_DAYS(' . $date_orig . '))';
2688
+            $col_vraie = '';// comparer a un int (par defaut)
2689
+            break;
2690
+        case 'mois_relatif':
2691
+            $col = 'MONTH(' . $date_compare . ')-MONTH(' .
2692
+                $date_orig . ')+12*(YEAR(' . $date_compare .
2693
+                ')-YEAR(' . $date_orig . '))';
2694
+            $col_vraie = '';// comparer a un int (par defaut)
2695
+            break;
2696
+        case 'annee_relatif':
2697
+            $col = 'YEAR(' . $date_compare . ')-YEAR(' .
2698
+                $date_orig . ')';
2699
+            $col_vraie = '';// comparer a un int (par defaut)
2700
+            break;
2701
+    }
2702
+
2703
+    return [$col, $col_vraie];
2704 2704
 }
2705 2705
 
2706 2706
 /**
@@ -2719,16 +2719,16 @@  discard block
 block discarded – undo
2719 2719
  *     de colonne SQL et une date.
2720 2720
  **/
2721 2721
 function calculer_param_date($date_compare, $date_orig) {
2722
-	if (preg_match(",'\" *\.(.*)\. *\"',", $date_compare, $r)) {
2723
-		$init = "'\" . (\$x = $r[1]) . \"'";
2724
-		$date_compare = '\'$x\'';
2725
-	} else {
2726
-		$init = $date_compare;
2727
-	}
2728
-
2729
-	return
2730
-		// optimisation : mais prevoir le support SQLite avant
2731
-		"TIMESTAMPDIFF(HOUR,$date_orig,$init)/24";
2722
+    if (preg_match(",'\" *\.(.*)\. *\"',", $date_compare, $r)) {
2723
+        $init = "'\" . (\$x = $r[1]) . \"'";
2724
+        $date_compare = '\'$x\'';
2725
+    } else {
2726
+        $init = $date_compare;
2727
+    }
2728
+
2729
+    return
2730
+        // optimisation : mais prevoir le support SQLite avant
2731
+        "TIMESTAMPDIFF(HOUR,$date_orig,$init)/24";
2732 2732
 }
2733 2733
 
2734 2734
 /**
@@ -2746,20 +2746,20 @@  discard block
 block discarded – undo
2746 2746
  * @param Critere $crit Paramètres du critère dans cette boucle
2747 2747
  */
2748 2748
 function critere_DATA_source_dist($idb, &$boucles, $crit) {
2749
-	$boucle = &$boucles[$idb];
2750
-
2751
-	$args = [];
2752
-	foreach ($crit->param as &$param) {
2753
-		array_push(
2754
-			$args,
2755
-			calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent)
2756
-		);
2757
-	}
2749
+    $boucle = &$boucles[$idb];
2758 2750
 
2759
-	$boucle->hash .= '
2751
+    $args = [];
2752
+    foreach ($crit->param as &$param) {
2753
+        array_push(
2754
+            $args,
2755
+            calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent)
2756
+        );
2757
+    }
2758
+
2759
+    $boucle->hash .= '
2760 2760
 	$command[\'sourcemode\'] = ' . array_shift($args) . ";\n";
2761 2761
 
2762
-	$boucle->hash .= '
2762
+    $boucle->hash .= '
2763 2763
 	$command[\'source\'] = array(' . join(', ', $args) . ");\n";
2764 2764
 }
2765 2765
 
@@ -2777,8 +2777,8 @@  discard block
 block discarded – undo
2777 2777
  * @param Critere $crit Paramètres du critère dans cette boucle
2778 2778
  */
2779 2779
 function critere_DATA_datacache_dist($idb, &$boucles, $crit) {
2780
-	$boucle = &$boucles[$idb];
2781
-	$boucle->hash .= '
2780
+    $boucle = &$boucles[$idb];
2781
+    $boucle->hash .= '
2782 2782
 	$command[\'datacache\'] = ' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent) . ';';
2783 2783
 }
2784 2784
 
@@ -2794,12 +2794,12 @@  discard block
 block discarded – undo
2794 2794
  * @param Critere $crit Paramètres du critère dans cette boucle
2795 2795
  */
2796 2796
 function critere_php_args_dist($idb, &$boucles, $crit) {
2797
-	$boucle = &$boucles[$idb];
2798
-	$boucle->hash .= '$command[\'args\']=array();';
2799
-	foreach ($crit->param as $param) {
2800
-		$boucle->hash .= '
2797
+    $boucle = &$boucles[$idb];
2798
+    $boucle->hash .= '$command[\'args\']=array();';
2799
+    foreach ($crit->param as $param) {
2800
+        $boucle->hash .= '
2801 2801
 			$command[\'args\'][] = ' . calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ';';
2802
-	}
2802
+    }
2803 2803
 }
2804 2804
 
2805 2805
 /**
@@ -2816,16 +2816,16 @@  discard block
 block discarded – undo
2816 2816
  * @param Critere $crit Paramètres du critère dans cette boucle
2817 2817
  */
2818 2818
 function critere_DATA_liste_dist($idb, &$boucles, $crit) {
2819
-	$boucle = &$boucles[$idb];
2820
-	$boucle->hash .= "\n\t" . '$command[\'liste\'] = array();' . "\n";
2821
-	foreach ($crit->param as $param) {
2822
-		$boucle->hash .= "\t" . '$command[\'liste\'][] = ' . calculer_liste(
2823
-			$param,
2824
-			$idb,
2825
-			$boucles,
2826
-			$boucles[$idb]->id_parent
2827
-		) . ";\n";
2828
-	}
2819
+    $boucle = &$boucles[$idb];
2820
+    $boucle->hash .= "\n\t" . '$command[\'liste\'] = array();' . "\n";
2821
+    foreach ($crit->param as $param) {
2822
+        $boucle->hash .= "\t" . '$command[\'liste\'][] = ' . calculer_liste(
2823
+            $param,
2824
+            $idb,
2825
+            $boucles,
2826
+            $boucles[$idb]->id_parent
2827
+        ) . ";\n";
2828
+    }
2829 2829
 }
2830 2830
 
2831 2831
 /**
@@ -2850,16 +2850,16 @@  discard block
 block discarded – undo
2850 2850
  * @param Critere $crit Paramètres du critère dans cette boucle
2851 2851
  */
2852 2852
 function critere_DATA_enum_dist($idb, &$boucles, $crit) {
2853
-	$boucle = &$boucles[$idb];
2854
-	$boucle->hash .= "\n\t" . '$command[\'enum\'] = array();' . "\n";
2855
-	foreach ($crit->param as $param) {
2856
-		$boucle->hash .= "\t" . '$command[\'enum\'][] = ' . calculer_liste(
2857
-			$param,
2858
-			$idb,
2859
-			$boucles,
2860
-			$boucles[$idb]->id_parent
2861
-		) . ";\n";
2862
-	}
2853
+    $boucle = &$boucles[$idb];
2854
+    $boucle->hash .= "\n\t" . '$command[\'enum\'] = array();' . "\n";
2855
+    foreach ($crit->param as $param) {
2856
+        $boucle->hash .= "\t" . '$command[\'enum\'][] = ' . calculer_liste(
2857
+            $param,
2858
+            $idb,
2859
+            $boucles,
2860
+            $boucles[$idb]->id_parent
2861
+        ) . ";\n";
2862
+    }
2863 2863
 }
2864 2864
 
2865 2865
 /**
@@ -2874,11 +2874,11 @@  discard block
 block discarded – undo
2874 2874
  * @param Critere $crit Paramètres du critère dans cette boucle
2875 2875
  */
2876 2876
 function critere_DATA_datapath_dist($idb, &$boucles, $crit) {
2877
-	$boucle = &$boucles[$idb];
2878
-	foreach ($crit->param as $param) {
2879
-		$boucle->hash .= '
2877
+    $boucle = &$boucles[$idb];
2878
+    foreach ($crit->param as $param) {
2879
+        $boucle->hash .= '
2880 2880
 			$command[\'datapath\'][] = ' . calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ';';
2881
-	}
2881
+    }
2882 2882
 }
2883 2883
 
2884 2884
 
@@ -2910,20 +2910,20 @@  discard block
 block discarded – undo
2910 2910
  * @param Critere $crit Paramètres du critère dans cette boucle
2911 2911
  */
2912 2912
 function critere_si_dist($idb, &$boucles, $crit) {
2913
-	$boucle = &$boucles[$idb];
2914
-	// il faut initialiser 1 fois le tableau a chaque appel de la boucle
2915
-	// (par exemple lorsque notre boucle est appelee dans une autre boucle)
2916
-	// mais ne pas l'initialiser n fois si il y a n criteres {si } dans la boucle !
2917
-	$boucle->hash .= "\n\tif (!isset(\$si_init)) { \$command['si'] = array(); \$si_init = true; }\n";
2918
-	if ($crit->param) {
2919
-		foreach ($crit->param as $param) {
2920
-			$boucle->hash .= "\t\$command['si'][] = "
2921
-				. calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ";\n";
2922
-		}
2923
-		// interdire {si 0} aussi !
2924
-	} else {
2925
-		$boucle->hash .= '$command[\'si\'][] = 0;';
2926
-	}
2913
+    $boucle = &$boucles[$idb];
2914
+    // il faut initialiser 1 fois le tableau a chaque appel de la boucle
2915
+    // (par exemple lorsque notre boucle est appelee dans une autre boucle)
2916
+    // mais ne pas l'initialiser n fois si il y a n criteres {si } dans la boucle !
2917
+    $boucle->hash .= "\n\tif (!isset(\$si_init)) { \$command['si'] = array(); \$si_init = true; }\n";
2918
+    if ($crit->param) {
2919
+        foreach ($crit->param as $param) {
2920
+            $boucle->hash .= "\t\$command['si'][] = "
2921
+                . calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ";\n";
2922
+        }
2923
+        // interdire {si 0} aussi !
2924
+    } else {
2925
+        $boucle->hash .= '$command[\'si\'][] = 0;';
2926
+    }
2927 2927
 }
2928 2928
 
2929 2929
 /**
@@ -2940,8 +2940,8 @@  discard block
 block discarded – undo
2940 2940
  * @param Critere $crit Paramètres du critère dans cette boucle
2941 2941
  */
2942 2942
 function critere_POUR_tableau_dist($idb, &$boucles, $crit) {
2943
-	$boucle = &$boucles[$idb];
2944
-	$boucle->hash .= '
2943
+    $boucle = &$boucles[$idb];
2944
+    $boucle->hash .= '
2945 2945
 	$command[\'source\'] = array(' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent) . ');
2946 2946
 	$command[\'sourcemode\'] = \'table\';';
2947 2947
 }
@@ -2962,27 +2962,27 @@  discard block
 block discarded – undo
2962 2962
  */
2963 2963
 function critere_noeud_dist($idb, &$boucles, $crit) {
2964 2964
 
2965
-	$not = $crit->not;
2966
-	$boucle = &$boucles[$idb];
2967
-	$primary = $boucle->primary;
2965
+    $not = $crit->not;
2966
+    $boucle = &$boucles[$idb];
2967
+    $primary = $boucle->primary;
2968 2968
 
2969
-	if (!$primary or strpos($primary, ',')) {
2970
-		erreur_squelette(_T('zbug_doublon_sur_table_sans_cle_primaire'), $boucle);
2969
+    if (!$primary or strpos($primary, ',')) {
2970
+        erreur_squelette(_T('zbug_doublon_sur_table_sans_cle_primaire'), $boucle);
2971 2971
 
2972
-		return;
2973
-	}
2974
-	$table = $boucle->type_requete;
2975
-	$table_sql = table_objet_sql(objet_type($table));
2972
+        return;
2973
+    }
2974
+    $table = $boucle->type_requete;
2975
+    $table_sql = table_objet_sql(objet_type($table));
2976 2976
 
2977
-	$id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
2977
+    $id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
2978 2978
 
2979
-	$in = 'IN';
2980
-	$where = ["'IN'", "'$boucle->id_table." . "$primary'", "'('.sql_get_select('$id_parent', '$table_sql').')'"];
2981
-	if ($not) {
2982
-		$where = ["'NOT'", $where];
2983
-	}
2979
+    $in = 'IN';
2980
+    $where = ["'IN'", "'$boucle->id_table." . "$primary'", "'('.sql_get_select('$id_parent', '$table_sql').')'"];
2981
+    if ($not) {
2982
+        $where = ["'NOT'", $where];
2983
+    }
2984 2984
 
2985
-	$boucle->where[] = $where;
2985
+    $boucle->where[] = $where;
2986 2986
 }
2987 2987
 
2988 2988
 /**
@@ -2998,8 +2998,8 @@  discard block
 block discarded – undo
2998 2998
  * @param Critere $crit Paramètres du critère dans cette boucle
2999 2999
  */
3000 3000
 function critere_feuille_dist($idb, &$boucles, $crit) {
3001
-	$not = $crit->not;
3002
-	$crit->not = $not ? false : true;
3003
-	critere_noeud_dist($idb, $boucles, $crit);
3004
-	$crit->not = $not;
3001
+    $not = $crit->not;
3002
+    $crit->not = $not ? false : true;
3003
+    critere_noeud_dist($idb, $boucles, $crit);
3004
+    $crit->not = $not;
3005 3005
 }
Please login to merge, or discard this patch.
ecrire/public/phraser_html.php 1 patch
Indentation   +1032 added lines, -1032 removed lines patch added patch discarded remove patch
@@ -27,7 +27,7 @@  discard block
 block discarded – undo
27 27
  **/
28 28
 
29 29
 if (!defined('_ECRIRE_INC_VERSION')) {
30
-	return;
30
+    return;
31 31
 }
32 32
 
33 33
 /** Début de la partie principale d'une boucle */
@@ -71,82 +71,82 @@  discard block
 block discarded – undo
71 71
 
72 72
 function phraser_inclure($texte, $ligne, $result) {
73 73
 
74
-	while (preg_match(BALISE_INCLURE, $texte, $match)) {
75
-		$match = array_pad($match, 3, null);
76
-		$p = strpos($texte, (string) $match[0]);
77
-		$debut = substr($texte, 0, $p);
78
-		if ($p) {
79
-			$result = phraser_idiomes($debut, $ligne, $result);
80
-		}
81
-		$ligne += substr_count($debut, "\n");
82
-		$champ = new Inclure();
83
-		$champ->ligne = $ligne;
84
-		$ligne += substr_count($match[0], "\n");
85
-		$fichier = $match[2];
86
-		# assurer ici la migration .php3 => .php
87
-		# et de l'ancienne syntaxe INCLURE(page.php3) devenue surperflue
88
-		if ($fichier and preg_match(',^(.*[.]php)3$,', $fichier, $r)) {
89
-			$fichier = $r[1];
90
-		}
91
-		$champ->texte = ($fichier !== 'page.php') ? $fichier : '';
92
-		$texte = substr($texte, $p + strlen($match[0]));
93
-		// on assimile {var=val} a une liste de un argument sans fonction
94
-		$pos_apres = 0;
95
-		phraser_args($texte, '/>', '', $result, $champ, $pos_apres);
96
-		if (!$champ->texte or (is_countable($champ->param) ? count($champ->param) : 0) > 1) {
97
-			if (!function_exists('normaliser_inclure')) {
98
-				include_spip('public/normaliser');
99
-			}
100
-			normaliser_inclure($champ);
101
-		}
102
-		$texte = substr($texte, strpos($texte, '>', $pos_apres) + 1);
103
-		$texte = preg_replace(',^</INCLU[DR]E>,', '', $texte);
104
-		$result[] = $champ;
105
-	}
106
-
107
-	return (($texte === '') ? $result : phraser_idiomes($texte, $ligne, $result));
74
+    while (preg_match(BALISE_INCLURE, $texte, $match)) {
75
+        $match = array_pad($match, 3, null);
76
+        $p = strpos($texte, (string) $match[0]);
77
+        $debut = substr($texte, 0, $p);
78
+        if ($p) {
79
+            $result = phraser_idiomes($debut, $ligne, $result);
80
+        }
81
+        $ligne += substr_count($debut, "\n");
82
+        $champ = new Inclure();
83
+        $champ->ligne = $ligne;
84
+        $ligne += substr_count($match[0], "\n");
85
+        $fichier = $match[2];
86
+        # assurer ici la migration .php3 => .php
87
+        # et de l'ancienne syntaxe INCLURE(page.php3) devenue surperflue
88
+        if ($fichier and preg_match(',^(.*[.]php)3$,', $fichier, $r)) {
89
+            $fichier = $r[1];
90
+        }
91
+        $champ->texte = ($fichier !== 'page.php') ? $fichier : '';
92
+        $texte = substr($texte, $p + strlen($match[0]));
93
+        // on assimile {var=val} a une liste de un argument sans fonction
94
+        $pos_apres = 0;
95
+        phraser_args($texte, '/>', '', $result, $champ, $pos_apres);
96
+        if (!$champ->texte or (is_countable($champ->param) ? count($champ->param) : 0) > 1) {
97
+            if (!function_exists('normaliser_inclure')) {
98
+                include_spip('public/normaliser');
99
+            }
100
+            normaliser_inclure($champ);
101
+        }
102
+        $texte = substr($texte, strpos($texte, '>', $pos_apres) + 1);
103
+        $texte = preg_replace(',^</INCLU[DR]E>,', '', $texte);
104
+        $result[] = $champ;
105
+    }
106
+
107
+    return (($texte === '') ? $result : phraser_idiomes($texte, $ligne, $result));
108 108
 }
109 109
 
110 110
 function phraser_polyglotte($texte, $ligne, $result) {
111 111
 
112
-	if (preg_match_all(BALISE_POLYGLOTTE, $texte, $m, PREG_SET_ORDER)) {
113
-		foreach ($m as $match) {
114
-			$p = strpos($texte, (string) $match[0]);
115
-			$debut = substr($texte, 0, $p);
116
-			if ($p) {
117
-				$champ = new Texte();
118
-				$champ->texte = $debut;
119
-				$champ->ligne = $ligne;
120
-				$result[] = $champ;
121
-				$ligne += substr_count($champ->texte, "\n");
122
-			}
123
-
124
-			$champ = new Polyglotte();
125
-			$champ->ligne = $ligne;
126
-			$ligne += substr_count($match[0], "\n");
127
-			$lang = '';
128
-			$bloc = $match[1];
129
-			$texte = substr($texte, $p + strlen($match[0]));
130
-			while (preg_match('/^[[:space:]]*([^[{]*)[[:space:]]*[[{]([a-z_]+)[]}](.*)$/si', $bloc, $regs)) {
131
-				$trad = $regs[1];
132
-				if ($trad or $lang) {
133
-					$champ->traductions[$lang] = $trad;
134
-				}
135
-				$lang = $regs[2];
136
-				$bloc = $regs[3];
137
-			}
138
-			$champ->traductions[$lang] = $bloc;
139
-			$result[] = $champ;
140
-		}
141
-	}
142
-	if ($texte !== '') {
143
-		$champ = new Texte();
144
-		$champ->texte = $texte;
145
-		$champ->ligne = $ligne;
146
-		$result[] = $champ;
147
-	}
148
-
149
-	return $result;
112
+    if (preg_match_all(BALISE_POLYGLOTTE, $texte, $m, PREG_SET_ORDER)) {
113
+        foreach ($m as $match) {
114
+            $p = strpos($texte, (string) $match[0]);
115
+            $debut = substr($texte, 0, $p);
116
+            if ($p) {
117
+                $champ = new Texte();
118
+                $champ->texte = $debut;
119
+                $champ->ligne = $ligne;
120
+                $result[] = $champ;
121
+                $ligne += substr_count($champ->texte, "\n");
122
+            }
123
+
124
+            $champ = new Polyglotte();
125
+            $champ->ligne = $ligne;
126
+            $ligne += substr_count($match[0], "\n");
127
+            $lang = '';
128
+            $bloc = $match[1];
129
+            $texte = substr($texte, $p + strlen($match[0]));
130
+            while (preg_match('/^[[:space:]]*([^[{]*)[[:space:]]*[[{]([a-z_]+)[]}](.*)$/si', $bloc, $regs)) {
131
+                $trad = $regs[1];
132
+                if ($trad or $lang) {
133
+                    $champ->traductions[$lang] = $trad;
134
+                }
135
+                $lang = $regs[2];
136
+                $bloc = $regs[3];
137
+            }
138
+            $champ->traductions[$lang] = $bloc;
139
+            $result[] = $champ;
140
+        }
141
+    }
142
+    if ($texte !== '') {
143
+        $champ = new Texte();
144
+        $champ->texte = $texte;
145
+        $champ->ligne = $ligne;
146
+        $result[] = $champ;
147
+    }
148
+
149
+    return $result;
150 150
 }
151 151
 
152 152
 
@@ -168,43 +168,43 @@  discard block
 block discarded – undo
168 168
  * @return array
169 169
  **/
170 170
 function phraser_idiomes($texte, $ligne, $result) {
171
-	while (preg_match(BALISE_IDIOMES, $texte, $match)) {
172
-		$match = array_pad($match, 8, null);
173
-		$p = strpos($texte, (string) $match[0]);
174
-		$ko = (!$match[3] && ($match[5][0] !== '='));
175
-		$debut = substr($texte, 0, $p + ($ko ? strlen($match[0]) : 0));
176
-		if ($debut) {
177
-			$result = phraser_champs($debut, $ligne, $result);
178
-		}
179
-		$texte = substr($texte, $p + strlen($match[0]));
180
-		$ligne += substr_count($debut, "\n");
181
-		if ($ko) {
182
-			continue;
183
-		} // faux idiome
184
-		$champ = new Idiome();
185
-		$champ->ligne = $ligne;
186
-		$ligne += substr_count($match[0], "\n");
187
-		// Stocker les arguments de la balise de traduction
188
-		$args = [];
189
-		$largs = $match[5];
190
-		while (preg_match(BALISE_IDIOMES_ARGS, $largs, $r)) {
191
-			$args[$r[1]] = phraser_champs($r[2], 0, []);
192
-			$largs = substr($largs, strlen($r[0]));
193
-		}
194
-		$champ->arg = $args;
195
-		$champ->nom_champ = strtolower($match[3]);
196
-		$champ->module = $match[2];
197
-		// pas d'imbrication pour les filtres sur langue
198
-		$pos_apres = 0;
199
-		phraser_args($match[7] ?? '', ':', '', [], $champ, $pos_apres);
200
-		$champ->apres = substr($match[7] ?? '', $pos_apres);
201
-		$result[] = $champ;
202
-	}
203
-	if ($texte !== '') {
204
-		$result = phraser_champs($texte, $ligne, $result);
205
-	}
206
-
207
-	return $result;
171
+    while (preg_match(BALISE_IDIOMES, $texte, $match)) {
172
+        $match = array_pad($match, 8, null);
173
+        $p = strpos($texte, (string) $match[0]);
174
+        $ko = (!$match[3] && ($match[5][0] !== '='));
175
+        $debut = substr($texte, 0, $p + ($ko ? strlen($match[0]) : 0));
176
+        if ($debut) {
177
+            $result = phraser_champs($debut, $ligne, $result);
178
+        }
179
+        $texte = substr($texte, $p + strlen($match[0]));
180
+        $ligne += substr_count($debut, "\n");
181
+        if ($ko) {
182
+            continue;
183
+        } // faux idiome
184
+        $champ = new Idiome();
185
+        $champ->ligne = $ligne;
186
+        $ligne += substr_count($match[0], "\n");
187
+        // Stocker les arguments de la balise de traduction
188
+        $args = [];
189
+        $largs = $match[5];
190
+        while (preg_match(BALISE_IDIOMES_ARGS, $largs, $r)) {
191
+            $args[$r[1]] = phraser_champs($r[2], 0, []);
192
+            $largs = substr($largs, strlen($r[0]));
193
+        }
194
+        $champ->arg = $args;
195
+        $champ->nom_champ = strtolower($match[3]);
196
+        $champ->module = $match[2];
197
+        // pas d'imbrication pour les filtres sur langue
198
+        $pos_apres = 0;
199
+        phraser_args($match[7] ?? '', ':', '', [], $champ, $pos_apres);
200
+        $champ->apres = substr($match[7] ?? '', $pos_apres);
201
+        $result[] = $champ;
202
+    }
203
+    if ($texte !== '') {
204
+        $result = phraser_champs($texte, $ligne, $result);
205
+    }
206
+
207
+    return $result;
208 208
 }
209 209
 
210 210
 /**
@@ -222,47 +222,47 @@  discard block
 block discarded – undo
222 222
  * @return array
223 223
  **/
224 224
 function phraser_champs($texte, $ligne, $result) {
225
-	while (preg_match('/' . NOM_DE_CHAMP . '/S', $texte, $match)) {
226
-		$p = strpos($texte, (string) $match[0]);
227
-		// texte après la balise
228
-		$suite = substr($texte, $p + strlen($match[0]));
229
-
230
-		$debut = substr($texte, 0, $p);
231
-		if ($p) {
232
-			$result = phraser_polyglotte($debut, $ligne, $result);
233
-		}
234
-		$ligne += substr_count($debut, "\n");
235
-		$champ = new Champ();
236
-		$champ->ligne = $ligne;
237
-		$ligne += substr_count($match[0], "\n");
238
-		$champ->nom_boucle = $match[2];
239
-		$champ->nom_champ = $match[3];
240
-		$champ->etoile = $match[5];
241
-
242
-		if ($suite and $suite[0] == '{') {
243
-			phraser_arg($suite, '', [], $champ);
244
-			// ce ltrim est une ereur de conception
245
-			// mais on le conserve par souci de compatibilite
246
-			$texte = ltrim($suite);
247
-			// Il faudrait le normaliser dans l'arbre de syntaxe abstraite
248
-			// pour faire sauter ce cas particulier a la decompilation.
249
-			/* Ce qui suit est malheureusement incomplet pour cela:
225
+    while (preg_match('/' . NOM_DE_CHAMP . '/S', $texte, $match)) {
226
+        $p = strpos($texte, (string) $match[0]);
227
+        // texte après la balise
228
+        $suite = substr($texte, $p + strlen($match[0]));
229
+
230
+        $debut = substr($texte, 0, $p);
231
+        if ($p) {
232
+            $result = phraser_polyglotte($debut, $ligne, $result);
233
+        }
234
+        $ligne += substr_count($debut, "\n");
235
+        $champ = new Champ();
236
+        $champ->ligne = $ligne;
237
+        $ligne += substr_count($match[0], "\n");
238
+        $champ->nom_boucle = $match[2];
239
+        $champ->nom_champ = $match[3];
240
+        $champ->etoile = $match[5];
241
+
242
+        if ($suite and $suite[0] == '{') {
243
+            phraser_arg($suite, '', [], $champ);
244
+            // ce ltrim est une ereur de conception
245
+            // mais on le conserve par souci de compatibilite
246
+            $texte = ltrim($suite);
247
+            // Il faudrait le normaliser dans l'arbre de syntaxe abstraite
248
+            // pour faire sauter ce cas particulier a la decompilation.
249
+            /* Ce qui suit est malheureusement incomplet pour cela:
250 250
 			if ($n = (strlen($suite) - strlen($texte))) {
251 251
 				$champ->apres = array(new Texte);
252 252
 				$champ->apres[0]->texte = substr($suite,0,$n);
253 253
 			}
254 254
 			*/
255
-		} else {
256
-			$texte = $suite;
257
-		}
258
-		phraser_vieux($champ);
259
-		$result[] = $champ;
260
-	}
261
-	if ($texte !== '') {
262
-		$result = phraser_polyglotte($texte, $ligne, $result);
263
-	}
264
-
265
-	return $result;
255
+        } else {
256
+            $texte = $suite;
257
+        }
258
+        phraser_vieux($champ);
259
+        $result[] = $champ;
260
+    }
261
+    if ($texte !== '') {
262
+        $result = phraser_polyglotte($texte, $ligne, $result);
263
+    }
264
+
265
+    return $result;
266 266
 }
267 267
 
268 268
 // Gestion des imbrications:
@@ -271,15 +271,15 @@  discard block
 block discarded – undo
271 271
 // on recommence tant qu'il y a des [...] en substituant a l'appel suivant
272 272
 
273 273
 function phraser_champs_etendus($texte, $ligne, $result) {
274
-	if ($texte === '') {
275
-		return $result;
276
-	}
277
-	$sep = '##';
278
-	while (strpos($texte, (string) $sep) !== false) {
279
-		$sep .= '#';
280
-	}
281
-
282
-	return array_merge($result, phraser_champs_interieurs($texte, $ligne, $sep, []));
274
+    if ($texte === '') {
275
+        return $result;
276
+    }
277
+    $sep = '##';
278
+    while (strpos($texte, (string) $sep) !== false) {
279
+        $sep .= '#';
280
+    }
281
+
282
+    return array_merge($result, phraser_champs_interieurs($texte, $ligne, $sep, []));
283 283
 }
284 284
 
285 285
 /**
@@ -298,275 +298,275 @@  discard block
 block discarded – undo
298 298
  * @return array
299 299
  */
300 300
 function phraser_args(string $texte, $fin, $sep, $result, &$pointeur_champ, &$pos_debut) {
301
-	$length = strlen($texte);
302
-	while ($pos_debut < $length and trim($texte[$pos_debut]) === '') {
303
-		$pos_debut++;
304
-	}
305
-	while (($pos_debut < $length) && !str_contains($fin, $texte[$pos_debut])) {
306
-		// phraser_arg modifie directement le $texte, on fait donc avec ici en passant par une sous chaine
307
-		$st = substr($texte, $pos_debut);
308
-		$result = phraser_arg($st, $sep, $result, $pointeur_champ);
309
-		$pos_debut = $length - strlen($st);
310
-		while ($pos_debut < $length and trim($texte[$pos_debut]) === '') {
311
-			$pos_debut++;
312
-		}
313
-	}
314
-
315
-	return $result;
301
+    $length = strlen($texte);
302
+    while ($pos_debut < $length and trim($texte[$pos_debut]) === '') {
303
+        $pos_debut++;
304
+    }
305
+    while (($pos_debut < $length) && !str_contains($fin, $texte[$pos_debut])) {
306
+        // phraser_arg modifie directement le $texte, on fait donc avec ici en passant par une sous chaine
307
+        $st = substr($texte, $pos_debut);
308
+        $result = phraser_arg($st, $sep, $result, $pointeur_champ);
309
+        $pos_debut = $length - strlen($st);
310
+        while ($pos_debut < $length and trim($texte[$pos_debut]) === '') {
311
+            $pos_debut++;
312
+        }
313
+    }
314
+
315
+    return $result;
316 316
 }
317 317
 
318 318
 function phraser_arg(&$texte, $sep, $result, &$pointeur_champ) {
319
-	preg_match(',^(\|?[^}{)|]*)(.*)$,ms', $texte, $match);
320
-	$suite = ltrim($match[2]);
321
-	$fonc = trim($match[1]);
322
-	if ($fonc && $fonc[0] == '|') {
323
-		$fonc = ltrim(substr($fonc, 1));
324
-	}
325
-	$res = [$fonc];
326
-	$err_f = '';
327
-	// cas du filtre sans argument ou du critere /
328
-	if (($suite && ($suite[0] != '{')) || ($fonc && $fonc[0] == '/')) {
329
-		// si pas d'argument, alors il faut une fonction ou un double |
330
-		if (!$match[1]) {
331
-			$err_f = ['zbug_erreur_filtre', ['filtre' => $texte]];
332
-			erreur_squelette($err_f, $pointeur_champ);
333
-			$texte = '';
334
-		} else {
335
-			$texte = $suite;
336
-		}
337
-		if ($err_f) {
338
-			$pointeur_champ->param = false;
339
-		} elseif ($fonc !== '') {
340
-			$pointeur_champ->param[] = $res;
341
-		}
342
-		// pour les balises avec faux filtres qui boudent ce dur larbeur
343
-		$pointeur_champ->fonctions[] = [$fonc, ''];
344
-
345
-		return $result;
346
-	}
347
-	$args = ltrim(substr($suite, 1)); // virer le '(' initial
348
-	$collecte = [];
349
-	while ($args && $args[0] != '}') {
350
-		if ($args[0] == '"') {
351
-			preg_match('/^(")([^"]*)(")(.*)$/ms', $args, $regs);
352
-		} elseif ($args[0] == "'") {
353
-			preg_match("/^(')([^']*)(')(.*)$/ms", $args, $regs);
354
-		} else {
355
-			preg_match('/^([[:space:]]*)([^,([{}]*([(\[{][^])}]*[])}])?[^,}]*)([,}].*)$/ms', $args, $regs);
356
-			if (!isset($regs[2]) or !strlen($regs[2])) {
357
-				$err_f = ['zbug_erreur_filtre', ['filtre' => $args]];
358
-				erreur_squelette($err_f, $pointeur_champ);
359
-				$champ = new Texte();
360
-				$champ->apres = $champ->avant = $args = '';
361
-				break;
362
-			}
363
-		}
364
-		$arg = $regs[2];
365
-		if (trim($regs[1])) {
366
-			$champ = new Texte();
367
-			$champ->texte = $arg;
368
-			$champ->apres = $champ->avant = $regs[1];
369
-			$result[] = $champ;
370
-			$collecte[] = $champ;
371
-			$args = ltrim($regs[count($regs) - 1]);
372
-		} else {
373
-			if (!preg_match('/' . NOM_DE_CHAMP . '([{|])/', $arg, $r)) {
374
-				// 0 est un aveu d'impuissance. A completer
375
-				$arg = phraser_champs_exterieurs($arg, 0, $sep, $result);
376
-
377
-				$args = ltrim($regs[count($regs) - 1]);
378
-				$collecte = array_merge($collecte, $arg);
379
-				$result = array_merge($result, $arg);
380
-			} else {
381
-				$n = strpos($args, (string) $r[0]);
382
-				$pred = substr($args, 0, $n);
383
-				$par = ',}';
384
-				if (preg_match('/^(.*)\($/', $pred, $m)) {
385
-					$pred = $m[1];
386
-					$par = ')';
387
-				}
388
-				if ($pred) {
389
-					$champ = new Texte();
390
-					$champ->texte = $pred;
391
-					$champ->apres = $champ->avant = '';
392
-					$result[] = $champ;
393
-					$collecte[] = $champ;
394
-				}
395
-				$rec = substr($args, $n + strlen($r[0]) - 1);
396
-				$champ = new Champ();
397
-				$champ->nom_boucle = $r[2];
398
-				$champ->nom_champ = $r[3];
399
-				$champ->etoile = $r[5];
400
-				$next = $r[6];
401
-				while ($next == '{') {
402
-					phraser_arg($rec, $sep, [], $champ);
403
-					$args = ltrim($rec);
404
-					$next = $args[0] ?? '';
405
-				}
406
-				while ($next == '|') {
407
-					$pos_apres = 0;
408
-					phraser_args($rec, $par, $sep, [], $champ, $pos_apres);
409
-					$args = substr($rec, $pos_apres);
410
-					$next = $args[0] ?? '';
411
-				}
412
-				// Si erreur de syntaxe dans un sous-argument, propager.
413
-				if ($champ->param === false) {
414
-					$err_f = true;
415
-				} else {
416
-					phraser_vieux($champ);
417
-				}
418
-				if ($par == ')') {
419
-					$args = substr($args, 1);
420
-				}
421
-				$collecte[] = $champ;
422
-				$result[] = $champ;
423
-			}
424
-		}
425
-		if (isset($args[0]) and $args[0] == ',') {
426
-			$args = ltrim(substr($args, 1));
427
-			if ($collecte) {
428
-				$res[] = $collecte;
429
-				$collecte = [];
430
-			}
431
-		}
432
-	}
433
-	if ($collecte) {
434
-		$res[] = $collecte;
435
-		$collecte = [];
436
-	}
437
-	$texte = substr($args, 1);
438
-	$source = substr($suite, 0, strlen($suite) - strlen($texte));
439
-	// propager les erreurs, et ignorer les param vides
440
-	if ($pointeur_champ->param !== false) {
441
-		if ($err_f) {
442
-			$pointeur_champ->param = false;
443
-		} elseif ($fonc !== '' || count($res) > 1) {
444
-			$pointeur_champ->param[] = $res;
445
-		}
446
-	}
447
-	// pour les balises avec faux filtres qui boudent ce dur larbeur
448
-	$pointeur_champ->fonctions[] = [$fonc, $source];
449
-
450
-	return $result;
319
+    preg_match(',^(\|?[^}{)|]*)(.*)$,ms', $texte, $match);
320
+    $suite = ltrim($match[2]);
321
+    $fonc = trim($match[1]);
322
+    if ($fonc && $fonc[0] == '|') {
323
+        $fonc = ltrim(substr($fonc, 1));
324
+    }
325
+    $res = [$fonc];
326
+    $err_f = '';
327
+    // cas du filtre sans argument ou du critere /
328
+    if (($suite && ($suite[0] != '{')) || ($fonc && $fonc[0] == '/')) {
329
+        // si pas d'argument, alors il faut une fonction ou un double |
330
+        if (!$match[1]) {
331
+            $err_f = ['zbug_erreur_filtre', ['filtre' => $texte]];
332
+            erreur_squelette($err_f, $pointeur_champ);
333
+            $texte = '';
334
+        } else {
335
+            $texte = $suite;
336
+        }
337
+        if ($err_f) {
338
+            $pointeur_champ->param = false;
339
+        } elseif ($fonc !== '') {
340
+            $pointeur_champ->param[] = $res;
341
+        }
342
+        // pour les balises avec faux filtres qui boudent ce dur larbeur
343
+        $pointeur_champ->fonctions[] = [$fonc, ''];
344
+
345
+        return $result;
346
+    }
347
+    $args = ltrim(substr($suite, 1)); // virer le '(' initial
348
+    $collecte = [];
349
+    while ($args && $args[0] != '}') {
350
+        if ($args[0] == '"') {
351
+            preg_match('/^(")([^"]*)(")(.*)$/ms', $args, $regs);
352
+        } elseif ($args[0] == "'") {
353
+            preg_match("/^(')([^']*)(')(.*)$/ms", $args, $regs);
354
+        } else {
355
+            preg_match('/^([[:space:]]*)([^,([{}]*([(\[{][^])}]*[])}])?[^,}]*)([,}].*)$/ms', $args, $regs);
356
+            if (!isset($regs[2]) or !strlen($regs[2])) {
357
+                $err_f = ['zbug_erreur_filtre', ['filtre' => $args]];
358
+                erreur_squelette($err_f, $pointeur_champ);
359
+                $champ = new Texte();
360
+                $champ->apres = $champ->avant = $args = '';
361
+                break;
362
+            }
363
+        }
364
+        $arg = $regs[2];
365
+        if (trim($regs[1])) {
366
+            $champ = new Texte();
367
+            $champ->texte = $arg;
368
+            $champ->apres = $champ->avant = $regs[1];
369
+            $result[] = $champ;
370
+            $collecte[] = $champ;
371
+            $args = ltrim($regs[count($regs) - 1]);
372
+        } else {
373
+            if (!preg_match('/' . NOM_DE_CHAMP . '([{|])/', $arg, $r)) {
374
+                // 0 est un aveu d'impuissance. A completer
375
+                $arg = phraser_champs_exterieurs($arg, 0, $sep, $result);
376
+
377
+                $args = ltrim($regs[count($regs) - 1]);
378
+                $collecte = array_merge($collecte, $arg);
379
+                $result = array_merge($result, $arg);
380
+            } else {
381
+                $n = strpos($args, (string) $r[0]);
382
+                $pred = substr($args, 0, $n);
383
+                $par = ',}';
384
+                if (preg_match('/^(.*)\($/', $pred, $m)) {
385
+                    $pred = $m[1];
386
+                    $par = ')';
387
+                }
388
+                if ($pred) {
389
+                    $champ = new Texte();
390
+                    $champ->texte = $pred;
391
+                    $champ->apres = $champ->avant = '';
392
+                    $result[] = $champ;
393
+                    $collecte[] = $champ;
394
+                }
395
+                $rec = substr($args, $n + strlen($r[0]) - 1);
396
+                $champ = new Champ();
397
+                $champ->nom_boucle = $r[2];
398
+                $champ->nom_champ = $r[3];
399
+                $champ->etoile = $r[5];
400
+                $next = $r[6];
401
+                while ($next == '{') {
402
+                    phraser_arg($rec, $sep, [], $champ);
403
+                    $args = ltrim($rec);
404
+                    $next = $args[0] ?? '';
405
+                }
406
+                while ($next == '|') {
407
+                    $pos_apres = 0;
408
+                    phraser_args($rec, $par, $sep, [], $champ, $pos_apres);
409
+                    $args = substr($rec, $pos_apres);
410
+                    $next = $args[0] ?? '';
411
+                }
412
+                // Si erreur de syntaxe dans un sous-argument, propager.
413
+                if ($champ->param === false) {
414
+                    $err_f = true;
415
+                } else {
416
+                    phraser_vieux($champ);
417
+                }
418
+                if ($par == ')') {
419
+                    $args = substr($args, 1);
420
+                }
421
+                $collecte[] = $champ;
422
+                $result[] = $champ;
423
+            }
424
+        }
425
+        if (isset($args[0]) and $args[0] == ',') {
426
+            $args = ltrim(substr($args, 1));
427
+            if ($collecte) {
428
+                $res[] = $collecte;
429
+                $collecte = [];
430
+            }
431
+        }
432
+    }
433
+    if ($collecte) {
434
+        $res[] = $collecte;
435
+        $collecte = [];
436
+    }
437
+    $texte = substr($args, 1);
438
+    $source = substr($suite, 0, strlen($suite) - strlen($texte));
439
+    // propager les erreurs, et ignorer les param vides
440
+    if ($pointeur_champ->param !== false) {
441
+        if ($err_f) {
442
+            $pointeur_champ->param = false;
443
+        } elseif ($fonc !== '' || count($res) > 1) {
444
+            $pointeur_champ->param[] = $res;
445
+        }
446
+    }
447
+    // pour les balises avec faux filtres qui boudent ce dur larbeur
448
+    $pointeur_champ->fonctions[] = [$fonc, $source];
449
+
450
+    return $result;
451 451
 }
452 452
 
453 453
 
454 454
 function phraser_champs_exterieurs($texte, $ligne, $sep, $nested) {
455
-	$res = [];
456
-	while (($p = strpos($texte, (string) "%$sep")) !== false) {
457
-		if (!preg_match(',^%' . preg_quote($sep) . '([0-9]+)@,', substr($texte, $p), $m)) {
458
-			break;
459
-		}
460
-		$debut = substr($texte, 0, $p);
461
-		$texte = substr($texte, $p + strlen($m[0]));
462
-		if ($p) {
463
-			$res = phraser_inclure($debut, $ligne, $res);
464
-		}
465
-		$ligne += substr_count($debut, "\n");
466
-		$res[] = $nested[$m[1]];
467
-	}
468
-
469
-	return (($texte === '') ? $res : phraser_inclure($texte, $ligne, $res));
455
+    $res = [];
456
+    while (($p = strpos($texte, (string) "%$sep")) !== false) {
457
+        if (!preg_match(',^%' . preg_quote($sep) . '([0-9]+)@,', substr($texte, $p), $m)) {
458
+            break;
459
+        }
460
+        $debut = substr($texte, 0, $p);
461
+        $texte = substr($texte, $p + strlen($m[0]));
462
+        if ($p) {
463
+            $res = phraser_inclure($debut, $ligne, $res);
464
+        }
465
+        $ligne += substr_count($debut, "\n");
466
+        $res[] = $nested[$m[1]];
467
+    }
468
+
469
+    return (($texte === '') ? $res : phraser_inclure($texte, $ligne, $res));
470 470
 }
471 471
 
472 472
 function phraser_champs_interieurs($texte, $ligne, $sep, $result) {
473
-	$i = 0; // en fait count($result)
474
-	$x = '';
475
-
476
-	while (true) {
477
-		$j = $i;
478
-		$n = $ligne;
479
-		while (preg_match(CHAMP_ETENDU, $texte, $match)) {
480
-			$p = strpos($texte, (string) $match[0]);
481
-			$debut = substr($texte, 0, $p);
482
-			if ($p) {
483
-				$result[$i] = $debut;
484
-				$i++;
485
-			}
486
-			$nom = $match[4];
487
-			$champ = new Champ();
488
-			// ca ne marche pas encore en cas de champ imbrique
489
-			$champ->ligne = $x ? 0 : ($n + substr_count($debut, "\n"));
490
-			$champ->nom_boucle = $match[3];
491
-			$champ->nom_champ = $nom;
492
-			$champ->etoile = $match[6];
493
-			// phraser_args indiquera ou commence apres
494
-			$pos_apres = 0;
495
-			$result = phraser_args($match[7], ')', $sep, $result, $champ, $pos_apres);
496
-			phraser_vieux($champ);
497
-			$champ->avant =	phraser_champs_exterieurs($match[1], $n, $sep, $result);
498
-			$debut = substr($match[7], $pos_apres + 1);
499
-			if (!empty($debut)) {
500
-				$n += substr_count(substr($texte, 0, strpos($texte, $debut)), "\n");
501
-			}
502
-			$champ->apres = phraser_champs_exterieurs($debut, $n, $sep, $result);
503
-
504
-			// reinjecter la boucle si c'en est une
505
-			phraser_boucle_placeholder($champ);
506
-
507
-			$result[$i] = $champ;
508
-			$i++;
509
-			$texte = substr($texte, $p + strlen($match[0]));
510
-		}
511
-		if ($texte !== '') {
512
-			$result[$i] = $texte;
513
-			$i++;
514
-		}
515
-		$x = '';
516
-
517
-		while ($j < $i) {
518
-			$z = $result[$j];
519
-			// j'aurais besoin de connaitre le nombre de lignes...
520
-			if (is_object($z)) {
521
-				$x .= "%$sep$j@";
522
-			} else {
523
-				$x .= $z;
524
-			}
525
-			$j++;
526
-		}
527
-		if (preg_match(CHAMP_ETENDU, $x)) {
528
-			$texte = $x;
529
-		} else {
530
-			return phraser_champs_exterieurs($x, $ligne, $sep, $result);
531
-		}
532
-	}
473
+    $i = 0; // en fait count($result)
474
+    $x = '';
475
+
476
+    while (true) {
477
+        $j = $i;
478
+        $n = $ligne;
479
+        while (preg_match(CHAMP_ETENDU, $texte, $match)) {
480
+            $p = strpos($texte, (string) $match[0]);
481
+            $debut = substr($texte, 0, $p);
482
+            if ($p) {
483
+                $result[$i] = $debut;
484
+                $i++;
485
+            }
486
+            $nom = $match[4];
487
+            $champ = new Champ();
488
+            // ca ne marche pas encore en cas de champ imbrique
489
+            $champ->ligne = $x ? 0 : ($n + substr_count($debut, "\n"));
490
+            $champ->nom_boucle = $match[3];
491
+            $champ->nom_champ = $nom;
492
+            $champ->etoile = $match[6];
493
+            // phraser_args indiquera ou commence apres
494
+            $pos_apres = 0;
495
+            $result = phraser_args($match[7], ')', $sep, $result, $champ, $pos_apres);
496
+            phraser_vieux($champ);
497
+            $champ->avant =	phraser_champs_exterieurs($match[1], $n, $sep, $result);
498
+            $debut = substr($match[7], $pos_apres + 1);
499
+            if (!empty($debut)) {
500
+                $n += substr_count(substr($texte, 0, strpos($texte, $debut)), "\n");
501
+            }
502
+            $champ->apres = phraser_champs_exterieurs($debut, $n, $sep, $result);
503
+
504
+            // reinjecter la boucle si c'en est une
505
+            phraser_boucle_placeholder($champ);
506
+
507
+            $result[$i] = $champ;
508
+            $i++;
509
+            $texte = substr($texte, $p + strlen($match[0]));
510
+        }
511
+        if ($texte !== '') {
512
+            $result[$i] = $texte;
513
+            $i++;
514
+        }
515
+        $x = '';
516
+
517
+        while ($j < $i) {
518
+            $z = $result[$j];
519
+            // j'aurais besoin de connaitre le nombre de lignes...
520
+            if (is_object($z)) {
521
+                $x .= "%$sep$j@";
522
+            } else {
523
+                $x .= $z;
524
+            }
525
+            $j++;
526
+        }
527
+        if (preg_match(CHAMP_ETENDU, $x)) {
528
+            $texte = $x;
529
+        } else {
530
+            return phraser_champs_exterieurs($x, $ligne, $sep, $result);
531
+        }
532
+    }
533 533
 }
534 534
 
535 535
 function phraser_vieux(&$champ) {
536
-	$nom = $champ->nom_champ;
537
-	if ($nom == 'EMBED_DOCUMENT') {
538
-		if (!function_exists('phraser_vieux_emb')) {
539
-			include_spip('public/normaliser');
540
-		}
541
-		phraser_vieux_emb($champ);
542
-	} elseif ($nom == 'EXPOSER') {
543
-		if (!function_exists('phraser_vieux_exposer')) {
544
-			include_spip('public/normaliser');
545
-		}
546
-		phraser_vieux_exposer($champ);
547
-	} elseif ($champ->param) {
548
-		if ($nom == 'FORMULAIRE_RECHERCHE') {
549
-			if (!function_exists('phraser_vieux_recherche')) {
550
-				include_spip('public/normaliser');
551
-			}
552
-			phraser_vieux_recherche($champ);
553
-		} elseif (preg_match(',^LOGO_[A-Z]+,', $nom)) {
554
-			if (!function_exists('phraser_vieux_logos')) {
555
-				include_spip('public/normaliser');
556
-			}
557
-			phraser_vieux_logos($champ);
558
-		} elseif ($nom == 'MODELE') {
559
-			if (!function_exists('phraser_vieux_modele')) {
560
-				include_spip('public/normaliser');
561
-			}
562
-			phraser_vieux_modele($champ);
563
-		} elseif ($nom == 'INCLURE' or $nom == 'INCLUDE') {
564
-			if (!function_exists('phraser_vieux_inclu')) {
565
-				include_spip('public/normaliser');
566
-			}
567
-			phraser_vieux_inclu($champ);
568
-		}
569
-	}
536
+    $nom = $champ->nom_champ;
537
+    if ($nom == 'EMBED_DOCUMENT') {
538
+        if (!function_exists('phraser_vieux_emb')) {
539
+            include_spip('public/normaliser');
540
+        }
541
+        phraser_vieux_emb($champ);
542
+    } elseif ($nom == 'EXPOSER') {
543
+        if (!function_exists('phraser_vieux_exposer')) {
544
+            include_spip('public/normaliser');
545
+        }
546
+        phraser_vieux_exposer($champ);
547
+    } elseif ($champ->param) {
548
+        if ($nom == 'FORMULAIRE_RECHERCHE') {
549
+            if (!function_exists('phraser_vieux_recherche')) {
550
+                include_spip('public/normaliser');
551
+            }
552
+            phraser_vieux_recherche($champ);
553
+        } elseif (preg_match(',^LOGO_[A-Z]+,', $nom)) {
554
+            if (!function_exists('phraser_vieux_logos')) {
555
+                include_spip('public/normaliser');
556
+            }
557
+            phraser_vieux_logos($champ);
558
+        } elseif ($nom == 'MODELE') {
559
+            if (!function_exists('phraser_vieux_modele')) {
560
+                include_spip('public/normaliser');
561
+            }
562
+            phraser_vieux_modele($champ);
563
+        } elseif ($nom == 'INCLURE' or $nom == 'INCLUDE') {
564
+            if (!function_exists('phraser_vieux_inclu')) {
565
+                include_spip('public/normaliser');
566
+            }
567
+            phraser_vieux_inclu($champ);
568
+        }
569
+    }
570 570
 }
571 571
 
572 572
 
@@ -594,200 +594,200 @@  discard block
 block discarded – undo
594 594
  **/
595 595
 function phraser_criteres($params, &$result) {
596 596
 
597
-	$err_ci = ''; // indiquera s'il y a eu une erreur
598
-	$args = [];
599
-	$type = $result->type_requete;
600
-	$doublons = [];
601
-	foreach ($params as $v) {
602
-		$var = $v[1][0];
603
-		$param = ($var->type != 'texte') ? '' : $var->texte;
604
-		if (((is_countable($v) ? count($v) : 0) > 2) && (!preg_match(',[^A-Za-z]IN[^A-Za-z],i', $param))) {
605
-			// plus d'un argument et pas le critere IN:
606
-			// detecter comme on peut si c'est le critere implicite LIMIT debut, fin
607
-			if (
608
-				$var->type != 'texte'
609
-				or preg_match('/^(n|n-|(n-)?\d+)$/S', $param)
610
-			) {
611
-				$op = ',';
612
-				$not = false;
613
-				$cond = false;
614
-			} else {
615
-				// Le debut du premier argument est l'operateur
616
-				preg_match('/^([!]?)([a-zA-Z][a-zA-Z0-9_]*)[[:space:]]*(\??)[[:space:]]*(.*)$/ms', $param, $m);
617
-				$op = $m[2];
618
-				$not = (bool) $m[1];
619
-				$cond = (bool) $m[3];
620
-				// virer le premier argument,
621
-				// et mettre son reliquat eventuel
622
-				// Recopier pour ne pas alterer le texte source
623
-				// utile au debusqueur
624
-				if ($m[4]) {
625
-					// une maniere tres sale de supprimer les "' autour de {critere "xxx","yyy"}
626
-					if (preg_match(',^(["\'])(.*)\1$,', $m[4])) {
627
-						$c = null;
628
-						eval('$c = ' . $m[4] . ';');
629
-						if (isset($c)) {
630
-							$m[4] = $c;
631
-						}
632
-					}
633
-					$texte = new Texte();
634
-					$texte->texte = $m[4];
635
-					$v[1][0] = $texte;
636
-				} else {
637
-					array_shift($v[1]);
638
-				}
639
-			}
640
-			array_shift($v); // $v[O] est vide
641
-			$crit = new Critere();
642
-			$crit->op = $op;
643
-			$crit->not = $not;
644
-			$crit->cond = $cond;
645
-			$crit->exclus = '';
646
-			$crit->param = $v;
647
-			$args[] = $crit;
648
-		} else {
649
-			if ($var->type != 'texte') {
650
-				// cas 1 seul arg ne commencant pas par du texte brut:
651
-				// erreur ou critere infixe "/"
652
-				if (($v[1][1]->type != 'texte') || (trim($v[1][1]->texte) != '/')) {
653
-					$err_ci = [
654
-						'zbug_critere_inconnu',
655
-						['critere' => $var->nom_champ]
656
-					];
657
-					erreur_squelette($err_ci, $result);
658
-				} else {
659
-					$crit = new Critere();
660
-					$crit->op = '/';
661
-					$crit->not = false;
662
-					$crit->exclus = '';
663
-					$crit->param = [[$v[1][0]], [$v[1][2]]];
664
-					$args[] = $crit;
665
-				}
666
-			} else {
667
-				// traiter qq lexemes particuliers pour faciliter la suite
668
-				// les separateurs
669
-				if ($var->apres) {
670
-					$result->separateur[] = $param;
671
-				} elseif (($param == 'tout') or ($param == 'tous')) {
672
-					$result->modificateur['tout'] = true;
673
-				} elseif ($param == 'plat') {
674
-					$result->modificateur['plat'] = true;
675
-				}
676
-
677
-				// Boucle hierarchie, analyser le critere id_rubrique
678
-				// et les autres critères {id_x} pour forcer {tout} sur
679
-				// ceux-ci pour avoir la rubrique mere...
680
-				// Les autres critères de la boucle hierarchie doivent être
681
-				// traités normalement.
682
-				elseif (
683
-					strcasecmp($type, 'hierarchie') == 0
684
-					and !preg_match(",^id_rubrique\b,", $param)
685
-					and preg_match(',^id_\w+\s*$,', $param)
686
-				) {
687
-					$result->modificateur['tout'] = true;
688
-				} elseif (strcasecmp($type, 'hierarchie') == 0 and $param == 'id_rubrique') {
689
-					// rien a faire sur {id_rubrique} tout seul
690
-				} else {
691
-					// pas d'emplacement statique, faut un dynamique
692
-					// mais il y a 2 cas qui ont les 2 !
693
-					if (($param == 'unique') || (preg_match(',^!?doublons *,', $param))) {
694
-						// cette variable sera inseree dans le code
695
-						// et son nom sert d'indicateur des maintenant
696
-						$result->doublons = '$doublons_index';
697
-						if ($param == 'unique') {
698
-							$param = 'doublons';
699
-						}
700
-					} elseif ($param == 'recherche') {
701
-						// meme chose (a cause de #nom_de_boucle:URL_*)
702
-						$result->hash = ' ';
703
-					}
704
-
705
-					if (preg_match(',^ *([0-9-]+) *(/) *(.+) *$,', $param, $m)) {
706
-						$crit = phraser_critere_infixe($m[1], $m[3], $v, '/', '', '');
707
-					} elseif (
708
-						preg_match(',^([!]?)(' . CHAMP_SQL_PLUS_FONC .
709
-						')[[:space:]]*(\??)(!?)(<=?|>=?|==?|\b(?:IN|LIKE)\b)(.*)$,is', $param, $m)
710
-					) {
711
-						$a2 = trim($m[8]);
712
-						if ($a2 and ($a2[0] == "'" or $a2[0] == '"') and ($a2[0] == substr($a2, -1))) {
713
-							$a2 = substr($a2, 1, -1);
714
-						}
715
-						$crit = phraser_critere_infixe(
716
-							$m[2],
717
-							$a2,
718
-							$v,
719
-							(($m[2] == 'lang_select') ? $m[2] : $m[7]),
720
-							$m[6],
721
-							$m[5]
722
-						);
723
-						$crit->exclus = $m[1];
724
-					} elseif (
725
-						preg_match('/^([!]?)\s*(' .
726
-						CHAMP_SQL_PLUS_FONC .
727
-						')\s*(\??)(.*)$/is', $param, $m)
728
-					) {
729
-						// contient aussi les comparaisons implicites !
730
-						// Comme ci-dessus:
731
-						// le premier arg contient l'operateur
732
-						array_shift($v);
733
-						if ($m[6]) {
734
-							$v[0][0] = new Texte();
735
-							$v[0][0]->texte = $m[6];
736
-						} else {
737
-							array_shift($v[0]);
738
-							if (!$v[0]) {
739
-								array_shift($v);
740
-							}
741
-						}
742
-						$crit = new Critere();
743
-						$crit->op = $m[2];
744
-						$crit->param = $v;
745
-						$crit->not = (bool) $m[1];
746
-						$crit->cond = (bool) $m[5];
747
-					} else {
748
-						$err_ci = [
749
-							'zbug_critere_inconnu',
750
-							['critere' => $param]
751
-						];
752
-						erreur_squelette($err_ci, $result);
753
-					}
754
-
755
-					if ((!preg_match(',^!?doublons *,', $param)) || $crit->not) {
756
-						$args[] = $crit;
757
-					} else {
758
-						$doublons[] = $crit;
759
-					}
760
-				}
761
-			}
762
-		}
763
-	}
764
-
765
-	// les doublons non nies doivent etre le dernier critere
766
-	// pour que la variable $doublon_index ait la bonne valeur
767
-	// cf critere_doublon
768
-	if ($doublons) {
769
-		$args = [...$args, ...$doublons];
770
-	}
771
-
772
-	// Si erreur, laisser la chaine dans ce champ pour le HTTP 503
773
-	if (!$err_ci) {
774
-		$result->criteres = $args;
775
-	}
597
+    $err_ci = ''; // indiquera s'il y a eu une erreur
598
+    $args = [];
599
+    $type = $result->type_requete;
600
+    $doublons = [];
601
+    foreach ($params as $v) {
602
+        $var = $v[1][0];
603
+        $param = ($var->type != 'texte') ? '' : $var->texte;
604
+        if (((is_countable($v) ? count($v) : 0) > 2) && (!preg_match(',[^A-Za-z]IN[^A-Za-z],i', $param))) {
605
+            // plus d'un argument et pas le critere IN:
606
+            // detecter comme on peut si c'est le critere implicite LIMIT debut, fin
607
+            if (
608
+                $var->type != 'texte'
609
+                or preg_match('/^(n|n-|(n-)?\d+)$/S', $param)
610
+            ) {
611
+                $op = ',';
612
+                $not = false;
613
+                $cond = false;
614
+            } else {
615
+                // Le debut du premier argument est l'operateur
616
+                preg_match('/^([!]?)([a-zA-Z][a-zA-Z0-9_]*)[[:space:]]*(\??)[[:space:]]*(.*)$/ms', $param, $m);
617
+                $op = $m[2];
618
+                $not = (bool) $m[1];
619
+                $cond = (bool) $m[3];
620
+                // virer le premier argument,
621
+                // et mettre son reliquat eventuel
622
+                // Recopier pour ne pas alterer le texte source
623
+                // utile au debusqueur
624
+                if ($m[4]) {
625
+                    // une maniere tres sale de supprimer les "' autour de {critere "xxx","yyy"}
626
+                    if (preg_match(',^(["\'])(.*)\1$,', $m[4])) {
627
+                        $c = null;
628
+                        eval('$c = ' . $m[4] . ';');
629
+                        if (isset($c)) {
630
+                            $m[4] = $c;
631
+                        }
632
+                    }
633
+                    $texte = new Texte();
634
+                    $texte->texte = $m[4];
635
+                    $v[1][0] = $texte;
636
+                } else {
637
+                    array_shift($v[1]);
638
+                }
639
+            }
640
+            array_shift($v); // $v[O] est vide
641
+            $crit = new Critere();
642
+            $crit->op = $op;
643
+            $crit->not = $not;
644
+            $crit->cond = $cond;
645
+            $crit->exclus = '';
646
+            $crit->param = $v;
647
+            $args[] = $crit;
648
+        } else {
649
+            if ($var->type != 'texte') {
650
+                // cas 1 seul arg ne commencant pas par du texte brut:
651
+                // erreur ou critere infixe "/"
652
+                if (($v[1][1]->type != 'texte') || (trim($v[1][1]->texte) != '/')) {
653
+                    $err_ci = [
654
+                        'zbug_critere_inconnu',
655
+                        ['critere' => $var->nom_champ]
656
+                    ];
657
+                    erreur_squelette($err_ci, $result);
658
+                } else {
659
+                    $crit = new Critere();
660
+                    $crit->op = '/';
661
+                    $crit->not = false;
662
+                    $crit->exclus = '';
663
+                    $crit->param = [[$v[1][0]], [$v[1][2]]];
664
+                    $args[] = $crit;
665
+                }
666
+            } else {
667
+                // traiter qq lexemes particuliers pour faciliter la suite
668
+                // les separateurs
669
+                if ($var->apres) {
670
+                    $result->separateur[] = $param;
671
+                } elseif (($param == 'tout') or ($param == 'tous')) {
672
+                    $result->modificateur['tout'] = true;
673
+                } elseif ($param == 'plat') {
674
+                    $result->modificateur['plat'] = true;
675
+                }
676
+
677
+                // Boucle hierarchie, analyser le critere id_rubrique
678
+                // et les autres critères {id_x} pour forcer {tout} sur
679
+                // ceux-ci pour avoir la rubrique mere...
680
+                // Les autres critères de la boucle hierarchie doivent être
681
+                // traités normalement.
682
+                elseif (
683
+                    strcasecmp($type, 'hierarchie') == 0
684
+                    and !preg_match(",^id_rubrique\b,", $param)
685
+                    and preg_match(',^id_\w+\s*$,', $param)
686
+                ) {
687
+                    $result->modificateur['tout'] = true;
688
+                } elseif (strcasecmp($type, 'hierarchie') == 0 and $param == 'id_rubrique') {
689
+                    // rien a faire sur {id_rubrique} tout seul
690
+                } else {
691
+                    // pas d'emplacement statique, faut un dynamique
692
+                    // mais il y a 2 cas qui ont les 2 !
693
+                    if (($param == 'unique') || (preg_match(',^!?doublons *,', $param))) {
694
+                        // cette variable sera inseree dans le code
695
+                        // et son nom sert d'indicateur des maintenant
696
+                        $result->doublons = '$doublons_index';
697
+                        if ($param == 'unique') {
698
+                            $param = 'doublons';
699
+                        }
700
+                    } elseif ($param == 'recherche') {
701
+                        // meme chose (a cause de #nom_de_boucle:URL_*)
702
+                        $result->hash = ' ';
703
+                    }
704
+
705
+                    if (preg_match(',^ *([0-9-]+) *(/) *(.+) *$,', $param, $m)) {
706
+                        $crit = phraser_critere_infixe($m[1], $m[3], $v, '/', '', '');
707
+                    } elseif (
708
+                        preg_match(',^([!]?)(' . CHAMP_SQL_PLUS_FONC .
709
+                        ')[[:space:]]*(\??)(!?)(<=?|>=?|==?|\b(?:IN|LIKE)\b)(.*)$,is', $param, $m)
710
+                    ) {
711
+                        $a2 = trim($m[8]);
712
+                        if ($a2 and ($a2[0] == "'" or $a2[0] == '"') and ($a2[0] == substr($a2, -1))) {
713
+                            $a2 = substr($a2, 1, -1);
714
+                        }
715
+                        $crit = phraser_critere_infixe(
716
+                            $m[2],
717
+                            $a2,
718
+                            $v,
719
+                            (($m[2] == 'lang_select') ? $m[2] : $m[7]),
720
+                            $m[6],
721
+                            $m[5]
722
+                        );
723
+                        $crit->exclus = $m[1];
724
+                    } elseif (
725
+                        preg_match('/^([!]?)\s*(' .
726
+                        CHAMP_SQL_PLUS_FONC .
727
+                        ')\s*(\??)(.*)$/is', $param, $m)
728
+                    ) {
729
+                        // contient aussi les comparaisons implicites !
730
+                        // Comme ci-dessus:
731
+                        // le premier arg contient l'operateur
732
+                        array_shift($v);
733
+                        if ($m[6]) {
734
+                            $v[0][0] = new Texte();
735
+                            $v[0][0]->texte = $m[6];
736
+                        } else {
737
+                            array_shift($v[0]);
738
+                            if (!$v[0]) {
739
+                                array_shift($v);
740
+                            }
741
+                        }
742
+                        $crit = new Critere();
743
+                        $crit->op = $m[2];
744
+                        $crit->param = $v;
745
+                        $crit->not = (bool) $m[1];
746
+                        $crit->cond = (bool) $m[5];
747
+                    } else {
748
+                        $err_ci = [
749
+                            'zbug_critere_inconnu',
750
+                            ['critere' => $param]
751
+                        ];
752
+                        erreur_squelette($err_ci, $result);
753
+                    }
754
+
755
+                    if ((!preg_match(',^!?doublons *,', $param)) || $crit->not) {
756
+                        $args[] = $crit;
757
+                    } else {
758
+                        $doublons[] = $crit;
759
+                    }
760
+                }
761
+            }
762
+        }
763
+    }
764
+
765
+    // les doublons non nies doivent etre le dernier critere
766
+    // pour que la variable $doublon_index ait la bonne valeur
767
+    // cf critere_doublon
768
+    if ($doublons) {
769
+        $args = [...$args, ...$doublons];
770
+    }
771
+
772
+    // Si erreur, laisser la chaine dans ce champ pour le HTTP 503
773
+    if (!$err_ci) {
774
+        $result->criteres = $args;
775
+    }
776 776
 }
777 777
 
778 778
 function phraser_critere_infixe($arg1, $arg2, $args, $op, $not, $cond) {
779
-	$args[0] = new Texte();
780
-	$args[0]->texte = $arg1;
781
-	$args[0] = [$args[0]];
782
-	$args[1][0] = new Texte();
783
-	$args[1][0]->texte = $arg2;
784
-	$crit = new Critere();
785
-	$crit->op = $op;
786
-	$crit->not = $not;
787
-	$crit->cond = $cond;
788
-	$crit->param = $args;
789
-
790
-	return $crit;
779
+    $args[0] = new Texte();
780
+    $args[0]->texte = $arg1;
781
+    $args[0] = [$args[0]];
782
+    $args[1][0] = new Texte();
783
+    $args[1][0]->texte = $arg2;
784
+    $crit = new Critere();
785
+    $crit->op = $op;
786
+    $crit->not = $not;
787
+    $crit->cond = $cond;
788
+    $crit->param = $args;
789
+
790
+    return $crit;
791 791
 }
792 792
 
793 793
 /**
@@ -798,12 +798,12 @@  discard block
 block discarded – undo
798 798
  * @return int
799 799
  */
800 800
 function public_compte_ligne($texte, $debut = 0, $fin = null) {
801
-	if (is_null($fin)) {
802
-		return substr_count($texte, "\n", $debut);
803
-	}
804
-	else {
805
-		return substr_count($texte, "\n", $debut, $fin - $debut);
806
-	}
801
+    if (is_null($fin)) {
802
+        return substr_count($texte, "\n", $debut);
803
+    }
804
+    else {
805
+        return substr_count($texte, "\n", $debut, $fin - $debut);
806
+    }
807 807
 }
808 808
 
809 809
 
@@ -819,87 +819,87 @@  discard block
 block discarded – undo
819 819
  * @return array|null
820 820
  */
821 821
 function public_trouver_premiere_boucle($texte, $id_parent, $descr, $pos_debut_texte = 0) {
822
-	$premiere_boucle = null;
823
-	$pos_derniere_boucle_anonyme = $pos_debut_texte;
824
-
825
-	$current_pos = $pos_debut_texte;
826
-	while (($pos_boucle = strpos($texte, BALISE_BOUCLE, $current_pos)) !== false) {
827
-		$current_pos = $pos_boucle + 1;
828
-		$pos_parent = strpos($texte, '(', $pos_boucle);
829
-
830
-		$id_boucle = '';
831
-		if ($pos_parent !== false) {
832
-			$id_boucle = trim(substr($texte, $pos_boucle + strlen(BALISE_BOUCLE), $pos_parent - $pos_boucle - strlen(BALISE_BOUCLE)));
833
-		}
834
-		if (
835
-			$pos_parent === false
836
-			or (strlen($id_boucle) and !(is_numeric($id_boucle) or strpos($id_boucle, '_') === 0))
837
-		) {
838
-			$result = new Boucle();
839
-			$result->id_parent = $id_parent;
840
-			$result->descr = $descr;
841
-
842
-			// un id_boucle pour l'affichage de l'erreur
843
-			if (!strlen($id_boucle)) {
844
-				$id_boucle = substr($texte, $pos_boucle + strlen(BALISE_BOUCLE), 15);
845
-			}
846
-			$result->id_boucle = $id_boucle;
847
-			$err_b = ['zbug_erreur_boucle_syntaxe', ['id' => $id_boucle]];
848
-			erreur_squelette($err_b, $result);
849
-
850
-			continue;
851
-		}
852
-		else {
853
-			$boucle = [
854
-				'id_boucle' => $id_boucle,
855
-				'id_boucle_err' => $id_boucle,
856
-				'debut_boucle' => $pos_boucle,
857
-				'pos_boucle' => $pos_boucle,
858
-				'pos_parent' => $pos_parent,
859
-				'pos_precond' => false,
860
-				'pos_precond_inside' => false,
861
-				'pos_preaff' => false,
862
-				'pos_preaff_inside' => false,
863
-			];
864
-
865
-			// un id_boucle pour l'affichage de l'erreur sur les boucle anonymes
866
-			if (!strlen($id_boucle)) {
867
-				$boucle['id_boucle_err'] = substr($texte, $pos_boucle + strlen(BALISE_BOUCLE), 15);
868
-			}
869
-
870
-			// trouver sa position de depart reelle : au <Bxx> ou au <BBxx>
871
-			$precond_boucle = BALISE_PRECOND_BOUCLE . $id_boucle . '>';
872
-			$pos_precond = strpos($texte, $precond_boucle, $id_boucle ? $pos_debut_texte : $pos_derniere_boucle_anonyme);
873
-			if (
874
-				$pos_precond !== false
875
-				and $pos_precond < $boucle['debut_boucle']
876
-			) {
877
-				$boucle['debut_boucle'] = $pos_precond;
878
-				$boucle['pos_precond'] = $pos_precond;
879
-				$boucle['pos_precond_inside'] = $pos_precond + strlen($precond_boucle);
880
-			}
881
-
882
-			$preaff_boucle = BALISE_PREAFF_BOUCLE . $id_boucle . '>';
883
-			$pos_preaff = strpos($texte, $preaff_boucle, $id_boucle ? $pos_debut_texte : $pos_derniere_boucle_anonyme);
884
-			if (
885
-				$pos_preaff !== false
886
-				and $pos_preaff < $boucle['debut_boucle']
887
-			) {
888
-				$boucle['debut_boucle'] = $pos_preaff;
889
-				$boucle['pos_preaff'] = $pos_preaff;
890
-				$boucle['pos_preaff_inside'] = $pos_preaff + strlen($preaff_boucle);
891
-			}
892
-			if (!strlen($id_boucle)) {
893
-				$pos_derniere_boucle_anonyme = $pos_boucle;
894
-			}
895
-
896
-			if (is_null($premiere_boucle) or $premiere_boucle['debut_boucle'] > $boucle['debut_boucle']) {
897
-				$premiere_boucle = $boucle;
898
-			}
899
-		}
900
-	}
901
-
902
-	return $premiere_boucle;
822
+    $premiere_boucle = null;
823
+    $pos_derniere_boucle_anonyme = $pos_debut_texte;
824
+
825
+    $current_pos = $pos_debut_texte;
826
+    while (($pos_boucle = strpos($texte, BALISE_BOUCLE, $current_pos)) !== false) {
827
+        $current_pos = $pos_boucle + 1;
828
+        $pos_parent = strpos($texte, '(', $pos_boucle);
829
+
830
+        $id_boucle = '';
831
+        if ($pos_parent !== false) {
832
+            $id_boucle = trim(substr($texte, $pos_boucle + strlen(BALISE_BOUCLE), $pos_parent - $pos_boucle - strlen(BALISE_BOUCLE)));
833
+        }
834
+        if (
835
+            $pos_parent === false
836
+            or (strlen($id_boucle) and !(is_numeric($id_boucle) or strpos($id_boucle, '_') === 0))
837
+        ) {
838
+            $result = new Boucle();
839
+            $result->id_parent = $id_parent;
840
+            $result->descr = $descr;
841
+
842
+            // un id_boucle pour l'affichage de l'erreur
843
+            if (!strlen($id_boucle)) {
844
+                $id_boucle = substr($texte, $pos_boucle + strlen(BALISE_BOUCLE), 15);
845
+            }
846
+            $result->id_boucle = $id_boucle;
847
+            $err_b = ['zbug_erreur_boucle_syntaxe', ['id' => $id_boucle]];
848
+            erreur_squelette($err_b, $result);
849
+
850
+            continue;
851
+        }
852
+        else {
853
+            $boucle = [
854
+                'id_boucle' => $id_boucle,
855
+                'id_boucle_err' => $id_boucle,
856
+                'debut_boucle' => $pos_boucle,
857
+                'pos_boucle' => $pos_boucle,
858
+                'pos_parent' => $pos_parent,
859
+                'pos_precond' => false,
860
+                'pos_precond_inside' => false,
861
+                'pos_preaff' => false,
862
+                'pos_preaff_inside' => false,
863
+            ];
864
+
865
+            // un id_boucle pour l'affichage de l'erreur sur les boucle anonymes
866
+            if (!strlen($id_boucle)) {
867
+                $boucle['id_boucle_err'] = substr($texte, $pos_boucle + strlen(BALISE_BOUCLE), 15);
868
+            }
869
+
870
+            // trouver sa position de depart reelle : au <Bxx> ou au <BBxx>
871
+            $precond_boucle = BALISE_PRECOND_BOUCLE . $id_boucle . '>';
872
+            $pos_precond = strpos($texte, $precond_boucle, $id_boucle ? $pos_debut_texte : $pos_derniere_boucle_anonyme);
873
+            if (
874
+                $pos_precond !== false
875
+                and $pos_precond < $boucle['debut_boucle']
876
+            ) {
877
+                $boucle['debut_boucle'] = $pos_precond;
878
+                $boucle['pos_precond'] = $pos_precond;
879
+                $boucle['pos_precond_inside'] = $pos_precond + strlen($precond_boucle);
880
+            }
881
+
882
+            $preaff_boucle = BALISE_PREAFF_BOUCLE . $id_boucle . '>';
883
+            $pos_preaff = strpos($texte, $preaff_boucle, $id_boucle ? $pos_debut_texte : $pos_derniere_boucle_anonyme);
884
+            if (
885
+                $pos_preaff !== false
886
+                and $pos_preaff < $boucle['debut_boucle']
887
+            ) {
888
+                $boucle['debut_boucle'] = $pos_preaff;
889
+                $boucle['pos_preaff'] = $pos_preaff;
890
+                $boucle['pos_preaff_inside'] = $pos_preaff + strlen($preaff_boucle);
891
+            }
892
+            if (!strlen($id_boucle)) {
893
+                $pos_derniere_boucle_anonyme = $pos_boucle;
894
+            }
895
+
896
+            if (is_null($premiere_boucle) or $premiere_boucle['debut_boucle'] > $boucle['debut_boucle']) {
897
+                $premiere_boucle = $boucle;
898
+            }
899
+        }
900
+    }
901
+
902
+    return $premiere_boucle;
903 903
 }
904 904
 
905 905
 /**
@@ -914,68 +914,68 @@  discard block
 block discarded – undo
914 914
  * @return mixed
915 915
  */
916 916
 function public_trouver_fin_boucle($texte, $id_parent, $boucle, $pos_debut_texte, $result) {
917
-	$id_boucle = $boucle['id_boucle'];
918
-	$pos_courante = $pos_debut_texte;
919
-
920
-	$boucle['pos_postcond'] = false;
921
-	$boucle['pos_postcond_inside'] = false;
922
-	$boucle['pos_altern'] = false;
923
-	$boucle['pos_altern_inside'] = false;
924
-	$boucle['pos_postaff'] = false;
925
-	$boucle['pos_postaff_inside'] = false;
926
-
927
-	$pos_anonyme_next = null;
928
-	// si c'est une boucle anonyme, chercher la position de la prochaine boucle anonyme
929
-	if (!strlen($id_boucle)) {
930
-		$pos_anonyme_next = strpos($texte, BALISE_BOUCLE . '(', $pos_courante);
931
-	}
932
-
933
-	//
934
-	// 1. Recuperer la partie conditionnelle apres
935
-	//
936
-	$apres_boucle = BALISE_POSTCOND_BOUCLE . $id_boucle . '>';
937
-	$pos_apres = strpos($texte, $apres_boucle, $pos_courante);
938
-	if (
939
-		$pos_apres !== false
940
-		and (!$pos_anonyme_next or $pos_apres < $pos_anonyme_next)
941
-	) {
942
-		$boucle['pos_postcond'] = $pos_apres;
943
-		$pos_apres += strlen($apres_boucle);
944
-		$boucle['pos_postcond_inside'] = $pos_apres;
945
-		$pos_courante = $pos_apres ;
946
-	}
947
-
948
-	//
949
-	// 2. Récuperer la partie alternative apres
950
-	//
951
-	$altern_boucle = BALISE_ALT_BOUCLE . $id_boucle . '>';
952
-	$pos_altern = strpos($texte, $altern_boucle, $pos_courante);
953
-	if (
954
-		$pos_altern !== false
955
-		and (!$pos_anonyme_next or $pos_altern < $pos_anonyme_next)
956
-	) {
957
-		$boucle['pos_altern'] = $pos_altern;
958
-		$pos_altern += strlen($altern_boucle);
959
-		$boucle['pos_altern_inside'] = $pos_altern;
960
-		$pos_courante = $pos_altern;
961
-	}
962
-
963
-	//
964
-	// 3. Recuperer la partie footer non alternative
965
-	//
966
-	$postaff_boucle = BALISE_POSTAFF_BOUCLE . $id_boucle . '>';
967
-	$pos_postaff = strpos($texte, $postaff_boucle, $pos_courante);
968
-	if (
969
-		$pos_postaff !== false
970
-		and (!$pos_anonyme_next or $pos_postaff < $pos_anonyme_next)
971
-	) {
972
-		$boucle['pos_postaff'] = $pos_postaff;
973
-		$pos_postaff += strlen($postaff_boucle);
974
-		$boucle['pos_postaff_inside'] = $pos_postaff;
975
-		$pos_courante = $pos_postaff ;
976
-	}
977
-
978
-	return $boucle;
917
+    $id_boucle = $boucle['id_boucle'];
918
+    $pos_courante = $pos_debut_texte;
919
+
920
+    $boucle['pos_postcond'] = false;
921
+    $boucle['pos_postcond_inside'] = false;
922
+    $boucle['pos_altern'] = false;
923
+    $boucle['pos_altern_inside'] = false;
924
+    $boucle['pos_postaff'] = false;
925
+    $boucle['pos_postaff_inside'] = false;
926
+
927
+    $pos_anonyme_next = null;
928
+    // si c'est une boucle anonyme, chercher la position de la prochaine boucle anonyme
929
+    if (!strlen($id_boucle)) {
930
+        $pos_anonyme_next = strpos($texte, BALISE_BOUCLE . '(', $pos_courante);
931
+    }
932
+
933
+    //
934
+    // 1. Recuperer la partie conditionnelle apres
935
+    //
936
+    $apres_boucle = BALISE_POSTCOND_BOUCLE . $id_boucle . '>';
937
+    $pos_apres = strpos($texte, $apres_boucle, $pos_courante);
938
+    if (
939
+        $pos_apres !== false
940
+        and (!$pos_anonyme_next or $pos_apres < $pos_anonyme_next)
941
+    ) {
942
+        $boucle['pos_postcond'] = $pos_apres;
943
+        $pos_apres += strlen($apres_boucle);
944
+        $boucle['pos_postcond_inside'] = $pos_apres;
945
+        $pos_courante = $pos_apres ;
946
+    }
947
+
948
+    //
949
+    // 2. Récuperer la partie alternative apres
950
+    //
951
+    $altern_boucle = BALISE_ALT_BOUCLE . $id_boucle . '>';
952
+    $pos_altern = strpos($texte, $altern_boucle, $pos_courante);
953
+    if (
954
+        $pos_altern !== false
955
+        and (!$pos_anonyme_next or $pos_altern < $pos_anonyme_next)
956
+    ) {
957
+        $boucle['pos_altern'] = $pos_altern;
958
+        $pos_altern += strlen($altern_boucle);
959
+        $boucle['pos_altern_inside'] = $pos_altern;
960
+        $pos_courante = $pos_altern;
961
+    }
962
+
963
+    //
964
+    // 3. Recuperer la partie footer non alternative
965
+    //
966
+    $postaff_boucle = BALISE_POSTAFF_BOUCLE . $id_boucle . '>';
967
+    $pos_postaff = strpos($texte, $postaff_boucle, $pos_courante);
968
+    if (
969
+        $pos_postaff !== false
970
+        and (!$pos_anonyme_next or $pos_postaff < $pos_anonyme_next)
971
+    ) {
972
+        $boucle['pos_postaff'] = $pos_postaff;
973
+        $pos_postaff += strlen($postaff_boucle);
974
+        $boucle['pos_postaff_inside'] = $pos_postaff;
975
+        $pos_courante = $pos_postaff ;
976
+    }
977
+
978
+    return $boucle;
979 979
 }
980 980
 
981 981
 
@@ -985,21 +985,21 @@  discard block
 block discarded – undo
985 985
  * @param null|object $boucle
986 986
  */
987 987
 function phraser_boucle_placeholder(&$champ, $boucle_placeholder = null, $boucle = null) {
988
-	static $boucles_connues = [];
989
-	// si c'est un appel pour memoriser une boucle, memorisons la
990
-	if (is_string($champ) and !empty($boucle_placeholder) and !empty($boucle)) {
991
-		$boucles_connues[$boucle_placeholder][$champ] = &$boucle;
992
-	}
993
-	else {
994
-		if (!empty($champ->nom_champ) and !empty($boucles_connues[$champ->nom_champ])) {
995
-			$placeholder = $champ->nom_champ;
996
-			$id = reset($champ->param[0][1]);
997
-			$id = $id->texte;
998
-			if (!empty($boucles_connues[$placeholder][$id])) {
999
-				$champ = $boucles_connues[$placeholder][$id];
1000
-			}
1001
-		}
1002
-	}
988
+    static $boucles_connues = [];
989
+    // si c'est un appel pour memoriser une boucle, memorisons la
990
+    if (is_string($champ) and !empty($boucle_placeholder) and !empty($boucle)) {
991
+        $boucles_connues[$boucle_placeholder][$champ] = &$boucle;
992
+    }
993
+    else {
994
+        if (!empty($champ->nom_champ) and !empty($boucles_connues[$champ->nom_champ])) {
995
+            $placeholder = $champ->nom_champ;
996
+            $id = reset($champ->param[0][1]);
997
+            $id = $id->texte;
998
+            if (!empty($boucles_connues[$placeholder][$id])) {
999
+                $champ = $boucles_connues[$placeholder][$id];
1000
+            }
1001
+        }
1002
+    }
1003 1003
 }
1004 1004
 
1005 1005
 
@@ -1012,274 +1012,274 @@  discard block
 block discarded – undo
1012 1012
  * @return string
1013 1013
  */
1014 1014
 function public_generer_boucle_placeholder($id_boucle, &$boucle, $boucle_placeholder, $nb_lignes) {
1015
-	$placeholder = "[(#{$boucle_placeholder}{" . $id_boucle . '})' . str_pad('', $nb_lignes, "\n") . ']';
1016
-	//memoriser la boucle a reinjecter
1017
-	$id_boucle = "$id_boucle";
1018
-	phraser_boucle_placeholder($id_boucle, $boucle_placeholder, $boucle);
1019
-	return $placeholder;
1015
+    $placeholder = "[(#{$boucle_placeholder}{" . $id_boucle . '})' . str_pad('', $nb_lignes, "\n") . ']';
1016
+    //memoriser la boucle a reinjecter
1017
+    $id_boucle = "$id_boucle";
1018
+    phraser_boucle_placeholder($id_boucle, $boucle_placeholder, $boucle);
1019
+    return $placeholder;
1020 1020
 }
1021 1021
 
1022 1022
 function public_phraser_html_dist($texte, $id_parent, &$boucles, $descr, $ligne_debut_texte = 1, $boucle_placeholder = null) {
1023 1023
 
1024
-	$all_res = [];
1025
-	// definir un placholder pour les boucles dont on est sur d'avoir aucune occurence dans le squelette
1026
-	if (is_null($boucle_placeholder)) {
1027
-		do {
1028
-			$boucle_placeholder = 'BOUCLE_PLACEHOLDER_' . strtoupper(md5(uniqid()));
1029
-		} while (strpos($texte, $boucle_placeholder) !== false);
1030
-	}
1031
-
1032
-	$ligne_debut_initial = $ligne_debut_texte;
1033
-	$pos_debut_texte = 0;
1034
-	while ($boucle = public_trouver_premiere_boucle($texte, $id_parent, $descr, $pos_debut_texte)) {
1035
-		$err_b = ''; // indiquera s'il y a eu une erreur
1036
-		$result = new Boucle();
1037
-		$result->id_parent = $id_parent;
1038
-		$result->descr = $descr;
1039
-
1040
-		$pos_courante = $boucle['pos_boucle'];
1041
-		$pos_parent = $boucle['pos_parent'];
1042
-		$id_boucle_search = $id_boucle = $boucle['id_boucle'];
1043
-
1044
-		$ligne_preaff = $ligne_avant = $ligne_milieu = $ligne_debut_texte + public_compte_ligne($texte, $pos_debut_texte, $pos_parent);
1045
-
1046
-		// boucle anonyme ?
1047
-		if (!strlen($id_boucle)) {
1048
-			$id_boucle = '_anon_L' . $ligne_milieu . '_' . substr(md5('anonyme:' . $id_parent . ':' . json_encode($boucle, JSON_THROW_ON_ERROR)), 0, 8);
1049
-		}
1050
-
1051
-		$pos_debut_boucle = $pos_courante;
1052
-
1053
-		$pos_milieu = $pos_parent;
1054
-
1055
-		// Regarder si on a une partie conditionnelle avant <B_xxx>
1056
-		if ($boucle['pos_precond'] !== false) {
1057
-			$pos_debut_boucle = $boucle['pos_precond'];
1058
-
1059
-			$pos_avant = $boucle['pos_precond_inside'];
1060
-			$result->avant = substr($texte, $pos_avant, $pos_courante - $pos_avant);
1061
-			$ligne_avant = $ligne_debut_texte +  public_compte_ligne($texte, $pos_debut_texte, $pos_avant);
1062
-		}
1063
-
1064
-		// Regarder si on a une partie inconditionnelle avant <BB_xxx>
1065
-		if ($boucle['pos_preaff'] !== false) {
1066
-			$end_preaff = $pos_debut_boucle;
1067
-
1068
-			$pos_preaff = $boucle['pos_preaff_inside'];
1069
-			$result->preaff = substr($texte, $pos_preaff, $end_preaff - $pos_preaff);
1070
-			$ligne_preaff = $ligne_debut_texte +  public_compte_ligne($texte, $pos_debut_texte, $pos_preaff);
1071
-		}
1072
-
1073
-		$result->id_boucle = $id_boucle;
1074
-
1075
-		if (
1076
-			!preg_match(SPEC_BOUCLE, $texte, $match, 0, $pos_milieu)
1077
-			or ($pos_match = strpos($texte, (string) $match[0], $pos_milieu)) === false
1078
-			or $pos_match > $pos_milieu
1079
-		) {
1080
-			$err_b = ['zbug_erreur_boucle_syntaxe', ['id' => $id_boucle]];
1081
-			erreur_squelette($err_b, $result);
1082
-
1083
-			$ligne_debut_texte += public_compte_ligne($texte, $pos_debut_texte, $pos_courante + 1);
1084
-			$pos_debut_texte = $pos_courante + 1;
1085
-			continue;
1086
-		}
1087
-
1088
-		$result->type_requete = $match[0];
1089
-		$pos_milieu += strlen($match[0]);
1090
-		$pos_courante = $pos_milieu; // on s'en sert pour compter les lignes plus precisemment
1091
-
1092
-		$type = $match[1];
1093
-		$jointures = trim($match[2]);
1094
-		$table_optionnelle = ($match[3]);
1095
-		if ($jointures) {
1096
-			// on affecte pas ici les jointures explicites, mais dans la compilation
1097
-			// ou elles seront completees des jointures declarees
1098
-			$result->jointures_explicites = $jointures;
1099
-		}
1100
-
1101
-		if ($table_optionnelle) {
1102
-			$result->table_optionnelle = $type;
1103
-		}
1104
-
1105
-		// 1ere passe sur les criteres, vu comme des arguments sans fct
1106
-		// Resultat mis dans result->param
1107
-		$pos_fin_criteres = $pos_milieu;
1108
-		phraser_args($texte, '/>', '', $all_res, $result, $pos_fin_criteres);
1109
-
1110
-		// En 2e passe result->criteres contiendra un tableau
1111
-		// pour l'instant on met le source (chaine) :
1112
-		// si elle reste ici au final, c'est qu'elle contient une erreur
1113
-		$pos_courante = $pos_fin_criteres; // on s'en sert pour compter les lignes plus precisemment
1114
-		$result->criteres = substr($texte, $pos_milieu, $pos_fin_criteres - $pos_milieu);
1115
-		$pos_milieu = $pos_fin_criteres;
1116
-
1117
-		//
1118
-		// Recuperer la fin :
1119
-		//
1120
-		if ($texte[$pos_milieu] === '/') {
1121
-			// boucle autofermante : pas de partie conditionnelle apres
1122
-			$pos_courante += 2;
1123
-			$result->milieu = '';
1124
-		} else {
1125
-			$pos_milieu += 1;
1126
-
1127
-			$fin_boucle = BALISE_FIN_BOUCLE . $id_boucle_search . '>';
1128
-			$pos_fin = strpos($texte, $fin_boucle, $pos_milieu);
1129
-			if ($pos_fin === false) {
1130
-				$err_b = [
1131
-					'zbug_erreur_boucle_fermant',
1132
-					['id' => $id_boucle]
1133
-				];
1134
-				erreur_squelette($err_b, $result);
1135
-				$pos_courante += strlen($fin_boucle);
1136
-			}
1137
-			else {
1138
-				// verifier une eventuelle imbrication d'une boucle homonyme
1139
-				// (interdite, generera une erreur plus loin, mais permet de signaler la bonne erreur)
1140
-				$search_debut_boucle = BALISE_BOUCLE . $id_boucle_search . '(';
1141
-				$search_from = $pos_milieu;
1142
-				$nb_open = 1;
1143
-				$nb_close = 1;
1144
-				$maxiter = 0;
1145
-				do {
1146
-					while (
1147
-						$nb_close < $nb_open
1148
-						and $p = strpos($texte, $fin_boucle, $pos_fin + 1)
1149
-					) {
1150
-						$nb_close++;
1151
-						$pos_fin = $p;
1152
-					}
1153
-					// si on a pas trouve assez de boucles fermantes, sortir de la, on a fait de notre mieux
1154
-					if ($nb_close < $nb_open) {
1155
-						break;
1156
-					}
1157
-					while (
1158
-						$p = strpos($texte, $search_debut_boucle, $search_from)
1159
-						and $p < $pos_fin
1160
-					) {
1161
-						$nb_open++;
1162
-						$search_from = $p + 1;
1163
-					}
1164
-				} while ($nb_close < $nb_open and $maxiter++ < 5);
1165
-
1166
-				$pos_courante = $pos_fin + strlen($fin_boucle);
1167
-			}
1168
-			$result->milieu = substr($texte, $pos_milieu, $pos_fin - $pos_milieu);
1169
-		}
1170
-
1171
-		$ligne_suite = $ligne_apres = $ligne_debut_texte + public_compte_ligne($texte, $pos_debut_texte, $pos_courante);
1172
-		$boucle = public_trouver_fin_boucle($texte, $id_parent, $boucle, $pos_courante, $result);
1173
-
1174
-		//
1175
-		// 1. Partie conditionnelle apres ?
1176
-		//
1177
-		if ($boucle['pos_postcond']) {
1178
-			$result->apres = substr($texte, $pos_courante, $boucle['pos_postcond'] - $pos_courante);
1179
-			$ligne_suite += public_compte_ligne($texte, $pos_courante, $boucle['pos_postcond_inside']);
1180
-			$pos_courante = $boucle['pos_postcond_inside'] ;
1181
-		}
1182
-
1183
-
1184
-		//
1185
-		// 2. Partie alternative apres ?
1186
-		//
1187
-		$ligne_altern = $ligne_suite;
1188
-		if ($boucle['pos_altern']) {
1189
-			$result->altern = substr($texte, $pos_courante, $boucle['pos_altern'] - $pos_courante);
1190
-			$ligne_suite += public_compte_ligne($texte, $pos_courante, $boucle['pos_altern_inside']);
1191
-			$pos_courante = $boucle['pos_altern_inside'];
1192
-		}
1193
-
1194
-		//
1195
-		// 3. Partie footer non alternative ?
1196
-		//
1197
-		$ligne_postaff = $ligne_suite;
1198
-		if ($boucle['pos_postaff']) {
1199
-			$result->postaff = substr($texte, $pos_courante, $boucle['pos_postaff'] - $pos_courante);
1200
-			$ligne_suite += public_compte_ligne($texte, $pos_courante, $boucle['pos_postaff_inside']);
1201
-			$pos_courante = $boucle['pos_postaff_inside'];
1202
-		}
1203
-
1204
-		$result->ligne = $ligne_preaff;
1205
-
1206
-		if ($p = strpos($type, ':')) {
1207
-			$result->sql_serveur = substr($type, 0, $p);
1208
-			$type = substr($type, $p + 1);
1209
-		}
1210
-		$soustype = strtolower($type);
1211
-
1212
-		if (!isset($GLOBALS['table_des_tables'][$soustype])) {
1213
-			$soustype = $type;
1214
-		}
1215
-
1216
-		$result->type_requete = $soustype;
1217
-		// Lancer la 2e passe sur les criteres si la 1ere etait bonne
1218
-		if (!is_array($result->param)) {
1219
-			$err_b = true;
1220
-		} else {
1221
-			phraser_criteres($result->param, $result);
1222
-			if (strncasecmp($soustype, TYPE_RECURSIF, strlen(TYPE_RECURSIF)) == 0) {
1223
-				$result->type_requete = TYPE_RECURSIF;
1224
-				$args = $result->param;
1225
-				array_unshift(
1226
-					$args,
1227
-					substr($type, strlen(TYPE_RECURSIF))
1228
-				);
1229
-				$result->param = $args;
1230
-			}
1231
-		}
1232
-
1233
-		$descr['id_mere_contexte'] = $id_boucle;
1234
-		$result->milieu = public_phraser_html_dist($result->milieu, $id_boucle, $boucles, $descr, $ligne_milieu, $boucle_placeholder);
1235
-		// reserver la place dans la pile des boucles pour compiler ensuite dans le bon ordre
1236
-		// ie les boucles qui apparaissent dans les partie conditionnelles doivent etre compilees apres cette boucle
1237
-		// si il y a deja une boucle de ce nom, cela declenchera une erreur ensuite
1238
-		if (empty($boucles[$id_boucle])) {
1239
-			$boucles[$id_boucle] = null;
1240
-		}
1241
-		$result->preaff = public_phraser_html_dist($result->preaff, $id_parent, $boucles, $descr, $ligne_preaff, $boucle_placeholder);
1242
-		$result->avant = public_phraser_html_dist($result->avant, $id_parent, $boucles, $descr, $ligne_avant, $boucle_placeholder);
1243
-		$result->apres = public_phraser_html_dist($result->apres, $id_parent, $boucles, $descr, $ligne_apres, $boucle_placeholder);
1244
-		$result->altern = public_phraser_html_dist($result->altern, $id_parent, $boucles, $descr, $ligne_altern, $boucle_placeholder);
1245
-		$result->postaff = public_phraser_html_dist($result->postaff, $id_parent, $boucles, $descr, $ligne_postaff, $boucle_placeholder);
1246
-
1247
-		// Prevenir le generateur de code que le squelette est faux
1248
-		if ($err_b) {
1249
-			$result->type_requete = false;
1250
-		}
1251
-
1252
-		// Verifier qu'il n'y a pas double definition
1253
-		// apres analyse des sous-parties (pas avant).
1254
-		if (!empty($boucles[$id_boucle])) {
1255
-			if ($boucles[$id_boucle]->type_requete !== false) {
1256
-				$err_b_d = [
1257
-					'zbug_erreur_boucle_double',
1258
-					['id' => $id_boucle]
1259
-				];
1260
-				erreur_squelette($err_b_d, $result);
1261
-				// Prevenir le generateur de code que le squelette est faux
1262
-				$boucles[$id_boucle]->type_requete = false;
1263
-			}
1264
-		} else {
1265
-			$boucles[$id_boucle] = $result;
1266
-		}
1267
-
1268
-		// remplacer la boucle par un placeholder qui compte le meme nombre de lignes
1269
-		$placeholder = public_generer_boucle_placeholder($id_boucle, $boucles[$id_boucle], $boucle_placeholder, $ligne_suite - $ligne_debut_texte);
1270
-		$longueur_boucle = $pos_courante - $boucle['debut_boucle'];
1271
-		$texte = substr_replace($texte, $placeholder, $boucle['debut_boucle'], $longueur_boucle);
1272
-		$pos_courante = $pos_courante - $longueur_boucle + strlen($placeholder);
1273
-
1274
-		// phraser la partie avant le debut de la boucle
1275
-		#$all_res = phraser_champs_etendus(substr($texte, $pos_debut_texte, $boucle['debut_boucle'] - $pos_debut_texte), $ligne_debut_texte, $all_res);
1276
-		#$all_res[] = &$boucles[$id_boucle];
1277
-
1278
-		$ligne_debut_texte = $ligne_suite;
1279
-		$pos_debut_texte = $pos_courante;
1280
-	}
1281
-
1282
-	$all_res = phraser_champs_etendus($texte, $ligne_debut_initial, $all_res);
1283
-
1284
-	return $all_res;
1024
+    $all_res = [];
1025
+    // definir un placholder pour les boucles dont on est sur d'avoir aucune occurence dans le squelette
1026
+    if (is_null($boucle_placeholder)) {
1027
+        do {
1028
+            $boucle_placeholder = 'BOUCLE_PLACEHOLDER_' . strtoupper(md5(uniqid()));
1029
+        } while (strpos($texte, $boucle_placeholder) !== false);
1030
+    }
1031
+
1032
+    $ligne_debut_initial = $ligne_debut_texte;
1033
+    $pos_debut_texte = 0;
1034
+    while ($boucle = public_trouver_premiere_boucle($texte, $id_parent, $descr, $pos_debut_texte)) {
1035
+        $err_b = ''; // indiquera s'il y a eu une erreur
1036
+        $result = new Boucle();
1037
+        $result->id_parent = $id_parent;
1038
+        $result->descr = $descr;
1039
+
1040
+        $pos_courante = $boucle['pos_boucle'];
1041
+        $pos_parent = $boucle['pos_parent'];
1042
+        $id_boucle_search = $id_boucle = $boucle['id_boucle'];
1043
+
1044
+        $ligne_preaff = $ligne_avant = $ligne_milieu = $ligne_debut_texte + public_compte_ligne($texte, $pos_debut_texte, $pos_parent);
1045
+
1046
+        // boucle anonyme ?
1047
+        if (!strlen($id_boucle)) {
1048
+            $id_boucle = '_anon_L' . $ligne_milieu . '_' . substr(md5('anonyme:' . $id_parent . ':' . json_encode($boucle, JSON_THROW_ON_ERROR)), 0, 8);
1049
+        }
1050
+
1051
+        $pos_debut_boucle = $pos_courante;
1052
+
1053
+        $pos_milieu = $pos_parent;
1054
+
1055
+        // Regarder si on a une partie conditionnelle avant <B_xxx>
1056
+        if ($boucle['pos_precond'] !== false) {
1057
+            $pos_debut_boucle = $boucle['pos_precond'];
1058
+
1059
+            $pos_avant = $boucle['pos_precond_inside'];
1060
+            $result->avant = substr($texte, $pos_avant, $pos_courante - $pos_avant);
1061
+            $ligne_avant = $ligne_debut_texte +  public_compte_ligne($texte, $pos_debut_texte, $pos_avant);
1062
+        }
1063
+
1064
+        // Regarder si on a une partie inconditionnelle avant <BB_xxx>
1065
+        if ($boucle['pos_preaff'] !== false) {
1066
+            $end_preaff = $pos_debut_boucle;
1067
+
1068
+            $pos_preaff = $boucle['pos_preaff_inside'];
1069
+            $result->preaff = substr($texte, $pos_preaff, $end_preaff - $pos_preaff);
1070
+            $ligne_preaff = $ligne_debut_texte +  public_compte_ligne($texte, $pos_debut_texte, $pos_preaff);
1071
+        }
1072
+
1073
+        $result->id_boucle = $id_boucle;
1074
+
1075
+        if (
1076
+            !preg_match(SPEC_BOUCLE, $texte, $match, 0, $pos_milieu)
1077
+            or ($pos_match = strpos($texte, (string) $match[0], $pos_milieu)) === false
1078
+            or $pos_match > $pos_milieu
1079
+        ) {
1080
+            $err_b = ['zbug_erreur_boucle_syntaxe', ['id' => $id_boucle]];
1081
+            erreur_squelette($err_b, $result);
1082
+
1083
+            $ligne_debut_texte += public_compte_ligne($texte, $pos_debut_texte, $pos_courante + 1);
1084
+            $pos_debut_texte = $pos_courante + 1;
1085
+            continue;
1086
+        }
1087
+
1088
+        $result->type_requete = $match[0];
1089
+        $pos_milieu += strlen($match[0]);
1090
+        $pos_courante = $pos_milieu; // on s'en sert pour compter les lignes plus precisemment
1091
+
1092
+        $type = $match[1];
1093
+        $jointures = trim($match[2]);
1094
+        $table_optionnelle = ($match[3]);
1095
+        if ($jointures) {
1096
+            // on affecte pas ici les jointures explicites, mais dans la compilation
1097
+            // ou elles seront completees des jointures declarees
1098
+            $result->jointures_explicites = $jointures;
1099
+        }
1100
+
1101
+        if ($table_optionnelle) {
1102
+            $result->table_optionnelle = $type;
1103
+        }
1104
+
1105
+        // 1ere passe sur les criteres, vu comme des arguments sans fct
1106
+        // Resultat mis dans result->param
1107
+        $pos_fin_criteres = $pos_milieu;
1108
+        phraser_args($texte, '/>', '', $all_res, $result, $pos_fin_criteres);
1109
+
1110
+        // En 2e passe result->criteres contiendra un tableau
1111
+        // pour l'instant on met le source (chaine) :
1112
+        // si elle reste ici au final, c'est qu'elle contient une erreur
1113
+        $pos_courante = $pos_fin_criteres; // on s'en sert pour compter les lignes plus precisemment
1114
+        $result->criteres = substr($texte, $pos_milieu, $pos_fin_criteres - $pos_milieu);
1115
+        $pos_milieu = $pos_fin_criteres;
1116
+
1117
+        //
1118
+        // Recuperer la fin :
1119
+        //
1120
+        if ($texte[$pos_milieu] === '/') {
1121
+            // boucle autofermante : pas de partie conditionnelle apres
1122
+            $pos_courante += 2;
1123
+            $result->milieu = '';
1124
+        } else {
1125
+            $pos_milieu += 1;
1126
+
1127
+            $fin_boucle = BALISE_FIN_BOUCLE . $id_boucle_search . '>';
1128
+            $pos_fin = strpos($texte, $fin_boucle, $pos_milieu);
1129
+            if ($pos_fin === false) {
1130
+                $err_b = [
1131
+                    'zbug_erreur_boucle_fermant',
1132
+                    ['id' => $id_boucle]
1133
+                ];
1134
+                erreur_squelette($err_b, $result);
1135
+                $pos_courante += strlen($fin_boucle);
1136
+            }
1137
+            else {
1138
+                // verifier une eventuelle imbrication d'une boucle homonyme
1139
+                // (interdite, generera une erreur plus loin, mais permet de signaler la bonne erreur)
1140
+                $search_debut_boucle = BALISE_BOUCLE . $id_boucle_search . '(';
1141
+                $search_from = $pos_milieu;
1142
+                $nb_open = 1;
1143
+                $nb_close = 1;
1144
+                $maxiter = 0;
1145
+                do {
1146
+                    while (
1147
+                        $nb_close < $nb_open
1148
+                        and $p = strpos($texte, $fin_boucle, $pos_fin + 1)
1149
+                    ) {
1150
+                        $nb_close++;
1151
+                        $pos_fin = $p;
1152
+                    }
1153
+                    // si on a pas trouve assez de boucles fermantes, sortir de la, on a fait de notre mieux
1154
+                    if ($nb_close < $nb_open) {
1155
+                        break;
1156
+                    }
1157
+                    while (
1158
+                        $p = strpos($texte, $search_debut_boucle, $search_from)
1159
+                        and $p < $pos_fin
1160
+                    ) {
1161
+                        $nb_open++;
1162
+                        $search_from = $p + 1;
1163
+                    }
1164
+                } while ($nb_close < $nb_open and $maxiter++ < 5);
1165
+
1166
+                $pos_courante = $pos_fin + strlen($fin_boucle);
1167
+            }
1168
+            $result->milieu = substr($texte, $pos_milieu, $pos_fin - $pos_milieu);
1169
+        }
1170
+
1171
+        $ligne_suite = $ligne_apres = $ligne_debut_texte + public_compte_ligne($texte, $pos_debut_texte, $pos_courante);
1172
+        $boucle = public_trouver_fin_boucle($texte, $id_parent, $boucle, $pos_courante, $result);
1173
+
1174
+        //
1175
+        // 1. Partie conditionnelle apres ?
1176
+        //
1177
+        if ($boucle['pos_postcond']) {
1178
+            $result->apres = substr($texte, $pos_courante, $boucle['pos_postcond'] - $pos_courante);
1179
+            $ligne_suite += public_compte_ligne($texte, $pos_courante, $boucle['pos_postcond_inside']);
1180
+            $pos_courante = $boucle['pos_postcond_inside'] ;
1181
+        }
1182
+
1183
+
1184
+        //
1185
+        // 2. Partie alternative apres ?
1186
+        //
1187
+        $ligne_altern = $ligne_suite;
1188
+        if ($boucle['pos_altern']) {
1189
+            $result->altern = substr($texte, $pos_courante, $boucle['pos_altern'] - $pos_courante);
1190
+            $ligne_suite += public_compte_ligne($texte, $pos_courante, $boucle['pos_altern_inside']);
1191
+            $pos_courante = $boucle['pos_altern_inside'];
1192
+        }
1193
+
1194
+        //
1195
+        // 3. Partie footer non alternative ?
1196
+        //
1197
+        $ligne_postaff = $ligne_suite;
1198
+        if ($boucle['pos_postaff']) {
1199
+            $result->postaff = substr($texte, $pos_courante, $boucle['pos_postaff'] - $pos_courante);
1200
+            $ligne_suite += public_compte_ligne($texte, $pos_courante, $boucle['pos_postaff_inside']);
1201
+            $pos_courante = $boucle['pos_postaff_inside'];
1202
+        }
1203
+
1204
+        $result->ligne = $ligne_preaff;
1205
+
1206
+        if ($p = strpos($type, ':')) {
1207
+            $result->sql_serveur = substr($type, 0, $p);
1208
+            $type = substr($type, $p + 1);
1209
+        }
1210
+        $soustype = strtolower($type);
1211
+
1212
+        if (!isset($GLOBALS['table_des_tables'][$soustype])) {
1213
+            $soustype = $type;
1214
+        }
1215
+
1216
+        $result->type_requete = $soustype;
1217
+        // Lancer la 2e passe sur les criteres si la 1ere etait bonne
1218
+        if (!is_array($result->param)) {
1219
+            $err_b = true;
1220
+        } else {
1221
+            phraser_criteres($result->param, $result);
1222
+            if (strncasecmp($soustype, TYPE_RECURSIF, strlen(TYPE_RECURSIF)) == 0) {
1223
+                $result->type_requete = TYPE_RECURSIF;
1224
+                $args = $result->param;
1225
+                array_unshift(
1226
+                    $args,
1227
+                    substr($type, strlen(TYPE_RECURSIF))
1228
+                );
1229
+                $result->param = $args;
1230
+            }
1231
+        }
1232
+
1233
+        $descr['id_mere_contexte'] = $id_boucle;
1234
+        $result->milieu = public_phraser_html_dist($result->milieu, $id_boucle, $boucles, $descr, $ligne_milieu, $boucle_placeholder);
1235
+        // reserver la place dans la pile des boucles pour compiler ensuite dans le bon ordre
1236
+        // ie les boucles qui apparaissent dans les partie conditionnelles doivent etre compilees apres cette boucle
1237
+        // si il y a deja une boucle de ce nom, cela declenchera une erreur ensuite
1238
+        if (empty($boucles[$id_boucle])) {
1239
+            $boucles[$id_boucle] = null;
1240
+        }
1241
+        $result->preaff = public_phraser_html_dist($result->preaff, $id_parent, $boucles, $descr, $ligne_preaff, $boucle_placeholder);
1242
+        $result->avant = public_phraser_html_dist($result->avant, $id_parent, $boucles, $descr, $ligne_avant, $boucle_placeholder);
1243
+        $result->apres = public_phraser_html_dist($result->apres, $id_parent, $boucles, $descr, $ligne_apres, $boucle_placeholder);
1244
+        $result->altern = public_phraser_html_dist($result->altern, $id_parent, $boucles, $descr, $ligne_altern, $boucle_placeholder);
1245
+        $result->postaff = public_phraser_html_dist($result->postaff, $id_parent, $boucles, $descr, $ligne_postaff, $boucle_placeholder);
1246
+
1247
+        // Prevenir le generateur de code que le squelette est faux
1248
+        if ($err_b) {
1249
+            $result->type_requete = false;
1250
+        }
1251
+
1252
+        // Verifier qu'il n'y a pas double definition
1253
+        // apres analyse des sous-parties (pas avant).
1254
+        if (!empty($boucles[$id_boucle])) {
1255
+            if ($boucles[$id_boucle]->type_requete !== false) {
1256
+                $err_b_d = [
1257
+                    'zbug_erreur_boucle_double',
1258
+                    ['id' => $id_boucle]
1259
+                ];
1260
+                erreur_squelette($err_b_d, $result);
1261
+                // Prevenir le generateur de code que le squelette est faux
1262
+                $boucles[$id_boucle]->type_requete = false;
1263
+            }
1264
+        } else {
1265
+            $boucles[$id_boucle] = $result;
1266
+        }
1267
+
1268
+        // remplacer la boucle par un placeholder qui compte le meme nombre de lignes
1269
+        $placeholder = public_generer_boucle_placeholder($id_boucle, $boucles[$id_boucle], $boucle_placeholder, $ligne_suite - $ligne_debut_texte);
1270
+        $longueur_boucle = $pos_courante - $boucle['debut_boucle'];
1271
+        $texte = substr_replace($texte, $placeholder, $boucle['debut_boucle'], $longueur_boucle);
1272
+        $pos_courante = $pos_courante - $longueur_boucle + strlen($placeholder);
1273
+
1274
+        // phraser la partie avant le debut de la boucle
1275
+        #$all_res = phraser_champs_etendus(substr($texte, $pos_debut_texte, $boucle['debut_boucle'] - $pos_debut_texte), $ligne_debut_texte, $all_res);
1276
+        #$all_res[] = &$boucles[$id_boucle];
1277
+
1278
+        $ligne_debut_texte = $ligne_suite;
1279
+        $pos_debut_texte = $pos_courante;
1280
+    }
1281
+
1282
+    $all_res = phraser_champs_etendus($texte, $ligne_debut_initial, $all_res);
1283
+
1284
+    return $all_res;
1285 1285
 }
Please login to merge, or discard this patch.