Completed
Push — master ( 6c9939...4ccfda )
by cam
01:06
created
ecrire/public/compiler.php 1 patch
Indentation   +1208 added lines, -1208 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
  **/
18 18
 
19 19
 if (!defined('_ECRIRE_INC_VERSION')) {
20
-	return;
20
+    return;
21 21
 }
22 22
 
23 23
 /** Repérer un code ne calculant rien, meme avec commentaire */
@@ -59,92 +59,92 @@  discard block
 block discarded – undo
59 59
 
60 60
 // https://code.spip.net/@argumenter_inclure
61 61
 function argumenter_inclure(
62
-	$params,
63
-	$rejet_filtres,
64
-	$p,
65
-	&$boucles,
66
-	$id_boucle,
67
-	$echap = true,
68
-	$lang = '',
69
-	$fond1 = false
62
+    $params,
63
+    $rejet_filtres,
64
+    $p,
65
+    &$boucles,
66
+    $id_boucle,
67
+    $echap = true,
68
+    $lang = '',
69
+    $fond1 = false
70 70
 ) {
71
-	$l = [];
72
-	$erreur_p_i_i = '';
73
-	if (!is_array($params)) {
74
-		return $l;
75
-	}
76
-	foreach ($params as $k => $couple) {
77
-		// la liste d'arguments d'inclusion peut se terminer par un filtre
78
-		$filtre = array_shift($couple);
79
-		if ($filtre) {
80
-			break;
81
-		}
82
-		foreach ($couple as $n => $val) {
83
-			$var = $val[0];
84
-			if ($var->type != 'texte') {
85
-				if ($n or $k or $fond1) {
86
-					$erreur_p_i_i = [
87
-						'zbug_parametres_inclus_incorrects',
88
-						['param' => $var->nom_champ]
89
-					];
90
-					erreur_squelette($erreur_p_i_i, $p);
91
-					break;
92
-				} else {
93
-					$l[1] = calculer_liste($val, $p->descr, $boucles, $id_boucle);
94
-				}
95
-			} else {
96
-				preg_match(',^([^=]*)(=?)(.*)$,m', $var->texte, $m);
97
-				$m = array_pad($m, 3, null);
98
-				$var = $m[1];
99
-				$auto = false;
71
+    $l = [];
72
+    $erreur_p_i_i = '';
73
+    if (!is_array($params)) {
74
+        return $l;
75
+    }
76
+    foreach ($params as $k => $couple) {
77
+        // la liste d'arguments d'inclusion peut se terminer par un filtre
78
+        $filtre = array_shift($couple);
79
+        if ($filtre) {
80
+            break;
81
+        }
82
+        foreach ($couple as $n => $val) {
83
+            $var = $val[0];
84
+            if ($var->type != 'texte') {
85
+                if ($n or $k or $fond1) {
86
+                    $erreur_p_i_i = [
87
+                        'zbug_parametres_inclus_incorrects',
88
+                        ['param' => $var->nom_champ]
89
+                    ];
90
+                    erreur_squelette($erreur_p_i_i, $p);
91
+                    break;
92
+                } else {
93
+                    $l[1] = calculer_liste($val, $p->descr, $boucles, $id_boucle);
94
+                }
95
+            } else {
96
+                preg_match(',^([^=]*)(=?)(.*)$,m', $var->texte, $m);
97
+                $m = array_pad($m, 3, null);
98
+                $var = $m[1];
99
+                $auto = false;
100 100
 ;
101
-				if ($m[2]) {
102
-					$v = $m[3];
103
-					if (preg_match(',^[\'"](.*)[\'"]$,', $v, $m)) {
104
-						$v = $m[1];
105
-					}
106
-					$val[0] = new Texte();
107
-					$val[0]->texte = $v;
108
-				} elseif ($k or $n or $fond1) {
109
-					$auto = true;
110
-				} else {
111
-					$var = 1;
112
-				}
113
-
114
-				if ($var == 'lang') {
115
-					$lang = !$auto
116
-						? calculer_liste($val, $p->descr, $boucles, $id_boucle)
117
-						: '$GLOBALS["spip_lang"]';
118
-				} else {
119
-					$val = $auto
120
-						? index_pile($id_boucle, $var, $boucles)
121
-						: calculer_liste($val, $p->descr, $boucles, $id_boucle);
122
-					if ($var !== 1) {
123
-						$val = ($echap ? "\'$var\' => ' . argumenter_squelette(" : "'$var' => ")
124
-							. $val . ($echap ? ") . '" : ' ');
125
-					} else {
126
-						$val = $echap ? "'.$val.'" : $val;
127
-					}
128
-					$l[$var] = $val;
129
-				}
130
-			}
131
-		}
132
-	}
133
-	if ($erreur_p_i_i) {
134
-		return false;
135
-	}
136
-	// Cas particulier de la langue : si {lang=xx} est definie, on
137
-	// la passe, sinon on passe la langue courante au moment du calcul
138
-	// sauf si on n'en veut pas
139
-	if ($lang === false) {
140
-		return $l;
141
-	}
142
-	if (!$lang) {
143
-		$lang = '$GLOBALS["spip_lang"]';
144
-	}
145
-	$l['lang'] = ($echap ? "\'lang\' => ' . argumenter_squelette(" : "'lang' => ") . $lang . ($echap ? ") . '" : ' ');
146
-
147
-	return $l;
101
+                if ($m[2]) {
102
+                    $v = $m[3];
103
+                    if (preg_match(',^[\'"](.*)[\'"]$,', $v, $m)) {
104
+                        $v = $m[1];
105
+                    }
106
+                    $val[0] = new Texte();
107
+                    $val[0]->texte = $v;
108
+                } elseif ($k or $n or $fond1) {
109
+                    $auto = true;
110
+                } else {
111
+                    $var = 1;
112
+                }
113
+
114
+                if ($var == 'lang') {
115
+                    $lang = !$auto
116
+                        ? calculer_liste($val, $p->descr, $boucles, $id_boucle)
117
+                        : '$GLOBALS["spip_lang"]';
118
+                } else {
119
+                    $val = $auto
120
+                        ? index_pile($id_boucle, $var, $boucles)
121
+                        : calculer_liste($val, $p->descr, $boucles, $id_boucle);
122
+                    if ($var !== 1) {
123
+                        $val = ($echap ? "\'$var\' => ' . argumenter_squelette(" : "'$var' => ")
124
+                            . $val . ($echap ? ") . '" : ' ');
125
+                    } else {
126
+                        $val = $echap ? "'.$val.'" : $val;
127
+                    }
128
+                    $l[$var] = $val;
129
+                }
130
+            }
131
+        }
132
+    }
133
+    if ($erreur_p_i_i) {
134
+        return false;
135
+    }
136
+    // Cas particulier de la langue : si {lang=xx} est definie, on
137
+    // la passe, sinon on passe la langue courante au moment du calcul
138
+    // sauf si on n'en veut pas
139
+    if ($lang === false) {
140
+        return $l;
141
+    }
142
+    if (!$lang) {
143
+        $lang = '$GLOBALS["spip_lang"]';
144
+    }
145
+    $l['lang'] = ($echap ? "\'lang\' => ' . argumenter_squelette(" : "'lang' => ") . $lang . ($echap ? ") . '" : ' ');
146
+
147
+    return $l;
148 148
 }
149 149
 
150 150
 /**
@@ -168,84 +168,84 @@  discard block
 block discarded – undo
168 168
  **/
169 169
 function calculer_inclure($p, &$boucles, $id_boucle) {
170 170
 
171
-	$_options = [];
172
-	$_contexte = argumenter_inclure($p->param, false, $p, $boucles, $id_boucle, true, '', true);
173
-	if (is_string($p->texte)) {
174
-		$fichier = $p->texte;
175
-		$code = '"' . str_replace('"', '\"', $fichier) . '"';
176
-	} else {
177
-		$code = calculer_liste($p->texte, $p->descr, $boucles, $id_boucle);
178
-		if ($code and preg_match("/^'([^']*)'/s", $code, $r)) {
179
-			$fichier = $r[1];
180
-		} else {
181
-			$fichier = '';
182
-		}
183
-	}
184
-	if (!$code or $code === '""' or $code === "''") {
185
-		$trace = $p->fonctions;
186
-		while (
187
-			is_array($trace)
188
-			and $trace = array_filter($trace)
189
-			and count($trace) == 1
190
-		) {
191
-			$trace = reset($trace);
192
-		}
193
-		$erreur_p_i_i = [
194
-			'zbug_parametres_inclus_incorrects',
195
-			['param' => print_r($trace, true)]
196
-		];
197
-		erreur_squelette($erreur_p_i_i, $p);
198
-
199
-		return "''";
200
-	}
201
-	$compil = texte_script(memoriser_contexte_compil($p));
202
-
203
-	if (is_array($_contexte)) {
204
-		// Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
205
-		if ($env = (isset($_contexte['env']) || isset($_contexte['self']))) {
206
-			unset($_contexte['env']);
207
-		}
208
-
209
-		// noter les doublons dans l'appel a public.php
210
-		if (isset($_contexte['doublons'])) {
211
-			$_contexte['doublons'] = "\\'doublons\\' => '.var_export(\$doublons,true).'";
212
-		}
213
-
214
-		if ($ajax = isset($_contexte['ajax'])) {
215
-			$ajax = preg_replace(',=>(.*)$,ims', '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
216
-			unset($_contexte['ajax']);
217
-		}
218
-
219
-		$_contexte = join(",\n\t", $_contexte);
220
-	} else {
221
-		return false;
222
-	} // j'aurais voulu toucher le fond ...
223
-
224
-	$contexte = 'array(' . $_contexte . ')';
225
-
226
-	if ($env) {
227
-		$contexte = "array_merge('.var_export(\$Pile[0],1).',$contexte)";
228
-	}
229
-
230
-	// s'il y a une extension .php, ce n'est pas un squelette
231
-	if ($fichier and preg_match('/^.+[.]php$/s', $fichier)) {
232
-		$code = sandbox_composer_inclure_php($fichier, $p, $contexte);
233
-	} else {
234
-		$_options[] = "\"compil\"=>array($compil)";
235
-		if ($ajax) {
236
-			$_options[] = $ajax;
237
-		}
238
-		$code = " ' . argumenter_squelette($code) . '";
239
-		$code = 'echo ' . sprintf(
240
-			CODE_RECUPERER_FOND,
241
-			$code,
242
-			$contexte,
243
-			implode(',', $_options),
244
-			"_request(\\'connect\\') ?? \\'\\'"
245
-		) . ';';
246
-	}
247
-
248
-	return "\n'<'.'" . '?php ' . $code . "\n?'." . "'>'";
171
+    $_options = [];
172
+    $_contexte = argumenter_inclure($p->param, false, $p, $boucles, $id_boucle, true, '', true);
173
+    if (is_string($p->texte)) {
174
+        $fichier = $p->texte;
175
+        $code = '"' . str_replace('"', '\"', $fichier) . '"';
176
+    } else {
177
+        $code = calculer_liste($p->texte, $p->descr, $boucles, $id_boucle);
178
+        if ($code and preg_match("/^'([^']*)'/s", $code, $r)) {
179
+            $fichier = $r[1];
180
+        } else {
181
+            $fichier = '';
182
+        }
183
+    }
184
+    if (!$code or $code === '""' or $code === "''") {
185
+        $trace = $p->fonctions;
186
+        while (
187
+            is_array($trace)
188
+            and $trace = array_filter($trace)
189
+            and count($trace) == 1
190
+        ) {
191
+            $trace = reset($trace);
192
+        }
193
+        $erreur_p_i_i = [
194
+            'zbug_parametres_inclus_incorrects',
195
+            ['param' => print_r($trace, true)]
196
+        ];
197
+        erreur_squelette($erreur_p_i_i, $p);
198
+
199
+        return "''";
200
+    }
201
+    $compil = texte_script(memoriser_contexte_compil($p));
202
+
203
+    if (is_array($_contexte)) {
204
+        // Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
205
+        if ($env = (isset($_contexte['env']) || isset($_contexte['self']))) {
206
+            unset($_contexte['env']);
207
+        }
208
+
209
+        // noter les doublons dans l'appel a public.php
210
+        if (isset($_contexte['doublons'])) {
211
+            $_contexte['doublons'] = "\\'doublons\\' => '.var_export(\$doublons,true).'";
212
+        }
213
+
214
+        if ($ajax = isset($_contexte['ajax'])) {
215
+            $ajax = preg_replace(',=>(.*)$,ims', '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
216
+            unset($_contexte['ajax']);
217
+        }
218
+
219
+        $_contexte = join(",\n\t", $_contexte);
220
+    } else {
221
+        return false;
222
+    } // j'aurais voulu toucher le fond ...
223
+
224
+    $contexte = 'array(' . $_contexte . ')';
225
+
226
+    if ($env) {
227
+        $contexte = "array_merge('.var_export(\$Pile[0],1).',$contexte)";
228
+    }
229
+
230
+    // s'il y a une extension .php, ce n'est pas un squelette
231
+    if ($fichier and preg_match('/^.+[.]php$/s', $fichier)) {
232
+        $code = sandbox_composer_inclure_php($fichier, $p, $contexte);
233
+    } else {
234
+        $_options[] = "\"compil\"=>array($compil)";
235
+        if ($ajax) {
236
+            $_options[] = $ajax;
237
+        }
238
+        $code = " ' . argumenter_squelette($code) . '";
239
+        $code = 'echo ' . sprintf(
240
+            CODE_RECUPERER_FOND,
241
+            $code,
242
+            $contexte,
243
+            implode(',', $_options),
244
+            "_request(\\'connect\\') ?? \\'\\'"
245
+        ) . ';';
246
+    }
247
+
248
+    return "\n'<'.'" . '?php ' . $code . "\n?'." . "'>'";
249 249
 }
250 250
 
251 251
 
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
  *     true pour ne tester que le cas publie et ignorer l'eventuel var_mode=preview de la page
264 264
  */
265 265
 function instituer_boucle(&$boucle, $echapper = true, $ignore_previsu = false) {
266
-	/*
266
+    /*
267 267
 	$show['statut'][] = array(
268 268
 		'champ'=>'statut',  // champ de la table sur lequel porte le filtrage par le statut
269 269
 		'publie'=>'publie', // valeur ou liste de valeurs, qui definissent l'objet comme publie.
@@ -287,74 +287,74 @@  discard block
 block discarded – undo
287 287
 	champstatut est alors le champ statut sur la tablen
288 288
 	dans les jointures, clen peut etre un tableau pour une jointure complexe : array('id_objet','id_article','objet','article')
289 289
 */
290
-	$id_table = $boucle->id_table;
291
-	$show = $boucle->show;
292
-	if (isset($show['statut']) and $show['statut']) {
293
-		foreach ($show['statut'] as $k => $s) {
294
-			// Restreindre aux elements publies si pas de {statut} ou autre dans les criteres
295
-			$filtrer = true;
296
-			if (isset($s['exception'])) {
297
-				foreach (is_array($s['exception']) ? $s['exception'] : [$s['exception']] as $m) {
298
-					if (isset($boucle->modificateur[$m]) or isset($boucle->modificateur['criteres'][$m])) {
299
-						$filtrer = false;
300
-						break;
301
-					}
302
-				}
303
-			}
304
-
305
-			if ($filtrer) {
306
-				if (is_array($s['champ'])) {
307
-					$statut = preg_replace(',\W,', '', array_pop($s['champ'])); // securite
308
-					$jointures = [];
309
-					// indiquer la description de chaque table dans le tableau de jointures,
310
-					// ce qui permet d'eviter certains GROUP BY inutiles.
311
-					$trouver_table = charger_fonction('trouver_table', 'base');
312
-					foreach ($s['champ'] as $j) {
313
-						$id = reset($j);
314
-						$def = $trouver_table($id);
315
-						$jointures[] = ['', [$id, $def], end($j)];
316
-					}
317
-					$jointures[0][0] = $id_table;
318
-					if (!array_search($id, $boucle->from)) {
319
-						include_spip('public/jointures');
320
-						fabrique_jointures($boucle, $jointures, true, $boucle->show, $id_table, '', $echapper);
321
-					}
322
-					// trouver l'alias de la table d'arrivee qui porte le statut
323
-					$id = array_search($id, $boucle->from);
324
-				} else {
325
-					$id = $id_table;
326
-					$statut = preg_replace(',\W,', '', $s['champ']); // securite
327
-				}
328
-				$mstatut = $id . '.' . $statut;
329
-
330
-				$arg_ignore_previsu = ($ignore_previsu ? ',true' : '');
331
-				include_spip('public/quete');
332
-				if (
333
-					isset($s['post_date']) and $s['post_date']
334
-					and $GLOBALS['meta']['post_dates'] == 'non'
335
-				) {
336
-					$date = $id . '.' . preg_replace(',\W,', '', $s['post_date']); // securite
337
-					array_unshift(
338
-						$boucle->where,
339
-						$echapper ?
340
-							"\nquete_condition_postdates('$date'," . _q($boucle->sql_serveur) . "$arg_ignore_previsu)"
341
-							:
342
-							quete_condition_postdates($date, $boucle->sql_serveur, $ignore_previsu)
343
-					);
344
-				}
345
-				array_unshift(
346
-					$boucle->where,
347
-					$echapper ?
348
-						"\nquete_condition_statut('$mstatut',"
349
-						. _q($s['previsu']) . ','
350
-						. _q($s['publie']) . ','
351
-						. _q($boucle->sql_serveur) . "$arg_ignore_previsu)"
352
-						:
353
-						quete_condition_statut($mstatut, $s['previsu'], $s['publie'], $boucle->sql_serveur, $ignore_previsu)
354
-				);
355
-			}
356
-		}
357
-	}
290
+    $id_table = $boucle->id_table;
291
+    $show = $boucle->show;
292
+    if (isset($show['statut']) and $show['statut']) {
293
+        foreach ($show['statut'] as $k => $s) {
294
+            // Restreindre aux elements publies si pas de {statut} ou autre dans les criteres
295
+            $filtrer = true;
296
+            if (isset($s['exception'])) {
297
+                foreach (is_array($s['exception']) ? $s['exception'] : [$s['exception']] as $m) {
298
+                    if (isset($boucle->modificateur[$m]) or isset($boucle->modificateur['criteres'][$m])) {
299
+                        $filtrer = false;
300
+                        break;
301
+                    }
302
+                }
303
+            }
304
+
305
+            if ($filtrer) {
306
+                if (is_array($s['champ'])) {
307
+                    $statut = preg_replace(',\W,', '', array_pop($s['champ'])); // securite
308
+                    $jointures = [];
309
+                    // indiquer la description de chaque table dans le tableau de jointures,
310
+                    // ce qui permet d'eviter certains GROUP BY inutiles.
311
+                    $trouver_table = charger_fonction('trouver_table', 'base');
312
+                    foreach ($s['champ'] as $j) {
313
+                        $id = reset($j);
314
+                        $def = $trouver_table($id);
315
+                        $jointures[] = ['', [$id, $def], end($j)];
316
+                    }
317
+                    $jointures[0][0] = $id_table;
318
+                    if (!array_search($id, $boucle->from)) {
319
+                        include_spip('public/jointures');
320
+                        fabrique_jointures($boucle, $jointures, true, $boucle->show, $id_table, '', $echapper);
321
+                    }
322
+                    // trouver l'alias de la table d'arrivee qui porte le statut
323
+                    $id = array_search($id, $boucle->from);
324
+                } else {
325
+                    $id = $id_table;
326
+                    $statut = preg_replace(',\W,', '', $s['champ']); // securite
327
+                }
328
+                $mstatut = $id . '.' . $statut;
329
+
330
+                $arg_ignore_previsu = ($ignore_previsu ? ',true' : '');
331
+                include_spip('public/quete');
332
+                if (
333
+                    isset($s['post_date']) and $s['post_date']
334
+                    and $GLOBALS['meta']['post_dates'] == 'non'
335
+                ) {
336
+                    $date = $id . '.' . preg_replace(',\W,', '', $s['post_date']); // securite
337
+                    array_unshift(
338
+                        $boucle->where,
339
+                        $echapper ?
340
+                            "\nquete_condition_postdates('$date'," . _q($boucle->sql_serveur) . "$arg_ignore_previsu)"
341
+                            :
342
+                            quete_condition_postdates($date, $boucle->sql_serveur, $ignore_previsu)
343
+                    );
344
+                }
345
+                array_unshift(
346
+                    $boucle->where,
347
+                    $echapper ?
348
+                        "\nquete_condition_statut('$mstatut',"
349
+                        . _q($s['previsu']) . ','
350
+                        . _q($s['publie']) . ','
351
+                        . _q($boucle->sql_serveur) . "$arg_ignore_previsu)"
352
+                        :
353
+                        quete_condition_statut($mstatut, $s['previsu'], $s['publie'], $boucle->sql_serveur, $ignore_previsu)
354
+                );
355
+            }
356
+        }
357
+    }
358 358
 }
359 359
 
360 360
 /**
@@ -373,29 +373,29 @@  discard block
 block discarded – undo
373 373
  */
374 374
 function calculer_boucle($id_boucle, &$boucles) {
375 375
 
376
-	$boucle = &$boucles[$id_boucle];
377
-	instituer_boucle($boucle);
378
-	$boucles[$id_boucle] = pipeline('post_boucle', $boucles[$id_boucle]);
379
-
380
-	// en mode debug memoriser les premiers passages dans la boucle,
381
-	// mais pas tous, sinon ca pete.
382
-	if (_request('var_mode_affiche') != 'resultat') {
383
-		$trace = '';
384
-	} else {
385
-		$_trace = $boucles[$id_boucle]->descr['nom'] . $id_boucle;
386
-		$_trace = "\$GLOBALS['debug_objets']['resultat']['$_trace']";
387
-		$trace = "
376
+    $boucle = &$boucles[$id_boucle];
377
+    instituer_boucle($boucle);
378
+    $boucles[$id_boucle] = pipeline('post_boucle', $boucles[$id_boucle]);
379
+
380
+    // en mode debug memoriser les premiers passages dans la boucle,
381
+    // mais pas tous, sinon ca pete.
382
+    if (_request('var_mode_affiche') != 'resultat') {
383
+        $trace = '';
384
+    } else {
385
+        $_trace = $boucles[$id_boucle]->descr['nom'] . $id_boucle;
386
+        $_trace = "\$GLOBALS['debug_objets']['resultat']['$_trace']";
387
+        $trace = "
388 388
 		if (empty($_trace)) { 
389 389
 			$_trace = []; 
390 390
 		}
391 391
 		if (count($_trace) < 3) { 
392 392
 			$_trace" . '[] = $t0; 
393 393
 		}';
394
-	}
394
+    }
395 395
 
396
-	return ($boucles[$id_boucle]->type_requete == TYPE_RECURSIF)
397
-		? calculer_boucle_rec($id_boucle, $boucles, $trace)
398
-		: calculer_boucle_nonrec($id_boucle, $boucles, $trace);
396
+    return ($boucles[$id_boucle]->type_requete == TYPE_RECURSIF)
397
+        ? calculer_boucle_rec($id_boucle, $boucles, $trace)
398
+        : calculer_boucle_nonrec($id_boucle, $boucles, $trace);
399 399
 }
400 400
 
401 401
 
@@ -418,15 +418,15 @@  discard block
 block discarded – undo
418 418
  *    Code PHP compilé de la boucle récursive
419 419
  **/
420 420
 function calculer_boucle_rec($id_boucle, &$boucles, $trace) {
421
-	$nom = $boucles[$id_boucle]->param[0];
422
-
423
-	return
424
-		// Numrows[$nom] peut ne pas être encore defini
425
-		"\n\t\$save_numrows = (isset(\$Numrows['$nom']) ? \$Numrows['$nom'] : array());"
426
-		. "\n\t\$t0 = " . $boucles[$id_boucle]->return . ';'
427
-		. "\n\t\$Numrows['$nom'] = (\$save_numrows);"
428
-		. $trace
429
-		. "\n\treturn \$t0;";
421
+    $nom = $boucles[$id_boucle]->param[0];
422
+
423
+    return
424
+        // Numrows[$nom] peut ne pas être encore defini
425
+        "\n\t\$save_numrows = (isset(\$Numrows['$nom']) ? \$Numrows['$nom'] : array());"
426
+        . "\n\t\$t0 = " . $boucles[$id_boucle]->return . ';'
427
+        . "\n\t\$Numrows['$nom'] = (\$save_numrows);"
428
+        . $trace
429
+        . "\n\treturn \$t0;";
430 430
 }
431 431
 
432 432
 /**
@@ -479,174 +479,174 @@  discard block
 block discarded – undo
479 479
  **/
480 480
 function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
481 481
 
482
-	$code_sep = null;
483
-	$boucle = &$boucles[$id_boucle];
484
-	$return = $boucle->return;
485
-	$type_boucle = $boucle->type_requete;
486
-	$primary = $boucle->primary;
487
-	$constant = preg_match(CODE_MONOTONE, str_replace("\\'", '', $return));
488
-	$flag_cpt = $boucle->mode_partie || $boucle->cptrows;
489
-	$corps = '';
490
-
491
-	// faudrait expanser le foreach a la compil, car y en a souvent qu'un
492
-	// et puis faire un [] plutot qu'un "','."
493
-	if ($boucle->doublons) {
494
-		$corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' .
495
-			index_pile($id_boucle, $primary, $boucles)
496
-			. "; // doublons\n";
497
-	}
498
-
499
-	// La boucle doit-elle selectionner la langue ?
500
-	// - par defaut, les boucles suivantes le font
501
-	//    (sauf si forcer_lang==true ou si le titre contient <multi>).
502
-	// - a moins d'une demande explicite via {!lang_select}
503
-	if (
504
-		!$constant && $boucle->lang_select != 'non' &&
505
-		(($boucle->lang_select == 'oui') ||
506
-			in_array($type_boucle, [
507
-				'articles',
508
-				'rubriques',
509
-				'hierarchie',
510
-				'breves'
511
-			]))
512
-	) {
513
-		// Memoriser la langue avant la boucle et la restituer apres
514
-		// afin que le corps de boucle affecte la globale directement
515
-		$init_lang = "lang_select(\$GLOBALS['spip_lang']);\n\t";
516
-		$fin_lang = "lang_select();\n\t";
517
-		$fin_lang_select_public = "\n\t\tlang_select();";
518
-
519
-		$corps .=
520
-			"\n\t\tlang_select_public("
521
-			. index_pile($id_boucle, 'lang', $boucles)
522
-			. ", '" . $boucle->lang_select . "'"
523
-			. (in_array($type_boucle, [
524
-				'articles',
525
-				'rubriques',
526
-				'hierarchie',
527
-				'breves'
528
-			]) ? ', ' . index_pile($id_boucle, 'titre', $boucles) : '')
529
-			. ');';
530
-	} else {
531
-		$init_lang = '';
532
-		$fin_lang = '';
533
-		$fin_lang_select_public = '';
534
-		// sortir les appels au traducteur (invariants de boucle)
535
-		if (
536
-			strpos($return, '?php') === false
537
-			and preg_match_all("/\W(_T[(]'[^']*'[)])/", $return, $r)
538
-		) {
539
-			$i = 1;
540
-			foreach ($r[1] as $t) {
541
-				$init_lang .= "\n\t\$l$i = $t;";
542
-				$return = str_replace($t, "\$l$i", $return);
543
-				$i++;
544
-			}
545
-		}
546
-	}
547
-
548
-	// gestion optimale des separateurs et des boucles constantes
549
-	if (is_countable($boucle->separateur) ? count($boucle->separateur) : 0) {
550
-		$code_sep = ("'" . str_replace("'", "\'", join('', $boucle->separateur)) . "'");
551
-	}
552
-
553
-	$corps .=
554
-		((!$boucle->separateur) ?
555
-			(($constant && !$corps && !$flag_cpt) ? $return :
556
-				(($return === "''") ? '' :
557
-					("\n\t\t" . '$t0 .= ' . $return . ';'))) :
558
-			("\n\t\t\$t1 " .
559
-				((strpos($return, '$t1.') === 0) ?
560
-					('.=' . substr($return, 4)) :
561
-					('= ' . $return)) .
562
-				";\n\t\t" .
563
-				'$t0 .= ((strlen($t1) && strlen($t0)) ? ' . $code_sep . " : '') . \$t1;"));
564
-
565
-	// Calculer les invalideurs si c'est une boucle non constante et si on
566
-	// souhaite invalider ces elements
567
-	if (!$constant and $primary) {
568
-		include_spip('inc/invalideur');
569
-		$corps = calcul_invalideurs($corps, $primary, $boucles, $id_boucle);
570
-	}
571
-
572
-	// gerer le compteur de boucle
573
-	// avec ou sans son utilisation par les criteres {1/3} {1,4} {n-2,1}...
574
-
575
-	if ($boucle->partie or $boucle->cptrows) {
576
-		$corps = "\n\t\t\$Numrows['$id_boucle']['compteur_boucle']++;"
577
-			. $boucle->partie
578
-			. $corps;
579
-	}
580
-
581
-	// depiler la lang de la boucle si besoin
582
-	$corps .= $fin_lang_select_public;
583
-
584
-	// si le corps est une constante, ne pas appeler le serveur N fois!
585
-
586
-	if (preg_match(CODE_MONOTONE, str_replace("\\'", '', $corps), $r)) {
587
-		if (!isset($r[2]) or (!$r[2])) {
588
-			if (!$boucle->numrows) {
589
-				return "\n\t\$t0 = '';";
590
-			} else {
591
-				$corps = '';
592
-			}
593
-		} else {
594
-			$boucle->numrows = true;
595
-			$corps = "\n\t\$t0 = str_repeat($corps, \$Numrows['$id_boucle']['total']);";
596
-		}
597
-	} else {
598
-		$corps = "while (\$Pile[\$SP]=\$iter->fetch()) {\n$corps\n	}";
599
-	}
600
-
601
-	$count = '';
602
-	if (!$boucle->select) {
603
-		if (!$boucle->numrows or $boucle->limit or $boucle->mode_partie or $boucle->group) {
604
-			$count = '1';
605
-		} else {
606
-			$count = 'count(*)';
607
-		}
608
-		$boucles[$id_boucle]->select[] = $count;
609
-	}
610
-
611
-	if ($flag_cpt) {
612
-		$nums = "\n\t// COMPTEUR\n\t"
613
-			. "\$Numrows['$id_boucle']['compteur_boucle'] = 0;\n\t";
614
-	} else {
615
-		$nums = '';
616
-	}
617
-
618
-	if ($boucle->numrows or $boucle->mode_partie) {
619
-		$nums .= "\$Numrows['$id_boucle']['command'] = \$command;\n\t"
620
-			. "\$Numrows['$id_boucle']['total'] = @intval(\$iter->count());"
621
-			. $boucle->mode_partie
622
-			. "\n\t";
623
-	}
624
-
625
-	// Ne calculer la requete que maintenant
626
-	// car ce qui precede appelle index_pile qui influe dessus
627
-
628
-	$init = (($init = $boucles[$id_boucle]->doublons)
629
-			? ("\n\t$init = array();") : '')
630
-		. calculer_requete_sql($boucles[$id_boucle]);
631
-
632
-	$contexte = memoriser_contexte_compil($boucle);
633
-
634
-	$a = sprintf(
635
-		CODE_CORPS_BOUCLE,
636
-		$init,
637
-		$boucle->iterateur,
638
-		'$command',
639
-		$contexte,
640
-		$nums,
641
-		$init_lang,
642
-		$corps,
643
-		$fin_lang,
644
-		$trace,
645
-		'BOUCLE' . $id_boucle . ' @ ' . ($boucle->descr['sourcefile'])
646
-	);
482
+    $code_sep = null;
483
+    $boucle = &$boucles[$id_boucle];
484
+    $return = $boucle->return;
485
+    $type_boucle = $boucle->type_requete;
486
+    $primary = $boucle->primary;
487
+    $constant = preg_match(CODE_MONOTONE, str_replace("\\'", '', $return));
488
+    $flag_cpt = $boucle->mode_partie || $boucle->cptrows;
489
+    $corps = '';
490
+
491
+    // faudrait expanser le foreach a la compil, car y en a souvent qu'un
492
+    // et puis faire un [] plutot qu'un "','."
493
+    if ($boucle->doublons) {
494
+        $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' .
495
+            index_pile($id_boucle, $primary, $boucles)
496
+            . "; // doublons\n";
497
+    }
498
+
499
+    // La boucle doit-elle selectionner la langue ?
500
+    // - par defaut, les boucles suivantes le font
501
+    //    (sauf si forcer_lang==true ou si le titre contient <multi>).
502
+    // - a moins d'une demande explicite via {!lang_select}
503
+    if (
504
+        !$constant && $boucle->lang_select != 'non' &&
505
+        (($boucle->lang_select == 'oui') ||
506
+            in_array($type_boucle, [
507
+                'articles',
508
+                'rubriques',
509
+                'hierarchie',
510
+                'breves'
511
+            ]))
512
+    ) {
513
+        // Memoriser la langue avant la boucle et la restituer apres
514
+        // afin que le corps de boucle affecte la globale directement
515
+        $init_lang = "lang_select(\$GLOBALS['spip_lang']);\n\t";
516
+        $fin_lang = "lang_select();\n\t";
517
+        $fin_lang_select_public = "\n\t\tlang_select();";
518
+
519
+        $corps .=
520
+            "\n\t\tlang_select_public("
521
+            . index_pile($id_boucle, 'lang', $boucles)
522
+            . ", '" . $boucle->lang_select . "'"
523
+            . (in_array($type_boucle, [
524
+                'articles',
525
+                'rubriques',
526
+                'hierarchie',
527
+                'breves'
528
+            ]) ? ', ' . index_pile($id_boucle, 'titre', $boucles) : '')
529
+            . ');';
530
+    } else {
531
+        $init_lang = '';
532
+        $fin_lang = '';
533
+        $fin_lang_select_public = '';
534
+        // sortir les appels au traducteur (invariants de boucle)
535
+        if (
536
+            strpos($return, '?php') === false
537
+            and preg_match_all("/\W(_T[(]'[^']*'[)])/", $return, $r)
538
+        ) {
539
+            $i = 1;
540
+            foreach ($r[1] as $t) {
541
+                $init_lang .= "\n\t\$l$i = $t;";
542
+                $return = str_replace($t, "\$l$i", $return);
543
+                $i++;
544
+            }
545
+        }
546
+    }
547
+
548
+    // gestion optimale des separateurs et des boucles constantes
549
+    if (is_countable($boucle->separateur) ? count($boucle->separateur) : 0) {
550
+        $code_sep = ("'" . str_replace("'", "\'", join('', $boucle->separateur)) . "'");
551
+    }
552
+
553
+    $corps .=
554
+        ((!$boucle->separateur) ?
555
+            (($constant && !$corps && !$flag_cpt) ? $return :
556
+                (($return === "''") ? '' :
557
+                    ("\n\t\t" . '$t0 .= ' . $return . ';'))) :
558
+            ("\n\t\t\$t1 " .
559
+                ((strpos($return, '$t1.') === 0) ?
560
+                    ('.=' . substr($return, 4)) :
561
+                    ('= ' . $return)) .
562
+                ";\n\t\t" .
563
+                '$t0 .= ((strlen($t1) && strlen($t0)) ? ' . $code_sep . " : '') . \$t1;"));
564
+
565
+    // Calculer les invalideurs si c'est une boucle non constante et si on
566
+    // souhaite invalider ces elements
567
+    if (!$constant and $primary) {
568
+        include_spip('inc/invalideur');
569
+        $corps = calcul_invalideurs($corps, $primary, $boucles, $id_boucle);
570
+    }
571
+
572
+    // gerer le compteur de boucle
573
+    // avec ou sans son utilisation par les criteres {1/3} {1,4} {n-2,1}...
574
+
575
+    if ($boucle->partie or $boucle->cptrows) {
576
+        $corps = "\n\t\t\$Numrows['$id_boucle']['compteur_boucle']++;"
577
+            . $boucle->partie
578
+            . $corps;
579
+    }
580
+
581
+    // depiler la lang de la boucle si besoin
582
+    $corps .= $fin_lang_select_public;
583
+
584
+    // si le corps est une constante, ne pas appeler le serveur N fois!
585
+
586
+    if (preg_match(CODE_MONOTONE, str_replace("\\'", '', $corps), $r)) {
587
+        if (!isset($r[2]) or (!$r[2])) {
588
+            if (!$boucle->numrows) {
589
+                return "\n\t\$t0 = '';";
590
+            } else {
591
+                $corps = '';
592
+            }
593
+        } else {
594
+            $boucle->numrows = true;
595
+            $corps = "\n\t\$t0 = str_repeat($corps, \$Numrows['$id_boucle']['total']);";
596
+        }
597
+    } else {
598
+        $corps = "while (\$Pile[\$SP]=\$iter->fetch()) {\n$corps\n	}";
599
+    }
600
+
601
+    $count = '';
602
+    if (!$boucle->select) {
603
+        if (!$boucle->numrows or $boucle->limit or $boucle->mode_partie or $boucle->group) {
604
+            $count = '1';
605
+        } else {
606
+            $count = 'count(*)';
607
+        }
608
+        $boucles[$id_boucle]->select[] = $count;
609
+    }
610
+
611
+    if ($flag_cpt) {
612
+        $nums = "\n\t// COMPTEUR\n\t"
613
+            . "\$Numrows['$id_boucle']['compteur_boucle'] = 0;\n\t";
614
+    } else {
615
+        $nums = '';
616
+    }
617
+
618
+    if ($boucle->numrows or $boucle->mode_partie) {
619
+        $nums .= "\$Numrows['$id_boucle']['command'] = \$command;\n\t"
620
+            . "\$Numrows['$id_boucle']['total'] = @intval(\$iter->count());"
621
+            . $boucle->mode_partie
622
+            . "\n\t";
623
+    }
624
+
625
+    // Ne calculer la requete que maintenant
626
+    // car ce qui precede appelle index_pile qui influe dessus
627
+
628
+    $init = (($init = $boucles[$id_boucle]->doublons)
629
+            ? ("\n\t$init = array();") : '')
630
+        . calculer_requete_sql($boucles[$id_boucle]);
631
+
632
+    $contexte = memoriser_contexte_compil($boucle);
633
+
634
+    $a = sprintf(
635
+        CODE_CORPS_BOUCLE,
636
+        $init,
637
+        $boucle->iterateur,
638
+        '$command',
639
+        $contexte,
640
+        $nums,
641
+        $init_lang,
642
+        $corps,
643
+        $fin_lang,
644
+        $trace,
645
+        'BOUCLE' . $id_boucle . ' @ ' . ($boucle->descr['sourcefile'])
646
+    );
647 647
 
648 648
 #	var_dump($a);exit;
649
-	return $a;
649
+    return $a;
650 650
 }
651 651
 
652 652
 
@@ -662,48 +662,48 @@  discard block
 block discarded – undo
662 662
  *     Code PHP compilé définissant les informations de requête
663 663
  **/
664 664
 function calculer_requete_sql($boucle) {
665
-	$init = [];
666
-	$init[] = calculer_dec('table', "'" . $boucle->id_table . "'");
667
-	$init[] = calculer_dec('id', "'" . $boucle->id_boucle . "'");
668
-	# En absence de champ c'est un decompte :
669
-	$init[] = calculer_dec('from', calculer_from($boucle));
670
-	$init[] = calculer_dec('type', calculer_from_type($boucle));
671
-	$init[] = calculer_dec(
672
-		'groupby',
673
-		'array(' . (($g = join("\",\n\t\t\"", $boucle->group)) ? '"' . $g . '"' : '') . ')'
674
-	);
675
-	$init[] = calculer_dec('select', 'array("' . join("\",\n\t\t\"", $boucle->select) . '")');
676
-	$init[] = calculer_dec('orderby', 'array(' . calculer_order($boucle) . ')');
677
-	$init[] = calculer_dec('where', calculer_dump_array($boucle->where));
678
-	$init[] = calculer_dec('join', calculer_dump_join($boucle->join));
679
-	$init[] = calculer_dec(
680
-		'limit',
681
-		(
682
-			strpos($boucle->limit, 'intval') === false ?
683
-			"'" . ($boucle->limit) . "'" :
684
-			$boucle->limit
685
-		)
686
-	);
687
-	$init[] = calculer_dec('having', calculer_dump_array($boucle->having));
688
-	$s = $d = '';
689
-	// l'index 0 de $i indique si l'affectation est statique (contenu)
690
-	// ou recalculée à chaque passage (vide)
691
-	foreach ($init as $i) {
692
-		if (reset($i)) {
693
-			$s .= "\n\t\t" . end($i);
694
-		} # statique
695
-		else {
696
-			$d .= "\n\t" . end($i);
697
-		} # dynamique
698
-	}
699
-
700
-	return ($boucle->hierarchie ? "\n\t$boucle->hierarchie" : '')
701
-	. $boucle->in
702
-	. $boucle->hash
703
-	. "\n\t" . 'if (!isset($command[\'table\'])) {'
704
-	. $s
705
-	. "\n\t}"
706
-	. $d;
665
+    $init = [];
666
+    $init[] = calculer_dec('table', "'" . $boucle->id_table . "'");
667
+    $init[] = calculer_dec('id', "'" . $boucle->id_boucle . "'");
668
+    # En absence de champ c'est un decompte :
669
+    $init[] = calculer_dec('from', calculer_from($boucle));
670
+    $init[] = calculer_dec('type', calculer_from_type($boucle));
671
+    $init[] = calculer_dec(
672
+        'groupby',
673
+        'array(' . (($g = join("\",\n\t\t\"", $boucle->group)) ? '"' . $g . '"' : '') . ')'
674
+    );
675
+    $init[] = calculer_dec('select', 'array("' . join("\",\n\t\t\"", $boucle->select) . '")');
676
+    $init[] = calculer_dec('orderby', 'array(' . calculer_order($boucle) . ')');
677
+    $init[] = calculer_dec('where', calculer_dump_array($boucle->where));
678
+    $init[] = calculer_dec('join', calculer_dump_join($boucle->join));
679
+    $init[] = calculer_dec(
680
+        'limit',
681
+        (
682
+            strpos($boucle->limit, 'intval') === false ?
683
+            "'" . ($boucle->limit) . "'" :
684
+            $boucle->limit
685
+        )
686
+    );
687
+    $init[] = calculer_dec('having', calculer_dump_array($boucle->having));
688
+    $s = $d = '';
689
+    // l'index 0 de $i indique si l'affectation est statique (contenu)
690
+    // ou recalculée à chaque passage (vide)
691
+    foreach ($init as $i) {
692
+        if (reset($i)) {
693
+            $s .= "\n\t\t" . end($i);
694
+        } # statique
695
+        else {
696
+            $d .= "\n\t" . end($i);
697
+        } # dynamique
698
+    }
699
+
700
+    return ($boucle->hierarchie ? "\n\t$boucle->hierarchie" : '')
701
+    . $boucle->in
702
+    . $boucle->hash
703
+    . "\n\t" . 'if (!isset($command[\'table\'])) {'
704
+    . $s
705
+    . "\n\t}"
706
+    . $d;
707 707
 }
708 708
 
709 709
 /**
@@ -721,13 +721,13 @@  discard block
 block discarded – undo
721 721
  *     qui peut être utilisé pour la production d'un tableau array()
722 722
  **/
723 723
 function memoriser_contexte_compil($p) {
724
-	return join(',', [
725
-		_q($p->descr['sourcefile'] ?? ''),
726
-		_q($p->descr['nom'] ?? ''),
727
-		_q($p->id_boucle ?? ''),
728
-		intval($p->ligne),
729
-		'$GLOBALS[\'spip_lang\']'
730
-	]);
724
+    return join(',', [
725
+        _q($p->descr['sourcefile'] ?? ''),
726
+        _q($p->descr['nom'] ?? ''),
727
+        _q($p->id_boucle ?? ''),
728
+        intval($p->ligne),
729
+        '$GLOBALS[\'spip_lang\']'
730
+    ]);
731 731
 }
732 732
 
733 733
 /**
@@ -745,19 +745,19 @@  discard block
 block discarded – undo
745 745
  *     Objet Contexte
746 746
  **/
747 747
 function reconstruire_contexte_compil($context_compil) {
748
-	if (!is_array($context_compil)) {
749
-		return $context_compil;
750
-	}
751
-	$p = new Contexte();
752
-	$p->descr = [
753
-		'sourcefile' => $context_compil[0],
754
-		'nom' => $context_compil[1]
755
-	];
756
-	$p->id_boucle = $context_compil[2];
757
-	$p->ligne = $context_compil[3];
758
-	$p->lang = $context_compil[4];
759
-
760
-	return $p;
748
+    if (!is_array($context_compil)) {
749
+        return $context_compil;
750
+    }
751
+    $p = new Contexte();
752
+    $p->descr = [
753
+        'sourcefile' => $context_compil[0],
754
+        'nom' => $context_compil[1]
755
+    ];
756
+    $p->id_boucle = $context_compil[2];
757
+    $p->ligne = $context_compil[3];
758
+    $p->lang = $context_compil[4];
759
+
760
+    return $p;
761 761
 }
762 762
 
763 763
 /**
@@ -783,12 +783,12 @@  discard block
 block discarded – undo
783 783
  *    - index 1 : Code de l'affectation
784 784
  **/
785 785
 function calculer_dec($nom, $val) {
786
-	$static = 'if (!isset($command[\'' . $nom . '\'])) ';
787
-	// si une variable apparait dans le calcul de la clause
788
-	// il faut la re-evaluer a chaque passage
789
-	if (
790
-		strpos($val, '$') !== false
791
-		/*
786
+    $static = 'if (!isset($command[\'' . $nom . '\'])) ';
787
+    // si une variable apparait dans le calcul de la clause
788
+    // il faut la re-evaluer a chaque passage
789
+    if (
790
+        strpos($val, '$') !== false
791
+        /*
792 792
 		OR strpos($val, 'sql_') !== false
793 793
 		OR (
794 794
 			$test = str_replace(array("array(",'\"',"\'"),array("","",""),$val) // supprimer les array( et les echappements de guillemets
@@ -796,11 +796,11 @@  discard block
 block discarded – undo
796 796
 			AND $test = preg_replace(",'[^']*',UimsS","",$test) // supprimer les chaines qui peuvent contenir des fonctions SQL qui ne genent pas
797 797
 			AND preg_match(",\w+\s*\(,UimsS",$test,$regs) // tester la presence de fonctions restantes
798 798
 		)*/
799
-	) {
800
-		$static = '';
801
-	}
799
+    ) {
800
+        $static = '';
801
+    }
802 802
 
803
-	return [$static, '$command[\'' . $nom . '\'] = ' . $val . ';'];
803
+    return [$static, '$command[\'' . $nom . '\'] = ' . $val . ';'];
804 804
 }
805 805
 
806 806
 /**
@@ -820,33 +820,33 @@  discard block
 block discarded – undo
820 820
  *     Expression PHP décrivant un texte ou un tableau
821 821
  **/
822 822
 function calculer_dump_array($a) {
823
-	if (!is_array($a)) {
824
-		return $a;
825
-	}
826
-	$res = '';
827
-	if ($a and $a[0] == "'?'") {
828
-		return ('(' . calculer_dump_array($a[1]) .
829
-			' ? ' . calculer_dump_array($a[2]) .
830
-			' : ' . calculer_dump_array($a[3]) .
831
-			')');
832
-	} else {
833
-		foreach ($a as $k => $v) {
834
-			$showk = (is_numeric($k) ? '' : sql_quote($k) . ' => ');
835
-			$res .= ', ' . $showk . calculer_dump_array($v);
836
-		}
837
-
838
-		return "\n\t\t\tarray(" . substr($res, 2) . ')';
839
-	}
823
+    if (!is_array($a)) {
824
+        return $a;
825
+    }
826
+    $res = '';
827
+    if ($a and $a[0] == "'?'") {
828
+        return ('(' . calculer_dump_array($a[1]) .
829
+            ' ? ' . calculer_dump_array($a[2]) .
830
+            ' : ' . calculer_dump_array($a[3]) .
831
+            ')');
832
+    } else {
833
+        foreach ($a as $k => $v) {
834
+            $showk = (is_numeric($k) ? '' : sql_quote($k) . ' => ');
835
+            $res .= ', ' . $showk . calculer_dump_array($v);
836
+        }
837
+
838
+        return "\n\t\t\tarray(" . substr($res, 2) . ')';
839
+    }
840 840
 }
841 841
 
842 842
 // https://code.spip.net/@calculer_dump_join
843 843
 function calculer_dump_join($a) {
844
-	$res = '';
845
-	foreach ($a as $k => $v) {
846
-		$res .= ", '$k' => array(" . implode(',', $v) . ')';
847
-	}
844
+    $res = '';
845
+    foreach ($a as $k => $v) {
846
+        $res .= ", '$k' => array(" . implode(',', $v) . ')';
847
+    }
848 848
 
849
-	return 'array(' . substr($res, 2) . ')';
849
+    return 'array(' . substr($res, 2) . ')';
850 850
 }
851 851
 
852 852
 /**
@@ -858,12 +858,12 @@  discard block
 block discarded – undo
858 858
  *     Code PHP construisant un tableau des alias et noms des tables du FROM
859 859
  **/
860 860
 function calculer_from(&$boucle) {
861
-	$res = '';
862
-	foreach ($boucle->from as $k => $v) {
863
-		$res .= ",'$k' => '$v'";
864
-	}
861
+    $res = '';
862
+    foreach ($boucle->from as $k => $v) {
863
+        $res .= ",'$k' => '$v'";
864
+    }
865 865
 
866
-	return 'array(' . substr($res, 1) . ')';
866
+    return 'array(' . substr($res, 1) . ')';
867 867
 }
868 868
 
869 869
 /**
@@ -876,31 +876,31 @@  discard block
 block discarded – undo
876 876
  *     Code PHP construisant un tableau des alias et type de jointure du FROM
877 877
  **/
878 878
 function calculer_from_type(&$boucle) {
879
-	$res = '';
880
-	foreach ($boucle->from_type as $k => $v) {
881
-		$res .= ",'$k' => '$v'";
882
-	}
879
+    $res = '';
880
+    foreach ($boucle->from_type as $k => $v) {
881
+        $res .= ",'$k' => '$v'";
882
+    }
883 883
 
884
-	return 'array(' . substr($res, 1) . ')';
884
+    return 'array(' . substr($res, 1) . ')';
885 885
 }
886 886
 
887 887
 // https://code.spip.net/@calculer_order
888 888
 function calculer_order(&$boucle) {
889
-	if (
890
-		!$order = $boucle->order
891
-		and !$order = $boucle->default_order
892
-	) {
893
-		$order = [];
894
-	}
895
-
896
-	/*if (isset($boucle->modificateur['collate'])){
889
+    if (
890
+        !$order = $boucle->order
891
+        and !$order = $boucle->default_order
892
+    ) {
893
+        $order = [];
894
+    }
895
+
896
+    /*if (isset($boucle->modificateur['collate'])){
897 897
 		$col = "." . $boucle->modificateur['collate'];
898 898
 		foreach($order as $k=>$o)
899 899
 			if (strpos($order[$k],'COLLATE')===false)
900 900
 				$order[$k].= $col;
901 901
 	}*/
902 902
 
903
-	return join(', ', $order);
903
+    return join(', ', $order);
904 904
 }
905 905
 
906 906
 // Production du code PHP a partir de la sequence livree par le phraseur
@@ -910,62 +910,62 @@  discard block
 block discarded – undo
910 910
 
911 911
 // https://code.spip.net/@calculer_liste
912 912
 function calculer_liste($tableau, $descr, &$boucles, $id_boucle = '') {
913
-	if (!$tableau) {
914
-		return "''";
915
-	}
916
-	if (is_string($descr)) {
917
-		if (isset($boucles[$descr])) {
918
-			$idb = $descr;
919
-			$descr = [];
920
-			if (isset($boucles[$idb]->descr['id_mere_contexte'])) {
921
-				$descr['id_mere'] = $boucles[$idb]->descr['id_mere_contexte'];
922
-			}
923
-			if (isset($boucles[$idb]->descr['sourcefile'])) {
924
-				$descr['sourcefile'] = $boucles[$idb]->descr['sourcefile'];
925
-			}
926
-		}
927
-		else {
928
-			$descr = [];
929
-		}
930
-	}
931
-	if (!isset($descr['niv'])) {
932
-		$descr['niv'] = 0;
933
-	}
934
-	$codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
935
-	if ($codes === false) {
936
-		return false;
937
-	}
938
-	$n = is_countable($codes) ? count($codes) : 0;
939
-	if (!$n) {
940
-		return "''";
941
-	}
942
-	$tab = str_repeat("\t", $descr['niv']);
943
-	if (_request('var_mode_affiche') != 'validation') {
944
-		if ($n == 1) {
945
-			return $codes[0];
946
-		} else {
947
-			$res = '';
948
-			foreach ($codes as $code) {
949
-				if (
950
-					!preg_match("/^'[^']*'$/", $code)
951
-					or substr($res, -1, 1) !== "'"
952
-				) {
953
-					$res .= " .\n$tab$code";
954
-				} else {
955
-					$res = substr($res, 0, -1) . substr($code, 1);
956
-				}
957
-			}
958
-
959
-			return '(' . substr($res, 2 + $descr['niv']) . ')';
960
-		}
961
-	} else {
962
-		$nom = $descr['nom'] . $id_boucle . ($descr['niv'] ?: '');
963
-
964
-		return "join('', array_map('array_shift', \$GLOBALS['debug_objets']['sequence']['$nom'] = array(" . join(
965
-			" ,\n$tab",
966
-			$codes
967
-		) . ')))';
968
-	}
913
+    if (!$tableau) {
914
+        return "''";
915
+    }
916
+    if (is_string($descr)) {
917
+        if (isset($boucles[$descr])) {
918
+            $idb = $descr;
919
+            $descr = [];
920
+            if (isset($boucles[$idb]->descr['id_mere_contexte'])) {
921
+                $descr['id_mere'] = $boucles[$idb]->descr['id_mere_contexte'];
922
+            }
923
+            if (isset($boucles[$idb]->descr['sourcefile'])) {
924
+                $descr['sourcefile'] = $boucles[$idb]->descr['sourcefile'];
925
+            }
926
+        }
927
+        else {
928
+            $descr = [];
929
+        }
930
+    }
931
+    if (!isset($descr['niv'])) {
932
+        $descr['niv'] = 0;
933
+    }
934
+    $codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
935
+    if ($codes === false) {
936
+        return false;
937
+    }
938
+    $n = is_countable($codes) ? count($codes) : 0;
939
+    if (!$n) {
940
+        return "''";
941
+    }
942
+    $tab = str_repeat("\t", $descr['niv']);
943
+    if (_request('var_mode_affiche') != 'validation') {
944
+        if ($n == 1) {
945
+            return $codes[0];
946
+        } else {
947
+            $res = '';
948
+            foreach ($codes as $code) {
949
+                if (
950
+                    !preg_match("/^'[^']*'$/", $code)
951
+                    or substr($res, -1, 1) !== "'"
952
+                ) {
953
+                    $res .= " .\n$tab$code";
954
+                } else {
955
+                    $res = substr($res, 0, -1) . substr($code, 1);
956
+                }
957
+            }
958
+
959
+            return '(' . substr($res, 2 + $descr['niv']) . ')';
960
+        }
961
+    } else {
962
+        $nom = $descr['nom'] . $id_boucle . ($descr['niv'] ?: '');
963
+
964
+        return "join('', array_map('array_shift', \$GLOBALS['debug_objets']['sequence']['$nom'] = array(" . join(
965
+            " ,\n$tab",
966
+            $codes
967
+        ) . ')))';
968
+    }
969 969
 }
970 970
 
971 971
 
@@ -976,213 +976,213 @@  discard block
 block discarded – undo
976 976
 // https://code.spip.net/@compile_cas
977 977
 function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
978 978
 
979
-	$codes = [];
980
-	// cas de la boucle recursive
981
-	if (is_array($id_boucle)) {
982
-		$id_boucle = $id_boucle[0];
983
-	}
984
-	$type = !$id_boucle ? '' : $boucles[$id_boucle]->type_requete;
985
-	$tab = str_repeat("\t", ++$descr['niv']);
986
-	$mode = _request('var_mode_affiche');
987
-	$err_e_c = '';
988
-	// chaque commentaire introduit dans le code doit commencer
989
-	// par un caractere distinguant le cas, pour exploitation par debug.
990
-	foreach ($tableau as $p) {
991
-		switch ($p->type) {
992
-			// texte seul
993
-			case 'texte':
994
-				$code = sandbox_composer_texte($p->texte, $p);
995
-				$commentaire = strlen($p->texte) . ' signes';
996
-				$avant = '';
997
-				$apres = '';
998
-				$altern = "''";
999
-				break;
1000
-
1001
-			case 'polyglotte':
1002
-				$code = '';
1003
-				foreach ($p->traductions as $k => $v) {
1004
-					$code .= ",'" .
1005
-						str_replace(['\\', "'"], ['\\\\', "\\'"], $k) .
1006
-						"' => '" .
1007
-						str_replace(['\\', "'"], ['\\\\', "\\'"], $v) .
1008
-						"'";
1009
-				}
1010
-				$code = 'choisir_traduction(array(' .
1011
-					substr($code, 1) .
1012
-					'))';
1013
-				$commentaire = '&';
1014
-				$avant = '';
1015
-				$apres = '';
1016
-				$altern = "''";
1017
-				break;
1018
-
1019
-			// inclure
1020
-			case 'include':
1021
-				$p->descr = $descr;
1022
-				$code = calculer_inclure($p, $boucles, $id_boucle);
1023
-				if ($code === false) {
1024
-					$err_e_c = true;
1025
-					$code = "''";
1026
-				} else {
1027
-					$commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
1028
-					$avant = '';
1029
-					$apres = '';
1030
-					$altern = "''";
1031
-				}
1032
-				break;
1033
-
1034
-			// boucle
1035
-			case TYPE_RECURSIF:
1036
-				$nom = $p->id_boucle;
1037
-				$newdescr = $descr;
1038
-				$newdescr['id_mere'] = $nom;
1039
-				$newdescr['niv']++;
1040
-				$preaff = calculer_liste($p->preaff, $newdescr, $boucles, $id_boucle);
1041
-				$avant = calculer_liste($p->avant, $newdescr, $boucles, $id_boucle);
1042
-				$apres = calculer_liste($p->apres, $newdescr, $boucles, $id_boucle);
1043
-				$postaff = calculer_liste($p->postaff, $newdescr, $boucles, $id_boucle);
1044
-				$newdescr['niv']--;
1045
-				$altern = calculer_liste($p->altern, $newdescr, $boucles, $id_boucle);
1046
-				if (
1047
-					$preaff === false
1048
-					or $avant === false
1049
-					or $apres === false
1050
-					or $altern === false
1051
-					or $postaff === false
1052
-				) {
1053
-					$err_e_c = true;
1054
-					$code = "''";
1055
-				} else {
1056
-					$code = 'BOUCLE' .
1057
-						str_replace('-', '_', $nom) . $descr['nom'] .
1058
-						'($Cache, $Pile, $doublons, $Numrows, $SP)';
1059
-					$commentaire = "?$nom";
1060
-					if (
1061
-						!$boucles[$nom]->milieu
1062
-						and $boucles[$nom]->type_requete <> TYPE_RECURSIF
1063
-					) {
1064
-						if ($preaff != "''") {
1065
-							$code .= "\n. $preaff";
1066
-						}
1067
-						if ($altern != "''") {
1068
-							$code .= "\n. $altern";
1069
-						}
1070
-						if ($postaff != "''") {
1071
-							$code .= "\n. $postaff";
1072
-						}
1073
-						if ($avant <> "''" or $apres <> "''") {
1074
-							spip_log("boucle $nom toujours vide, code superflu dans $descr[sourcefile]");
1075
-						}
1076
-						$avant = $apres = $altern = "''";
1077
-					} else {
1078
-						if ($preaff != "''") {
1079
-							$avant = compile_concatene_parties_codes($preaff, $avant);
1080
-							$altern = compile_concatene_parties_codes($preaff, $altern);
1081
-						}
1082
-						if ($postaff != "''") {
1083
-							$apres = compile_concatene_parties_codes($apres, $postaff);
1084
-							$altern = compile_concatene_parties_codes($altern, $postaff);
1085
-						}
1086
-						if ($altern != "''") {
1087
-							$altern = "($altern)";
1088
-						}
1089
-					}
1090
-				}
1091
-				break;
1092
-
1093
-			case 'idiome':
1094
-				$l = [];
1095
-				$code = '';
1096
-				foreach ($p->arg as $k => $v) {
1097
-					$_v = calculer_liste($v, $descr, $boucles, $id_boucle);
1098
-					if ($k) {
1099
-						$l[] = _q($k) . ' => ' . $_v;
1100
-					} else {
1101
-						$code = $_v;
1102
-					}
1103
-				}
1104
-				// Si le module n'est pas fourni, l'expliciter sauf si calculé
1105
-				if ($p->module) {
1106
-					$m = $p->module . ':' . $p->nom_champ;
1107
-				} elseif ($p->nom_champ) {
1108
-					$m = MODULES_IDIOMES . ':' . $p->nom_champ;
1109
-				} else {
1110
-					$m = '';
1111
-				}
1112
-
1113
-				$code = (!$code ? "'$m'" :
1114
-						($m ? "'$m' . $code" :
1115
-							("(strpos(\$x=$code, ':') ? \$x : ('" . MODULES_IDIOMES . ":' . \$x))")))
1116
-					. (!$l ? '' : (', array(' . implode(",\n", $l) . ')'));
1117
-				$code = "_T($code)";
1118
-				if ($p->param) {
1119
-					$p->id_boucle = $id_boucle;
1120
-					$p->boucles = &$boucles;
1121
-					$code = compose_filtres($p, $code);
1122
-				}
1123
-				$commentaire = ':';
1124
-				$avant = '';
1125
-				$apres = '';
1126
-				$altern = "''";
1127
-				break;
1128
-
1129
-			case 'champ':
1130
-				// cette structure pourrait etre completee des le phrase' (a faire)
1131
-				$p->id_boucle = $id_boucle;
1132
-				$p->boucles = &$boucles;
1133
-				$p->descr = $descr;
1134
-				#$p->interdire_scripts = true;
1135
-				$p->type_requete = $type;
1136
-
1137
-				$code = calculer_champ($p);
1138
-				$commentaire = '#' . $p->nom_champ . $p->etoile;
1139
-				$avant = calculer_liste(
1140
-					$p->avant,
1141
-					$descr,
1142
-					$boucles,
1143
-					$id_boucle
1144
-				);
1145
-				$apres = calculer_liste(
1146
-					$p->apres,
1147
-					$descr,
1148
-					$boucles,
1149
-					$id_boucle
1150
-				);
1151
-				$altern = "''";
1152
-				// Si la valeur est destinee a une comparaison a ''
1153
-				// forcer la conversion en une chaine par strval
1154
-				// si ca peut etre autre chose qu'une chaine
1155
-				if (
1156
-					($avant != "''" or $apres != "''")
1157
-					and $code[0] != "'"
979
+    $codes = [];
980
+    // cas de la boucle recursive
981
+    if (is_array($id_boucle)) {
982
+        $id_boucle = $id_boucle[0];
983
+    }
984
+    $type = !$id_boucle ? '' : $boucles[$id_boucle]->type_requete;
985
+    $tab = str_repeat("\t", ++$descr['niv']);
986
+    $mode = _request('var_mode_affiche');
987
+    $err_e_c = '';
988
+    // chaque commentaire introduit dans le code doit commencer
989
+    // par un caractere distinguant le cas, pour exploitation par debug.
990
+    foreach ($tableau as $p) {
991
+        switch ($p->type) {
992
+            // texte seul
993
+            case 'texte':
994
+                $code = sandbox_composer_texte($p->texte, $p);
995
+                $commentaire = strlen($p->texte) . ' signes';
996
+                $avant = '';
997
+                $apres = '';
998
+                $altern = "''";
999
+                break;
1000
+
1001
+            case 'polyglotte':
1002
+                $code = '';
1003
+                foreach ($p->traductions as $k => $v) {
1004
+                    $code .= ",'" .
1005
+                        str_replace(['\\', "'"], ['\\\\', "\\'"], $k) .
1006
+                        "' => '" .
1007
+                        str_replace(['\\', "'"], ['\\\\', "\\'"], $v) .
1008
+                        "'";
1009
+                }
1010
+                $code = 'choisir_traduction(array(' .
1011
+                    substr($code, 1) .
1012
+                    '))';
1013
+                $commentaire = '&';
1014
+                $avant = '';
1015
+                $apres = '';
1016
+                $altern = "''";
1017
+                break;
1018
+
1019
+            // inclure
1020
+            case 'include':
1021
+                $p->descr = $descr;
1022
+                $code = calculer_inclure($p, $boucles, $id_boucle);
1023
+                if ($code === false) {
1024
+                    $err_e_c = true;
1025
+                    $code = "''";
1026
+                } else {
1027
+                    $commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
1028
+                    $avant = '';
1029
+                    $apres = '';
1030
+                    $altern = "''";
1031
+                }
1032
+                break;
1033
+
1034
+            // boucle
1035
+            case TYPE_RECURSIF:
1036
+                $nom = $p->id_boucle;
1037
+                $newdescr = $descr;
1038
+                $newdescr['id_mere'] = $nom;
1039
+                $newdescr['niv']++;
1040
+                $preaff = calculer_liste($p->preaff, $newdescr, $boucles, $id_boucle);
1041
+                $avant = calculer_liste($p->avant, $newdescr, $boucles, $id_boucle);
1042
+                $apres = calculer_liste($p->apres, $newdescr, $boucles, $id_boucle);
1043
+                $postaff = calculer_liste($p->postaff, $newdescr, $boucles, $id_boucle);
1044
+                $newdescr['niv']--;
1045
+                $altern = calculer_liste($p->altern, $newdescr, $boucles, $id_boucle);
1046
+                if (
1047
+                    $preaff === false
1048
+                    or $avant === false
1049
+                    or $apres === false
1050
+                    or $altern === false
1051
+                    or $postaff === false
1052
+                ) {
1053
+                    $err_e_c = true;
1054
+                    $code = "''";
1055
+                } else {
1056
+                    $code = 'BOUCLE' .
1057
+                        str_replace('-', '_', $nom) . $descr['nom'] .
1058
+                        '($Cache, $Pile, $doublons, $Numrows, $SP)';
1059
+                    $commentaire = "?$nom";
1060
+                    if (
1061
+                        !$boucles[$nom]->milieu
1062
+                        and $boucles[$nom]->type_requete <> TYPE_RECURSIF
1063
+                    ) {
1064
+                        if ($preaff != "''") {
1065
+                            $code .= "\n. $preaff";
1066
+                        }
1067
+                        if ($altern != "''") {
1068
+                            $code .= "\n. $altern";
1069
+                        }
1070
+                        if ($postaff != "''") {
1071
+                            $code .= "\n. $postaff";
1072
+                        }
1073
+                        if ($avant <> "''" or $apres <> "''") {
1074
+                            spip_log("boucle $nom toujours vide, code superflu dans $descr[sourcefile]");
1075
+                        }
1076
+                        $avant = $apres = $altern = "''";
1077
+                    } else {
1078
+                        if ($preaff != "''") {
1079
+                            $avant = compile_concatene_parties_codes($preaff, $avant);
1080
+                            $altern = compile_concatene_parties_codes($preaff, $altern);
1081
+                        }
1082
+                        if ($postaff != "''") {
1083
+                            $apres = compile_concatene_parties_codes($apres, $postaff);
1084
+                            $altern = compile_concatene_parties_codes($altern, $postaff);
1085
+                        }
1086
+                        if ($altern != "''") {
1087
+                            $altern = "($altern)";
1088
+                        }
1089
+                    }
1090
+                }
1091
+                break;
1092
+
1093
+            case 'idiome':
1094
+                $l = [];
1095
+                $code = '';
1096
+                foreach ($p->arg as $k => $v) {
1097
+                    $_v = calculer_liste($v, $descr, $boucles, $id_boucle);
1098
+                    if ($k) {
1099
+                        $l[] = _q($k) . ' => ' . $_v;
1100
+                    } else {
1101
+                        $code = $_v;
1102
+                    }
1103
+                }
1104
+                // Si le module n'est pas fourni, l'expliciter sauf si calculé
1105
+                if ($p->module) {
1106
+                    $m = $p->module . ':' . $p->nom_champ;
1107
+                } elseif ($p->nom_champ) {
1108
+                    $m = MODULES_IDIOMES . ':' . $p->nom_champ;
1109
+                } else {
1110
+                    $m = '';
1111
+                }
1112
+
1113
+                $code = (!$code ? "'$m'" :
1114
+                        ($m ? "'$m' . $code" :
1115
+                            ("(strpos(\$x=$code, ':') ? \$x : ('" . MODULES_IDIOMES . ":' . \$x))")))
1116
+                    . (!$l ? '' : (', array(' . implode(",\n", $l) . ')'));
1117
+                $code = "_T($code)";
1118
+                if ($p->param) {
1119
+                    $p->id_boucle = $id_boucle;
1120
+                    $p->boucles = &$boucles;
1121
+                    $code = compose_filtres($p, $code);
1122
+                }
1123
+                $commentaire = ':';
1124
+                $avant = '';
1125
+                $apres = '';
1126
+                $altern = "''";
1127
+                break;
1128
+
1129
+            case 'champ':
1130
+                // cette structure pourrait etre completee des le phrase' (a faire)
1131
+                $p->id_boucle = $id_boucle;
1132
+                $p->boucles = &$boucles;
1133
+                $p->descr = $descr;
1134
+                #$p->interdire_scripts = true;
1135
+                $p->type_requete = $type;
1136
+
1137
+                $code = calculer_champ($p);
1138
+                $commentaire = '#' . $p->nom_champ . $p->etoile;
1139
+                $avant = calculer_liste(
1140
+                    $p->avant,
1141
+                    $descr,
1142
+                    $boucles,
1143
+                    $id_boucle
1144
+                );
1145
+                $apres = calculer_liste(
1146
+                    $p->apres,
1147
+                    $descr,
1148
+                    $boucles,
1149
+                    $id_boucle
1150
+                );
1151
+                $altern = "''";
1152
+                // Si la valeur est destinee a une comparaison a ''
1153
+                // forcer la conversion en une chaine par strval
1154
+                // si ca peut etre autre chose qu'une chaine
1155
+                if (
1156
+                    ($avant != "''" or $apres != "''")
1157
+                    and $code[0] != "'"
1158 1158
 #			AND (strpos($code,'interdire_scripts') !== 0)
1159
-					and !preg_match(_REGEXP_COND_VIDE_NONVIDE, $code)
1160
-					and !preg_match(_REGEXP_COND_NONVIDE_VIDE, $code)
1161
-					and !preg_match(_REGEXP_CONCAT_NON_VIDE, $code)
1162
-				) {
1163
-					$code = "strval($code)";
1164
-				}
1165
-				break;
1166
-
1167
-			default:
1168
-				// Erreur de construction de l'arbre de syntaxe abstraite
1169
-				$code = "''";
1170
-				$p->descr = $descr;
1171
-				$err_e_c = _T('zbug_erreur_compilation');
1172
-				erreur_squelette($err_e_c, $p);
1173
-		} // switch
1174
-
1175
-		if ($code != "''") {
1176
-			$code = compile_retour($code, $avant, $apres, $altern, $tab, $descr['niv']);
1177
-			$codes[] = (($mode == 'validation') ?
1178
-				"array($code, '$commentaire', " . $p->ligne . ')'
1179
-				: (($mode == 'code') ?
1180
-					"\n// $commentaire\n$code" :
1181
-					$code));
1182
-		}
1183
-	} // foreach
1184
-
1185
-	return $err_e_c ? false : $codes;
1159
+                    and !preg_match(_REGEXP_COND_VIDE_NONVIDE, $code)
1160
+                    and !preg_match(_REGEXP_COND_NONVIDE_VIDE, $code)
1161
+                    and !preg_match(_REGEXP_CONCAT_NON_VIDE, $code)
1162
+                ) {
1163
+                    $code = "strval($code)";
1164
+                }
1165
+                break;
1166
+
1167
+            default:
1168
+                // Erreur de construction de l'arbre de syntaxe abstraite
1169
+                $code = "''";
1170
+                $p->descr = $descr;
1171
+                $err_e_c = _T('zbug_erreur_compilation');
1172
+                erreur_squelette($err_e_c, $p);
1173
+        } // switch
1174
+
1175
+        if ($code != "''") {
1176
+            $code = compile_retour($code, $avant, $apres, $altern, $tab, $descr['niv']);
1177
+            $codes[] = (($mode == 'validation') ?
1178
+                "array($code, '$commentaire', " . $p->ligne . ')'
1179
+                : (($mode == 'code') ?
1180
+                    "\n// $commentaire\n$code" :
1181
+                    $code));
1182
+        }
1183
+    } // foreach
1184
+
1185
+    return $err_e_c ? false : $codes;
1186 1186
 }
1187 1187
 
1188 1188
 /**
@@ -1192,13 +1192,13 @@  discard block
 block discarded – undo
1192 1192
  * @return string
1193 1193
  */
1194 1194
 function compile_concatene_parties_codes($partie1, $partie2) {
1195
-	if ($partie1 === "''") {
1196
-		return $partie2;
1197
-	}
1198
-	if ($partie2 === "''") {
1199
-		return $partie1;
1200
-	}
1201
-	return "$partie1\n. $partie2";
1195
+    if ($partie1 === "''") {
1196
+        return $partie2;
1197
+    }
1198
+    if ($partie2 === "''") {
1199
+        return $partie1;
1200
+    }
1201
+    return "$partie1\n. $partie2";
1202 1202
 }
1203 1203
 
1204 1204
 
@@ -1223,56 +1223,56 @@  discard block
 block discarded – undo
1223 1223
  * @return mixed|string
1224 1224
  */
1225 1225
 function compile_retour($code, $avant, $apres, $altern, $tab, $n) {
1226
-	if ($avant === "''") {
1227
-		$avant = '';
1228
-	}
1229
-	if ($apres === "''") {
1230
-		$apres = '';
1231
-	}
1232
-	if ($avant or $apres or ($altern !== "''")) {
1233
-		if (preg_match(_REGEXP_CONCAT_NON_VIDE, $code)) {
1234
-			$t = $code;
1235
-			$cond = '';
1236
-		} elseif (preg_match(_REGEXP_COND_VIDE_NONVIDE, $code, $r)) {
1237
-			$t = $r[2];
1238
-			$cond = '!' . $r[1];
1239
-		} else {
1240
-			if (preg_match(_REGEXP_COND_NONVIDE_VIDE, $code, $r)) {
1241
-				$t = $r[2];
1242
-				$cond = $r[1];
1243
-			} else {
1244
-				$t = '$t' . $n;
1245
-				$cond = "($t = $code)!==''";
1246
-			}
1247
-		}
1248
-
1249
-		$res = (!$avant ? '' : "$avant . ") .
1250
-			$t .
1251
-			(!$apres ? '' : " . $apres");
1252
-
1253
-		if ($res !== $t) {
1254
-			$res = "($res)";
1255
-		}
1256
-
1257
-		$code = (!$cond ? $res : "($cond ?\n\t$tab$res :\n\t$tab$altern)");
1258
-	}
1259
-
1260
-	return $code;
1226
+    if ($avant === "''") {
1227
+        $avant = '';
1228
+    }
1229
+    if ($apres === "''") {
1230
+        $apres = '';
1231
+    }
1232
+    if ($avant or $apres or ($altern !== "''")) {
1233
+        if (preg_match(_REGEXP_CONCAT_NON_VIDE, $code)) {
1234
+            $t = $code;
1235
+            $cond = '';
1236
+        } elseif (preg_match(_REGEXP_COND_VIDE_NONVIDE, $code, $r)) {
1237
+            $t = $r[2];
1238
+            $cond = '!' . $r[1];
1239
+        } else {
1240
+            if (preg_match(_REGEXP_COND_NONVIDE_VIDE, $code, $r)) {
1241
+                $t = $r[2];
1242
+                $cond = $r[1];
1243
+            } else {
1244
+                $t = '$t' . $n;
1245
+                $cond = "($t = $code)!==''";
1246
+            }
1247
+        }
1248
+
1249
+        $res = (!$avant ? '' : "$avant . ") .
1250
+            $t .
1251
+            (!$apres ? '' : " . $apres");
1252
+
1253
+        if ($res !== $t) {
1254
+            $res = "($res)";
1255
+        }
1256
+
1257
+        $code = (!$cond ? $res : "($cond ?\n\t$tab$res :\n\t$tab$altern)");
1258
+    }
1259
+
1260
+    return $code;
1261 1261
 }
1262 1262
 
1263 1263
 
1264 1264
 function compile_inclure_doublons($lexemes) {
1265
-	foreach ($lexemes as $v) {
1266
-		if ($v->type === 'include' and $v->param) {
1267
-			foreach ($v->param as $r) {
1268
-				if (trim($r[0]) === 'doublons') {
1269
-					return true;
1270
-				}
1271
-			}
1272
-		}
1273
-	}
1274
-
1275
-	return false;
1265
+    foreach ($lexemes as $v) {
1266
+        if ($v->type === 'include' and $v->param) {
1267
+            foreach ($v->param as $r) {
1268
+                if (trim($r[0]) === 'doublons') {
1269
+                    return true;
1270
+                }
1271
+            }
1272
+        }
1273
+    }
1274
+
1275
+    return false;
1276 1276
 }
1277 1277
 
1278 1278
 // Prend en argument le texte d'un squelette, le nom de son fichier d'origine,
@@ -1292,354 +1292,354 @@  discard block
 block discarded – undo
1292 1292
 
1293 1293
 // https://code.spip.net/@public_compiler_dist
1294 1294
 function public_compiler_dist($squelette, $nom, $gram, $sourcefile, string $connect = '') {
1295
-	// Pre-traitement : reperer le charset du squelette, et le convertir
1296
-	// Bonus : supprime le BOM
1297
-	include_spip('inc/charsets');
1298
-	$squelette = transcoder_page($squelette);
1299
-
1300
-	// rendre inertes les echappements de #[](){}<>
1301
-	$i = 0;
1302
-	while (false !== strpos($squelette, $inerte = '-INERTE' . $i)) {
1303
-		$i++;
1304
-	}
1305
-	$squelette = preg_replace_callback(
1306
-		',\\\\([#[()\]{}<>]),',
1307
-		fn($a) => "$inerte-" . ord($a[1]) . '-',
1308
-		$squelette,
1309
-		-1,
1310
-		$esc
1311
-	);
1312
-
1313
-	$descr = [
1314
-		'nom' => $nom,
1315
-		'gram' => $gram,
1316
-		'sourcefile' => $sourcefile,
1317
-		'squelette' => $squelette
1318
-	];
1319
-
1320
-	// Phraser le squelette, selon sa grammaire
1321
-
1322
-	$boucles = [];
1323
-	$f = charger_fonction('phraser_' . $gram, 'public');
1324
-
1325
-	$squelette = $f($squelette, '', $boucles, $descr);
1326
-
1327
-	$boucles = compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
1328
-
1329
-	// restituer les echappements
1330
-	if ($esc) {
1331
-		foreach ($boucles as $i => $boucle) {
1332
-			$boucles[$i]->return = preg_replace_callback(
1333
-				",$inerte-(\d+)-,",
1334
-				fn($a) => chr($a[1]),
1335
-				$boucle->return
1336
-			);
1337
-			$boucles[$i]->descr['squelette'] = preg_replace_callback(
1338
-				",$inerte-(\d+)-,",
1339
-				fn($a) => '\\\\' . chr($a[1]),
1340
-				$boucle->descr['squelette']
1341
-			);
1342
-		}
1343
-	}
1344
-
1345
-	$debug = ($boucles and defined('_VAR_MODE') and _VAR_MODE == 'debug');
1346
-	if ($debug) {
1347
-		include_spip('public/decompiler');
1348
-		foreach ($boucles as $id => $boucle) {
1349
-			if ($id) {
1350
-				$decomp = "\n/* BOUCLE " .
1351
-					$boucle->type_requete .
1352
-					' ' .
1353
-					str_replace('*/', '* /', public_decompiler($boucle, $gram, 0, 'criteres')) .
1354
-					($boucle->debug ? "\n *\n * " . implode("\n * ", $boucle->debug) . "\n" : '') .
1355
-					" */\n";
1356
-			} else {
1357
-				$decomp = ("\n/*\n" .
1358
-					str_replace('*/', '* /', public_decompiler($squelette, $gram))
1359
-					. "\n*/");
1360
-			}
1361
-			$boucles[$id]->return = $decomp . $boucle->return;
1362
-			$GLOBALS['debug_objets']['code'][$nom . $id] = $boucle->return;
1363
-		}
1364
-	}
1365
-
1366
-	return $boucles;
1295
+    // Pre-traitement : reperer le charset du squelette, et le convertir
1296
+    // Bonus : supprime le BOM
1297
+    include_spip('inc/charsets');
1298
+    $squelette = transcoder_page($squelette);
1299
+
1300
+    // rendre inertes les echappements de #[](){}<>
1301
+    $i = 0;
1302
+    while (false !== strpos($squelette, $inerte = '-INERTE' . $i)) {
1303
+        $i++;
1304
+    }
1305
+    $squelette = preg_replace_callback(
1306
+        ',\\\\([#[()\]{}<>]),',
1307
+        fn($a) => "$inerte-" . ord($a[1]) . '-',
1308
+        $squelette,
1309
+        -1,
1310
+        $esc
1311
+    );
1312
+
1313
+    $descr = [
1314
+        'nom' => $nom,
1315
+        'gram' => $gram,
1316
+        'sourcefile' => $sourcefile,
1317
+        'squelette' => $squelette
1318
+    ];
1319
+
1320
+    // Phraser le squelette, selon sa grammaire
1321
+
1322
+    $boucles = [];
1323
+    $f = charger_fonction('phraser_' . $gram, 'public');
1324
+
1325
+    $squelette = $f($squelette, '', $boucles, $descr);
1326
+
1327
+    $boucles = compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
1328
+
1329
+    // restituer les echappements
1330
+    if ($esc) {
1331
+        foreach ($boucles as $i => $boucle) {
1332
+            $boucles[$i]->return = preg_replace_callback(
1333
+                ",$inerte-(\d+)-,",
1334
+                fn($a) => chr($a[1]),
1335
+                $boucle->return
1336
+            );
1337
+            $boucles[$i]->descr['squelette'] = preg_replace_callback(
1338
+                ",$inerte-(\d+)-,",
1339
+                fn($a) => '\\\\' . chr($a[1]),
1340
+                $boucle->descr['squelette']
1341
+            );
1342
+        }
1343
+    }
1344
+
1345
+    $debug = ($boucles and defined('_VAR_MODE') and _VAR_MODE == 'debug');
1346
+    if ($debug) {
1347
+        include_spip('public/decompiler');
1348
+        foreach ($boucles as $id => $boucle) {
1349
+            if ($id) {
1350
+                $decomp = "\n/* BOUCLE " .
1351
+                    $boucle->type_requete .
1352
+                    ' ' .
1353
+                    str_replace('*/', '* /', public_decompiler($boucle, $gram, 0, 'criteres')) .
1354
+                    ($boucle->debug ? "\n *\n * " . implode("\n * ", $boucle->debug) . "\n" : '') .
1355
+                    " */\n";
1356
+            } else {
1357
+                $decomp = ("\n/*\n" .
1358
+                    str_replace('*/', '* /', public_decompiler($squelette, $gram))
1359
+                    . "\n*/");
1360
+            }
1361
+            $boucles[$id]->return = $decomp . $boucle->return;
1362
+            $GLOBALS['debug_objets']['code'][$nom . $id] = $boucle->return;
1363
+        }
1364
+    }
1365
+
1366
+    return $boucles;
1367 1367
 }
1368 1368
 
1369 1369
 // Point d'entree pour arbre de syntaxe abstraite fourni en premier argument
1370 1370
 // Autres specifications comme ci-dessus
1371 1371
 
1372 1372
 function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, string $connect = '') {
1373
-	static $trouver_table;
1374
-	spip_timer('calcul_skel');
1375
-
1376
-	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
1377
-		$GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette'];
1378
-		$GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile;
1379
-
1380
-		if (!isset($GLOBALS['debug_objets']['principal'])) {
1381
-			$GLOBALS['debug_objets']['principal'] = $nom;
1382
-		}
1383
-	}
1384
-	foreach ($boucles as $id => $boucle) {
1385
-		$GLOBALS['debug_objets']['boucle'][$nom . $id] = $boucle;
1386
-	}
1387
-	$descr['documents'] = compile_inclure_doublons($squelette);
1388
-
1389
-	// Demander la description des tables une fois pour toutes
1390
-	if (!$trouver_table) {
1391
-		$trouver_table = charger_fonction('trouver_table', 'base');
1392
-	}
1393
-
1394
-	// reperer si les doublons sont demandes
1395
-	// pour un inclure ou une boucle document
1396
-	// c'est utile a la fonction champs_traitements
1397
-	foreach ($boucles as $id => $boucle) {
1398
-		if (!($type = $boucle->type_requete)) {
1399
-			continue;
1400
-		}
1401
-		if (
1402
-			!$descr['documents'] and (
1403
-				(($type == 'documents') and $boucle->doublons) or
1404
-				compile_inclure_doublons($boucle->avant) or
1405
-				compile_inclure_doublons($boucle->apres) or
1406
-				compile_inclure_doublons($boucle->milieu) or
1407
-				compile_inclure_doublons($boucle->altern))
1408
-		) {
1409
-			$descr['documents'] = true;
1410
-		}
1411
-		if ($type != TYPE_RECURSIF) {
1412
-			if (!$boucles[$id]->sql_serveur and $connect) {
1413
-				$boucles[$id]->sql_serveur = $connect;
1414
-			}
1415
-
1416
-			// chercher dans les iterateurs du repertoire iterateur/
1417
-			if (
1418
-				$g = charger_fonction(
1419
-					preg_replace('/\W/', '_', $boucle->type_requete),
1420
-					'iterateur',
1421
-					true
1422
-				)
1423
-			) {
1424
-				$boucles[$id] = $g($boucle);
1425
-
1426
-				// sinon, en cas de requeteur d'un type predefini,
1427
-				// utiliser les informations donnees par le requeteur
1428
-				// cas "php:xx" et "data:xx".
1429
-			} else {
1430
-				if ($boucle->sql_serveur and $requeteur = charger_fonction($boucle->sql_serveur, 'requeteur', true)) {
1431
-					$requeteur($boucles, $boucle, $id);
1432
-
1433
-					// utiliser la description des champs transmis
1434
-				} else {
1435
-					$show = $trouver_table($type, $boucles[$id]->sql_serveur);
1436
-					// si la table n'existe pas avec le connecteur par defaut,
1437
-					// c'est peut etre une table qui necessite son connecteur dedie fourni
1438
-					// permet une ecriture allegee (GEO) -> (geo:GEO)
1439
-					if (
1440
-						!$show
1441
-						and $show = $trouver_table($type, strtolower($type))
1442
-					) {
1443
-						$boucles[$id]->sql_serveur = strtolower($type);
1444
-					}
1445
-					if ($show) {
1446
-						$boucles[$id]->show = $show;
1447
-						// recopie les infos les plus importantes
1448
-						$boucles[$id]->primary = $show['key']['PRIMARY KEY'] ?? '';
1449
-						$boucles[$id]->id_table = $x = preg_replace(',^spip_,', '', $show['id_table']);
1450
-						$boucles[$id]->from[$x] = $nom_table = $show['table'];
1451
-						$boucles[$id]->iterateur = 'SQL';
1452
-
1453
-						if (empty($boucles[$id]->descr)) {
1454
-							$boucles[$id]->descr = &$descr;
1455
-						}
1456
-						if (
1457
-							(!$boucles[$id]->jointures)
1458
-							and is_array($show['tables_jointures'])
1459
-							and count($x = $show['tables_jointures'])
1460
-						) {
1461
-							$boucles[$id]->jointures = $x;
1462
-						}
1463
-						if ($boucles[$id]->jointures_explicites) {
1464
-							$jointures = preg_split('/\s+/', $boucles[$id]->jointures_explicites);
1465
-							while ($j = array_pop($jointures)) {
1466
-								array_unshift($boucles[$id]->jointures, $j);
1467
-							}
1468
-						}
1469
-					} else {
1470
-						// Pas une erreur si la table est optionnelle
1471
-						if ($boucles[$id]->table_optionnelle) {
1472
-							$boucles[$id]->type_requete = '';
1473
-						} else {
1474
-							$boucles[$id]->type_requete = false;
1475
-							$boucle = $boucles[$id];
1476
-							$x = (!$boucle->sql_serveur ? '' :
1477
-									($boucle->sql_serveur . ':')) .
1478
-								$type;
1479
-							$msg = [
1480
-								'zbug_table_inconnue',
1481
-								['table' => $x]
1482
-							];
1483
-							erreur_squelette($msg, $boucle);
1484
-						}
1485
-					}
1486
-				}
1487
-			}
1488
-		}
1489
-	}
1490
-
1491
-	// Commencer par reperer les boucles appelees explicitement
1492
-	// car elles indexent les arguments de maniere derogatoire
1493
-	foreach ($boucles as $id => $boucle) {
1494
-		if ($boucle->type_requete == TYPE_RECURSIF and $boucle->param) {
1495
-			$boucles[$id]->descr = &$descr;
1496
-			$rec = &$boucles[$boucle->param[0]];
1497
-			if (!$rec) {
1498
-				$msg = [
1499
-					'zbug_boucle_recursive_undef',
1500
-					['nom' => $boucle->param[0]]
1501
-				];
1502
-				erreur_squelette($msg, $boucle);
1503
-				$boucles[$id]->type_requete = false;
1504
-			} else {
1505
-				$rec->externe = $id;
1506
-				$descr['id_mere'] = $id;
1507
-				$boucles[$id]->return =
1508
-					calculer_liste(
1509
-						[$rec],
1510
-						$descr,
1511
-						$boucles,
1512
-						$boucle->param
1513
-					);
1514
-			}
1515
-		}
1516
-	}
1517
-	foreach ($boucles as $id => $boucle) {
1518
-		$id = strval($id); // attention au type dans index_pile
1519
-		$type = $boucle->type_requete;
1520
-		if ($type and $type != TYPE_RECURSIF) {
1521
-			$res = '';
1522
-			if ($boucle->param) {
1523
-				// retourne un tableau en cas d'erreur
1524
-				$res = calculer_criteres($id, $boucles);
1525
-			}
1526
-			$descr['id_mere'] = $id;
1527
-			$boucles[$id]->return =
1528
-				calculer_liste(
1529
-					$boucle->milieu,
1530
-					$descr,
1531
-					$boucles,
1532
-					$id
1533
-				);
1534
-			// Si les criteres se sont mal compiles
1535
-			// ne pas tenter d'assembler le code final
1536
-			// (mais compiler le corps pour detection d'erreurs)
1537
-			if (is_array($res)) {
1538
-				$boucles[$id]->type_requete = false;
1539
-			}
1540
-		}
1541
-	}
1542
-
1543
-	// idem pour la racine
1544
-	$descr['id_mere'] = '';
1545
-	$corps = calculer_liste($squelette, $descr, $boucles);
1546
-
1547
-
1548
-	// Calcul du corps de toutes les fonctions PHP,
1549
-	// en particulier les requetes SQL et TOTAL_BOUCLE
1550
-	// de'terminables seulement maintenant
1551
-
1552
-	foreach ($boucles as $id => $boucle) {
1553
-		$boucle = $boucles[$id] = pipeline('pre_boucle', $boucle);
1554
-		if ($boucle->return === false) {
1555
-			$corps = false;
1556
-			continue;
1557
-		}
1558
-		// appeler la fonction de definition de la boucle
1559
-
1560
-		if ($req = $boucle->type_requete) {
1561
-			// boucle personnalisée ?
1562
-			$table = strtoupper($boucle->type_requete);
1563
-			$serveur = strtolower($boucle->sql_serveur);
1564
-			if (
1565
-				// fonction de boucle avec serveur & table
1566
-				(!$serveur or
1567
-					((!function_exists($f = 'boucle_' . $serveur . '_' . $table))
1568
-						and (!function_exists($f = $f . '_dist'))
1569
-					)
1570
-				)
1571
-				// fonction de boucle avec table
1572
-				and (!function_exists($f = 'boucle_' . $table))
1573
-				and (!function_exists($f = $f . '_dist'))
1574
-			) {
1575
-				// fonction de boucle standard
1576
-				if (!function_exists($f = 'boucle_DEFAUT')) {
1577
-					$f = 'boucle_DEFAUT_dist';
1578
-				}
1579
-			}
1580
-
1581
-			$req = "\n\n\tstatic \$command = array();\n\t" .
1582
-				"static \$connect;\n\t" .
1583
-				"\$command['connect'] = \$connect = " .
1584
-				_q($boucle->sql_serveur) .
1585
-				';' .
1586
-				$f($id, $boucles);
1587
-		} else {
1588
-			$req = ("\n\treturn '';");
1589
-		}
1590
-
1591
-		$boucles[$id]->return =
1592
-			"\n\nfunction BOUCLE" . strtr($id, '-', '_') . $nom .
1593
-			'(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
1594
-			$req .
1595
-			"\n}\n";
1596
-	}
1597
-
1598
-	// Au final, si le corps ou un critere au moins s'est mal compile
1599
-	// retourner False, sinon inserer leur decompilation
1600
-	if (is_bool($corps)) {
1601
-		return false;
1602
-	}
1603
-
1604
-	$principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons = array(), $Numrows = array(), $SP = 0) {
1373
+    static $trouver_table;
1374
+    spip_timer('calcul_skel');
1375
+
1376
+    if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
1377
+        $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette'];
1378
+        $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile;
1379
+
1380
+        if (!isset($GLOBALS['debug_objets']['principal'])) {
1381
+            $GLOBALS['debug_objets']['principal'] = $nom;
1382
+        }
1383
+    }
1384
+    foreach ($boucles as $id => $boucle) {
1385
+        $GLOBALS['debug_objets']['boucle'][$nom . $id] = $boucle;
1386
+    }
1387
+    $descr['documents'] = compile_inclure_doublons($squelette);
1388
+
1389
+    // Demander la description des tables une fois pour toutes
1390
+    if (!$trouver_table) {
1391
+        $trouver_table = charger_fonction('trouver_table', 'base');
1392
+    }
1393
+
1394
+    // reperer si les doublons sont demandes
1395
+    // pour un inclure ou une boucle document
1396
+    // c'est utile a la fonction champs_traitements
1397
+    foreach ($boucles as $id => $boucle) {
1398
+        if (!($type = $boucle->type_requete)) {
1399
+            continue;
1400
+        }
1401
+        if (
1402
+            !$descr['documents'] and (
1403
+                (($type == 'documents') and $boucle->doublons) or
1404
+                compile_inclure_doublons($boucle->avant) or
1405
+                compile_inclure_doublons($boucle->apres) or
1406
+                compile_inclure_doublons($boucle->milieu) or
1407
+                compile_inclure_doublons($boucle->altern))
1408
+        ) {
1409
+            $descr['documents'] = true;
1410
+        }
1411
+        if ($type != TYPE_RECURSIF) {
1412
+            if (!$boucles[$id]->sql_serveur and $connect) {
1413
+                $boucles[$id]->sql_serveur = $connect;
1414
+            }
1415
+
1416
+            // chercher dans les iterateurs du repertoire iterateur/
1417
+            if (
1418
+                $g = charger_fonction(
1419
+                    preg_replace('/\W/', '_', $boucle->type_requete),
1420
+                    'iterateur',
1421
+                    true
1422
+                )
1423
+            ) {
1424
+                $boucles[$id] = $g($boucle);
1425
+
1426
+                // sinon, en cas de requeteur d'un type predefini,
1427
+                // utiliser les informations donnees par le requeteur
1428
+                // cas "php:xx" et "data:xx".
1429
+            } else {
1430
+                if ($boucle->sql_serveur and $requeteur = charger_fonction($boucle->sql_serveur, 'requeteur', true)) {
1431
+                    $requeteur($boucles, $boucle, $id);
1432
+
1433
+                    // utiliser la description des champs transmis
1434
+                } else {
1435
+                    $show = $trouver_table($type, $boucles[$id]->sql_serveur);
1436
+                    // si la table n'existe pas avec le connecteur par defaut,
1437
+                    // c'est peut etre une table qui necessite son connecteur dedie fourni
1438
+                    // permet une ecriture allegee (GEO) -> (geo:GEO)
1439
+                    if (
1440
+                        !$show
1441
+                        and $show = $trouver_table($type, strtolower($type))
1442
+                    ) {
1443
+                        $boucles[$id]->sql_serveur = strtolower($type);
1444
+                    }
1445
+                    if ($show) {
1446
+                        $boucles[$id]->show = $show;
1447
+                        // recopie les infos les plus importantes
1448
+                        $boucles[$id]->primary = $show['key']['PRIMARY KEY'] ?? '';
1449
+                        $boucles[$id]->id_table = $x = preg_replace(',^spip_,', '', $show['id_table']);
1450
+                        $boucles[$id]->from[$x] = $nom_table = $show['table'];
1451
+                        $boucles[$id]->iterateur = 'SQL';
1452
+
1453
+                        if (empty($boucles[$id]->descr)) {
1454
+                            $boucles[$id]->descr = &$descr;
1455
+                        }
1456
+                        if (
1457
+                            (!$boucles[$id]->jointures)
1458
+                            and is_array($show['tables_jointures'])
1459
+                            and count($x = $show['tables_jointures'])
1460
+                        ) {
1461
+                            $boucles[$id]->jointures = $x;
1462
+                        }
1463
+                        if ($boucles[$id]->jointures_explicites) {
1464
+                            $jointures = preg_split('/\s+/', $boucles[$id]->jointures_explicites);
1465
+                            while ($j = array_pop($jointures)) {
1466
+                                array_unshift($boucles[$id]->jointures, $j);
1467
+                            }
1468
+                        }
1469
+                    } else {
1470
+                        // Pas une erreur si la table est optionnelle
1471
+                        if ($boucles[$id]->table_optionnelle) {
1472
+                            $boucles[$id]->type_requete = '';
1473
+                        } else {
1474
+                            $boucles[$id]->type_requete = false;
1475
+                            $boucle = $boucles[$id];
1476
+                            $x = (!$boucle->sql_serveur ? '' :
1477
+                                    ($boucle->sql_serveur . ':')) .
1478
+                                $type;
1479
+                            $msg = [
1480
+                                'zbug_table_inconnue',
1481
+                                ['table' => $x]
1482
+                            ];
1483
+                            erreur_squelette($msg, $boucle);
1484
+                        }
1485
+                    }
1486
+                }
1487
+            }
1488
+        }
1489
+    }
1490
+
1491
+    // Commencer par reperer les boucles appelees explicitement
1492
+    // car elles indexent les arguments de maniere derogatoire
1493
+    foreach ($boucles as $id => $boucle) {
1494
+        if ($boucle->type_requete == TYPE_RECURSIF and $boucle->param) {
1495
+            $boucles[$id]->descr = &$descr;
1496
+            $rec = &$boucles[$boucle->param[0]];
1497
+            if (!$rec) {
1498
+                $msg = [
1499
+                    'zbug_boucle_recursive_undef',
1500
+                    ['nom' => $boucle->param[0]]
1501
+                ];
1502
+                erreur_squelette($msg, $boucle);
1503
+                $boucles[$id]->type_requete = false;
1504
+            } else {
1505
+                $rec->externe = $id;
1506
+                $descr['id_mere'] = $id;
1507
+                $boucles[$id]->return =
1508
+                    calculer_liste(
1509
+                        [$rec],
1510
+                        $descr,
1511
+                        $boucles,
1512
+                        $boucle->param
1513
+                    );
1514
+            }
1515
+        }
1516
+    }
1517
+    foreach ($boucles as $id => $boucle) {
1518
+        $id = strval($id); // attention au type dans index_pile
1519
+        $type = $boucle->type_requete;
1520
+        if ($type and $type != TYPE_RECURSIF) {
1521
+            $res = '';
1522
+            if ($boucle->param) {
1523
+                // retourne un tableau en cas d'erreur
1524
+                $res = calculer_criteres($id, $boucles);
1525
+            }
1526
+            $descr['id_mere'] = $id;
1527
+            $boucles[$id]->return =
1528
+                calculer_liste(
1529
+                    $boucle->milieu,
1530
+                    $descr,
1531
+                    $boucles,
1532
+                    $id
1533
+                );
1534
+            // Si les criteres se sont mal compiles
1535
+            // ne pas tenter d'assembler le code final
1536
+            // (mais compiler le corps pour detection d'erreurs)
1537
+            if (is_array($res)) {
1538
+                $boucles[$id]->type_requete = false;
1539
+            }
1540
+        }
1541
+    }
1542
+
1543
+    // idem pour la racine
1544
+    $descr['id_mere'] = '';
1545
+    $corps = calculer_liste($squelette, $descr, $boucles);
1546
+
1547
+
1548
+    // Calcul du corps de toutes les fonctions PHP,
1549
+    // en particulier les requetes SQL et TOTAL_BOUCLE
1550
+    // de'terminables seulement maintenant
1551
+
1552
+    foreach ($boucles as $id => $boucle) {
1553
+        $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle);
1554
+        if ($boucle->return === false) {
1555
+            $corps = false;
1556
+            continue;
1557
+        }
1558
+        // appeler la fonction de definition de la boucle
1559
+
1560
+        if ($req = $boucle->type_requete) {
1561
+            // boucle personnalisée ?
1562
+            $table = strtoupper($boucle->type_requete);
1563
+            $serveur = strtolower($boucle->sql_serveur);
1564
+            if (
1565
+                // fonction de boucle avec serveur & table
1566
+                (!$serveur or
1567
+                    ((!function_exists($f = 'boucle_' . $serveur . '_' . $table))
1568
+                        and (!function_exists($f = $f . '_dist'))
1569
+                    )
1570
+                )
1571
+                // fonction de boucle avec table
1572
+                and (!function_exists($f = 'boucle_' . $table))
1573
+                and (!function_exists($f = $f . '_dist'))
1574
+            ) {
1575
+                // fonction de boucle standard
1576
+                if (!function_exists($f = 'boucle_DEFAUT')) {
1577
+                    $f = 'boucle_DEFAUT_dist';
1578
+                }
1579
+            }
1580
+
1581
+            $req = "\n\n\tstatic \$command = array();\n\t" .
1582
+                "static \$connect;\n\t" .
1583
+                "\$command['connect'] = \$connect = " .
1584
+                _q($boucle->sql_serveur) .
1585
+                ';' .
1586
+                $f($id, $boucles);
1587
+        } else {
1588
+            $req = ("\n\treturn '';");
1589
+        }
1590
+
1591
+        $boucles[$id]->return =
1592
+            "\n\nfunction BOUCLE" . strtr($id, '-', '_') . $nom .
1593
+            '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
1594
+            $req .
1595
+            "\n}\n";
1596
+    }
1597
+
1598
+    // Au final, si le corps ou un critere au moins s'est mal compile
1599
+    // retourner False, sinon inserer leur decompilation
1600
+    if (is_bool($corps)) {
1601
+        return false;
1602
+    }
1603
+
1604
+    $principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons = array(), $Numrows = array(), $SP = 0) {
1605 1605
 '
1606
-		// reporter de maniere securisee les doublons inclus
1607
-		. '
1606
+        // reporter de maniere securisee les doublons inclus
1607
+        . '
1608 1608
 	if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"]))
1609 1609
 		$doublons = nettoyer_env_doublons($Pile[0]["doublons"]);
1610 1610
 
1611 1611
 	$connect = ' .
1612
-		_q($connect) . ';
1612
+        _q($connect) . ';
1613 1613
 	$page = ' .
1614
-		// ATTENTION, le calcul de l'expression $corps affectera $Cache
1615
-		// c'est pourquoi on l'affecte a la variable auxiliaire $page.
1616
-		// avant de referencer $Cache
1617
-		$corps . ';
1614
+        // ATTENTION, le calcul de l'expression $corps affectera $Cache
1615
+        // c'est pourquoi on l'affecte a la variable auxiliaire $page.
1616
+        // avant de referencer $Cache
1617
+        $corps . ';
1618 1618
 
1619 1619
 	return analyse_resultat_skel(' . var_export($nom, true)
1620
-		. ', $Cache, $page, ' . var_export($sourcefile, true) . ');
1620
+        . ', $Cache, $page, ' . var_export($sourcefile, true) . ');
1621 1621
 }';
1622 1622
 
1623
-	$secondes = spip_timer('calcul_skel');
1624
-	spip_log("COMPIL ($secondes) [$sourcefile] $nom.php");
1625
-	// $connect n'est pas sûr : on nettoie
1626
-	$connect = preg_replace(',[^\w],', '', $connect);
1623
+    $secondes = spip_timer('calcul_skel');
1624
+    spip_log("COMPIL ($secondes) [$sourcefile] $nom.php");
1625
+    // $connect n'est pas sûr : on nettoie
1626
+    $connect = preg_replace(',[^\w],', '', $connect);
1627 1627
 
1628
-	// Assimiler la fct principale a une boucle anonyme, pour retourner un resultat simple
1629
-	$code = new Boucle();
1630
-	$code->descr = $descr;
1631
-	$code->return = '
1628
+    // Assimiler la fct principale a une boucle anonyme, pour retourner un resultat simple
1629
+    $code = new Boucle();
1630
+    $code->descr = $descr;
1631
+    $code->return = '
1632 1632
 //
1633 1633
 // Fonction principale du squelette ' .
1634
-		$sourcefile .
1635
-		($connect ? " pour $connect" : '') .
1636
-		(!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
1637
-		"\n//\n" .
1638
-		$principal;
1634
+        $sourcefile .
1635
+        ($connect ? " pour $connect" : '') .
1636
+        (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
1637
+        "\n//\n" .
1638
+        $principal;
1639 1639
 
1640
-	$boucles[''] = $code;
1640
+    $boucles[''] = $code;
1641 1641
 
1642
-	return $boucles;
1642
+    return $boucles;
1643 1643
 }
1644 1644
 
1645 1645
 
@@ -1656,18 +1656,18 @@  discard block
 block discarded – undo
1656 1656
  *
1657 1657
  **/
1658 1658
 function requeteur_php_dist(&$boucles, &$boucle, &$id) {
1659
-	if (class_exists($boucle->type_requete)) {
1660
-		$g = charger_fonction('php', 'iterateur');
1661
-		$boucles[$id] = $g($boucle, $boucle->type_requete);
1662
-	} else {
1663
-		$x = $boucle->type_requete;
1664
-		$boucle->type_requete = false;
1665
-		$msg = [
1666
-			'zbug_iterateur_inconnu',
1667
-			['iterateur' => $x]
1668
-		];
1669
-		erreur_squelette($msg, $boucle);
1670
-	}
1659
+    if (class_exists($boucle->type_requete)) {
1660
+        $g = charger_fonction('php', 'iterateur');
1661
+        $boucles[$id] = $g($boucle, $boucle->type_requete);
1662
+    } else {
1663
+        $x = $boucle->type_requete;
1664
+        $boucle->type_requete = false;
1665
+        $msg = [
1666
+            'zbug_iterateur_inconnu',
1667
+            ['iterateur' => $x]
1668
+        ];
1669
+        erreur_squelette($msg, $boucle);
1670
+    }
1671 1671
 }
1672 1672
 
1673 1673
 
@@ -1685,22 +1685,22 @@  discard block
 block discarded – undo
1685 1685
  *
1686 1686
  **/
1687 1687
 function requeteur_data_dist(&$boucles, &$boucle, &$id) {
1688
-	include_spip('iterateur/data');
1689
-	if ($h = charger_fonction($boucle->type_requete . '_to_array', 'inc', true)) {
1690
-		$g = charger_fonction('data', 'iterateur');
1691
-		$boucles[$id] = $g($boucle);
1692
-		// from[0] stocke le type de data (rss, yql, ...)
1693
-		$boucles[$id]->from[] = $boucle->type_requete;
1694
-	} else {
1695
-		$x = $boucle->type_requete;
1696
-		$boucle->type_requete = false;
1697
-		$msg = [
1698
-			'zbug_requeteur_inconnu',
1699
-			[
1700
-				'requeteur' => 'data',
1701
-				'type' => $x
1702
-			]
1703
-		];
1704
-		erreur_squelette($msg, $boucle);
1705
-	}
1688
+    include_spip('iterateur/data');
1689
+    if ($h = charger_fonction($boucle->type_requete . '_to_array', 'inc', true)) {
1690
+        $g = charger_fonction('data', 'iterateur');
1691
+        $boucles[$id] = $g($boucle);
1692
+        // from[0] stocke le type de data (rss, yql, ...)
1693
+        $boucles[$id]->from[] = $boucle->type_requete;
1694
+    } else {
1695
+        $x = $boucle->type_requete;
1696
+        $boucle->type_requete = false;
1697
+        $msg = [
1698
+            'zbug_requeteur_inconnu',
1699
+            [
1700
+                'requeteur' => 'data',
1701
+                'type' => $x
1702
+            ]
1703
+        ];
1704
+        erreur_squelette($msg, $boucle);
1705
+    }
1706 1706
 }
Please login to merge, or discard this patch.
ecrire/public/sandbox.php 1 patch
Indentation   +99 added lines, -99 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@  discard block
 block discarded – undo
23 23
  **/
24 24
 
25 25
 if (!defined('_ECRIRE_INC_VERSION')) {
26
-	return;
26
+    return;
27 27
 }
28 28
 
29 29
 /**
@@ -41,9 +41,9 @@  discard block
 block discarded – undo
41 41
  *     Texte
42 42
  */
43 43
 function sandbox_composer_texte($texte, &$p) {
44
-	$code = "'" . str_replace(['\\', "'"], ['\\\\', "\\'"], $texte) . "'";
44
+    $code = "'" . str_replace(['\\', "'"], ['\\\\', "\\'"], $texte) . "'";
45 45
 
46
-	return $code;
46
+    return $code;
47 47
 }
48 48
 
49 49
 
@@ -59,42 +59,42 @@  discard block
 block discarded – undo
59 59
  * @return string
60 60
  */
61 61
 function sandbox_composer_filtre($fonc, $code, $arglist, &$p, $nb_arg_droite = 1000): string {
62
-	if (isset($GLOBALS['spip_matrice'][$fonc])) {
63
-		$code = "filtrer('$fonc',$code$arglist)";
64
-	}
65
-
66
-	// le filtre est defini sous forme de fonction ou de methode
67
-	// par ex. dans inc_texte, inc_filtres ou mes_fonctions
68
-	elseif ($f = chercher_filtre($fonc)) {
69
-		// cas particulier : le filtre |set doit acceder a la $Pile
70
-		// proto: filtre_set(&$Pile, $val, $args...)
71
-		if (strpbrk($f, ':')) { // Class::method
72
-			$refl = new ReflectionMethod($f);
73
-		} else {
74
-			$refl = new ReflectionFunction($f);
75
-		}
76
-		$refs = $refl->getParameters();
77
-		if (isset($refs[0]) and $refs[0]->name == 'Pile') {
78
-			$code = "$f(\$Pile,$code$arglist)";
79
-			$nb_arg_gauche = 2; // la balise à laquelle s'applique le filtre + $Pile
80
-		} else {
81
-			$code = "$f($code$arglist)";
82
-			$nb_arg_gauche = 1; // la balise à laquelle s'applique le filtre
83
-		}
84
-		$nb_args_f = $nb_arg_gauche + $nb_arg_droite;
85
-		$min_f = $refl->getNumberOfRequiredParameters();
86
-		if (($nb_args_f < $min_f)) {
87
-			$msg_args = ['filtre' => texte_script($fonc), 'nb' => $min_f - $nb_args_f];
88
-			erreur_squelette([ 'zbug_erreur_filtre_nbarg_min', $msg_args], $p);
89
-		}
90
-	}
91
-	// le filtre n'existe pas,
92
-	// on le notifie
93
-	else {
94
-		erreur_squelette(['zbug_erreur_filtre', ['filtre' => texte_script($fonc)]], $p);
95
-	}
96
-
97
-	return $code;
62
+    if (isset($GLOBALS['spip_matrice'][$fonc])) {
63
+        $code = "filtrer('$fonc',$code$arglist)";
64
+    }
65
+
66
+    // le filtre est defini sous forme de fonction ou de methode
67
+    // par ex. dans inc_texte, inc_filtres ou mes_fonctions
68
+    elseif ($f = chercher_filtre($fonc)) {
69
+        // cas particulier : le filtre |set doit acceder a la $Pile
70
+        // proto: filtre_set(&$Pile, $val, $args...)
71
+        if (strpbrk($f, ':')) { // Class::method
72
+            $refl = new ReflectionMethod($f);
73
+        } else {
74
+            $refl = new ReflectionFunction($f);
75
+        }
76
+        $refs = $refl->getParameters();
77
+        if (isset($refs[0]) and $refs[0]->name == 'Pile') {
78
+            $code = "$f(\$Pile,$code$arglist)";
79
+            $nb_arg_gauche = 2; // la balise à laquelle s'applique le filtre + $Pile
80
+        } else {
81
+            $code = "$f($code$arglist)";
82
+            $nb_arg_gauche = 1; // la balise à laquelle s'applique le filtre
83
+        }
84
+        $nb_args_f = $nb_arg_gauche + $nb_arg_droite;
85
+        $min_f = $refl->getNumberOfRequiredParameters();
86
+        if (($nb_args_f < $min_f)) {
87
+            $msg_args = ['filtre' => texte_script($fonc), 'nb' => $min_f - $nb_args_f];
88
+            erreur_squelette([ 'zbug_erreur_filtre_nbarg_min', $msg_args], $p);
89
+        }
90
+    }
91
+    // le filtre n'existe pas,
92
+    // on le notifie
93
+    else {
94
+        erreur_squelette(['zbug_erreur_filtre', ['filtre' => texte_script($fonc)]], $p);
95
+    }
96
+
97
+    return $code;
98 98
 }
99 99
 
100 100
 // Calculer un <INCLURE(xx.php)>
@@ -117,15 +117,15 @@  discard block
 block discarded – undo
117 117
  * @return string
118 118
  */
119 119
 function sandbox_composer_inclure_php($fichier, &$p, $_contexte) {
120
-	$compil = texte_script(memoriser_contexte_compil($p));
121
-	// si inexistant, on essaiera a l'execution
122
-	if ($path = find_in_path($fichier)) {
123
-		$path = "\"$path\"";
124
-	} else {
125
-		$path = "find_in_path(\"$fichier\")";
126
-	}
127
-
128
-	return sprintf(CODE_INCLURE_SCRIPT, $path, $fichier, $compil, $_contexte);
120
+    $compil = texte_script(memoriser_contexte_compil($p));
121
+    // si inexistant, on essaiera a l'execution
122
+    if ($path = find_in_path($fichier)) {
123
+        $path = "\"$path\"";
124
+    } else {
125
+        $path = "find_in_path(\"$fichier\")";
126
+    }
127
+
128
+    return sprintf(CODE_INCLURE_SCRIPT, $path, $fichier, $compil, $_contexte);
129 129
 }
130 130
 
131 131
 /**
@@ -137,20 +137,20 @@  discard block
 block discarded – undo
137 137
  * @return string
138 138
  */
139 139
 function sandbox_composer_interdire_scripts($code, &$p) {
140
-	// Securite
141
-	if (
142
-		$p->interdire_scripts
143
-		and $p->etoile != '**'
144
-	) {
145
-		if (!preg_match("/^sinon[(](.*),'([^']*)'[)]$/", $code, $r)) {
146
-			$code = "interdire_scripts($code)";
147
-		} else {
148
-			$code = interdire_scripts($r[2]);
149
-			$code = "sinon(interdire_scripts($r[1]),'$code')";
150
-		}
151
-	}
152
-
153
-	return $code;
140
+    // Securite
141
+    if (
142
+        $p->interdire_scripts
143
+        and $p->etoile != '**'
144
+    ) {
145
+        if (!preg_match("/^sinon[(](.*),'([^']*)'[)]$/", $code, $r)) {
146
+            $code = "interdire_scripts($code)";
147
+        } else {
148
+            $code = interdire_scripts($r[2]);
149
+            $code = "sinon(interdire_scripts($r[1]),'$code')";
150
+        }
151
+    }
152
+
153
+    return $code;
154 154
 }
155 155
 
156 156
 
@@ -169,30 +169,30 @@  discard block
 block discarded – undo
169 169
  * @return mixed|string
170 170
  */
171 171
 function sandbox_filtrer_squelette($skel, $corps, $filtres) {
172
-	$series_filtres = func_get_args();
173
-	array_shift($series_filtres);// skel
174
-	array_shift($series_filtres);// corps
175
-
176
-	// proteger les <INCLUDE> et tous les morceaux de php licites
177
-	if ($skel['process_ins'] == 'php') {
178
-		$corps = preg_replace_callback(',<[?](\s|php|=).*[?]>,UimsS', 'echapper_php_callback', $corps);
179
-	}
180
-
181
-	// recuperer les couples de remplacement
182
-	$replace = echapper_php_callback();
183
-
184
-	foreach ($series_filtres as $filtres) {
185
-		if (is_countable($filtres) ? count($filtres) : 0) {
186
-			foreach ($filtres as $filtre) {
187
-				if ($filtre and $f = chercher_filtre($filtre)) {
188
-					$corps = $f($corps);
189
-				}
190
-			}
191
-		}
192
-	}
193
-
194
-	// restaurer les echappements
195
-	return str_replace($replace[0], $replace[1], $corps);
172
+    $series_filtres = func_get_args();
173
+    array_shift($series_filtres);// skel
174
+    array_shift($series_filtres);// corps
175
+
176
+    // proteger les <INCLUDE> et tous les morceaux de php licites
177
+    if ($skel['process_ins'] == 'php') {
178
+        $corps = preg_replace_callback(',<[?](\s|php|=).*[?]>,UimsS', 'echapper_php_callback', $corps);
179
+    }
180
+
181
+    // recuperer les couples de remplacement
182
+    $replace = echapper_php_callback();
183
+
184
+    foreach ($series_filtres as $filtres) {
185
+        if (is_countable($filtres) ? count($filtres) : 0) {
186
+            foreach ($filtres as $filtre) {
187
+                if ($filtre and $f = chercher_filtre($filtre)) {
188
+                    $corps = $f($corps);
189
+                }
190
+            }
191
+        }
192
+    }
193
+
194
+    // restaurer les echappements
195
+    return str_replace($replace[0], $replace[1], $corps);
196 196
 }
197 197
 
198 198
 
@@ -211,21 +211,21 @@  discard block
 block discarded – undo
211 211
  *     - array : Liste( liste des codes PHP, liste des substitutions )
212 212
  **/
213 213
 function echapper_php_callback($r = null) {
214
-	static $src = [];
215
-	static $dst = [];
214
+    static $src = [];
215
+    static $dst = [];
216 216
 
217
-	// si on recoit un tableau, on est en mode echappement
218
-	// on enregistre le code a echapper dans dst, et le code echappe dans src
219
-	if (is_array($r)) {
220
-		$dst[] = $r[0];
217
+    // si on recoit un tableau, on est en mode echappement
218
+    // on enregistre le code a echapper dans dst, et le code echappe dans src
219
+    if (is_array($r)) {
220
+        $dst[] = $r[0];
221 221
 
222
-		return $src[] = '___' . md5($r[0]) . '___';
223
-	}
222
+        return $src[] = '___' . md5($r[0]) . '___';
223
+    }
224 224
 
225
-	// si on recoit pas un tableau, on renvoit les couples de substitution
226
-	// et on RAZ les remplacements
227
-	$r = [$src, $dst];
228
-	$src = $dst = [];
225
+    // si on recoit pas un tableau, on renvoit les couples de substitution
226
+    // et on RAZ les remplacements
227
+    $r = [$src, $dst];
228
+    $src = $dst = [];
229 229
 
230
-	return $r;
230
+    return $r;
231 231
 }
Please login to merge, or discard this patch.
ecrire/public/decompiler.php 1 patch
Indentation   +176 added lines, -176 removed lines patch added patch discarded remove patch
@@ -11,129 +11,129 @@  discard block
 block discarded – undo
11 11
 \***************************************************************************/
12 12
 
13 13
 if (!defined('_ECRIRE_INC_VERSION')) {
14
-	return;
14
+    return;
15 15
 }
16 16
 
17 17
 // Decompilation de l'arbre de syntaxe abstraite d'un squelette SPIP
18 18
 
19 19
 function decompiler_boucle($struct, $fmt = '', $prof = 0) {
20
-	$nom = $struct->id_boucle;
21
-	$preaff = decompiler_($struct->preaff, $fmt, $prof);
22
-	$avant = decompiler_($struct->avant, $fmt, $prof);
23
-	$apres = decompiler_($struct->apres, $fmt, $prof);
24
-	$altern = decompiler_($struct->altern, $fmt, $prof);
25
-	$milieu = decompiler_($struct->milieu, $fmt, $prof);
26
-	$postaff = decompiler_($struct->postaff, $fmt, $prof);
27
-
28
-	$type = $struct->sql_serveur ? "$struct->sql_serveur:" : '';
29
-	$type .= ($struct->type_requete ?: $struct->table_optionnelle);
30
-
31
-	if ($struct->jointures_explicites) {
32
-		$type .= ' ' . $struct->jointures_explicites;
33
-	}
34
-	if ($struct->table_optionnelle) {
35
-		$type .= '?';
36
-	}
37
-	// Revoir le cas de la boucle recursive
38
-
39
-	$crit = $struct->param;
40
-	if ($crit and !is_array($crit[0])) {
41
-		$type = strtolower($type) . array_shift($crit);
42
-	}
43
-	$crit = decompiler_criteres($struct, $fmt, $prof);
44
-
45
-	$f = 'format_boucle_' . $fmt;
46
-
47
-	return $f($preaff, $avant, $nom, $type, $crit, $milieu, $apres, $altern, $postaff, $prof);
20
+    $nom = $struct->id_boucle;
21
+    $preaff = decompiler_($struct->preaff, $fmt, $prof);
22
+    $avant = decompiler_($struct->avant, $fmt, $prof);
23
+    $apres = decompiler_($struct->apres, $fmt, $prof);
24
+    $altern = decompiler_($struct->altern, $fmt, $prof);
25
+    $milieu = decompiler_($struct->milieu, $fmt, $prof);
26
+    $postaff = decompiler_($struct->postaff, $fmt, $prof);
27
+
28
+    $type = $struct->sql_serveur ? "$struct->sql_serveur:" : '';
29
+    $type .= ($struct->type_requete ?: $struct->table_optionnelle);
30
+
31
+    if ($struct->jointures_explicites) {
32
+        $type .= ' ' . $struct->jointures_explicites;
33
+    }
34
+    if ($struct->table_optionnelle) {
35
+        $type .= '?';
36
+    }
37
+    // Revoir le cas de la boucle recursive
38
+
39
+    $crit = $struct->param;
40
+    if ($crit and !is_array($crit[0])) {
41
+        $type = strtolower($type) . array_shift($crit);
42
+    }
43
+    $crit = decompiler_criteres($struct, $fmt, $prof);
44
+
45
+    $f = 'format_boucle_' . $fmt;
46
+
47
+    return $f($preaff, $avant, $nom, $type, $crit, $milieu, $apres, $altern, $postaff, $prof);
48 48
 }
49 49
 
50 50
 function decompiler_include($struct, $fmt = '', $prof = 0) {
51
-	$res = [];
52
-	foreach ($struct->param ?: [] as $couple) {
53
-		array_shift($couple);
54
-		foreach ($couple as $v) {
55
-			$res[] = decompiler_($v, $fmt, $prof);
56
-		}
57
-	}
58
-	$file = is_string($struct->texte) ? $struct->texte :
59
-		decompiler_($struct->texte, $fmt, $prof);
60
-	$f = 'format_inclure_' . $fmt;
61
-
62
-	return $f($file, $res, $prof);
51
+    $res = [];
52
+    foreach ($struct->param ?: [] as $couple) {
53
+        array_shift($couple);
54
+        foreach ($couple as $v) {
55
+            $res[] = decompiler_($v, $fmt, $prof);
56
+        }
57
+    }
58
+    $file = is_string($struct->texte) ? $struct->texte :
59
+        decompiler_($struct->texte, $fmt, $prof);
60
+    $f = 'format_inclure_' . $fmt;
61
+
62
+    return $f($file, $res, $prof);
63 63
 }
64 64
 
65 65
 function decompiler_texte($struct, $fmt = '', $prof = 0) {
66
-	$f = 'format_texte_' . $fmt;
66
+    $f = 'format_texte_' . $fmt;
67 67
 
68
-	return strlen($struct->texte) ? $f($struct->texte, $prof) : '';
68
+    return strlen($struct->texte) ? $f($struct->texte, $prof) : '';
69 69
 }
70 70
 
71 71
 function decompiler_polyglotte($struct, $fmt = '', $prof = 0) {
72
-	$f = 'format_polyglotte_' . $fmt;
72
+    $f = 'format_polyglotte_' . $fmt;
73 73
 
74
-	return $f($struct->traductions, $prof);
74
+    return $f($struct->traductions, $prof);
75 75
 }
76 76
 
77 77
 function decompiler_idiome($struct, $fmt = '', $prof = 0) {
78
-	$args = [];
79
-	foreach ($struct->arg as $k => $v) {
80
-		$args[$k] = public_decompiler($v, $fmt, $prof);
81
-	}
78
+    $args = [];
79
+    foreach ($struct->arg as $k => $v) {
80
+        $args[$k] = public_decompiler($v, $fmt, $prof);
81
+    }
82 82
 
83
-	$filtres = decompiler_liste($struct->param, $fmt, $prof);
83
+    $filtres = decompiler_liste($struct->param, $fmt, $prof);
84 84
 
85
-	$f = 'format_idiome_' . $fmt;
85
+    $f = 'format_idiome_' . $fmt;
86 86
 
87
-	return $f($struct->nom_champ, $struct->module, $args, $filtres, $prof);
87
+    return $f($struct->nom_champ, $struct->module, $args, $filtres, $prof);
88 88
 }
89 89
 
90 90
 function decompiler_champ($struct, $fmt = '', $prof = 0) {
91
-	$avant = decompiler_($struct->avant, $fmt, $prof);
92
-	$apres = decompiler_($struct->apres, $fmt, $prof);
93
-	$args = $filtres = '';
94
-	if ($p = $struct->param) {
95
-		if ($p[0][0] === '') {
96
-			$args = decompiler_liste([array_shift($p)], $fmt, $prof);
97
-		}
98
-		$filtres = decompiler_liste($p, $fmt, $prof);
99
-	}
100
-	$f = 'format_champ_' . $fmt;
101
-
102
-	return $f($struct->nom_champ, $struct->nom_boucle, $struct->etoile, $avant, $apres, $args, $filtres, $prof);
91
+    $avant = decompiler_($struct->avant, $fmt, $prof);
92
+    $apres = decompiler_($struct->apres, $fmt, $prof);
93
+    $args = $filtres = '';
94
+    if ($p = $struct->param) {
95
+        if ($p[0][0] === '') {
96
+            $args = decompiler_liste([array_shift($p)], $fmt, $prof);
97
+        }
98
+        $filtres = decompiler_liste($p, $fmt, $prof);
99
+    }
100
+    $f = 'format_champ_' . $fmt;
101
+
102
+    return $f($struct->nom_champ, $struct->nom_boucle, $struct->etoile, $avant, $apres, $args, $filtres, $prof);
103 103
 }
104 104
 
105 105
 function decompiler_liste($sources, $fmt = '', $prof = 0) {
106
-	if (!is_array($sources)) {
107
-		return '';
108
-	}
109
-	$f = 'format_liste_' . $fmt;
110
-	$res = '';
111
-	foreach ($sources as $arg) {
112
-		if (!is_array($arg)) {
113
-			continue; // ne devrait pas arriver.
114
-		} else {
115
-			$r = array_shift($arg);
116
-		}
117
-		$args = [];
118
-		foreach ($arg as $v) {
119
-			// cas des arguments entoures de ' ou "
120
-			if (
121
-				((is_countable($v) ? count($v) : 0) == 1)
122
-				and $v[0]->type == 'texte'
123
-				and (strlen($v[0]->apres) == 1)
124
-				and $v[0]->apres == $v[0]->avant
125
-			) {
126
-				$args[] = $v[0]->avant . $v[0]->texte . $v[0]->apres;
127
-			} else {
128
-				$args[] = decompiler_($v, $fmt, 0 - $prof);
129
-			}
130
-		}
131
-		if (($r !== '') or $args) {
132
-			$res .= $f($r, $args, $prof);
133
-		}
134
-	}
135
-
136
-	return $res;
106
+    if (!is_array($sources)) {
107
+        return '';
108
+    }
109
+    $f = 'format_liste_' . $fmt;
110
+    $res = '';
111
+    foreach ($sources as $arg) {
112
+        if (!is_array($arg)) {
113
+            continue; // ne devrait pas arriver.
114
+        } else {
115
+            $r = array_shift($arg);
116
+        }
117
+        $args = [];
118
+        foreach ($arg as $v) {
119
+            // cas des arguments entoures de ' ou "
120
+            if (
121
+                ((is_countable($v) ? count($v) : 0) == 1)
122
+                and $v[0]->type == 'texte'
123
+                and (strlen($v[0]->apres) == 1)
124
+                and $v[0]->apres == $v[0]->avant
125
+            ) {
126
+                $args[] = $v[0]->avant . $v[0]->texte . $v[0]->apres;
127
+            } else {
128
+                $args[] = decompiler_($v, $fmt, 0 - $prof);
129
+            }
130
+        }
131
+        if (($r !== '') or $args) {
132
+            $res .= $f($r, $args, $prof);
133
+        }
134
+    }
135
+
136
+    return $res;
137 137
 }
138 138
 
139 139
 // Decompilation des criteres: on triche et on deroge:
@@ -141,93 +141,93 @@  discard block
 block discarded – undo
141 141
 // - le champ apres signale le critere {"separateur"} ou {'separateur'}
142 142
 // - les champs sont implicitement etendus (crochets implicites mais interdits)
143 143
 function decompiler_criteres($boucle, $fmt = '', $prof = 0) {
144
-	$sources = $boucle->param;
145
-	if (!is_array($sources)) {
146
-		return '';
147
-	}
148
-	$res = '';
149
-	$f = 'format_critere_' . $fmt;
150
-	foreach ($sources as $crit) {
151
-		if (!is_array($crit)) {
152
-			continue;
153
-		} // boucle recursive
154
-		array_shift($crit);
155
-		$args = [];
156
-		foreach ($crit as $i => $v) {
157
-			if (
158
-				((is_countable($v) ? count($v) : 0) == 1)
159
-				and $v[0]->type == 'texte'
160
-				and $v[0]->apres
161
-			) {
162
-				$args[] = [['texte', ($v[0]->apres . $v[0]->texte . $v[0]->apres)]];
163
-			} else {
164
-				$res2 = [];
165
-				foreach ($v as $k => $p) {
166
-					if (
167
-						isset($p->type)
168
-						and function_exists($d = 'decompiler_' . $p->type)
169
-					) {
170
-						$r = $d($p, $fmt, (0 - $prof), @$v[$k + 1]);
171
-						$res2[] = [$p->type, $r];
172
-					} else {
173
-						spip_log("critere $i / $k mal forme");
174
-					}
175
-				}
176
-				$args[] = $res2;
177
-			}
178
-		}
179
-		$res .= $f($args);
180
-	}
181
-
182
-	return $res;
144
+    $sources = $boucle->param;
145
+    if (!is_array($sources)) {
146
+        return '';
147
+    }
148
+    $res = '';
149
+    $f = 'format_critere_' . $fmt;
150
+    foreach ($sources as $crit) {
151
+        if (!is_array($crit)) {
152
+            continue;
153
+        } // boucle recursive
154
+        array_shift($crit);
155
+        $args = [];
156
+        foreach ($crit as $i => $v) {
157
+            if (
158
+                ((is_countable($v) ? count($v) : 0) == 1)
159
+                and $v[0]->type == 'texte'
160
+                and $v[0]->apres
161
+            ) {
162
+                $args[] = [['texte', ($v[0]->apres . $v[0]->texte . $v[0]->apres)]];
163
+            } else {
164
+                $res2 = [];
165
+                foreach ($v as $k => $p) {
166
+                    if (
167
+                        isset($p->type)
168
+                        and function_exists($d = 'decompiler_' . $p->type)
169
+                    ) {
170
+                        $r = $d($p, $fmt, (0 - $prof), @$v[$k + 1]);
171
+                        $res2[] = [$p->type, $r];
172
+                    } else {
173
+                        spip_log("critere $i / $k mal forme");
174
+                    }
175
+                }
176
+                $args[] = $res2;
177
+            }
178
+        }
179
+        $res .= $f($args);
180
+    }
181
+
182
+    return $res;
183 183
 }
184 184
 
185 185
 
186 186
 function decompiler_($liste, $fmt = '', $prof = 0) {
187
-	if (!is_array($liste)) {
188
-		return '';
189
-	}
190
-	$prof2 = ($prof < 0) ? ($prof - 1) : ($prof + 1);
191
-	$contenu = [];
192
-	foreach ($liste as $k => $p) {
193
-		if (!isset($p->type)) {
194
-			continue;
195
-		} #??????
196
-		$d = 'decompiler_' . $p->type;
197
-		$next = $liste[$k + 1] ?? false;
198
-		// Forcer le champ etendu si son source (pas les reecritures)
199
-		// contenait des args et s'il est suivi d'espaces,
200
-		// le champ simple les eliminant est un bug helas perenne.
201
-
202
-		if (
203
-			$next
204
-			and ($next->type == 'texte')
205
-			and $p->type == 'champ'
206
-			and !$p->apres
207
-			and !$p->avant
208
-			and $p->fonctions
209
-		) {
210
-			$n = strlen($next->texte) - strlen(ltrim($next->texte));
211
-			if ($n) {
212
-				$champ = new Texte();
213
-				$champ->texte = substr($next->texte, 0, $n);
214
-				$champ->ligne = $p->ligne;
215
-				$p->apres = [$champ];
216
-				$next->texte = substr($next->texte, $n);
217
-			}
218
-		}
219
-		$contenu[] = [$d($p, $fmt, $prof2), $p->type];
220
-	}
221
-	$f = 'format_suite_' . $fmt;
222
-
223
-	return $f($contenu);
187
+    if (!is_array($liste)) {
188
+        return '';
189
+    }
190
+    $prof2 = ($prof < 0) ? ($prof - 1) : ($prof + 1);
191
+    $contenu = [];
192
+    foreach ($liste as $k => $p) {
193
+        if (!isset($p->type)) {
194
+            continue;
195
+        } #??????
196
+        $d = 'decompiler_' . $p->type;
197
+        $next = $liste[$k + 1] ?? false;
198
+        // Forcer le champ etendu si son source (pas les reecritures)
199
+        // contenait des args et s'il est suivi d'espaces,
200
+        // le champ simple les eliminant est un bug helas perenne.
201
+
202
+        if (
203
+            $next
204
+            and ($next->type == 'texte')
205
+            and $p->type == 'champ'
206
+            and !$p->apres
207
+            and !$p->avant
208
+            and $p->fonctions
209
+        ) {
210
+            $n = strlen($next->texte) - strlen(ltrim($next->texte));
211
+            if ($n) {
212
+                $champ = new Texte();
213
+                $champ->texte = substr($next->texte, 0, $n);
214
+                $champ->ligne = $p->ligne;
215
+                $p->apres = [$champ];
216
+                $next->texte = substr($next->texte, $n);
217
+            }
218
+        }
219
+        $contenu[] = [$d($p, $fmt, $prof2), $p->type];
220
+    }
221
+    $f = 'format_suite_' . $fmt;
222
+
223
+    return $f($contenu);
224 224
 }
225 225
 
226 226
 function public_decompiler($liste, $fmt = '', $prof = 0, $quoi = '') {
227
-	if (!include_spip('public/format_' . $fmt)) {
228
-		return "'$fmt'?";
229
-	}
230
-	$f = 'decompiler_' . $quoi;
227
+    if (!include_spip('public/format_' . $fmt)) {
228
+        return "'$fmt'?";
229
+    }
230
+    $f = 'decompiler_' . $quoi;
231 231
 
232
-	return $f($liste, $fmt, $prof);
232
+    return $f($liste, $fmt, $prof);
233 233
 }
Please login to merge, or discard this patch.
ecrire/public/composer.php 1 patch
Indentation   +760 added lines, -760 removed lines patch added patch discarded remove patch
@@ -18,7 +18,7 @@  discard block
 block discarded – undo
18 18
  **/
19 19
 
20 20
 if (!defined('_ECRIRE_INC_VERSION')) {
21
-	return;
21
+    return;
22 22
 }
23 23
 
24 24
 include_spip('inc/texte');
@@ -43,236 +43,236 @@  discard block
 block discarded – undo
43 43
 // https://code.spip.net/@public_composer_dist
44 44
 function public_composer_dist($squelette, $mime_type, $gram, $source, string $connect = '') {
45 45
 
46
-	$skel = null;
47
-	$boucle = null;
48
-	$nom = calculer_nom_fonction_squel($squelette, $mime_type, $connect);
49
-
50
-	//  si deja en memoire (INCLURE  a repetition) c'est bon.
51
-	if (function_exists($nom)) {
52
-		return $nom;
53
-	}
54
-
55
-	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
56
-		$GLOBALS['debug_objets']['courant'] = $nom;
57
-	}
58
-
59
-	$phpfile = sous_repertoire(_DIR_SKELS, '', false, true) . $nom . '.php';
60
-
61
-	// si squelette est deja compile et perenne, le charger
62
-	if (!squelette_obsolete($phpfile, $source)) {
63
-		include_once $phpfile;
64
-		#if (!squelette_obsolete($phpfile, $source)
65
-		#  AND lire_fichier ($phpfile, $skel_code,
66
-		#  array('critique' => 'oui', 'phpcheck' => 'oui'))){
67
-		## eval('?'.'>'.$skel_code);
68
-		#	 spip_log($skel_code, 'comp')
69
-		#}
70
-	}
71
-
72
-	if (file_exists($lib = $squelette . '_fonctions' . '.php')) {
73
-		include_once $lib;
74
-	}
75
-
76
-	// tester si le eval ci-dessus a mis le squelette en memoire
77
-
78
-	if (function_exists($nom)) {
79
-		return $nom;
80
-	}
81
-
82
-	// charger le source, si possible, et compiler
83
-	$skel_code = '';
84
-	if (lire_fichier($source, $skel)) {
85
-		$compiler = charger_fonction('compiler', 'public');
86
-		$skel_code = $compiler($skel, $nom, $gram, $source, $connect);
87
-	}
88
-
89
-	// Ne plus rien faire si le compilateur n'a pas pu operer.
90
-	if (!$skel_code) {
91
-		return false;
92
-	}
93
-
94
-	foreach ($skel_code as $id => $boucle) {
95
-		$f = $boucle->return;
96
-		try {
97
-			eval("return true; $f ;");
98
-		} catch (\ParseError $e) {
99
-			// Code syntaxiquement faux (critere etc mal programme')
100
-			$msg = _T('zbug_erreur_compilation') . ' | Line ' . $e->getLine() . ' : ' . $e->getMessage();
101
-			erreur_squelette($msg, $boucle);
102
-			// continuer pour trouver d'autres fautes eventuelles
103
-			// mais prevenir que c'est mort
104
-			$nom = '';
105
-		}
106
-
107
-		// Contexte de compil inutile a present
108
-		// (mais la derniere valeur de $boucle est utilisee ci-dessous)
109
-		$skel_code[$id] = $f;
110
-	}
111
-
112
-	$code = '';
113
-	if ($nom) {
114
-		// Si le code est bon, concatener et mettre en cache
115
-		if (function_exists($nom)) {
116
-			$code = squelette_traduit($skel, $source, $phpfile, $skel_code);
117
-		} else {
118
-			// code semantiquement faux: bug du compilateur
119
-			// $boucle est en fait ici la fct principale du squelette
120
-			$msg = _T('zbug_erreur_compilation');
121
-			erreur_squelette($msg, $boucle);
122
-			$nom = '';
123
-		}
124
-	}
125
-
126
-	if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
127
-		// Tracer ce qui vient d'etre compile
128
-		$GLOBALS['debug_objets']['code'][$nom . 'tout'] = $code;
129
-
130
-		// si c'est ce que demande le debusqueur, lui passer la main
131
-		if (
132
-			$GLOBALS['debug_objets']['sourcefile']
133
-			and (_request('var_mode_objet') == $nom)
134
-			and (_request('var_mode_affiche') == 'code')
135
-		) {
136
-			erreur_squelette();
137
-		}
138
-	}
139
-
140
-	return $nom ?: false;
46
+    $skel = null;
47
+    $boucle = null;
48
+    $nom = calculer_nom_fonction_squel($squelette, $mime_type, $connect);
49
+
50
+    //  si deja en memoire (INCLURE  a repetition) c'est bon.
51
+    if (function_exists($nom)) {
52
+        return $nom;
53
+    }
54
+
55
+    if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
56
+        $GLOBALS['debug_objets']['courant'] = $nom;
57
+    }
58
+
59
+    $phpfile = sous_repertoire(_DIR_SKELS, '', false, true) . $nom . '.php';
60
+
61
+    // si squelette est deja compile et perenne, le charger
62
+    if (!squelette_obsolete($phpfile, $source)) {
63
+        include_once $phpfile;
64
+        #if (!squelette_obsolete($phpfile, $source)
65
+        #  AND lire_fichier ($phpfile, $skel_code,
66
+        #  array('critique' => 'oui', 'phpcheck' => 'oui'))){
67
+        ## eval('?'.'>'.$skel_code);
68
+        #	 spip_log($skel_code, 'comp')
69
+        #}
70
+    }
71
+
72
+    if (file_exists($lib = $squelette . '_fonctions' . '.php')) {
73
+        include_once $lib;
74
+    }
75
+
76
+    // tester si le eval ci-dessus a mis le squelette en memoire
77
+
78
+    if (function_exists($nom)) {
79
+        return $nom;
80
+    }
81
+
82
+    // charger le source, si possible, et compiler
83
+    $skel_code = '';
84
+    if (lire_fichier($source, $skel)) {
85
+        $compiler = charger_fonction('compiler', 'public');
86
+        $skel_code = $compiler($skel, $nom, $gram, $source, $connect);
87
+    }
88
+
89
+    // Ne plus rien faire si le compilateur n'a pas pu operer.
90
+    if (!$skel_code) {
91
+        return false;
92
+    }
93
+
94
+    foreach ($skel_code as $id => $boucle) {
95
+        $f = $boucle->return;
96
+        try {
97
+            eval("return true; $f ;");
98
+        } catch (\ParseError $e) {
99
+            // Code syntaxiquement faux (critere etc mal programme')
100
+            $msg = _T('zbug_erreur_compilation') . ' | Line ' . $e->getLine() . ' : ' . $e->getMessage();
101
+            erreur_squelette($msg, $boucle);
102
+            // continuer pour trouver d'autres fautes eventuelles
103
+            // mais prevenir que c'est mort
104
+            $nom = '';
105
+        }
106
+
107
+        // Contexte de compil inutile a present
108
+        // (mais la derniere valeur de $boucle est utilisee ci-dessous)
109
+        $skel_code[$id] = $f;
110
+    }
111
+
112
+    $code = '';
113
+    if ($nom) {
114
+        // Si le code est bon, concatener et mettre en cache
115
+        if (function_exists($nom)) {
116
+            $code = squelette_traduit($skel, $source, $phpfile, $skel_code);
117
+        } else {
118
+            // code semantiquement faux: bug du compilateur
119
+            // $boucle est en fait ici la fct principale du squelette
120
+            $msg = _T('zbug_erreur_compilation');
121
+            erreur_squelette($msg, $boucle);
122
+            $nom = '';
123
+        }
124
+    }
125
+
126
+    if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
127
+        // Tracer ce qui vient d'etre compile
128
+        $GLOBALS['debug_objets']['code'][$nom . 'tout'] = $code;
129
+
130
+        // si c'est ce que demande le debusqueur, lui passer la main
131
+        if (
132
+            $GLOBALS['debug_objets']['sourcefile']
133
+            and (_request('var_mode_objet') == $nom)
134
+            and (_request('var_mode_affiche') == 'code')
135
+        ) {
136
+            erreur_squelette();
137
+        }
138
+    }
139
+
140
+    return $nom ?: false;
141 141
 }
142 142
 
143 143
 function squelette_traduit($squelette, $sourcefile, $phpfile, $boucles) {
144 144
 
145
-	$code = null;
146
-	// Le dernier index est '' (fonction principale)
147
-	$noms = substr(join(', ', array_keys($boucles)), 0, -2);
148
-	if (CODE_COMMENTE) {
149
-		$code = "
145
+    $code = null;
146
+    // Le dernier index est '' (fonction principale)
147
+    $noms = substr(join(', ', array_keys($boucles)), 0, -2);
148
+    if (CODE_COMMENTE) {
149
+        $code = "
150 150
 /*
151 151
  * Squelette : $sourcefile
152 152
  * Date :      " . gmdate('D, d M Y H:i:s', @filemtime($sourcefile)) . ' GMT
153 153
  * Compile :   ' . gmdate('D, d M Y H:i:s', time()) . ' GMT
154 154
  * ' . (!$boucles ? 'Pas de boucle' : ('Boucles :   ' . $noms)) . '
155 155
  */ ';
156
-	}
156
+    }
157 157
 
158
-	$code = '<' . "?php\n" . $code . join('', $boucles) . "\n?" . '>';
159
-	if (!defined('_VAR_NOCACHE') or !_VAR_NOCACHE) {
160
-		ecrire_fichier($phpfile, $code);
161
-	}
158
+    $code = '<' . "?php\n" . $code . join('', $boucles) . "\n?" . '>';
159
+    if (!defined('_VAR_NOCACHE') or !_VAR_NOCACHE) {
160
+        ecrire_fichier($phpfile, $code);
161
+    }
162 162
 
163
-	return $code;
163
+    return $code;
164 164
 }
165 165
 
166 166
 // Le squelette compile est-il trop vieux ?
167 167
 // https://code.spip.net/@squelette_obsolete
168 168
 function squelette_obsolete($skel, $squelette) {
169
-	static $date_change = null;
170
-	// ne verifier la date de mes_fonctions et mes_options qu'une seule fois
171
-	// par hit
172
-	if (is_null($date_change)) {
173
-		if (@file_exists($fonc = 'mes_fonctions.php')) {
174
-			$date_change = @filemtime($fonc);
175
-		} # compatibilite
176
-		if (defined('_FILE_OPTIONS')) {
177
-			$date_change = max($date_change, @filemtime(_FILE_OPTIONS));
178
-		}
179
-	}
180
-
181
-	return (
182
-		(defined('_VAR_MODE') and in_array(_VAR_MODE, ['recalcul', 'preview', 'debug']))
183
-		or !@file_exists($skel)
184
-		or ((@file_exists($squelette) ? @filemtime($squelette) : 0)
185
-			> ($date = @filemtime($skel)))
186
-		or ($date_change > $date)
187
-	);
169
+    static $date_change = null;
170
+    // ne verifier la date de mes_fonctions et mes_options qu'une seule fois
171
+    // par hit
172
+    if (is_null($date_change)) {
173
+        if (@file_exists($fonc = 'mes_fonctions.php')) {
174
+            $date_change = @filemtime($fonc);
175
+        } # compatibilite
176
+        if (defined('_FILE_OPTIONS')) {
177
+            $date_change = max($date_change, @filemtime(_FILE_OPTIONS));
178
+        }
179
+    }
180
+
181
+    return (
182
+        (defined('_VAR_MODE') and in_array(_VAR_MODE, ['recalcul', 'preview', 'debug']))
183
+        or !@file_exists($skel)
184
+        or ((@file_exists($squelette) ? @filemtime($squelette) : 0)
185
+            > ($date = @filemtime($skel)))
186
+        or ($date_change > $date)
187
+    );
188 188
 }
189 189
 
190 190
 // Activer l'invalideur de session
191 191
 // https://code.spip.net/@invalideur_session
192 192
 function invalideur_session(&$Cache, $code = null) {
193
-	$Cache['session'] = spip_session();
193
+    $Cache['session'] = spip_session();
194 194
 
195
-	return $code;
195
+    return $code;
196 196
 }
197 197
 
198 198
 
199 199
 // https://code.spip.net/@analyse_resultat_skel
200 200
 function analyse_resultat_skel($nom, $cache, $corps, $source = '') {
201
-	static $filtres = [];
202
-	$headers = [];
203
-
204
-	// Recupere les < ?php header('Xx: y'); ? > pour $page['headers']
205
-	// note: on essaie d'attrapper aussi certains de ces entetes codes
206
-	// "a la main" dans les squelettes, mais evidemment sans exhaustivite
207
-	if (
208
-		stripos($corps, 'header') !== false
209
-		and preg_match_all(
210
-			'/(<[?]php\s+)@?header\s*\(\s*.([^:\'"]*):?\s*([^)]*)[^)]\s*\)\s*[;]?\s*[?]>/ims',
211
-			$corps,
212
-			$regs,
213
-			PREG_SET_ORDER
214
-		)
215
-	) {
216
-		foreach ($regs as $r) {
217
-			$corps = str_replace($r[0], '', $corps);
218
-			# $j = Content-Type, et pas content-TYPE.
219
-			$j = join('-', array_map('ucwords', explode('-', strtolower($r[2]))));
220
-
221
-			if ($j == 'X-Spip-Filtre' and isset($headers[$j])) {
222
-				$headers[$j] .= '|' . $r[3];
223
-			} else {
224
-				$headers[$j] = $r[3];
225
-			}
226
-		}
227
-	}
228
-	// S'agit-il d'un resultat constant ou contenant du code php
229
-	$process_ins = (
230
-		strpos($corps, '<' . '?') === false
231
-		or
232
-		(strpos($corps, '<' . '?xml') !== false and
233
-			strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
234
-	)
235
-		? 'html'
236
-		: 'php';
237
-
238
-	$skel = [
239
-		'squelette' => $nom,
240
-		'source' => $source,
241
-		'process_ins' => $process_ins,
242
-		'invalideurs' => $cache,
243
-		'entetes' => $headers,
244
-		'duree' => isset($headers['X-Spip-Cache']) ? intval($headers['X-Spip-Cache']) : 0
245
-	];
246
-
247
-	// traiter #FILTRE{} et filtres
248
-	if (!isset($filtres[$nom])) {
249
-		$filtres[$nom] = pipeline('declarer_filtres_squelettes', ['args' => $skel, 'data' => []]);
250
-	}
251
-	$filtres_headers = [];
252
-	if (isset($headers['X-Spip-Filtre']) and strlen($headers['X-Spip-Filtre'])) {
253
-		$filtres_headers = array_filter(explode('|', $headers['X-Spip-Filtre']));
254
-		unset($headers['X-Spip-Filtre']);
255
-	}
256
-	if (is_array($filtres[$nom]) || $filtres[$nom] instanceof \Countable ? count($filtres[$nom]) : 0 or count($filtres_headers)) {
257
-		include_spip('public/sandbox');
258
-		$corps = sandbox_filtrer_squelette($skel, $corps, $filtres_headers, $filtres[$nom]);
259
-
260
-		if ($process_ins == 'html') {
261
-			$skel['process_ins'] = (
262
-				strpos($corps, '<' . '?') === false
263
-				or
264
-				(strpos($corps, '<' . '?xml') !== false and
265
-					strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
266
-			)
267
-				? 'html'
268
-				: 'php';
269
-		}
270
-	}
271
-
272
-	$skel['entetes'] = $headers;
273
-	$skel['texte'] = $corps;
274
-
275
-	return $skel;
201
+    static $filtres = [];
202
+    $headers = [];
203
+
204
+    // Recupere les < ?php header('Xx: y'); ? > pour $page['headers']
205
+    // note: on essaie d'attrapper aussi certains de ces entetes codes
206
+    // "a la main" dans les squelettes, mais evidemment sans exhaustivite
207
+    if (
208
+        stripos($corps, 'header') !== false
209
+        and preg_match_all(
210
+            '/(<[?]php\s+)@?header\s*\(\s*.([^:\'"]*):?\s*([^)]*)[^)]\s*\)\s*[;]?\s*[?]>/ims',
211
+            $corps,
212
+            $regs,
213
+            PREG_SET_ORDER
214
+        )
215
+    ) {
216
+        foreach ($regs as $r) {
217
+            $corps = str_replace($r[0], '', $corps);
218
+            # $j = Content-Type, et pas content-TYPE.
219
+            $j = join('-', array_map('ucwords', explode('-', strtolower($r[2]))));
220
+
221
+            if ($j == 'X-Spip-Filtre' and isset($headers[$j])) {
222
+                $headers[$j] .= '|' . $r[3];
223
+            } else {
224
+                $headers[$j] = $r[3];
225
+            }
226
+        }
227
+    }
228
+    // S'agit-il d'un resultat constant ou contenant du code php
229
+    $process_ins = (
230
+        strpos($corps, '<' . '?') === false
231
+        or
232
+        (strpos($corps, '<' . '?xml') !== false and
233
+            strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
234
+    )
235
+        ? 'html'
236
+        : 'php';
237
+
238
+    $skel = [
239
+        'squelette' => $nom,
240
+        'source' => $source,
241
+        'process_ins' => $process_ins,
242
+        'invalideurs' => $cache,
243
+        'entetes' => $headers,
244
+        'duree' => isset($headers['X-Spip-Cache']) ? intval($headers['X-Spip-Cache']) : 0
245
+    ];
246
+
247
+    // traiter #FILTRE{} et filtres
248
+    if (!isset($filtres[$nom])) {
249
+        $filtres[$nom] = pipeline('declarer_filtres_squelettes', ['args' => $skel, 'data' => []]);
250
+    }
251
+    $filtres_headers = [];
252
+    if (isset($headers['X-Spip-Filtre']) and strlen($headers['X-Spip-Filtre'])) {
253
+        $filtres_headers = array_filter(explode('|', $headers['X-Spip-Filtre']));
254
+        unset($headers['X-Spip-Filtre']);
255
+    }
256
+    if (is_array($filtres[$nom]) || $filtres[$nom] instanceof \Countable ? count($filtres[$nom]) : 0 or count($filtres_headers)) {
257
+        include_spip('public/sandbox');
258
+        $corps = sandbox_filtrer_squelette($skel, $corps, $filtres_headers, $filtres[$nom]);
259
+
260
+        if ($process_ins == 'html') {
261
+            $skel['process_ins'] = (
262
+                strpos($corps, '<' . '?') === false
263
+                or
264
+                (strpos($corps, '<' . '?xml') !== false and
265
+                    strpos(str_replace('<' . '?xml', '', $corps), '<' . '?') === false)
266
+            )
267
+                ? 'html'
268
+                : 'php';
269
+        }
270
+    }
271
+
272
+    $skel['entetes'] = $headers;
273
+    $skel['texte'] = $corps;
274
+
275
+    return $skel;
276 276
 }
277 277
 
278 278
 //
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
 inserer_balise_dynamique(balise_%s_dyn(%s), array(%s));
287 287
 if ($lang_select) lang_select();
288 288
 ?'
289
-	. '>');
289
+    . '>');
290 290
 
291 291
 /**
292 292
  * Synthétise une balise dynamique : crée l'appel à l'inclusion
@@ -306,35 +306,35 @@  discard block
 block discarded – undo
306 306
  *     Code PHP pour inclure le squelette de la balise dynamique
307 307
  **/
308 308
 function synthetiser_balise_dynamique($nom, $args, $file, $context_compil) {
309
-	if (
310
-		strncmp($file, '/', 1) !== 0
311
-		// pas de lien symbolique sous Windows
312
-		and !(stristr(PHP_OS, 'WIN') and strpos($file, ':') !== false)
313
-	) {
314
-		$file = './" . _DIR_RACINE . "' . $file;
315
-	}
316
-
317
-	$lang = $context_compil[4];
318
-	if (preg_match(',\W,', $lang)) {
319
-		$lang = '';
320
-	}
321
-
322
-	$args = array_map('argumenter_squelette', $args);
323
-	if (!empty($context_compil['appel_php_depuis_modele'])) {
324
-		$args[0] = 'arguments_balise_dyn_depuis_modele(' . $args[0] . ')';
325
-	}
326
-	$args = join(', ', $args);
327
-
328
-	$r = sprintf(
329
-		CODE_INCLURE_BALISE,
330
-		$file,
331
-		$lang,
332
-		$nom,
333
-		$args,
334
-		join(', ', array_map('_q', $context_compil))
335
-	);
336
-
337
-	return $r;
309
+    if (
310
+        strncmp($file, '/', 1) !== 0
311
+        // pas de lien symbolique sous Windows
312
+        and !(stristr(PHP_OS, 'WIN') and strpos($file, ':') !== false)
313
+    ) {
314
+        $file = './" . _DIR_RACINE . "' . $file;
315
+    }
316
+
317
+    $lang = $context_compil[4];
318
+    if (preg_match(',\W,', $lang)) {
319
+        $lang = '';
320
+    }
321
+
322
+    $args = array_map('argumenter_squelette', $args);
323
+    if (!empty($context_compil['appel_php_depuis_modele'])) {
324
+        $args[0] = 'arguments_balise_dyn_depuis_modele(' . $args[0] . ')';
325
+    }
326
+    $args = join(', ', $args);
327
+
328
+    $r = sprintf(
329
+        CODE_INCLURE_BALISE,
330
+        $file,
331
+        $lang,
332
+        $nom,
333
+        $args,
334
+        join(', ', array_map('_q', $context_compil))
335
+    );
336
+
337
+    return $r;
338 338
 }
339 339
 
340 340
 /**
@@ -352,18 +352,18 @@  discard block
 block discarded – undo
352 352
  **/
353 353
 function argumenter_squelette($v) {
354 354
 
355
-	if (is_object($v)) {
356
-		return var_export($v, true);
357
-	} elseif (!is_array($v)) {
358
-		return "'" . texte_script((string) $v) . "'";
359
-	} else {
360
-		$out = [];
361
-		foreach ($v as $k => $val) {
362
-			$out [] = argumenter_squelette($k) . '=>' . argumenter_squelette($val);
363
-		}
364
-
365
-		return 'array(' . join(', ', $out) . ')';
366
-	}
355
+    if (is_object($v)) {
356
+        return var_export($v, true);
357
+    } elseif (!is_array($v)) {
358
+        return "'" . texte_script((string) $v) . "'";
359
+    } else {
360
+        $out = [];
361
+        foreach ($v as $k => $val) {
362
+            $out [] = argumenter_squelette($k) . '=>' . argumenter_squelette($val);
363
+        }
364
+
365
+        return 'array(' . join(', ', $out) . ')';
366
+    }
367 367
 }
368 368
 
369 369
 
@@ -394,87 +394,87 @@  discard block
 block discarded – undo
394 394
  *     Code PHP d'exécutant l'inclusion du squelette (ou texte) de la balise dynamique
395 395
  **/
396 396
 function executer_balise_dynamique($nom, $args, $context_compil) {
397
-	/** @var string Nom de la balise à charger (balise demandée ou balise générique) */
398
-	$nom_balise = $nom;
399
-	/** @var string Nom de la balise générique (si utilisée) */
400
-	$nom_balise_generique = '';
401
-
402
-	$appel_php_depuis_modele = false;
403
-	if (
404
-		is_array($context_compil)
405
-		and !is_numeric($context_compil[3])
406
-		and empty($context_compil[0])
407
-		and empty($context_compil[1])
408
-		and empty($context_compil[2])
409
-		and empty($context_compil[3])
410
-	) {
411
-		$appel_php_depuis_modele = true;
412
-	}
413
-
414
-	if (!$fonction_balise = charger_fonction($nom_balise, 'balise', true)) {
415
-		// Calculer un nom générique (ie. 'formulaire_' dans 'formulaire_editer_article')
416
-		if ($balise_generique = chercher_balise_generique($nom)) {
417
-			// injecter en premier arg le nom de la balise
418
-			array_unshift($args, $nom);
419
-			$nom_balise_generique = $balise_generique['nom_generique'];
420
-			$fonction_balise = $balise_generique['fonction_generique'];
421
-			$nom_balise = $nom_balise_generique;
422
-		}
423
-		unset($balise_generique);
424
-	}
425
-
426
-	if (!$fonction_balise) {
427
-		$msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
428
-		erreur_squelette($msg, $context_compil);
429
-
430
-		return '';
431
-	}
432
-
433
-	// retrouver le fichier qui a déclaré la fonction
434
-	// même si la fonction dynamique est déclarée dans un fichier de fonctions.
435
-	// Attention sous windows, getFileName() retourne un antislash.
436
-	$reflector = new ReflectionFunction($fonction_balise);
437
-	$file = str_replace('\\', '/', $reflector->getFileName());
438
-	if (strncmp($file, str_replace('\\', '/', _ROOT_RACINE), strlen(_ROOT_RACINE)) === 0) {
439
-		$file = substr($file, strlen(_ROOT_RACINE));
440
-	}
441
-
442
-	// Y a-t-il une fonction de traitement des arguments ?
443
-	$f = 'balise_' . $nom_balise . '_stat';
444
-
445
-	$r = !function_exists($f) ? $args : $f($args, $context_compil);
446
-
447
-	if (!is_array($r)) {
448
-		return $r;
449
-	}
450
-
451
-	// verifier que la fonction dyn est la,
452
-	// sinon se replier sur la generique si elle existe
453
-	if (!function_exists('balise_' . $nom_balise . '_dyn')) {
454
-		if (
455
-			$balise_generique = chercher_balise_generique($nom)
456
-			and $nom_balise_generique = $balise_generique['nom_generique']
457
-			and $file = include_spip('balise/' . strtolower($nom_balise_generique))
458
-			and function_exists('balise_' . $nom_balise_generique . '_dyn')
459
-		) {
460
-			// et lui injecter en premier arg le nom de la balise
461
-			array_unshift($r, $nom);
462
-			$nom_balise = $nom_balise_generique;
463
-			if (!_DIR_RESTREINT) {
464
-				$file = _DIR_RESTREINT_ABS . $file;
465
-			}
466
-		} else {
467
-			$msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
468
-			erreur_squelette($msg, $context_compil);
469
-
470
-			return '';
471
-		}
472
-	}
473
-
474
-	if ($appel_php_depuis_modele) {
475
-		$context_compil['appel_php_depuis_modele'] = true;
476
-	}
477
-	return synthetiser_balise_dynamique($nom_balise, $r, $file, $context_compil);
397
+    /** @var string Nom de la balise à charger (balise demandée ou balise générique) */
398
+    $nom_balise = $nom;
399
+    /** @var string Nom de la balise générique (si utilisée) */
400
+    $nom_balise_generique = '';
401
+
402
+    $appel_php_depuis_modele = false;
403
+    if (
404
+        is_array($context_compil)
405
+        and !is_numeric($context_compil[3])
406
+        and empty($context_compil[0])
407
+        and empty($context_compil[1])
408
+        and empty($context_compil[2])
409
+        and empty($context_compil[3])
410
+    ) {
411
+        $appel_php_depuis_modele = true;
412
+    }
413
+
414
+    if (!$fonction_balise = charger_fonction($nom_balise, 'balise', true)) {
415
+        // Calculer un nom générique (ie. 'formulaire_' dans 'formulaire_editer_article')
416
+        if ($balise_generique = chercher_balise_generique($nom)) {
417
+            // injecter en premier arg le nom de la balise
418
+            array_unshift($args, $nom);
419
+            $nom_balise_generique = $balise_generique['nom_generique'];
420
+            $fonction_balise = $balise_generique['fonction_generique'];
421
+            $nom_balise = $nom_balise_generique;
422
+        }
423
+        unset($balise_generique);
424
+    }
425
+
426
+    if (!$fonction_balise) {
427
+        $msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
428
+        erreur_squelette($msg, $context_compil);
429
+
430
+        return '';
431
+    }
432
+
433
+    // retrouver le fichier qui a déclaré la fonction
434
+    // même si la fonction dynamique est déclarée dans un fichier de fonctions.
435
+    // Attention sous windows, getFileName() retourne un antislash.
436
+    $reflector = new ReflectionFunction($fonction_balise);
437
+    $file = str_replace('\\', '/', $reflector->getFileName());
438
+    if (strncmp($file, str_replace('\\', '/', _ROOT_RACINE), strlen(_ROOT_RACINE)) === 0) {
439
+        $file = substr($file, strlen(_ROOT_RACINE));
440
+    }
441
+
442
+    // Y a-t-il une fonction de traitement des arguments ?
443
+    $f = 'balise_' . $nom_balise . '_stat';
444
+
445
+    $r = !function_exists($f) ? $args : $f($args, $context_compil);
446
+
447
+    if (!is_array($r)) {
448
+        return $r;
449
+    }
450
+
451
+    // verifier que la fonction dyn est la,
452
+    // sinon se replier sur la generique si elle existe
453
+    if (!function_exists('balise_' . $nom_balise . '_dyn')) {
454
+        if (
455
+            $balise_generique = chercher_balise_generique($nom)
456
+            and $nom_balise_generique = $balise_generique['nom_generique']
457
+            and $file = include_spip('balise/' . strtolower($nom_balise_generique))
458
+            and function_exists('balise_' . $nom_balise_generique . '_dyn')
459
+        ) {
460
+            // et lui injecter en premier arg le nom de la balise
461
+            array_unshift($r, $nom);
462
+            $nom_balise = $nom_balise_generique;
463
+            if (!_DIR_RESTREINT) {
464
+                $file = _DIR_RESTREINT_ABS . $file;
465
+            }
466
+        } else {
467
+            $msg = ['zbug_balise_inexistante', ['from' => 'CVT', 'balise' => $nom]];
468
+            erreur_squelette($msg, $context_compil);
469
+
470
+            return '';
471
+        }
472
+    }
473
+
474
+    if ($appel_php_depuis_modele) {
475
+        $context_compil['appel_php_depuis_modele'] = true;
476
+    }
477
+    return synthetiser_balise_dynamique($nom_balise, $r, $file, $context_compil);
478 478
 }
479 479
 
480 480
 /**
@@ -489,23 +489,23 @@  discard block
 block discarded – undo
489 489
  * @return array|null
490 490
  */
491 491
 function chercher_balise_generique($nom) {
492
-	if (false === strpos($nom, '_')) {
493
-		return null;
494
-	}
495
-	$nom_generique = $nom;
496
-	while (false !== ($p = strrpos($nom_generique, '_'))) {
497
-		$nom_generique = substr($nom_generique, 0, $p + 1);
498
-		$fonction_generique = charger_fonction($nom_generique, 'balise', true);
499
-		if ($fonction_generique) {
500
-			return [
501
-				'nom' => $nom,
502
-				'nom_generique' => $nom_generique,
503
-				'fonction_generique' => $fonction_generique,
504
-			];
505
-		}
506
-		$nom_generique = substr($nom_generique, 0, -1);
507
-	}
508
-	return null;
492
+    if (false === strpos($nom, '_')) {
493
+        return null;
494
+    }
495
+    $nom_generique = $nom;
496
+    while (false !== ($p = strrpos($nom_generique, '_'))) {
497
+        $nom_generique = substr($nom_generique, 0, $p + 1);
498
+        $fonction_generique = charger_fonction($nom_generique, 'balise', true);
499
+        if ($fonction_generique) {
500
+            return [
501
+                'nom' => $nom,
502
+                'nom_generique' => $nom_generique,
503
+                'fonction_generique' => $fonction_generique,
504
+            ];
505
+        }
506
+        $nom_generique = substr($nom_generique, 0, -1);
507
+    }
508
+    return null;
509 509
 }
510 510
 
511 511
 
@@ -529,29 +529,29 @@  discard block
 block discarded – undo
529 529
  * @return null;
530 530
  **/
531 531
 function lang_select_public($lang, $lang_select, $titre = null) {
532
-	// Cas 1. forcer_lang = true et pas de critere {lang_select}
533
-	if (
534
-		isset($GLOBALS['forcer_lang']) and $GLOBALS['forcer_lang']
535
-		and $lang_select !== 'oui'
536
-	) {
537
-		$lang = $GLOBALS['spip_lang'];
538
-	} // Cas 2. l'objet n'a pas de langue definie (ou definie a '')
539
-	elseif (!strlen($lang)) {
540
-		$lang = $GLOBALS['spip_lang'];
541
-	} // Cas 3. l'objet est multilingue !
542
-	elseif (
543
-		$lang_select !== 'oui'
544
-		and strlen($titre) > 10
545
-		and strpos($titre, '<multi>') !== false
546
-		and strpos(echappe_html($titre), '<multi>') !== false
547
-	) {
548
-		$lang = $GLOBALS['spip_lang'];
549
-	}
550
-
551
-	// faire un lang_select() eventuellement sur la langue inchangee
552
-	lang_select($lang);
553
-
554
-	return;
532
+    // Cas 1. forcer_lang = true et pas de critere {lang_select}
533
+    if (
534
+        isset($GLOBALS['forcer_lang']) and $GLOBALS['forcer_lang']
535
+        and $lang_select !== 'oui'
536
+    ) {
537
+        $lang = $GLOBALS['spip_lang'];
538
+    } // Cas 2. l'objet n'a pas de langue definie (ou definie a '')
539
+    elseif (!strlen($lang)) {
540
+        $lang = $GLOBALS['spip_lang'];
541
+    } // Cas 3. l'objet est multilingue !
542
+    elseif (
543
+        $lang_select !== 'oui'
544
+        and strlen($titre) > 10
545
+        and strpos($titre, '<multi>') !== false
546
+        and strpos(echappe_html($titre), '<multi>') !== false
547
+    ) {
548
+        $lang = $GLOBALS['spip_lang'];
549
+    }
550
+
551
+    // faire un lang_select() eventuellement sur la langue inchangee
552
+    lang_select($lang);
553
+
554
+    return;
555 555
 }
556 556
 
557 557
 
@@ -559,21 +559,21 @@  discard block
 block discarded – undo
559 559
 // il faut le nettoyer car il pourrait etre injecte en SQL
560 560
 // https://code.spip.net/@nettoyer_env_doublons
561 561
 function nettoyer_env_doublons($envd) {
562
-	foreach ($envd as $table => $liste) {
563
-		$n = '';
564
-		foreach (explode(',', $liste) as $val) {
565
-			if ($a = intval($val) and $val === strval($a)) {
566
-				$n .= ',' . $val;
567
-			}
568
-		}
569
-		if (strlen($n)) {
570
-			$envd[$table] = $n;
571
-		} else {
572
-			unset($envd[$table]);
573
-		}
574
-	}
575
-
576
-	return $envd;
562
+    foreach ($envd as $table => $liste) {
563
+        $n = '';
564
+        foreach (explode(',', $liste) as $val) {
565
+            if ($a = intval($val) and $val === strval($a)) {
566
+                $n .= ',' . $val;
567
+            }
568
+        }
569
+        if (strlen($n)) {
570
+            $envd[$table] = $n;
571
+        } else {
572
+            unset($envd[$table]);
573
+        }
574
+    }
575
+
576
+    return $envd;
577 577
 }
578 578
 
579 579
 /**
@@ -592,21 +592,21 @@  discard block
 block discarded – undo
592 592
  *     Opérateur trouvé (SELF ou SUBSELECT) sinon false.
593 593
  **/
594 594
 function match_self($w) {
595
-	if (is_string($w)) {
596
-		return false;
597
-	}
598
-	if (is_array($w)) {
599
-		if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
600
-			return $w;
601
-		}
602
-		foreach (array_filter($w, 'is_array') as $sw) {
603
-			if ($m = match_self($sw)) {
604
-				return $m;
605
-			}
606
-		}
607
-	}
608
-
609
-	return false;
595
+    if (is_string($w)) {
596
+        return false;
597
+    }
598
+    if (is_array($w)) {
599
+        if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
600
+            return $w;
601
+        }
602
+        foreach (array_filter($w, 'is_array') as $sw) {
603
+            if ($m = match_self($sw)) {
604
+                return $m;
605
+            }
606
+        }
607
+    }
608
+
609
+    return false;
610 610
 }
611 611
 
612 612
 /**
@@ -622,16 +622,16 @@  discard block
 block discarded – undo
622 622
  *     est remplacée par son code.
623 623
  **/
624 624
 function remplace_sous_requete($w, $sousrequete) {
625
-	if (is_array($w)) {
626
-		if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
627
-			return $sousrequete;
628
-		}
629
-		foreach ($w as $k => $sw) {
630
-			$w[$k] = remplace_sous_requete($sw, $sousrequete);
631
-		}
632
-	}
633
-
634
-	return $w;
625
+    if (is_array($w)) {
626
+        if (in_array(reset($w), ['SELF', 'SUBSELECT'])) {
627
+            return $sousrequete;
628
+        }
629
+        foreach ($w as $k => $sw) {
630
+            $w[$k] = remplace_sous_requete($sw, $sousrequete);
631
+        }
632
+    }
633
+
634
+    return $w;
635 635
 }
636 636
 
637 637
 /**
@@ -645,17 +645,17 @@  discard block
 block discarded – undo
645 645
  *     - Conditions avec des sous requêtes
646 646
  **/
647 647
 function trouver_sous_requetes($where) {
648
-	$where_simples = [];
649
-	$where_sous = [];
650
-	foreach ($where as $k => $w) {
651
-		if (match_self($w)) {
652
-			$where_sous[$k] = $w;
653
-		} else {
654
-			$where_simples[$k] = $w;
655
-		}
656
-	}
657
-
658
-	return [$where_simples, $where_sous];
648
+    $where_simples = [];
649
+    $where_sous = [];
650
+    foreach ($where as $k => $w) {
651
+        if (match_self($w)) {
652
+            $where_sous[$k] = $w;
653
+        } else {
654
+            $where_simples[$k] = $w;
655
+        }
656
+    }
657
+
658
+    return [$where_simples, $where_sous];
659 659
 }
660 660
 
661 661
 
@@ -681,292 +681,292 @@  discard block
 block discarded – undo
681 681
  * @return resource
682 682
  */
683 683
 function calculer_select(
684
-	$select = [],
685
-	$from = [],
686
-	$from_type = [],
687
-	$where = [],
688
-	$join = [],
689
-	$groupby = [],
690
-	$orderby = [],
691
-	$limit = '',
692
-	$having = [],
693
-	$table = '',
694
-	$id = '',
695
-	$serveur = '',
696
-	$requeter = true
684
+    $select = [],
685
+    $from = [],
686
+    $from_type = [],
687
+    $where = [],
688
+    $join = [],
689
+    $groupby = [],
690
+    $orderby = [],
691
+    $limit = '',
692
+    $having = [],
693
+    $table = '',
694
+    $id = '',
695
+    $serveur = '',
696
+    $requeter = true
697 697
 ) {
698 698
 
699
-	// retirer les criteres vides:
700
-	// {X ?} avec X absent de l'URL
701
-	// {par #ENV{X}} avec X absent de l'URL
702
-	// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
703
-	$menage = false;
704
-	foreach ($where as $k => $v) {
705
-		if (is_array($v)) {
706
-			if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
707
-				$op = false;
708
-			} elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
709
-				$op = false;
710
-			} else {
711
-				$op = $v[0] ?: $v;
712
-			}
713
-		} else {
714
-			$op = $v;
715
-		}
716
-		if ((!$op) or ($op == 1) or ($op == '0=0')) {
717
-			unset($where[$k]);
718
-			$menage = true;
719
-		}
720
-	}
721
-
722
-	// evacuer les eventuels groupby vide issus d'un calcul dynamique
723
-	$groupby = array_diff($groupby, ['']);
724
-
725
-	// remplacer les sous requetes recursives au calcul
726
-	[$where_simples, $where_sous] = trouver_sous_requetes($where);
727
-	foreach ($where_sous as $k => $w) {
728
-		$menage = true;
729
-		// on recupere la sous requete
730
-		$sous = match_self($w);
731
-		if ($sous[0] == 'SELF') {
732
-			// c'est une sous requete identique a elle meme sous la forme (SELF,$select,$where)
733
-			array_push($where_simples, $sous[2]);
734
-			$wheresub = [
735
-				$sous[2],
736
-				'0=0'
737
-			]; // pour accepter une string et forcer a faire le menage car on a surement simplifie select et where
738
-			$jsub = $join;
739
-			// trouver les jointures utiles a
740
-			// reinjecter dans le where de la sous requete les conditions supplementaires des jointures qui y sont mentionnees
741
-			// ie L1.objet='article'
742
-			// on construit le where une fois, puis on ajoute les where complentaires si besoin, et on reconstruit le where en fonction
743
-			$i = 0;
744
-			do {
745
-				$where[$k] = remplace_sous_requete($w, '(' . calculer_select(
746
-					[$sous[1] . ' AS id'],
747
-					$from,
748
-					$from_type,
749
-					$wheresub,
750
-					$jsub,
751
-					[],
752
-					[],
753
-					'',
754
-					$having,
755
-					$table,
756
-					$id,
757
-					$serveur,
758
-					false
759
-				) . ')');
760
-				if (!$i) {
761
-					$i = 1;
762
-					$wherestring = calculer_where_to_string($where[$k]);
763
-					foreach ($join as $cle => $wj) {
764
-						if (
765
-							(is_countable($wj) ? count($wj) : 0) == 4
766
-							and strpos($wherestring, (string) "{$cle}.") !== false
767
-						) {
768
-							$i = 0;
769
-							$wheresub[] = $wj[3];
770
-							unset($jsub[$cle][3]);
771
-						}
772
-					}
773
-				}
774
-			} while ($i++ < 1);
775
-		}
776
-		if ($sous[0] == 'SUBSELECT') {
777
-			// c'est une sous requete explicite sous la forme identique a sql_select : (SUBSELECT,$select,$from,$where,$groupby,$orderby,$limit,$having)
778
-			array_push($where_simples, $sous[3]); // est-ce utile dans ce cas ?
779
-			$where[$k] = remplace_sous_requete($w, '(' . calculer_select(
780
-				$sous[1], # select
781
-				$sous[2], #from
782
-				[], #from_type
783
-				$sous[3] ? (is_array($sous[3]) ? $sous[3] : [$sous[3]]) : [],
784
-				#where, qui peut etre de la forme string comme dans sql_select
785
-					[], #join
786
-				$sous[4] ?: [], #groupby
787
-				$sous[5] ?: [], #orderby
788
-				$sous[6], #limit
789
-				$sous[7] ?: [], #having
790
-				$table,
791
-				$id,
792
-				$serveur,
793
-				false
794
-			) . ')');
795
-		}
796
-		array_pop($where_simples);
797
-	}
798
-
799
-	foreach ($having as $k => $v) {
800
-		if ((!$v) or ($v == 1) or ($v == '0=0')) {
801
-			unset($having[$k]);
802
-		}
803
-	}
804
-
805
-	// Installer les jointures.
806
-	// Retirer celles seulement utiles aux criteres finalement absents mais
807
-	// parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
808
-	// si elle est seulement utile a Ln+1 elle meme inutile
809
-
810
-	$afrom = [];
811
-	$equiv = [];
812
-	$k = count($join);
813
-	foreach (array_reverse($join, true) as $cledef => $j) {
814
-		$cle = $cledef;
815
-		// le format de join est :
816
-		// array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
817
-		$join[$cle] = array_values($join[$cle]); // recalculer les cles car des unset ont pu perturber
818
-		if (count($join[$cle]) == 2) {
819
-			$join[$cle][] = $join[$cle][1];
820
-		}
821
-		if ((is_array($join[$cle]) || $join[$cle] instanceof \Countable ? count($join[$cle]) : 0) == 3) {
822
-			$join[$cle][] = '';
823
-		}
824
-		[$t, $c, $carr, $and] = $join[$cle];
825
-		// si le nom de la jointure n'a pas ete specifiee, on prend Lx avec x sont rang dans la liste
826
-		// pour compat avec ancienne convention
827
-		if (is_numeric($cle)) {
828
-			$cle = "L$k";
829
-		}
830
-		$cle_where_lie = "JOIN-$cle";
831
-		if (
832
-			!$menage
833
-			or isset($afrom[$cle])
834
-			or calculer_jointnul($cle, $select)
835
-			or calculer_jointnul($cle, array_diff_key($join, [$cle => $join[$cle]]))
836
-			or calculer_jointnul($cle, $having)
837
-			or calculer_jointnul($cle, array_diff_key($where_simples, [$cle_where_lie => '']))
838
-		) {
839
-			// corriger les references non explicites dans select
840
-			// ou groupby
841
-			foreach ($select as $i => $s) {
842
-				if ($s == $c) {
843
-					$select[$i] = "$cle.$c AS $c";
844
-					break;
845
-				}
846
-			}
847
-			foreach ($groupby as $i => $g) {
848
-				if ($g == $c) {
849
-					$groupby[$i] = "$cle.$c";
850
-					break;
851
-				}
852
-			}
853
-			// on garde une ecriture decomposee pour permettre une simplification ulterieure si besoin
854
-			// sans recours a preg_match
855
-			// un implode(' ',..) est fait dans reinjecte_joint un peu plus bas
856
-			$afrom[$t][$cle] = [
857
-				"\n" .
858
-				($from_type[$cle] ?? 'INNER') . ' JOIN',
859
-				$from[$cle],
860
-				"AS $cle",
861
-				'ON (',
862
-				"$cle.$c",
863
-				'=',
864
-				"$t.$carr",
865
-				($and ? 'AND ' . $and : '') .
866
-				')'
867
-			];
868
-			if (isset($afrom[$cle])) {
869
-				$afrom[$t] = $afrom[$t] + $afrom[$cle];
870
-				unset($afrom[$cle]);
871
-			}
872
-			$equiv[] = $carr;
873
-		} else {
874
-			unset($join[$cledef]);
875
-			if (isset($where_simples[$cle_where_lie])) {
876
-				unset($where_simples[$cle_where_lie]);
877
-				unset($where[$cle_where_lie]);
878
-			}
879
-		}
880
-		unset($from[$cle]);
881
-		$k--;
882
-	}
883
-
884
-	if (count($afrom)) {
885
-		// Regarder si la table principale ne sert finalement a rien comme dans
886
-		//<BOUCLE3(MOTS){id_article}{id_mot}> class='on'</BOUCLE3>
887
-		//<BOUCLE2(MOTS){id_article} />#TOTAL_BOUCLE<//B2>
888
-		//<BOUCLE5(RUBRIQUES){id_mot}{tout} />#TOTAL_BOUCLE<//B5>
889
-		// ou dans
890
-		//<BOUCLE8(HIERARCHIE){id_rubrique}{tout}{type='Squelette'}{inverse}{0,1}{lang_select=non} />#TOTAL_BOUCLE<//B8>
891
-		// qui comporte plusieurs jointures
892
-		// ou dans
893
-		// <BOUCLE6(ARTICLES){id_mot=2}{statut==.*} />#TOTAL_BOUCLE<//B6>
894
-		// <BOUCLE7(ARTICLES){id_mot>0}{statut?} />#TOTAL_BOUCLE<//B7>
895
-		// penser a regarder aussi la clause orderby pour ne pas simplifier abusivement
896
-		// <BOUCLE9(ARTICLES){recherche truc}{par titre}>#ID_ARTICLE</BOUCLE9>
897
-		// penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
898
-		// <BOUCLE10(EVENEMENTS){id_rubrique} />#TOTAL_BOUCLE<//B10>
899
-
900
-		$t = key($from);
901
-		$c = current($from);
902
-		reset($from);
903
-		$e = '/\b(' . "$t\\." . join('|' . $t . '\.', $equiv) . ')\b/';
904
-		if (
905
-			!(strpos($t, ' ') or // jointure des le depart cf boucle_doc
906
-				calculer_jointnul($t, $select, $e) or
907
-				calculer_jointnul($t, $join, $e) or
908
-				calculer_jointnul($t, $where, $e) or
909
-				calculer_jointnul($t, $orderby, $e) or
910
-				calculer_jointnul($t, $groupby, $e) or
911
-				calculer_jointnul($t, $having, $e))
912
-			&& count($afrom[$t])
913
-		) {
914
-			$nfrom = reset($afrom[$t]);
915
-			$nt = array_key_first($afrom[$t]);
916
-			unset($from[$t]);
917
-			$from[$nt] = $nfrom[1];
918
-			unset($afrom[$t][$nt]);
919
-			$afrom[$nt] = $afrom[$t];
920
-			unset($afrom[$t]);
921
-			$e = '/\b' . preg_quote($nfrom[6]) . '\b/';
922
-			$t = $nfrom[4];
923
-			$alias = '';
924
-			// verifier que les deux cles sont homonymes, sinon installer un alias dans le select
925
-			$oldcle = explode('.', $nfrom[6]);
926
-			$oldcle = end($oldcle);
927
-			$newcle = explode('.', $nfrom[4]);
928
-			$newcle = end($newcle);
929
-			if ($newcle != $oldcle) {
930
-				// si l'ancienne cle etait deja dans le select avec un AS
931
-				// reprendre simplement ce AS
932
-				$as = '/\b' . preg_quote($nfrom[6]) . '\s+(AS\s+\w+)\b/';
933
-				if (preg_match($as, implode(',', $select), $m)) {
934
-					$alias = '';
935
-				} else {
936
-					$alias = ', ' . $nfrom[4] . " AS $oldcle";
937
-				}
938
-			}
939
-			$select = remplacer_jointnul($t . $alias, $select, $e);
940
-			$join = remplacer_jointnul($t, $join, $e);
941
-			$where = remplacer_jointnul($t, $where, $e);
942
-			$having = remplacer_jointnul($t, $having, $e);
943
-			$groupby = remplacer_jointnul($t, $groupby, $e);
944
-			$orderby = remplacer_jointnul($t, $orderby, $e);
945
-		}
946
-		$from = reinjecte_joint($afrom, $from);
947
-	}
948
-	if (empty($GLOBALS['debug']) or !is_array($GLOBALS['debug'])) {
949
-		$wasdebug = empty($GLOBALS['debug']) ? false : $GLOBALS['debug'];
950
-		$GLOBALS['debug'] = [];
951
-		if ($wasdebug) {
952
-			$GLOBALS['debug']['debug'] = true;
953
-		}
954
-	}
955
-	$GLOBALS['debug']['aucasou'] = [$table, $id, $serveur, $requeter];
956
-	$r = sql_select(
957
-		$select,
958
-		$from,
959
-		$where,
960
-		$groupby,
961
-		array_filter($orderby),
962
-		$limit,
963
-		$having,
964
-		$serveur,
965
-		$requeter
966
-	);
967
-	unset($GLOBALS['debug']['aucasou']);
968
-
969
-	return $r;
699
+    // retirer les criteres vides:
700
+    // {X ?} avec X absent de l'URL
701
+    // {par #ENV{X}} avec X absent de l'URL
702
+    // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
703
+    $menage = false;
704
+    foreach ($where as $k => $v) {
705
+        if (is_array($v)) {
706
+            if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
707
+                $op = false;
708
+            } elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
709
+                $op = false;
710
+            } else {
711
+                $op = $v[0] ?: $v;
712
+            }
713
+        } else {
714
+            $op = $v;
715
+        }
716
+        if ((!$op) or ($op == 1) or ($op == '0=0')) {
717
+            unset($where[$k]);
718
+            $menage = true;
719
+        }
720
+    }
721
+
722
+    // evacuer les eventuels groupby vide issus d'un calcul dynamique
723
+    $groupby = array_diff($groupby, ['']);
724
+
725
+    // remplacer les sous requetes recursives au calcul
726
+    [$where_simples, $where_sous] = trouver_sous_requetes($where);
727
+    foreach ($where_sous as $k => $w) {
728
+        $menage = true;
729
+        // on recupere la sous requete
730
+        $sous = match_self($w);
731
+        if ($sous[0] == 'SELF') {
732
+            // c'est une sous requete identique a elle meme sous la forme (SELF,$select,$where)
733
+            array_push($where_simples, $sous[2]);
734
+            $wheresub = [
735
+                $sous[2],
736
+                '0=0'
737
+            ]; // pour accepter une string et forcer a faire le menage car on a surement simplifie select et where
738
+            $jsub = $join;
739
+            // trouver les jointures utiles a
740
+            // reinjecter dans le where de la sous requete les conditions supplementaires des jointures qui y sont mentionnees
741
+            // ie L1.objet='article'
742
+            // on construit le where une fois, puis on ajoute les where complentaires si besoin, et on reconstruit le where en fonction
743
+            $i = 0;
744
+            do {
745
+                $where[$k] = remplace_sous_requete($w, '(' . calculer_select(
746
+                    [$sous[1] . ' AS id'],
747
+                    $from,
748
+                    $from_type,
749
+                    $wheresub,
750
+                    $jsub,
751
+                    [],
752
+                    [],
753
+                    '',
754
+                    $having,
755
+                    $table,
756
+                    $id,
757
+                    $serveur,
758
+                    false
759
+                ) . ')');
760
+                if (!$i) {
761
+                    $i = 1;
762
+                    $wherestring = calculer_where_to_string($where[$k]);
763
+                    foreach ($join as $cle => $wj) {
764
+                        if (
765
+                            (is_countable($wj) ? count($wj) : 0) == 4
766
+                            and strpos($wherestring, (string) "{$cle}.") !== false
767
+                        ) {
768
+                            $i = 0;
769
+                            $wheresub[] = $wj[3];
770
+                            unset($jsub[$cle][3]);
771
+                        }
772
+                    }
773
+                }
774
+            } while ($i++ < 1);
775
+        }
776
+        if ($sous[0] == 'SUBSELECT') {
777
+            // c'est une sous requete explicite sous la forme identique a sql_select : (SUBSELECT,$select,$from,$where,$groupby,$orderby,$limit,$having)
778
+            array_push($where_simples, $sous[3]); // est-ce utile dans ce cas ?
779
+            $where[$k] = remplace_sous_requete($w, '(' . calculer_select(
780
+                $sous[1], # select
781
+                $sous[2], #from
782
+                [], #from_type
783
+                $sous[3] ? (is_array($sous[3]) ? $sous[3] : [$sous[3]]) : [],
784
+                #where, qui peut etre de la forme string comme dans sql_select
785
+                    [], #join
786
+                $sous[4] ?: [], #groupby
787
+                $sous[5] ?: [], #orderby
788
+                $sous[6], #limit
789
+                $sous[7] ?: [], #having
790
+                $table,
791
+                $id,
792
+                $serveur,
793
+                false
794
+            ) . ')');
795
+        }
796
+        array_pop($where_simples);
797
+    }
798
+
799
+    foreach ($having as $k => $v) {
800
+        if ((!$v) or ($v == 1) or ($v == '0=0')) {
801
+            unset($having[$k]);
802
+        }
803
+    }
804
+
805
+    // Installer les jointures.
806
+    // Retirer celles seulement utiles aux criteres finalement absents mais
807
+    // parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
808
+    // si elle est seulement utile a Ln+1 elle meme inutile
809
+
810
+    $afrom = [];
811
+    $equiv = [];
812
+    $k = count($join);
813
+    foreach (array_reverse($join, true) as $cledef => $j) {
814
+        $cle = $cledef;
815
+        // le format de join est :
816
+        // array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
817
+        $join[$cle] = array_values($join[$cle]); // recalculer les cles car des unset ont pu perturber
818
+        if (count($join[$cle]) == 2) {
819
+            $join[$cle][] = $join[$cle][1];
820
+        }
821
+        if ((is_array($join[$cle]) || $join[$cle] instanceof \Countable ? count($join[$cle]) : 0) == 3) {
822
+            $join[$cle][] = '';
823
+        }
824
+        [$t, $c, $carr, $and] = $join[$cle];
825
+        // si le nom de la jointure n'a pas ete specifiee, on prend Lx avec x sont rang dans la liste
826
+        // pour compat avec ancienne convention
827
+        if (is_numeric($cle)) {
828
+            $cle = "L$k";
829
+        }
830
+        $cle_where_lie = "JOIN-$cle";
831
+        if (
832
+            !$menage
833
+            or isset($afrom[$cle])
834
+            or calculer_jointnul($cle, $select)
835
+            or calculer_jointnul($cle, array_diff_key($join, [$cle => $join[$cle]]))
836
+            or calculer_jointnul($cle, $having)
837
+            or calculer_jointnul($cle, array_diff_key($where_simples, [$cle_where_lie => '']))
838
+        ) {
839
+            // corriger les references non explicites dans select
840
+            // ou groupby
841
+            foreach ($select as $i => $s) {
842
+                if ($s == $c) {
843
+                    $select[$i] = "$cle.$c AS $c";
844
+                    break;
845
+                }
846
+            }
847
+            foreach ($groupby as $i => $g) {
848
+                if ($g == $c) {
849
+                    $groupby[$i] = "$cle.$c";
850
+                    break;
851
+                }
852
+            }
853
+            // on garde une ecriture decomposee pour permettre une simplification ulterieure si besoin
854
+            // sans recours a preg_match
855
+            // un implode(' ',..) est fait dans reinjecte_joint un peu plus bas
856
+            $afrom[$t][$cle] = [
857
+                "\n" .
858
+                ($from_type[$cle] ?? 'INNER') . ' JOIN',
859
+                $from[$cle],
860
+                "AS $cle",
861
+                'ON (',
862
+                "$cle.$c",
863
+                '=',
864
+                "$t.$carr",
865
+                ($and ? 'AND ' . $and : '') .
866
+                ')'
867
+            ];
868
+            if (isset($afrom[$cle])) {
869
+                $afrom[$t] = $afrom[$t] + $afrom[$cle];
870
+                unset($afrom[$cle]);
871
+            }
872
+            $equiv[] = $carr;
873
+        } else {
874
+            unset($join[$cledef]);
875
+            if (isset($where_simples[$cle_where_lie])) {
876
+                unset($where_simples[$cle_where_lie]);
877
+                unset($where[$cle_where_lie]);
878
+            }
879
+        }
880
+        unset($from[$cle]);
881
+        $k--;
882
+    }
883
+
884
+    if (count($afrom)) {
885
+        // Regarder si la table principale ne sert finalement a rien comme dans
886
+        //<BOUCLE3(MOTS){id_article}{id_mot}> class='on'</BOUCLE3>
887
+        //<BOUCLE2(MOTS){id_article} />#TOTAL_BOUCLE<//B2>
888
+        //<BOUCLE5(RUBRIQUES){id_mot}{tout} />#TOTAL_BOUCLE<//B5>
889
+        // ou dans
890
+        //<BOUCLE8(HIERARCHIE){id_rubrique}{tout}{type='Squelette'}{inverse}{0,1}{lang_select=non} />#TOTAL_BOUCLE<//B8>
891
+        // qui comporte plusieurs jointures
892
+        // ou dans
893
+        // <BOUCLE6(ARTICLES){id_mot=2}{statut==.*} />#TOTAL_BOUCLE<//B6>
894
+        // <BOUCLE7(ARTICLES){id_mot>0}{statut?} />#TOTAL_BOUCLE<//B7>
895
+        // penser a regarder aussi la clause orderby pour ne pas simplifier abusivement
896
+        // <BOUCLE9(ARTICLES){recherche truc}{par titre}>#ID_ARTICLE</BOUCLE9>
897
+        // penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
898
+        // <BOUCLE10(EVENEMENTS){id_rubrique} />#TOTAL_BOUCLE<//B10>
899
+
900
+        $t = key($from);
901
+        $c = current($from);
902
+        reset($from);
903
+        $e = '/\b(' . "$t\\." . join('|' . $t . '\.', $equiv) . ')\b/';
904
+        if (
905
+            !(strpos($t, ' ') or // jointure des le depart cf boucle_doc
906
+                calculer_jointnul($t, $select, $e) or
907
+                calculer_jointnul($t, $join, $e) or
908
+                calculer_jointnul($t, $where, $e) or
909
+                calculer_jointnul($t, $orderby, $e) or
910
+                calculer_jointnul($t, $groupby, $e) or
911
+                calculer_jointnul($t, $having, $e))
912
+            && count($afrom[$t])
913
+        ) {
914
+            $nfrom = reset($afrom[$t]);
915
+            $nt = array_key_first($afrom[$t]);
916
+            unset($from[$t]);
917
+            $from[$nt] = $nfrom[1];
918
+            unset($afrom[$t][$nt]);
919
+            $afrom[$nt] = $afrom[$t];
920
+            unset($afrom[$t]);
921
+            $e = '/\b' . preg_quote($nfrom[6]) . '\b/';
922
+            $t = $nfrom[4];
923
+            $alias = '';
924
+            // verifier que les deux cles sont homonymes, sinon installer un alias dans le select
925
+            $oldcle = explode('.', $nfrom[6]);
926
+            $oldcle = end($oldcle);
927
+            $newcle = explode('.', $nfrom[4]);
928
+            $newcle = end($newcle);
929
+            if ($newcle != $oldcle) {
930
+                // si l'ancienne cle etait deja dans le select avec un AS
931
+                // reprendre simplement ce AS
932
+                $as = '/\b' . preg_quote($nfrom[6]) . '\s+(AS\s+\w+)\b/';
933
+                if (preg_match($as, implode(',', $select), $m)) {
934
+                    $alias = '';
935
+                } else {
936
+                    $alias = ', ' . $nfrom[4] . " AS $oldcle";
937
+                }
938
+            }
939
+            $select = remplacer_jointnul($t . $alias, $select, $e);
940
+            $join = remplacer_jointnul($t, $join, $e);
941
+            $where = remplacer_jointnul($t, $where, $e);
942
+            $having = remplacer_jointnul($t, $having, $e);
943
+            $groupby = remplacer_jointnul($t, $groupby, $e);
944
+            $orderby = remplacer_jointnul($t, $orderby, $e);
945
+        }
946
+        $from = reinjecte_joint($afrom, $from);
947
+    }
948
+    if (empty($GLOBALS['debug']) or !is_array($GLOBALS['debug'])) {
949
+        $wasdebug = empty($GLOBALS['debug']) ? false : $GLOBALS['debug'];
950
+        $GLOBALS['debug'] = [];
951
+        if ($wasdebug) {
952
+            $GLOBALS['debug']['debug'] = true;
953
+        }
954
+    }
955
+    $GLOBALS['debug']['aucasou'] = [$table, $id, $serveur, $requeter];
956
+    $r = sql_select(
957
+        $select,
958
+        $from,
959
+        $where,
960
+        $groupby,
961
+        array_filter($orderby),
962
+        $limit,
963
+        $having,
964
+        $serveur,
965
+        $requeter
966
+    );
967
+    unset($GLOBALS['debug']['aucasou']);
968
+
969
+    return $r;
970 970
 }
971 971
 
972 972
 /**
@@ -977,20 +977,20 @@  discard block
 block discarded – undo
977 977
  * @return string
978 978
  */
979 979
 function calculer_where_to_string($v, $join = 'AND') {
980
-	if (empty($v)) {
981
-		return '';
982
-	}
983
-
984
-	if (!is_array($v)) {
985
-		return $v;
986
-	} else {
987
-		$exp = '';
988
-		if (strtoupper($join) === 'AND') {
989
-			return $exp . join(" $join ", array_map('calculer_where_to_string', $v));
990
-		} else {
991
-			return $exp . join($join, $v);
992
-		}
993
-	}
980
+    if (empty($v)) {
981
+        return '';
982
+    }
983
+
984
+    if (!is_array($v)) {
985
+        return $v;
986
+    } else {
987
+        $exp = '';
988
+        if (strtoupper($join) === 'AND') {
989
+            return $exp . join(" $join ", array_map('calculer_where_to_string', $v));
990
+        } else {
991
+            return $exp . join($join, $v);
992
+        }
993
+    }
994 994
 }
995 995
 
996 996
 
@@ -998,62 +998,62 @@  discard block
 block discarded – undo
998 998
 
999 999
 // https://code.spip.net/@calculer_jointnul
1000 1000
 function calculer_jointnul($cle, $exp, $equiv = '') {
1001
-	if (!is_array($exp)) {
1002
-		if ($equiv) {
1003
-			$exp = preg_replace($equiv, '', $exp);
1004
-		}
1005
-
1006
-		return preg_match("/\\b$cle\\./", $exp);
1007
-	} else {
1008
-		foreach ($exp as $v) {
1009
-			if (calculer_jointnul($cle, $v, $equiv)) {
1010
-				return true;
1011
-			}
1012
-		}
1013
-
1014
-		return false;
1015
-	}
1001
+    if (!is_array($exp)) {
1002
+        if ($equiv) {
1003
+            $exp = preg_replace($equiv, '', $exp);
1004
+        }
1005
+
1006
+        return preg_match("/\\b$cle\\./", $exp);
1007
+    } else {
1008
+        foreach ($exp as $v) {
1009
+            if (calculer_jointnul($cle, $v, $equiv)) {
1010
+                return true;
1011
+            }
1012
+        }
1013
+
1014
+        return false;
1015
+    }
1016 1016
 }
1017 1017
 
1018 1018
 // https://code.spip.net/@reinjecte_joint
1019 1019
 function reinjecte_joint($afrom, $from) {
1020
-	$from_synth = [];
1021
-	foreach ($from as $k => $v) {
1022
-		$from_synth[$k] = $from[$k];
1023
-		if (isset($afrom[$k])) {
1024
-			foreach ($afrom[$k] as $kk => $vv) {
1025
-				$afrom[$k][$kk] = implode(' ', $afrom[$k][$kk]);
1026
-			}
1027
-			$from_synth["$k@"] = implode(' ', $afrom[$k]);
1028
-			unset($afrom[$k]);
1029
-		}
1030
-	}
1031
-
1032
-	return $from_synth;
1020
+    $from_synth = [];
1021
+    foreach ($from as $k => $v) {
1022
+        $from_synth[$k] = $from[$k];
1023
+        if (isset($afrom[$k])) {
1024
+            foreach ($afrom[$k] as $kk => $vv) {
1025
+                $afrom[$k][$kk] = implode(' ', $afrom[$k][$kk]);
1026
+            }
1027
+            $from_synth["$k@"] = implode(' ', $afrom[$k]);
1028
+            unset($afrom[$k]);
1029
+        }
1030
+    }
1031
+
1032
+    return $from_synth;
1033 1033
 }
1034 1034
 
1035 1035
 // https://code.spip.net/@remplacer_jointnul
1036 1036
 function remplacer_jointnul($cle, $exp, $equiv = '') {
1037
-	if (!is_array($exp)) {
1038
-		return preg_replace($equiv, $cle, $exp);
1039
-	} else {
1040
-		foreach ($exp as $k => $v) {
1041
-			$exp[$k] = remplacer_jointnul($cle, $v, $equiv);
1042
-		}
1043
-
1044
-		return $exp;
1045
-	}
1037
+    if (!is_array($exp)) {
1038
+        return preg_replace($equiv, $cle, $exp);
1039
+    } else {
1040
+        foreach ($exp as $k => $v) {
1041
+            $exp[$k] = remplacer_jointnul($cle, $v, $equiv);
1042
+        }
1043
+
1044
+        return $exp;
1045
+    }
1046 1046
 }
1047 1047
 
1048 1048
 // calcul du nom du squelette
1049 1049
 // https://code.spip.net/@calculer_nom_fonction_squel
1050 1050
 function calculer_nom_fonction_squel($skel, $mime_type = 'html', string $connect = '') {
1051
-	// ne pas doublonner les squelette selon qu'ils sont calcules depuis ecrire/ ou depuis la racine
1052
-	if ($l = strlen(_DIR_RACINE) and strncmp($skel, _DIR_RACINE, $l) == 0) {
1053
-		$skel = substr($skel, strlen(_DIR_RACINE));
1054
-	}
1055
-
1056
-	return $mime_type
1057
-	. (!$connect ? '' : preg_replace('/\W/', '_', $connect)) . '_'
1058
-	. md5($GLOBALS['spip_version_code'] . ' * ' . $skel . (isset($GLOBALS['marqueur_skel']) ? '*' . $GLOBALS['marqueur_skel'] : ''));
1051
+    // ne pas doublonner les squelette selon qu'ils sont calcules depuis ecrire/ ou depuis la racine
1052
+    if ($l = strlen(_DIR_RACINE) and strncmp($skel, _DIR_RACINE, $l) == 0) {
1053
+        $skel = substr($skel, strlen(_DIR_RACINE));
1054
+    }
1055
+
1056
+    return $mime_type
1057
+    . (!$connect ? '' : preg_replace('/\W/', '_', $connect)) . '_'
1058
+    . md5($GLOBALS['spip_version_code'] . ' * ' . $skel . (isset($GLOBALS['marqueur_skel']) ? '*' . $GLOBALS['marqueur_skel'] : ''));
1059 1059
 }
Please login to merge, or discard this patch.
ecrire/public/styliser.php 1 patch
Indentation   +126 added lines, -126 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
 // Ce fichier doit imperativement definir la fonction ci-dessous:
@@ -39,59 +39,59 @@  discard block
 block discarded – undo
39 39
  * @return array
40 40
  */
41 41
 function public_styliser_dist($fond, $contexte, $lang = '', string $connect = '') {
42
-	static $styliser_par_z;
43
-
44
-	// s'assurer que le fond est licite
45
-	// car il peut etre construit a partir d'une variable d'environnement
46
-	if (strpos($fond, '../') !== false or strncmp($fond, '/', 1) == 0) {
47
-		$fond = '404';
48
-	}
49
-
50
-	if (strncmp($fond, 'modeles/', 8) == 0) {
51
-		$modele = substr($fond, 8);
52
-		$modele = styliser_modele($modele, null, $contexte);
53
-		$fond = "modeles/$modele";
54
-	}
55
-
56
-	// Choisir entre $fond-dist.html, $fond=7.html, etc?
57
-	$id_rubrique = 0;
58
-	// Chercher le fond qui va servir de squelette
59
-	if ($r = quete_rubrique_fond($contexte)) {
60
-		[$id_rubrique, $lang] = $r;
61
-	}
62
-
63
-	// trouver un squelette du nom demande
64
-	// ne rien dire si on ne trouve pas,
65
-	// c'est l'appelant qui sait comment gerer la situation
66
-	// ou les plugins qui feront mieux dans le pipeline
67
-	$squelette = trouver_fond($fond, '', true);
68
-	$ext = $squelette['extension'];
69
-
70
-	$flux = [
71
-		'args' => [
72
-			'id_rubrique' => $id_rubrique,
73
-			'ext' => $ext,
74
-			'fond' => $fond,
75
-			'lang' => $lang,
76
-			'contexte' => $contexte, // le style d'un objet peut dependre de lui meme
77
-			'connect' => $connect
78
-		],
79
-		'data' => $squelette['fond'],
80
-	];
81
-
82
-	if (test_espace_prive() or defined('_ZPIP')) {
83
-		if (!$styliser_par_z) {
84
-			$styliser_par_z = charger_fonction('styliser_par_z', 'public');
85
-		}
86
-		$flux = $styliser_par_z($flux);
87
-	}
88
-
89
-	$flux = styliser_par_objets($flux);
90
-
91
-	// pipeline styliser
92
-	$squelette = pipeline('styliser', $flux);
93
-
94
-	return [$squelette, $ext, $ext, "$squelette.$ext"];
42
+    static $styliser_par_z;
43
+
44
+    // s'assurer que le fond est licite
45
+    // car il peut etre construit a partir d'une variable d'environnement
46
+    if (strpos($fond, '../') !== false or strncmp($fond, '/', 1) == 0) {
47
+        $fond = '404';
48
+    }
49
+
50
+    if (strncmp($fond, 'modeles/', 8) == 0) {
51
+        $modele = substr($fond, 8);
52
+        $modele = styliser_modele($modele, null, $contexte);
53
+        $fond = "modeles/$modele";
54
+    }
55
+
56
+    // Choisir entre $fond-dist.html, $fond=7.html, etc?
57
+    $id_rubrique = 0;
58
+    // Chercher le fond qui va servir de squelette
59
+    if ($r = quete_rubrique_fond($contexte)) {
60
+        [$id_rubrique, $lang] = $r;
61
+    }
62
+
63
+    // trouver un squelette du nom demande
64
+    // ne rien dire si on ne trouve pas,
65
+    // c'est l'appelant qui sait comment gerer la situation
66
+    // ou les plugins qui feront mieux dans le pipeline
67
+    $squelette = trouver_fond($fond, '', true);
68
+    $ext = $squelette['extension'];
69
+
70
+    $flux = [
71
+        'args' => [
72
+            'id_rubrique' => $id_rubrique,
73
+            'ext' => $ext,
74
+            'fond' => $fond,
75
+            'lang' => $lang,
76
+            'contexte' => $contexte, // le style d'un objet peut dependre de lui meme
77
+            'connect' => $connect
78
+        ],
79
+        'data' => $squelette['fond'],
80
+    ];
81
+
82
+    if (test_espace_prive() or defined('_ZPIP')) {
83
+        if (!$styliser_par_z) {
84
+            $styliser_par_z = charger_fonction('styliser_par_z', 'public');
85
+        }
86
+        $flux = $styliser_par_z($flux);
87
+    }
88
+
89
+    $flux = styliser_par_objets($flux);
90
+
91
+    // pipeline styliser
92
+    $squelette = pipeline('styliser', $flux);
93
+
94
+    return [$squelette, $ext, $ext, "$squelette.$ext"];
95 95
 }
96 96
 
97 97
 /**
@@ -110,32 +110,32 @@  discard block
 block discarded – undo
110 110
  *     Données du pipeline styliser
111 111
  **/
112 112
 function styliser_par_objets($flux) {
113
-	if (
114
-		test_espace_prive()
115
-		and !$squelette = $flux['data']
116
-		and strncmp($flux['args']['fond'], 'prive/objets/', 13) == 0
117
-		and $echafauder = charger_fonction('echafauder', 'prive', true)
118
-	) {
119
-		if (strncmp($flux['args']['fond'], 'prive/objets/liste/', 19) == 0) {
120
-			$table = table_objet(substr($flux['args']['fond'], 19));
121
-			$table_sql = table_objet_sql($table);
122
-			$objets = lister_tables_objets_sql();
123
-			if (isset($objets[$table_sql])) {
124
-				$flux['data'] = $echafauder($table, $table, $table_sql, 'prive/objets/liste/objets', $flux['args']['ext']);
125
-			}
126
-		}
127
-		if (strncmp($flux['args']['fond'], 'prive/objets/contenu/', 21) == 0) {
128
-			$type = substr($flux['args']['fond'], 21);
129
-			$table = table_objet($type);
130
-			$table_sql = table_objet_sql($table);
131
-			$objets = lister_tables_objets_sql();
132
-			if (isset($objets[$table_sql])) {
133
-				$flux['data'] = $echafauder($type, $table, $table_sql, 'prive/objets/contenu/objet', $flux['args']['ext']);
134
-			}
135
-		}
136
-	}
137
-
138
-	return $flux;
113
+    if (
114
+        test_espace_prive()
115
+        and !$squelette = $flux['data']
116
+        and strncmp($flux['args']['fond'], 'prive/objets/', 13) == 0
117
+        and $echafauder = charger_fonction('echafauder', 'prive', true)
118
+    ) {
119
+        if (strncmp($flux['args']['fond'], 'prive/objets/liste/', 19) == 0) {
120
+            $table = table_objet(substr($flux['args']['fond'], 19));
121
+            $table_sql = table_objet_sql($table);
122
+            $objets = lister_tables_objets_sql();
123
+            if (isset($objets[$table_sql])) {
124
+                $flux['data'] = $echafauder($table, $table, $table_sql, 'prive/objets/liste/objets', $flux['args']['ext']);
125
+            }
126
+        }
127
+        if (strncmp($flux['args']['fond'], 'prive/objets/contenu/', 21) == 0) {
128
+            $type = substr($flux['args']['fond'], 21);
129
+            $table = table_objet($type);
130
+            $table_sql = table_objet_sql($table);
131
+            $objets = lister_tables_objets_sql();
132
+            if (isset($objets[$table_sql])) {
133
+                $flux['data'] = $echafauder($type, $table, $table_sql, 'prive/objets/contenu/objet', $flux['args']['ext']);
134
+            }
135
+        }
136
+    }
137
+
138
+    return $flux;
139 139
 }
140 140
 
141 141
 /**
@@ -151,50 +151,50 @@  discard block
 block discarded – undo
151 151
  * @return array
152 152
  */
153 153
 function quete_rubrique_fond($contexte) {
154
-	static $liste_objets = null;
155
-	static $quete = [];
156
-	if (is_null($liste_objets)) {
157
-		$liste_objets = [];
158
-		include_spip('inc/urls');
159
-		include_spip('public/quete');
160
-		$l = urls_liste_objets(false);
161
-		// placer la rubrique en tete des objets
162
-		$l = array_diff($l, ['rubrique']);
163
-		array_unshift($l, 'rubrique');
164
-		foreach ($l as $objet) {
165
-			$id = id_table_objet($objet);
166
-			if (!isset($liste_objets[$id])) {
167
-				$liste_objets[$id] = objet_type($objet, false);
168
-			}
169
-		}
170
-	}
171
-	$c = array_intersect_key($contexte, $liste_objets);
172
-	if (!count($c)) {
173
-		return false;
174
-	}
175
-
176
-	$c = array_map('intval', $c);
177
-	$s = serialize($c);
178
-	if (isset($quete[$s])) {
179
-		return $quete[$s];
180
-	}
181
-
182
-	if (isset($c['id_rubrique']) and $r = $c['id_rubrique']) {
183
-		unset($c['id_rubrique']);
184
-		$c = ['id_rubrique' => $r] + $c;
185
-	}
186
-
187
-	foreach ($c as $_id => $id) {
188
-		if (
189
-			$id
190
-			and $row = quete_parent_lang(table_objet_sql($liste_objets[$_id]), $id)
191
-		) {
192
-			$lang = $row['lang'] ?? '';
193
-			if ($_id == 'id_rubrique' or (isset($row['id_rubrique']) and $id = $row['id_rubrique'])) {
194
-				return $quete[$s] = [$id, $lang];
195
-			}
196
-		}
197
-	}
198
-
199
-	return $quete[$s] = false;
154
+    static $liste_objets = null;
155
+    static $quete = [];
156
+    if (is_null($liste_objets)) {
157
+        $liste_objets = [];
158
+        include_spip('inc/urls');
159
+        include_spip('public/quete');
160
+        $l = urls_liste_objets(false);
161
+        // placer la rubrique en tete des objets
162
+        $l = array_diff($l, ['rubrique']);
163
+        array_unshift($l, 'rubrique');
164
+        foreach ($l as $objet) {
165
+            $id = id_table_objet($objet);
166
+            if (!isset($liste_objets[$id])) {
167
+                $liste_objets[$id] = objet_type($objet, false);
168
+            }
169
+        }
170
+    }
171
+    $c = array_intersect_key($contexte, $liste_objets);
172
+    if (!count($c)) {
173
+        return false;
174
+    }
175
+
176
+    $c = array_map('intval', $c);
177
+    $s = serialize($c);
178
+    if (isset($quete[$s])) {
179
+        return $quete[$s];
180
+    }
181
+
182
+    if (isset($c['id_rubrique']) and $r = $c['id_rubrique']) {
183
+        unset($c['id_rubrique']);
184
+        $c = ['id_rubrique' => $r] + $c;
185
+    }
186
+
187
+    foreach ($c as $_id => $id) {
188
+        if (
189
+            $id
190
+            and $row = quete_parent_lang(table_objet_sql($liste_objets[$_id]), $id)
191
+        ) {
192
+            $lang = $row['lang'] ?? '';
193
+            if ($_id == 'id_rubrique' or (isset($row['id_rubrique']) and $id = $row['id_rubrique'])) {
194
+                return $quete[$s] = [$id, $lang];
195
+            }
196
+        }
197
+    }
198
+
199
+    return $quete[$s] = false;
200 200
 }
Please login to merge, or discard this patch.
ecrire/public/iterateur.php 1 patch
Indentation   +654 added lines, -654 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
11 11
 \***************************************************************************/
12 12
 
13 13
 if (!defined('_ECRIRE_INC_VERSION')) {
14
-	return;
14
+    return;
15 15
 }
16 16
 
17 17
 /**
@@ -21,667 +21,667 @@  discard block
 block discarded – undo
21 21
  *
22 22
  */
23 23
 class IterFactory {
24
-	public static function create($iterateur, $command, $info = null) {
25
-
26
-		$iter = null;
27
-		// cas des SI {si expression} analises tres tot
28
-		// pour eviter le chargement de tout iterateur
29
-		if (isset($command['si'])) {
30
-			foreach ($command['si'] as $si) {
31
-				if (!$si) {
32
-					// $command pour boucle SQL peut generer des erreurs de compilation
33
-					// s'il est transmis alors qu'on est dans un iterateur vide
34
-					return new IterDecorator(new EmptyIterator(), [], $info);
35
-				}
36
-			}
37
-		}
38
-
39
-		// chercher un iterateur PHP existant (par exemple dans SPL)
40
-		// (il faudrait passer l'argument ->sql_serveur
41
-		// pour etre certain qu'on est sur un "php:")
42
-		if (class_exists($iterateur)) {
43
-			$a = $command['args'] ?? [];
44
-
45
-			// permettre de passer un Iterateur directement {args #ITERATEUR} :
46
-			// si on recoit deja un iterateur en argument, on l'utilise
47
-			if ((is_countable($a) ? count($a) : 0) == 1 and is_object($a[0]) and is_subclass_of($a[0], \Iterator::class)) {
48
-				$iter = $a[0];
49
-
50
-				// sinon, on cree un iterateur du type donne
51
-			} else {
52
-				// arguments de creation de l'iterateur...
53
-				// (pas glop)
54
-				try {
55
-					switch (is_countable($a) ? count($a) : 0) {
56
-						case 0:
57
-							$iter = new $iterateur();
58
-							break;
59
-						case 1:
60
-							$iter = new $iterateur($a[0]);
61
-							break;
62
-						case 2:
63
-							$iter = new $iterateur($a[0], $a[1]);
64
-							break;
65
-						case 3:
66
-							$iter = new $iterateur($a[0], $a[1], $a[2]);
67
-							break;
68
-						case 4:
69
-							$iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);
70
-							break;
71
-					}
72
-				} catch (Exception $e) {
73
-					spip_log("Erreur de chargement de l'iterateur $iterateur");
74
-					spip_log($e->getMessage());
75
-					$iter = new EmptyIterator();
76
-				}
77
-			}
78
-		} else {
79
-			// chercher la classe d'iterateur
80
-			// IterateurXXX
81
-			// definie dans le fichier iterateurs/xxx.php
82
-			$class = 'Iterateur' . $iterateur;
83
-			if (!class_exists($class)) {
84
-				if (
85
-					!include_spip('iterateur/' . strtolower($iterateur))
86
-					or !class_exists($class)
87
-				) {
88
-					die("Iterateur $iterateur non trouv&#233;");
89
-					// si l'iterateur n'existe pas, on se rabat sur le generique
90
-					# $iter = new EmptyIterator();
91
-				}
92
-			}
93
-			$iter = new $class($command, $info);
94
-		}
95
-
96
-		return new IterDecorator($iter, $command, $info);
97
-	}
24
+    public static function create($iterateur, $command, $info = null) {
25
+
26
+        $iter = null;
27
+        // cas des SI {si expression} analises tres tot
28
+        // pour eviter le chargement de tout iterateur
29
+        if (isset($command['si'])) {
30
+            foreach ($command['si'] as $si) {
31
+                if (!$si) {
32
+                    // $command pour boucle SQL peut generer des erreurs de compilation
33
+                    // s'il est transmis alors qu'on est dans un iterateur vide
34
+                    return new IterDecorator(new EmptyIterator(), [], $info);
35
+                }
36
+            }
37
+        }
38
+
39
+        // chercher un iterateur PHP existant (par exemple dans SPL)
40
+        // (il faudrait passer l'argument ->sql_serveur
41
+        // pour etre certain qu'on est sur un "php:")
42
+        if (class_exists($iterateur)) {
43
+            $a = $command['args'] ?? [];
44
+
45
+            // permettre de passer un Iterateur directement {args #ITERATEUR} :
46
+            // si on recoit deja un iterateur en argument, on l'utilise
47
+            if ((is_countable($a) ? count($a) : 0) == 1 and is_object($a[0]) and is_subclass_of($a[0], \Iterator::class)) {
48
+                $iter = $a[0];
49
+
50
+                // sinon, on cree un iterateur du type donne
51
+            } else {
52
+                // arguments de creation de l'iterateur...
53
+                // (pas glop)
54
+                try {
55
+                    switch (is_countable($a) ? count($a) : 0) {
56
+                        case 0:
57
+                            $iter = new $iterateur();
58
+                            break;
59
+                        case 1:
60
+                            $iter = new $iterateur($a[0]);
61
+                            break;
62
+                        case 2:
63
+                            $iter = new $iterateur($a[0], $a[1]);
64
+                            break;
65
+                        case 3:
66
+                            $iter = new $iterateur($a[0], $a[1], $a[2]);
67
+                            break;
68
+                        case 4:
69
+                            $iter = new $iterateur($a[0], $a[1], $a[2], $a[3]);
70
+                            break;
71
+                    }
72
+                } catch (Exception $e) {
73
+                    spip_log("Erreur de chargement de l'iterateur $iterateur");
74
+                    spip_log($e->getMessage());
75
+                    $iter = new EmptyIterator();
76
+                }
77
+            }
78
+        } else {
79
+            // chercher la classe d'iterateur
80
+            // IterateurXXX
81
+            // definie dans le fichier iterateurs/xxx.php
82
+            $class = 'Iterateur' . $iterateur;
83
+            if (!class_exists($class)) {
84
+                if (
85
+                    !include_spip('iterateur/' . strtolower($iterateur))
86
+                    or !class_exists($class)
87
+                ) {
88
+                    die("Iterateur $iterateur non trouv&#233;");
89
+                    // si l'iterateur n'existe pas, on se rabat sur le generique
90
+                    # $iter = new EmptyIterator();
91
+                }
92
+            }
93
+            $iter = new $class($command, $info);
94
+        }
95
+
96
+        return new IterDecorator($iter, $command, $info);
97
+    }
98 98
 }
99 99
 
100 100
 
101 101
 class IterDecorator extends FilterIterator {
102
-	private $iter;
103
-
104
-	/**
105
-	 * Conditions de filtrage
106
-	 * ie criteres de selection
107
-	 *
108
-	 * @var array
109
-	 */
110
-	protected $filtre = [];
111
-
112
-	/**
113
-	 * Fonction de filtrage compilee a partir des criteres de filtre
114
-	 *
115
-	 * @var string
116
-	 */
117
-	protected $func_filtre = null;
118
-
119
-	/**
120
-	 * Critere {offset, limit}
121
-	 *
122
-	 * @var int
123
-	 * @var int
124
-	 */
125
-	protected $offset = null;
126
-	protected $limit = null;
127
-
128
-	/**
129
-	 * nombre d'elements recuperes depuis la position 0,
130
-	 * en tenant compte des filtres
131
-	 *
132
-	 * @var int
133
-	 */
134
-	protected $fetched = 0;
135
-
136
-	/**
137
-	 * Y a t'il une erreur ?
138
-	 *
139
-	 * @var bool
140
-	 **/
141
-	protected $err = false;
142
-
143
-	/**
144
-	 * Drapeau a activer en cas d'echec
145
-	 * (select SQL errone, non chargement des DATA, etc)
146
-	 */
147
-	public function err() {
148
-		if (method_exists($this->iter, 'err')) {
149
-			return $this->iter->err();
150
-		}
151
-		if (property_exists($this->iter, 'err')) {
152
-			return $this->iter->err;
153
-		}
154
-
155
-		return false;
156
-	}
157
-
158
-	public function __construct(Iterator $iter, $command, $info) {
159
-		parent::__construct($iter);
160
-		parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
161
-
162
-		// recuperer l'iterateur transmis
163
-		$this->iter = $this->getInnerIterator();
164
-		$this->command = $command;
165
-		$this->info = $info;
166
-		$this->pos = 0;
167
-		$this->fetched = 0;
168
-
169
-		// chercher la liste des champs a retourner par
170
-		// fetch si l'objet ne les calcule pas tout seul
171
-		if (!method_exists($this->iter, 'fetch')) {
172
-			$this->calculer_select();
173
-			$this->calculer_filtres();
174
-		}
175
-
176
-		// emptyIterator critere {si} faux n'a pas d'erreur !
177
-		if (isset($this->iter->err)) {
178
-			$this->err = $this->iter->err;
179
-		}
180
-
181
-		// pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
182
-		//$this->total = $this->count();
183
-	}
184
-
185
-
186
-	// calcule les elements a retournes par fetch()
187
-	// enleve les elements inutiles du select()
188
-	//
189
-	private function calculer_select() {
190
-		if ($select = &$this->command['select']) {
191
-			foreach ($select as $s) {
192
-				// /!\ $s = '.nom'
193
-				if ($s[0] == '.') {
194
-					$s = substr($s, 1);
195
-				}
196
-				$this->select[] = $s;
197
-			}
198
-		}
199
-	}
200
-
201
-	// recuperer la valeur d'une balise #X
202
-	// en fonction des methodes
203
-	// et proprietes disponibles
204
-	public function get_select($nom) {
205
-		if (
206
-			is_object($this->iter)
207
-			and method_exists($this->iter, $nom)
208
-		) {
209
-			try {
210
-				return $this->iter->$nom();
211
-			} catch (Exception $e) {
212
-				// #GETCHILDREN sur un fichier de DirectoryIterator ...
213
-				spip_log("Methode $nom en echec sur " . get_class($this->iter));
214
-				spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
215
-
216
-				return '';
217
-			}
218
-		}
219
-		/*
102
+    private $iter;
103
+
104
+    /**
105
+     * Conditions de filtrage
106
+     * ie criteres de selection
107
+     *
108
+     * @var array
109
+     */
110
+    protected $filtre = [];
111
+
112
+    /**
113
+     * Fonction de filtrage compilee a partir des criteres de filtre
114
+     *
115
+     * @var string
116
+     */
117
+    protected $func_filtre = null;
118
+
119
+    /**
120
+     * Critere {offset, limit}
121
+     *
122
+     * @var int
123
+     * @var int
124
+     */
125
+    protected $offset = null;
126
+    protected $limit = null;
127
+
128
+    /**
129
+     * nombre d'elements recuperes depuis la position 0,
130
+     * en tenant compte des filtres
131
+     *
132
+     * @var int
133
+     */
134
+    protected $fetched = 0;
135
+
136
+    /**
137
+     * Y a t'il une erreur ?
138
+     *
139
+     * @var bool
140
+     **/
141
+    protected $err = false;
142
+
143
+    /**
144
+     * Drapeau a activer en cas d'echec
145
+     * (select SQL errone, non chargement des DATA, etc)
146
+     */
147
+    public function err() {
148
+        if (method_exists($this->iter, 'err')) {
149
+            return $this->iter->err();
150
+        }
151
+        if (property_exists($this->iter, 'err')) {
152
+            return $this->iter->err;
153
+        }
154
+
155
+        return false;
156
+    }
157
+
158
+    public function __construct(Iterator $iter, $command, $info) {
159
+        parent::__construct($iter);
160
+        parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
161
+
162
+        // recuperer l'iterateur transmis
163
+        $this->iter = $this->getInnerIterator();
164
+        $this->command = $command;
165
+        $this->info = $info;
166
+        $this->pos = 0;
167
+        $this->fetched = 0;
168
+
169
+        // chercher la liste des champs a retourner par
170
+        // fetch si l'objet ne les calcule pas tout seul
171
+        if (!method_exists($this->iter, 'fetch')) {
172
+            $this->calculer_select();
173
+            $this->calculer_filtres();
174
+        }
175
+
176
+        // emptyIterator critere {si} faux n'a pas d'erreur !
177
+        if (isset($this->iter->err)) {
178
+            $this->err = $this->iter->err;
179
+        }
180
+
181
+        // pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
182
+        //$this->total = $this->count();
183
+    }
184
+
185
+
186
+    // calcule les elements a retournes par fetch()
187
+    // enleve les elements inutiles du select()
188
+    //
189
+    private function calculer_select() {
190
+        if ($select = &$this->command['select']) {
191
+            foreach ($select as $s) {
192
+                // /!\ $s = '.nom'
193
+                if ($s[0] == '.') {
194
+                    $s = substr($s, 1);
195
+                }
196
+                $this->select[] = $s;
197
+            }
198
+        }
199
+    }
200
+
201
+    // recuperer la valeur d'une balise #X
202
+    // en fonction des methodes
203
+    // et proprietes disponibles
204
+    public function get_select($nom) {
205
+        if (
206
+            is_object($this->iter)
207
+            and method_exists($this->iter, $nom)
208
+        ) {
209
+            try {
210
+                return $this->iter->$nom();
211
+            } catch (Exception $e) {
212
+                // #GETCHILDREN sur un fichier de DirectoryIterator ...
213
+                spip_log("Methode $nom en echec sur " . get_class($this->iter));
214
+                spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
215
+
216
+                return '';
217
+            }
218
+        }
219
+        /*
220 220
 		if (property_exists($this->iter, $nom)) {
221 221
 			return $this->iter->$nom;
222 222
 		}*/
223
-		// cle et valeur par defaut
224
-		// ICI PLANTAGE SI ON NE CONTROLE PAS $nom
225
-		if (
226
-			in_array($nom, ['cle', 'valeur'])
227
-			and method_exists($this, $nom)
228
-		) {
229
-			return $this->$nom();
230
-		}
231
-
232
-		// Par defaut chercher en xpath dans la valeur()
233
-		return table_valeur($this->valeur(), $nom, null);
234
-	}
235
-
236
-
237
-	private function calculer_filtres() {
238
-
239
-		// Issu de calculer_select() de public/composer L.519
240
-		// TODO: externaliser...
241
-		//
242
-		// retirer les criteres vides:
243
-		// {X ?} avec X absent de l'URL
244
-		// {par #ENV{X}} avec X absent de l'URL
245
-		// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
246
-		if ($where = &$this->command['where']) {
247
-			foreach ($where as $k => $v) {
248
-				$this->filtre[] = $this->traduire_condition_sql_en_filtre($v);
249
-			}
250
-		}
251
-
252
-		// critere {2,7}
253
-		if (isset($this->command['limit']) and $this->command['limit']) {
254
-			$limit = explode(',', $this->command['limit']);
255
-			$this->offset = $limit[0];
256
-			$this->limit = $limit[1];
257
-		}
258
-
259
-		// Creer la fonction de filtrage sur $this
260
-		if ($this->filtre) {
261
-			if ($filtres = $this->assembler_filtres($this->filtre)) {
262
-				$filtres = 'return ' . $filtres . ';';
263
-				$this->func_filtre = fn() => eval($filtres);
264
-			}
265
-			else {
266
-				$this->func_filtre = null;
267
-			}
268
-		}
269
-	}
270
-
271
-	/**
272
-	 * Assembler le tableau de filtres traduits depuis les conditions SQL
273
-	 * les filtres vides ou null sont ignores
274
-	 * @param $filtres
275
-	 * @param string $operateur
276
-	 * @return string|null
277
-	 */
278
-	protected function assembler_filtres($filtres, $operateur = 'AND') {
279
-
280
-		$filtres_string = [];
281
-		foreach ($filtres as $k => $v) {
282
-			// si c'est un tableau de OR/AND + 2 sous-filtres, on recurse pour transformer en chaine
283
-			if (is_array($v) and in_array(reset($v), ['OR', 'AND'])) {
284
-				$op = array_shift($v);
285
-				$v = $this->assembler_filtres($v, $op);
286
-			}
287
-			if (is_null($v) or !is_string($v) or empty($v)) {
288
-				continue;
289
-			}
290
-			$filtres_string[] = $v;
291
-		}
292
-
293
-		if (!count($filtres_string)) {
294
-			return null;
295
-		}
296
-
297
-		return '(' . implode(") $operateur (", $filtres_string) . ')';
298
-	}
299
-
300
-	/**
301
-	 * Traduire un element du tableau where SQL en un filtre
302
-	 * @param $v
303
-	 * @return string|array|null
304
-	 */
305
-	protected function traduire_condition_sql_en_filtre($v) {
306
-		if (is_array($v)) {
307
-			if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
308
-				return 'true';
309
-			} elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
310
-				return 'true';
311
-			} else {
312
-				$op = $v[0] ?: $v;
313
-			}
314
-		} else {
315
-			$op = $v;
316
-		}
317
-		if ((!$op) or ($op == 1) or ($op == '0=0')) {
318
-			return 'true';
319
-		}
320
-		if ($op === '0=1') {
321
-			return 'false';
322
-		}
323
-		// traiter {cle IN a,b} ou {valeur !IN a,b}
324
-		if (preg_match(',^\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)$,', $op, $regs)) {
325
-			return $this->composer_filtre($regs[1], 'IN', $regs[3], $regs[2]);
326
-		}
327
-
328
-		// 3 possibilites : count($v) =
329
-		// * 1 : {x y} ; on recoit $v[0] = y
330
-		// * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
331
-		// * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
332
-
333
-		// 1 : forcement traite par un critere, on passe
334
-		if (!$v or !is_array($v) or count($v) == 1) {
335
-			return null; // sera ignore
336
-		}
337
-		if (count($v) == 2 and is_array($v[1])) {
338
-			return $this->composer_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
339
-		}
340
-		if (count($v) == 3) {
341
-			// traiter le OR/AND suivi de 2 valeurs
342
-			if (in_array($op, ['OR', 'AND'])) {
343
-				array_shift($v);
344
-				foreach (array_keys($v) as $k) {
345
-					$v[$k] = $this->traduire_condition_sql_en_filtre($v[$k]);
346
-					if ($v[$k] === null) {
347
-						unset($v[$k]);
348
-					}
349
-					elseif ($v[$k] === 'true') {
350
-						if ($op === 'OR') {
351
-							return 'true';
352
-						}
353
-						if ($op === 'AND') {
354
-							unset($v[$k]);
355
-						}
356
-					}
357
-					elseif ($v[$k] === 'false') {
358
-						if ($op === 'OR') {
359
-							unset($v[$k]);
360
-						}
361
-						if ($op === 'AND') {
362
-							return 'false';
363
-						}
364
-					}
365
-				}
366
-				if (!count($v)) {
367
-					return null;
368
-				}
369
-				if (count($v) === 1) {
370
-					return reset($v);
371
-				}
372
-				array_unshift($v, $op);
373
-				return $v;
374
-			}
375
-			return $this->composer_filtre($v[1], $v[0], $v[2]);
376
-		}
377
-
378
-		return null;  // sera ignore
379
-	}
380
-
381
-	/**
382
-	 * Calculer un filtre sur un champ du tableau
383
-	 * @param $cle
384
-	 * @param $op
385
-	 * @param $valeur
386
-	 * @param false $not
387
-	 * @return string|null
388
-	 */
389
-	protected function composer_filtre($cle, $op, $valeur, $not = false) {
390
-		if (method_exists($this->iter, 'exception_des_criteres')) {
391
-			if (in_array($cle, $this->iter->exception_des_criteres())) {
392
-				return null;
393
-			}
394
-		}
395
-		// TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
396
-		# mais c'est normalement deja opere par calculer_critere_infixe()
397
-		# qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
398
-		# ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
399
-		# il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
400
-
401
-		# if (!in_array($cle, array('cle', 'valeur')))
402
-		#	return;
403
-
404
-		$a = '$this->get_select(\'' . $cle . '\')';
405
-
406
-		$filtre = '';
407
-
408
-		if ($op == 'REGEXP') {
409
-			$filtre = 'filtrer("match", ' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
410
-			$op = '';
411
-		} else {
412
-			if ($op == 'LIKE') {
413
-				$valeur = str_replace(['\"', '_', '%'], ['"', '.', '.*'], preg_quote($valeur));
414
-				$filtre = 'filtrer("match", ' . $a . ', ' . $valeur . ')';
415
-				$op = '';
416
-			} else {
417
-				if ($op == '=') {
418
-					$op = '==';
419
-				} else {
420
-					if ($op == 'IN') {
421
-						$filtre = 'in_array(' . $a . ', array' . $valeur . ')';
422
-						$op = '';
423
-					} else {
424
-						if (!in_array($op, ['<', '<=', '>', '>='])) {
425
-							spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
426
-							$op = '';
427
-						}
428
-					}
429
-				}
430
-			}
431
-		}
432
-
433
-		if ($op) {
434
-			$filtre = $a . $op . str_replace('\"', '"', $valeur);
435
-		}
436
-
437
-		if ($not) {
438
-			$filtre = "!($filtre)";
439
-		}
440
-
441
-		return $filtre;
442
-	}
443
-
444
-
445
-	public function next() : void {
446
-		$this->pos++;
447
-		parent::next();
448
-	}
449
-
450
-	/**
451
-	 * revient au depart
452
-	 *
453
-	 * @return void
454
-	 */
455
-	public function rewind() : void {
456
-		$this->pos = 0;
457
-		$this->fetched = 0;
458
-		parent::rewind();
459
-	}
460
-
461
-
462
-	# Extension SPIP des iterateurs PHP
463
-	/**
464
-	 * type de l'iterateur
465
-	 *
466
-	 * @var string
467
-	 */
468
-	protected $type;
469
-
470
-	/**
471
-	 * parametres de l'iterateur
472
-	 *
473
-	 * @var array
474
-	 */
475
-	protected $command;
476
-
477
-	/**
478
-	 * infos de compilateur
479
-	 *
480
-	 * @var array
481
-	 */
482
-	protected $info;
483
-
484
-	/**
485
-	 * position courante de l'iterateur
486
-	 *
487
-	 * @var int
488
-	 */
489
-	protected $pos = null;
490
-
491
-	/**
492
-	 * nombre total resultats dans l'iterateur
493
-	 *
494
-	 * @var int
495
-	 */
496
-	protected $total = null;
497
-
498
-	/**
499
-	 * nombre maximal de recherche pour $total
500
-	 * si l'iterateur n'implemente pas de fonction specifique
501
-	 */
502
-	protected $max = 100000;
503
-
504
-
505
-	/**
506
-	 * Liste des champs a inserer dans les $row
507
-	 * retournes par ->fetch()
508
-	 */
509
-	protected $select = [];
510
-
511
-
512
-	/**
513
-	 * aller a la position absolue n,
514
-	 * comptee depuis le debut
515
-	 *
516
-	 * @param int $n
517
-	 *   absolute pos
518
-	 * @param string $continue
519
-	 *   param for sql_ api
520
-	 * @return bool
521
-	 *   success or fail if not implemented
522
-	 */
523
-	public function seek($n = 0, $continue = null) {
524
-		if ($this->func_filtre or !method_exists($this->iter, 'seek') or !$this->iter->seek($n)) {
525
-			$this->seek_loop($n);
526
-		}
527
-		$this->pos = $n;
528
-		$this->fetched = $n;
529
-
530
-		return true;
531
-	}
532
-
533
-	/*
223
+        // cle et valeur par defaut
224
+        // ICI PLANTAGE SI ON NE CONTROLE PAS $nom
225
+        if (
226
+            in_array($nom, ['cle', 'valeur'])
227
+            and method_exists($this, $nom)
228
+        ) {
229
+            return $this->$nom();
230
+        }
231
+
232
+        // Par defaut chercher en xpath dans la valeur()
233
+        return table_valeur($this->valeur(), $nom, null);
234
+    }
235
+
236
+
237
+    private function calculer_filtres() {
238
+
239
+        // Issu de calculer_select() de public/composer L.519
240
+        // TODO: externaliser...
241
+        //
242
+        // retirer les criteres vides:
243
+        // {X ?} avec X absent de l'URL
244
+        // {par #ENV{X}} avec X absent de l'URL
245
+        // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
246
+        if ($where = &$this->command['where']) {
247
+            foreach ($where as $k => $v) {
248
+                $this->filtre[] = $this->traduire_condition_sql_en_filtre($v);
249
+            }
250
+        }
251
+
252
+        // critere {2,7}
253
+        if (isset($this->command['limit']) and $this->command['limit']) {
254
+            $limit = explode(',', $this->command['limit']);
255
+            $this->offset = $limit[0];
256
+            $this->limit = $limit[1];
257
+        }
258
+
259
+        // Creer la fonction de filtrage sur $this
260
+        if ($this->filtre) {
261
+            if ($filtres = $this->assembler_filtres($this->filtre)) {
262
+                $filtres = 'return ' . $filtres . ';';
263
+                $this->func_filtre = fn() => eval($filtres);
264
+            }
265
+            else {
266
+                $this->func_filtre = null;
267
+            }
268
+        }
269
+    }
270
+
271
+    /**
272
+     * Assembler le tableau de filtres traduits depuis les conditions SQL
273
+     * les filtres vides ou null sont ignores
274
+     * @param $filtres
275
+     * @param string $operateur
276
+     * @return string|null
277
+     */
278
+    protected function assembler_filtres($filtres, $operateur = 'AND') {
279
+
280
+        $filtres_string = [];
281
+        foreach ($filtres as $k => $v) {
282
+            // si c'est un tableau de OR/AND + 2 sous-filtres, on recurse pour transformer en chaine
283
+            if (is_array($v) and in_array(reset($v), ['OR', 'AND'])) {
284
+                $op = array_shift($v);
285
+                $v = $this->assembler_filtres($v, $op);
286
+            }
287
+            if (is_null($v) or !is_string($v) or empty($v)) {
288
+                continue;
289
+            }
290
+            $filtres_string[] = $v;
291
+        }
292
+
293
+        if (!count($filtres_string)) {
294
+            return null;
295
+        }
296
+
297
+        return '(' . implode(") $operateur (", $filtres_string) . ')';
298
+    }
299
+
300
+    /**
301
+     * Traduire un element du tableau where SQL en un filtre
302
+     * @param $v
303
+     * @return string|array|null
304
+     */
305
+    protected function traduire_condition_sql_en_filtre($v) {
306
+        if (is_array($v)) {
307
+            if ((count($v) >= 2) && ($v[0] == 'REGEXP') && ($v[2] == "'.*'")) {
308
+                return 'true';
309
+            } elseif ((count($v) >= 2) && ($v[0] == 'LIKE') && ($v[2] == "'%'")) {
310
+                return 'true';
311
+            } else {
312
+                $op = $v[0] ?: $v;
313
+            }
314
+        } else {
315
+            $op = $v;
316
+        }
317
+        if ((!$op) or ($op == 1) or ($op == '0=0')) {
318
+            return 'true';
319
+        }
320
+        if ($op === '0=1') {
321
+            return 'false';
322
+        }
323
+        // traiter {cle IN a,b} ou {valeur !IN a,b}
324
+        if (preg_match(',^\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)$,', $op, $regs)) {
325
+            return $this->composer_filtre($regs[1], 'IN', $regs[3], $regs[2]);
326
+        }
327
+
328
+        // 3 possibilites : count($v) =
329
+        // * 1 : {x y} ; on recoit $v[0] = y
330
+        // * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
331
+        // * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
332
+
333
+        // 1 : forcement traite par un critere, on passe
334
+        if (!$v or !is_array($v) or count($v) == 1) {
335
+            return null; // sera ignore
336
+        }
337
+        if (count($v) == 2 and is_array($v[1])) {
338
+            return $this->composer_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
339
+        }
340
+        if (count($v) == 3) {
341
+            // traiter le OR/AND suivi de 2 valeurs
342
+            if (in_array($op, ['OR', 'AND'])) {
343
+                array_shift($v);
344
+                foreach (array_keys($v) as $k) {
345
+                    $v[$k] = $this->traduire_condition_sql_en_filtre($v[$k]);
346
+                    if ($v[$k] === null) {
347
+                        unset($v[$k]);
348
+                    }
349
+                    elseif ($v[$k] === 'true') {
350
+                        if ($op === 'OR') {
351
+                            return 'true';
352
+                        }
353
+                        if ($op === 'AND') {
354
+                            unset($v[$k]);
355
+                        }
356
+                    }
357
+                    elseif ($v[$k] === 'false') {
358
+                        if ($op === 'OR') {
359
+                            unset($v[$k]);
360
+                        }
361
+                        if ($op === 'AND') {
362
+                            return 'false';
363
+                        }
364
+                    }
365
+                }
366
+                if (!count($v)) {
367
+                    return null;
368
+                }
369
+                if (count($v) === 1) {
370
+                    return reset($v);
371
+                }
372
+                array_unshift($v, $op);
373
+                return $v;
374
+            }
375
+            return $this->composer_filtre($v[1], $v[0], $v[2]);
376
+        }
377
+
378
+        return null;  // sera ignore
379
+    }
380
+
381
+    /**
382
+     * Calculer un filtre sur un champ du tableau
383
+     * @param $cle
384
+     * @param $op
385
+     * @param $valeur
386
+     * @param false $not
387
+     * @return string|null
388
+     */
389
+    protected function composer_filtre($cle, $op, $valeur, $not = false) {
390
+        if (method_exists($this->iter, 'exception_des_criteres')) {
391
+            if (in_array($cle, $this->iter->exception_des_criteres())) {
392
+                return null;
393
+            }
394
+        }
395
+        // TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
396
+        # mais c'est normalement deja opere par calculer_critere_infixe()
397
+        # qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
398
+        # ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
399
+        # il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
400
+
401
+        # if (!in_array($cle, array('cle', 'valeur')))
402
+        #	return;
403
+
404
+        $a = '$this->get_select(\'' . $cle . '\')';
405
+
406
+        $filtre = '';
407
+
408
+        if ($op == 'REGEXP') {
409
+            $filtre = 'filtrer("match", ' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
410
+            $op = '';
411
+        } else {
412
+            if ($op == 'LIKE') {
413
+                $valeur = str_replace(['\"', '_', '%'], ['"', '.', '.*'], preg_quote($valeur));
414
+                $filtre = 'filtrer("match", ' . $a . ', ' . $valeur . ')';
415
+                $op = '';
416
+            } else {
417
+                if ($op == '=') {
418
+                    $op = '==';
419
+                } else {
420
+                    if ($op == 'IN') {
421
+                        $filtre = 'in_array(' . $a . ', array' . $valeur . ')';
422
+                        $op = '';
423
+                    } else {
424
+                        if (!in_array($op, ['<', '<=', '>', '>='])) {
425
+                            spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
426
+                            $op = '';
427
+                        }
428
+                    }
429
+                }
430
+            }
431
+        }
432
+
433
+        if ($op) {
434
+            $filtre = $a . $op . str_replace('\"', '"', $valeur);
435
+        }
436
+
437
+        if ($not) {
438
+            $filtre = "!($filtre)";
439
+        }
440
+
441
+        return $filtre;
442
+    }
443
+
444
+
445
+    public function next() : void {
446
+        $this->pos++;
447
+        parent::next();
448
+    }
449
+
450
+    /**
451
+     * revient au depart
452
+     *
453
+     * @return void
454
+     */
455
+    public function rewind() : void {
456
+        $this->pos = 0;
457
+        $this->fetched = 0;
458
+        parent::rewind();
459
+    }
460
+
461
+
462
+    # Extension SPIP des iterateurs PHP
463
+    /**
464
+     * type de l'iterateur
465
+     *
466
+     * @var string
467
+     */
468
+    protected $type;
469
+
470
+    /**
471
+     * parametres de l'iterateur
472
+     *
473
+     * @var array
474
+     */
475
+    protected $command;
476
+
477
+    /**
478
+     * infos de compilateur
479
+     *
480
+     * @var array
481
+     */
482
+    protected $info;
483
+
484
+    /**
485
+     * position courante de l'iterateur
486
+     *
487
+     * @var int
488
+     */
489
+    protected $pos = null;
490
+
491
+    /**
492
+     * nombre total resultats dans l'iterateur
493
+     *
494
+     * @var int
495
+     */
496
+    protected $total = null;
497
+
498
+    /**
499
+     * nombre maximal de recherche pour $total
500
+     * si l'iterateur n'implemente pas de fonction specifique
501
+     */
502
+    protected $max = 100000;
503
+
504
+
505
+    /**
506
+     * Liste des champs a inserer dans les $row
507
+     * retournes par ->fetch()
508
+     */
509
+    protected $select = [];
510
+
511
+
512
+    /**
513
+     * aller a la position absolue n,
514
+     * comptee depuis le debut
515
+     *
516
+     * @param int $n
517
+     *   absolute pos
518
+     * @param string $continue
519
+     *   param for sql_ api
520
+     * @return bool
521
+     *   success or fail if not implemented
522
+     */
523
+    public function seek($n = 0, $continue = null) {
524
+        if ($this->func_filtre or !method_exists($this->iter, 'seek') or !$this->iter->seek($n)) {
525
+            $this->seek_loop($n);
526
+        }
527
+        $this->pos = $n;
528
+        $this->fetched = $n;
529
+
530
+        return true;
531
+    }
532
+
533
+    /*
534 534
 	 * aller a la position $n en parcourant
535 535
 	 * un par un tous les elements
536 536
 	 */
537
-	private function seek_loop($n) {
538
-		if ($this->pos > $n) {
539
-			$this->rewind();
540
-		}
541
-
542
-		while ($this->pos < $n and $this->valid()) {
543
-			$this->next();
544
-		}
545
-
546
-		return true;
547
-	}
548
-
549
-	/**
550
-	 * Avancer de $saut pas
551
-	 *
552
-	 * @param  $saut
553
-	 * @param  $max
554
-	 * @return int
555
-	 */
556
-	public function skip($saut, $max = null) {
557
-		// pas de saut en arriere autorise pour cette fonction
558
-		if (($saut = intval($saut)) <= 0) {
559
-			return $this->pos;
560
-		}
561
-		$seek = $this->pos + $saut;
562
-		// si le saut fait depasser le maxi, on libere la resource
563
-		// et on sort
564
-		if (is_null($max)) {
565
-			$max = $this->count();
566
-		}
567
-
568
-		if ($seek >= $max or $seek >= $this->count()) {
569
-			// sortie plus rapide que de faire next() jusqu'a la fin !
570
-			$this->free();
571
-
572
-			return $max;
573
-		}
574
-
575
-		$this->seek($seek);
576
-
577
-		return $this->pos;
578
-	}
579
-
580
-	/**
581
-	 * Renvoyer un tableau des donnees correspondantes
582
-	 * a la position courante de l'iterateur
583
-	 * en controlant si on respecte le filtre
584
-	 * Appliquer aussi le critere {offset,limit}
585
-	 *
586
-	 * @return array|bool
587
-	 */
588
-	public function fetch() {
589
-		if (method_exists($this->iter, 'fetch')) {
590
-			return $this->iter->fetch();
591
-		} else {
592
-			while (
593
-				$this->valid()
594
-				and (
595
-					!$this->accept()
596
-					or (isset($this->offset) and $this->fetched++ < $this->offset)
597
-				)
598
-			) {
599
-				$this->next();
600
-			}
601
-
602
-			if (!$this->valid()) {
603
-				return false;
604
-			}
605
-
606
-			if (
607
-				isset($this->limit)
608
-				and $this->fetched > $this->offset + $this->limit
609
-			) {
610
-				return false;
611
-			}
612
-
613
-			$r = [];
614
-			foreach ($this->select as $nom) {
615
-				$r[$nom] = $this->get_select($nom);
616
-			}
617
-			$this->next();
618
-
619
-			return $r;
620
-		}
621
-	}
622
-
623
-	// retourner la cle pour #CLE
624
-	public function cle() {
625
-		return $this->key();
626
-	}
627
-
628
-	// retourner la valeur pour #VALEUR
629
-	public function valeur() {
630
-		return $this->current();
631
-	}
632
-
633
-	/**
634
-	 * Accepte-t-on l'entree courante lue ?
635
-	 * On execute les filtres pour le savoir.
636
-	 **/
637
-	public function accept(): bool {
638
-		if ($f = $this->func_filtre) {
639
-			return $f();
640
-		}
641
-
642
-		return true;
643
-	}
644
-
645
-	/**
646
-	 * liberer la ressource
647
-	 *
648
-	 * @return bool
649
-	 */
650
-	public function free() {
651
-		if (method_exists($this->iter, 'free')) {
652
-			$this->iter->free();
653
-		}
654
-		$this->pos = $this->total = 0;
655
-
656
-		return true;
657
-	}
658
-
659
-	/**
660
-	 * Compter le nombre total de resultats
661
-	 * pour #TOTAL_BOUCLE
662
-	 *
663
-	 * @return int
664
-	 */
665
-	public function count() {
666
-		if (is_null($this->total)) {
667
-			if (
668
-				method_exists($this->iter, 'count')
669
-				and !$this->func_filtre
670
-			) {
671
-				return $this->total = $this->iter->count();
672
-			} else {
673
-				// compter les lignes et rembobiner
674
-				$total = 0;
675
-				$pos = $this->pos; // sauver la position
676
-				$this->rewind();
677
-				while ($this->fetch() and $total < $this->max) {
678
-					$total++;
679
-				}
680
-				$this->seek($pos);
681
-				$this->total = $total;
682
-			}
683
-		}
684
-
685
-		return $this->total;
686
-	}
537
+    private function seek_loop($n) {
538
+        if ($this->pos > $n) {
539
+            $this->rewind();
540
+        }
541
+
542
+        while ($this->pos < $n and $this->valid()) {
543
+            $this->next();
544
+        }
545
+
546
+        return true;
547
+    }
548
+
549
+    /**
550
+     * Avancer de $saut pas
551
+     *
552
+     * @param  $saut
553
+     * @param  $max
554
+     * @return int
555
+     */
556
+    public function skip($saut, $max = null) {
557
+        // pas de saut en arriere autorise pour cette fonction
558
+        if (($saut = intval($saut)) <= 0) {
559
+            return $this->pos;
560
+        }
561
+        $seek = $this->pos + $saut;
562
+        // si le saut fait depasser le maxi, on libere la resource
563
+        // et on sort
564
+        if (is_null($max)) {
565
+            $max = $this->count();
566
+        }
567
+
568
+        if ($seek >= $max or $seek >= $this->count()) {
569
+            // sortie plus rapide que de faire next() jusqu'a la fin !
570
+            $this->free();
571
+
572
+            return $max;
573
+        }
574
+
575
+        $this->seek($seek);
576
+
577
+        return $this->pos;
578
+    }
579
+
580
+    /**
581
+     * Renvoyer un tableau des donnees correspondantes
582
+     * a la position courante de l'iterateur
583
+     * en controlant si on respecte le filtre
584
+     * Appliquer aussi le critere {offset,limit}
585
+     *
586
+     * @return array|bool
587
+     */
588
+    public function fetch() {
589
+        if (method_exists($this->iter, 'fetch')) {
590
+            return $this->iter->fetch();
591
+        } else {
592
+            while (
593
+                $this->valid()
594
+                and (
595
+                    !$this->accept()
596
+                    or (isset($this->offset) and $this->fetched++ < $this->offset)
597
+                )
598
+            ) {
599
+                $this->next();
600
+            }
601
+
602
+            if (!$this->valid()) {
603
+                return false;
604
+            }
605
+
606
+            if (
607
+                isset($this->limit)
608
+                and $this->fetched > $this->offset + $this->limit
609
+            ) {
610
+                return false;
611
+            }
612
+
613
+            $r = [];
614
+            foreach ($this->select as $nom) {
615
+                $r[$nom] = $this->get_select($nom);
616
+            }
617
+            $this->next();
618
+
619
+            return $r;
620
+        }
621
+    }
622
+
623
+    // retourner la cle pour #CLE
624
+    public function cle() {
625
+        return $this->key();
626
+    }
627
+
628
+    // retourner la valeur pour #VALEUR
629
+    public function valeur() {
630
+        return $this->current();
631
+    }
632
+
633
+    /**
634
+     * Accepte-t-on l'entree courante lue ?
635
+     * On execute les filtres pour le savoir.
636
+     **/
637
+    public function accept(): bool {
638
+        if ($f = $this->func_filtre) {
639
+            return $f();
640
+        }
641
+
642
+        return true;
643
+    }
644
+
645
+    /**
646
+     * liberer la ressource
647
+     *
648
+     * @return bool
649
+     */
650
+    public function free() {
651
+        if (method_exists($this->iter, 'free')) {
652
+            $this->iter->free();
653
+        }
654
+        $this->pos = $this->total = 0;
655
+
656
+        return true;
657
+    }
658
+
659
+    /**
660
+     * Compter le nombre total de resultats
661
+     * pour #TOTAL_BOUCLE
662
+     *
663
+     * @return int
664
+     */
665
+    public function count() {
666
+        if (is_null($this->total)) {
667
+            if (
668
+                method_exists($this->iter, 'count')
669
+                and !$this->func_filtre
670
+            ) {
671
+                return $this->total = $this->iter->count();
672
+            } else {
673
+                // compter les lignes et rembobiner
674
+                $total = 0;
675
+                $pos = $this->pos; // sauver la position
676
+                $this->rewind();
677
+                while ($this->fetch() and $total < $this->max) {
678
+                    $total++;
679
+                }
680
+                $this->seek($pos);
681
+                $this->total = $total;
682
+            }
683
+        }
684
+
685
+        return $this->total;
686
+    }
687 687
 }
Please login to merge, or discard this patch.
ecrire/public/quete.php 1 patch
Indentation   +412 added lines, -412 removed lines patch added patch discarded remove patch
@@ -19,7 +19,7 @@  discard block
 block discarded – undo
19 19
  **/
20 20
 
21 21
 if (!defined('_ECRIRE_INC_VERSION')) {
22
-	return;
22
+    return;
23 23
 }
24 24
 
25 25
 
@@ -33,16 +33,16 @@  discard block
 block discarded – undo
33 33
  * @return array|bool|null
34 34
  */
35 35
 function quete_virtuel($id_article, $connect) {
36
-	return sql_getfetsel(
37
-		'virtuel',
38
-		'spip_articles',
39
-		['id_article=' . intval($id_article), "statut='publie'"],
40
-		'',
41
-		'',
42
-		'',
43
-		'',
44
-		$connect
45
-	);
36
+    return sql_getfetsel(
37
+        'virtuel',
38
+        'spip_articles',
39
+        ['id_article=' . intval($id_article), "statut='publie'"],
40
+        '',
41
+        '',
42
+        '',
43
+        '',
44
+        $connect
45
+    );
46 46
 }
47 47
 
48 48
 /**
@@ -57,41 +57,41 @@  discard block
 block discarded – undo
57 57
  * @return array
58 58
  */
59 59
 function quete_parent_lang($table, $id, string $connect = '') {
60
-	static $cache_quete = [];
61
-
62
-	if (!isset($cache_quete[$connect][$table][$id])) {
63
-		if (!isset($cache_quete[$connect][$table]['_select'])) {
64
-			$trouver_table = charger_fonction('trouver_table', 'base');
65
-			if (
66
-				!$desc = $trouver_table(
67
-					$table,
68
-					$connect
69
-				) or !isset($desc['field']['id_rubrique'])
70
-			) {
71
-				// pas de parent rubrique, on passe
72
-				$cache_quete[$connect][$table]['_select'] = false;
73
-			} else {
74
-				$select = ($table == 'spip_rubriques' ? 'id_parent' : 'id_rubrique');
75
-				$select .= isset($desc['field']['lang']) ? ', lang' : '';
76
-				$cache_quete[$connect][$table]['_select'] = $select;
77
-				$cache_quete[$connect][$table]['_id'] = id_table_objet(objet_type($table));
78
-			}
79
-		}
80
-		if ($cache_quete[$connect][$table]['_select']) {
81
-			$cache_quete[$connect][$table][$id] = sql_fetsel(
82
-				$cache_quete[$connect][$table]['_select'],
83
-				$table,
84
-				$cache_quete[$connect][$table]['_id'] . '=' . intval($id),
85
-				'',
86
-				'',
87
-				'',
88
-				'',
89
-				$connect
90
-			);
91
-		}
92
-	}
93
-
94
-	return $cache_quete[$connect][$table][$id] ?? null;
60
+    static $cache_quete = [];
61
+
62
+    if (!isset($cache_quete[$connect][$table][$id])) {
63
+        if (!isset($cache_quete[$connect][$table]['_select'])) {
64
+            $trouver_table = charger_fonction('trouver_table', 'base');
65
+            if (
66
+                !$desc = $trouver_table(
67
+                    $table,
68
+                    $connect
69
+                ) or !isset($desc['field']['id_rubrique'])
70
+            ) {
71
+                // pas de parent rubrique, on passe
72
+                $cache_quete[$connect][$table]['_select'] = false;
73
+            } else {
74
+                $select = ($table == 'spip_rubriques' ? 'id_parent' : 'id_rubrique');
75
+                $select .= isset($desc['field']['lang']) ? ', lang' : '';
76
+                $cache_quete[$connect][$table]['_select'] = $select;
77
+                $cache_quete[$connect][$table]['_id'] = id_table_objet(objet_type($table));
78
+            }
79
+        }
80
+        if ($cache_quete[$connect][$table]['_select']) {
81
+            $cache_quete[$connect][$table][$id] = sql_fetsel(
82
+                $cache_quete[$connect][$table]['_select'],
83
+                $table,
84
+                $cache_quete[$connect][$table]['_id'] . '=' . intval($id),
85
+                '',
86
+                '',
87
+                '',
88
+                '',
89
+                $connect
90
+            );
91
+        }
92
+    }
93
+
94
+    return $cache_quete[$connect][$table][$id] ?? null;
95 95
 }
96 96
 
97 97
 
@@ -108,11 +108,11 @@  discard block
 block discarded – undo
108 108
  * @return int
109 109
  */
110 110
 function quete_parent($id_rubrique, string $connect = '') {
111
-	if (!$id_rubrique = intval($id_rubrique)) {
112
-		return 0;
113
-	}
114
-	$id_parent = quete_parent_lang('spip_rubriques', $id_rubrique, $connect);
115
-	return $id_parent ? $id_parent['id_parent'] : 0;
111
+    if (!$id_rubrique = intval($id_rubrique)) {
112
+        return 0;
113
+    }
114
+    $id_parent = quete_parent_lang('spip_rubriques', $id_rubrique, $connect);
115
+    return $id_parent ? $id_parent['id_parent'] : 0;
116 116
 }
117 117
 
118 118
 /**
@@ -128,9 +128,9 @@  discard block
 block discarded – undo
128 128
  * @return int
129 129
  */
130 130
 function quete_rubrique($id_article, $serveur) {
131
-	$id_parent = quete_parent_lang('spip_articles', $id_article, $serveur);
131
+    $id_parent = quete_parent_lang('spip_articles', $id_article, $serveur);
132 132
 
133
-	return $id_parent['id_rubrique'];
133
+    return $id_parent['id_rubrique'];
134 134
 }
135 135
 
136 136
 
@@ -144,13 +144,13 @@  discard block
 block discarded – undo
144 144
  * @return int
145 145
  */
146 146
 function quete_profondeur($id, string $connect = '') {
147
-	$n = 0;
148
-	while ($id) {
149
-		$n++;
150
-		$id = quete_parent($id, $connect);
151
-	}
147
+    $n = 0;
148
+    while ($id) {
149
+        $n++;
150
+        $id = quete_parent($id, $connect);
151
+    }
152 152
 
153
-	return $n;
153
+    return $n;
154 154
 }
155 155
 
156 156
 
@@ -166,15 +166,15 @@  discard block
 block discarded – undo
166 166
  *     Morceau de la requête SQL testant la date
167 167
  */
168 168
 function quete_condition_postdates($champ_date, $serveur = '', $ignore_previsu = false) {
169
-	if (defined('_VAR_PREVIEW') and _VAR_PREVIEW and !$ignore_previsu) {
170
-		return '1=1';
171
-	}
172
-
173
-	return
174
-		(isset($GLOBALS['meta']['date_prochain_postdate'])
175
-			and $GLOBALS['meta']['date_prochain_postdate'] > time())
176
-			? "$champ_date<" . sql_quote(date('Y-m-d H:i:s', $GLOBALS['meta']['date_prochain_postdate']), $serveur)
177
-			: '1=1';
169
+    if (defined('_VAR_PREVIEW') and _VAR_PREVIEW and !$ignore_previsu) {
170
+        return '1=1';
171
+    }
172
+
173
+    return
174
+        (isset($GLOBALS['meta']['date_prochain_postdate'])
175
+            and $GLOBALS['meta']['date_prochain_postdate'] > time())
176
+            ? "$champ_date<" . sql_quote(date('Y-m-d H:i:s', $GLOBALS['meta']['date_prochain_postdate']), $serveur)
177
+            : '1=1';
178 178
 }
179 179
 
180 180
 
@@ -194,101 +194,101 @@  discard block
 block discarded – undo
194 194
  * @return array|string
195 195
  */
196 196
 function quete_condition_statut($mstatut, $previsu, $publie, $serveur = '', $ignore_previsu = false) {
197
-	static $cond = [];
198
-	$key = func_get_args();
199
-	$key = implode('-', $key);
200
-	if (isset($cond[$key])) {
201
-		return $cond[$key];
202
-	}
203
-
204
-	$liste_statuts = $publie;
205
-	if (defined('_VAR_PREVIEW') and _VAR_PREVIEW and !$ignore_previsu) {
206
-		$liste_statuts = $previsu;
207
-	}
208
-	$not = false;
209
-	if (strncmp($liste_statuts, '!', 1) == 0) {
210
-		$not = true;
211
-		$liste_statuts = substr($liste_statuts, 1);
212
-	}
213
-	// '' => ne rien afficher, '!'=> ne rien filtrer
214
-	if (!strlen($liste_statuts)) {
215
-		return $cond[$key] = ($not ? '1=1' : '0=1');
216
-	}
217
-
218
-	$liste_statuts = explode(',', $liste_statuts);
219
-	$where = [];
220
-	foreach ($liste_statuts as $k => $v) {
221
-		// filtrage /auteur pour limiter les objets d'un statut (prepa en general)
222
-		// a ceux de l'auteur identifie
223
-		if (strpos($v, '/') !== false) {
224
-			$v = explode('/', $v);
225
-			$filtre = end($v);
226
-			$v = reset($v);
227
-			$v = preg_replace(',\W,', '', $v);
228
-			if (
229
-				$filtre == 'auteur'
230
-				and (strpos($mstatut, '.') !== false)
231
-				and $objet = explode('.', $mstatut)
232
-				and $id_table = reset($objet)
233
-				and $objet = objet_type($id_table)
234
-			) {
235
-				$w = "$mstatut<>" . sql_quote($v);
236
-
237
-				// retrouver l’id_auteur qui a filé un lien de prévisu éventuellement,
238
-				// sinon l’auteur en session
239
-				include_spip('inc/securiser_action');
240
-				if ($desc = decrire_token_previsu()) {
241
-					$id_auteur = $desc['id_auteur'];
242
-				} elseif (isset($GLOBALS['visiteur_session']['id_auteur'])) {
243
-					$id_auteur = intval($GLOBALS['visiteur_session']['id_auteur']);
244
-				} else {
245
-					$id_auteur = null;
246
-				}
247
-
248
-				// dans ce cas (admin en general), pas de filtrage sur ce statut
249
-				if (!autoriser('previsualiser' . $v, $objet, '', $id_auteur)) {
250
-					// si pas d'auteur identifie pas de sous-requete car pas d'article qui matche
251
-					if (!$id_auteur) {
252
-						$where[] = $w;
253
-					} else {
254
-						$primary = id_table_objet($objet);
255
-						$where[] = "($w OR $id_table.$primary IN (" . sql_get_select(
256
-							'ssss.id_objet',
257
-							'spip_auteurs_liens AS ssss',
258
-							'ssss.objet=' . sql_quote($objet) . ' AND ssss.id_auteur=' . intval($id_auteur),
259
-							'',
260
-							'',
261
-							'',
262
-							'',
263
-							$serveur
264
-						) . '))';
265
-					}
266
-				}
267
-			} // ignorer ce statut si on ne sait pas comment le filtrer
268
-			else {
269
-				$v = '';
270
-			}
271
-		}
272
-		// securite
273
-		$liste_statuts[$k] = preg_replace(',\W,', '', $v);
274
-	}
275
-	$liste_statuts = array_filter($liste_statuts);
276
-	if (count($liste_statuts) == 1) {
277
-		$where[] = ['=', $mstatut, sql_quote(reset($liste_statuts), $serveur)];
278
-	} else {
279
-		$where[] = sql_in($mstatut, $liste_statuts, $not, $serveur);
280
-	}
281
-
282
-	while (count($where) > 1) {
283
-		$and = ['AND', array_pop($where), array_pop($where)];
284
-		$where[] = $and;
285
-	}
286
-	$cond[$key] = reset($where);
287
-	if ($not) {
288
-		$cond[$key] = ['NOT', $cond[$key]];
289
-	}
290
-
291
-	return $cond[$key];
197
+    static $cond = [];
198
+    $key = func_get_args();
199
+    $key = implode('-', $key);
200
+    if (isset($cond[$key])) {
201
+        return $cond[$key];
202
+    }
203
+
204
+    $liste_statuts = $publie;
205
+    if (defined('_VAR_PREVIEW') and _VAR_PREVIEW and !$ignore_previsu) {
206
+        $liste_statuts = $previsu;
207
+    }
208
+    $not = false;
209
+    if (strncmp($liste_statuts, '!', 1) == 0) {
210
+        $not = true;
211
+        $liste_statuts = substr($liste_statuts, 1);
212
+    }
213
+    // '' => ne rien afficher, '!'=> ne rien filtrer
214
+    if (!strlen($liste_statuts)) {
215
+        return $cond[$key] = ($not ? '1=1' : '0=1');
216
+    }
217
+
218
+    $liste_statuts = explode(',', $liste_statuts);
219
+    $where = [];
220
+    foreach ($liste_statuts as $k => $v) {
221
+        // filtrage /auteur pour limiter les objets d'un statut (prepa en general)
222
+        // a ceux de l'auteur identifie
223
+        if (strpos($v, '/') !== false) {
224
+            $v = explode('/', $v);
225
+            $filtre = end($v);
226
+            $v = reset($v);
227
+            $v = preg_replace(',\W,', '', $v);
228
+            if (
229
+                $filtre == 'auteur'
230
+                and (strpos($mstatut, '.') !== false)
231
+                and $objet = explode('.', $mstatut)
232
+                and $id_table = reset($objet)
233
+                and $objet = objet_type($id_table)
234
+            ) {
235
+                $w = "$mstatut<>" . sql_quote($v);
236
+
237
+                // retrouver l’id_auteur qui a filé un lien de prévisu éventuellement,
238
+                // sinon l’auteur en session
239
+                include_spip('inc/securiser_action');
240
+                if ($desc = decrire_token_previsu()) {
241
+                    $id_auteur = $desc['id_auteur'];
242
+                } elseif (isset($GLOBALS['visiteur_session']['id_auteur'])) {
243
+                    $id_auteur = intval($GLOBALS['visiteur_session']['id_auteur']);
244
+                } else {
245
+                    $id_auteur = null;
246
+                }
247
+
248
+                // dans ce cas (admin en general), pas de filtrage sur ce statut
249
+                if (!autoriser('previsualiser' . $v, $objet, '', $id_auteur)) {
250
+                    // si pas d'auteur identifie pas de sous-requete car pas d'article qui matche
251
+                    if (!$id_auteur) {
252
+                        $where[] = $w;
253
+                    } else {
254
+                        $primary = id_table_objet($objet);
255
+                        $where[] = "($w OR $id_table.$primary IN (" . sql_get_select(
256
+                            'ssss.id_objet',
257
+                            'spip_auteurs_liens AS ssss',
258
+                            'ssss.objet=' . sql_quote($objet) . ' AND ssss.id_auteur=' . intval($id_auteur),
259
+                            '',
260
+                            '',
261
+                            '',
262
+                            '',
263
+                            $serveur
264
+                        ) . '))';
265
+                    }
266
+                }
267
+            } // ignorer ce statut si on ne sait pas comment le filtrer
268
+            else {
269
+                $v = '';
270
+            }
271
+        }
272
+        // securite
273
+        $liste_statuts[$k] = preg_replace(',\W,', '', $v);
274
+    }
275
+    $liste_statuts = array_filter($liste_statuts);
276
+    if (count($liste_statuts) == 1) {
277
+        $where[] = ['=', $mstatut, sql_quote(reset($liste_statuts), $serveur)];
278
+    } else {
279
+        $where[] = sql_in($mstatut, $liste_statuts, $not, $serveur);
280
+    }
281
+
282
+    while (count($where) > 1) {
283
+        $and = ['AND', array_pop($where), array_pop($where)];
284
+        $where[] = $and;
285
+    }
286
+    $cond[$key] = reset($where);
287
+    if ($not) {
288
+        $cond[$key] = ['NOT', $cond[$key]];
289
+    }
290
+
291
+    return $cond[$key];
292 292
 }
293 293
 
294 294
 /**
@@ -299,7 +299,7 @@  discard block
 block discarded – undo
299 299
  * @return array|bool|null
300 300
  */
301 301
 function quete_fichier($id_document, $serveur = '') {
302
-	return sql_getfetsel('fichier', 'spip_documents', ('id_document=' . intval($id_document)), '', [], '', '', $serveur);
302
+    return sql_getfetsel('fichier', 'spip_documents', ('id_document=' . intval($id_document)), '', [], '', '', $serveur);
303 303
 }
304 304
 
305 305
 /**
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
  * @return array|bool
311 311
  */
312 312
 function quete_document($id_document, $serveur = '') {
313
-	return sql_fetsel('*', 'spip_documents', ('id_document=' . intval($id_document)), '', [], '', '', $serveur);
313
+    return sql_fetsel('*', 'spip_documents', ('id_document=' . intval($id_document)), '', [], '', '', $serveur);
314 314
 }
315 315
 
316 316
 /**
@@ -321,7 +321,7 @@  discard block
 block discarded – undo
321 321
  * @return array|bool|null
322 322
  */
323 323
 function quete_meta($nom, $serveur) {
324
-	return sql_getfetsel('valeur', 'spip_meta', 'nom=' . sql_quote($nom), '', '', '', '', $serveur);
324
+    return sql_getfetsel('valeur', 'spip_meta', 'nom=' . sql_quote($nom), '', '', '', '', $serveur);
325 325
 }
326 326
 
327 327
 /**
@@ -347,66 +347,66 @@  discard block
 block discarded – undo
347 347
  *     Retourne soit un tableau, soit le chemin du fichier.
348 348
  */
349 349
 function quete_logo($cle_objet, $onoff, $id, $id_rubrique, $flag) {
350
-	include_spip('base/objets');
351
-	$nom = strtolower($onoff);
352
-
353
-	$cle_objet = id_table_objet($cle_objet);
354
-
355
-	while (1) {
356
-		$objet = objet_type($cle_objet);
357
-
358
-		$on = quete_logo_objet($id, $objet, $nom);
359
-
360
-		if ($on) {
361
-			if ($flag) {
362
-				return basename($on['chemin']);
363
-			} else {
364
-				$taille = @spip_getimagesize($on['chemin']);
365
-
366
-				// Si on a déjà demandé un survol directement ($onoff = off)
367
-				// ou qu'on a demandé uniquement le normal ($onoff = on)
368
-				// alors on ne cherche pas du tout le survol ici
369
-				if ($onoff != 'ON') {
370
-					$off = '';
371
-				} else {
372
-					// Sinon, c'est qu'on demande normal ET survol à la fois, donc on cherche maintenant le survol
373
-					$off = quete_logo_objet($id, $objet, 'off');
374
-				}
375
-
376
-				// on retourne une url du type IMG/artonXX?timestamp
377
-				// qui permet de distinguer le changement de logo
378
-				// et placer un expire sur le dossier IMG/
379
-				$res = [
380
-					$on['chemin'] . ($on['timestamp'] ? "?{$on['timestamp']}" : ''),
381
-					($off ? $off['chemin'] . ($off['timestamp'] ? "?{$off['timestamp']}" : '') : ''),
382
-					(!$taille ? '' : (' ' . $taille[3]))
383
-				];
384
-				$res['src'] = $res[0];
385
-				$res['logo_on'] = $res[0];
386
-				$res['logo_off'] = $res[1];
387
-				$res['width'] = ($taille ? $taille[0] : '');
388
-				$res['height'] = ($taille ? $taille[1] : '');
389
-
390
-				return $res;
391
-			}
392
-		} else {
393
-			if (defined('_LOGO_RUBRIQUE_DESACTIVER_HERITAGE')) {
394
-				return '';
395
-			} else {
396
-				if ($id_rubrique) {
397
-					$cle_objet = 'id_rubrique';
398
-					$id = $id_rubrique;
399
-					$id_rubrique = 0;
400
-				} else {
401
-					if ($id and $cle_objet == 'id_rubrique') {
402
-						$id = quete_parent($id);
403
-					} else {
404
-						return '';
405
-					}
406
-				}
407
-			}
408
-		}
409
-	}
350
+    include_spip('base/objets');
351
+    $nom = strtolower($onoff);
352
+
353
+    $cle_objet = id_table_objet($cle_objet);
354
+
355
+    while (1) {
356
+        $objet = objet_type($cle_objet);
357
+
358
+        $on = quete_logo_objet($id, $objet, $nom);
359
+
360
+        if ($on) {
361
+            if ($flag) {
362
+                return basename($on['chemin']);
363
+            } else {
364
+                $taille = @spip_getimagesize($on['chemin']);
365
+
366
+                // Si on a déjà demandé un survol directement ($onoff = off)
367
+                // ou qu'on a demandé uniquement le normal ($onoff = on)
368
+                // alors on ne cherche pas du tout le survol ici
369
+                if ($onoff != 'ON') {
370
+                    $off = '';
371
+                } else {
372
+                    // Sinon, c'est qu'on demande normal ET survol à la fois, donc on cherche maintenant le survol
373
+                    $off = quete_logo_objet($id, $objet, 'off');
374
+                }
375
+
376
+                // on retourne une url du type IMG/artonXX?timestamp
377
+                // qui permet de distinguer le changement de logo
378
+                // et placer un expire sur le dossier IMG/
379
+                $res = [
380
+                    $on['chemin'] . ($on['timestamp'] ? "?{$on['timestamp']}" : ''),
381
+                    ($off ? $off['chemin'] . ($off['timestamp'] ? "?{$off['timestamp']}" : '') : ''),
382
+                    (!$taille ? '' : (' ' . $taille[3]))
383
+                ];
384
+                $res['src'] = $res[0];
385
+                $res['logo_on'] = $res[0];
386
+                $res['logo_off'] = $res[1];
387
+                $res['width'] = ($taille ? $taille[0] : '');
388
+                $res['height'] = ($taille ? $taille[1] : '');
389
+
390
+                return $res;
391
+            }
392
+        } else {
393
+            if (defined('_LOGO_RUBRIQUE_DESACTIVER_HERITAGE')) {
394
+                return '';
395
+            } else {
396
+                if ($id_rubrique) {
397
+                    $cle_objet = 'id_rubrique';
398
+                    $id = $id_rubrique;
399
+                    $id_rubrique = 0;
400
+                } else {
401
+                    if ($id and $cle_objet == 'id_rubrique') {
402
+                        $id = quete_parent($id);
403
+                    } else {
404
+                        return '';
405
+                    }
406
+                }
407
+            }
408
+        }
409
+    }
410 410
 }
411 411
 
412 412
 /**
@@ -420,37 +420,37 @@  discard block
 block discarded – undo
420 420
  * 		"on" ou "off" suivant le logo normal ou survol
421 421
  **/
422 422
 function quete_logo_objet($id_objet, $objet, $mode) {
423
-	static $chercher_logo;
424
-	if (is_null($chercher_logo)) {
425
-		$chercher_logo = charger_fonction('chercher_logo', 'inc');
426
-	}
427
-	$cle_objet = id_table_objet($objet);
428
-
429
-	// On cherche pas la méthode classique
430
-	$infos_logo = $chercher_logo($id_objet, $cle_objet, $mode);
431
-	// Si la méthode classique a trouvé quelque chose, on utilise le nouveau format
432
-	if (!empty($infos_logo)) {
433
-		$infos_logo = [
434
-			'chemin' => $infos_logo[0],
435
-			'timestamp' => $infos_logo[4],
436
-		];
437
-	}
438
-
439
-	// On passe cette recherche de logo dans un pipeline
440
-	$infos_logo = pipeline(
441
-		'quete_logo_objet',
442
-		[
443
-			'args' => [
444
-				'id_objet' => $id_objet,
445
-				'objet' => $objet,
446
-				'cle_objet' => $cle_objet,
447
-				'mode' => $mode,
448
-			],
449
-			'data' => $infos_logo,
450
-		]
451
-	);
452
-
453
-	return $infos_logo;
423
+    static $chercher_logo;
424
+    if (is_null($chercher_logo)) {
425
+        $chercher_logo = charger_fonction('chercher_logo', 'inc');
426
+    }
427
+    $cle_objet = id_table_objet($objet);
428
+
429
+    // On cherche pas la méthode classique
430
+    $infos_logo = $chercher_logo($id_objet, $cle_objet, $mode);
431
+    // Si la méthode classique a trouvé quelque chose, on utilise le nouveau format
432
+    if (!empty($infos_logo)) {
433
+        $infos_logo = [
434
+            'chemin' => $infos_logo[0],
435
+            'timestamp' => $infos_logo[4],
436
+        ];
437
+    }
438
+
439
+    // On passe cette recherche de logo dans un pipeline
440
+    $infos_logo = pipeline(
441
+        'quete_logo_objet',
442
+        [
443
+            'args' => [
444
+                'id_objet' => $id_objet,
445
+                'objet' => $objet,
446
+                'cle_objet' => $cle_objet,
447
+                'mode' => $mode,
448
+            ],
449
+            'data' => $infos_logo,
450
+        ]
451
+    );
452
+
453
+    return $infos_logo;
454 454
 }
455 455
 
456 456
 /**
@@ -463,25 +463,25 @@  discard block
 block discarded – undo
463 463
  * @return bool|string
464 464
  */
465 465
 function quete_logo_file($row, $connect = null) {
466
-	include_spip('inc/documents');
467
-	$logo = vignette_logo_document($row, $connect);
468
-	if (!$logo) {
469
-		$logo = image_du_document($row, $connect);
470
-	}
471
-	if (!$logo) {
472
-		$f = charger_fonction('vignette', 'inc');
473
-		$logo = $f($row['extension'], false);
474
-	}
475
-	// si c'est une vignette type doc, la renvoyer direct
476
-	if (
477
-		strcmp($logo, _DIR_PLUGINS) == 0
478
-		or strcmp($logo, _DIR_PLUGINS_DIST) == 0
479
-		or strcmp($logo, _DIR_RACINE . 'prive/') == 0
480
-	) {
481
-		return $logo;
482
-	}
483
-
484
-	return get_spip_doc($logo);
466
+    include_spip('inc/documents');
467
+    $logo = vignette_logo_document($row, $connect);
468
+    if (!$logo) {
469
+        $logo = image_du_document($row, $connect);
470
+    }
471
+    if (!$logo) {
472
+        $f = charger_fonction('vignette', 'inc');
473
+        $logo = $f($row['extension'], false);
474
+    }
475
+    // si c'est une vignette type doc, la renvoyer direct
476
+    if (
477
+        strcmp($logo, _DIR_PLUGINS) == 0
478
+        or strcmp($logo, _DIR_PLUGINS_DIST) == 0
479
+        or strcmp($logo, _DIR_RACINE . 'prive/') == 0
480
+    ) {
481
+        return $logo;
482
+    }
483
+
484
+    return get_spip_doc($logo);
485 485
 }
486 486
 
487 487
 /**
@@ -509,20 +509,20 @@  discard block
 block discarded – undo
509 509
  */
510 510
 function quete_logo_document($row, $lien, $align, $mode_logo, $x, $y, string $connect = '') {
511 511
 
512
-	include_spip('inc/documents');
513
-	$logo = '';
514
-	if (!in_array($mode_logo, ['icone', 'apercu'])) {
515
-		$logo = vignette_logo_document($row, $connect);
516
-	}
517
-	// si on veut explicitement la vignette, ne rien renvoyer si il n'y en a pas
518
-	if ($mode_logo == 'vignette' and !$logo) {
519
-		return '';
520
-	}
521
-	if ($mode_logo == 'icone') {
522
-		$row['fichier'] = '';
523
-	}
524
-
525
-	return vignette_automatique($logo, $row, $lien, $x, $y, $align, null, $connect);
512
+    include_spip('inc/documents');
513
+    $logo = '';
514
+    if (!in_array($mode_logo, ['icone', 'apercu'])) {
515
+        $logo = vignette_logo_document($row, $connect);
516
+    }
517
+    // si on veut explicitement la vignette, ne rien renvoyer si il n'y en a pas
518
+    if ($mode_logo == 'vignette' and !$logo) {
519
+        return '';
520
+    }
521
+    if ($mode_logo == 'icone') {
522
+        $row['fichier'] = '';
523
+    }
524
+
525
+    return vignette_automatique($logo, $row, $lien, $x, $y, $align, null, $connect);
526 526
 }
527 527
 
528 528
 /**
@@ -534,19 +534,19 @@  discard block
 block discarded – undo
534 534
  */
535 535
 function quete_html_logo($logo, $align, $lien) {
536 536
 
537
-	if (!is_array($logo)) {
538
-		return '';
539
-	}
540
-
541
-	$contexte = [];
542
-	foreach ($logo as $k => $v) {
543
-		if (!is_numeric($k)) {
544
-			$contexte[$k] = $v;
545
-		}
546
-	}
547
-	$contexte['align'] = $align;
548
-	$contexte['lien'] = $lien;
549
-	return recuperer_fond('modeles/logo', $contexte);
537
+    if (!is_array($logo)) {
538
+        return '';
539
+    }
540
+
541
+    $contexte = [];
542
+    foreach ($logo as $k => $v) {
543
+        if (!is_numeric($k)) {
544
+            $contexte[$k] = $v;
545
+        }
546
+    }
547
+    $contexte['align'] = $align;
548
+    $contexte['lien'] = $lien;
549
+    return recuperer_fond('modeles/logo', $contexte);
550 550
 }
551 551
 
552 552
 /**
@@ -560,14 +560,14 @@  discard block
 block discarded – undo
560 560
  * @return string|false
561 561
  */
562 562
 function document_spip_externe($fichier, $connect) {
563
-	if ($connect) {
564
-		$site = quete_meta('adresse_site', $connect);
565
-		if ($site) {
566
-			$dir = quete_meta('dir_img', $connect);
567
-			return "$site/$dir$fichier";
568
-		}
569
-	}
570
-	return false;
563
+    if ($connect) {
564
+        $site = quete_meta('adresse_site', $connect);
565
+        if ($site) {
566
+            $dir = quete_meta('dir_img', $connect);
567
+            return "$site/$dir$fichier";
568
+        }
569
+    }
570
+    return false;
571 571
 }
572 572
 
573 573
 /**
@@ -580,23 +580,23 @@  discard block
 block discarded – undo
580 580
  * @return string
581 581
  */
582 582
 function vignette_logo_document($row, string $connect = '') {
583
-	if (!$row['id_vignette']) {
584
-		return '';
585
-	}
586
-	$fichier = quete_fichier($row['id_vignette'], $connect);
587
-	if ($url = document_spip_externe($fichier, $connect)) {
588
-		return $url;
589
-	}
590
-
591
-	$f = get_spip_doc($fichier);
592
-	if ($f and @file_exists($f)) {
593
-		return $f;
594
-	}
595
-	if ($row['mode'] !== 'vignette') {
596
-		return '';
597
-	}
598
-
599
-	return generer_url_entite($row['id_document'], 'document', '', '', $connect);
583
+    if (!$row['id_vignette']) {
584
+        return '';
585
+    }
586
+    $fichier = quete_fichier($row['id_vignette'], $connect);
587
+    if ($url = document_spip_externe($fichier, $connect)) {
588
+        return $url;
589
+    }
590
+
591
+    $f = get_spip_doc($fichier);
592
+    if ($f and @file_exists($f)) {
593
+        return $f;
594
+    }
595
+    if ($row['mode'] !== 'vignette') {
596
+        return '';
597
+    }
598
+
599
+    return generer_url_entite($row['id_document'], 'document', '', '', $connect);
600 600
 }
601 601
 
602 602
 /**
@@ -612,66 +612,66 @@  discard block
 block discarded – undo
612 612
  * @return bool|string
613 613
  */
614 614
 function calcul_exposer($id, $prim, $reference, $parent, $type, string $connect = '') {
615
-	static $exposer = [];
616
-
617
-	// Que faut-il exposer ? Tous les elements de $reference
618
-	// ainsi que leur hierarchie ; on ne fait donc ce calcul
619
-	// qu'une fois (par squelette) et on conserve le resultat
620
-	// en static.
621
-	if (!isset($exposer[$m = md5(serialize($reference))][$prim])) {
622
-		$principal = $reference[$type] ?? $reference["@$type"] ?? '';
623
-		// le parent fournit en argument est le parent de $id, pas celui de $principal
624
-		// il n'est donc pas utile
625
-		$parent = 0;
626
-		if (!$principal) { // regarder si un enfant est dans le contexte, auquel cas il expose peut etre le parent courant
627
-			$enfants = ['id_rubrique' => ['id_article'], 'id_groupe' => ['id_mot']];
628
-			if (isset($enfants[$type])) {
629
-				foreach ($enfants[$type] as $t) {
630
-					if (
631
-						isset($reference[$t])
632
-						// cas de la reference donnee dynamiquement par la pagination
633
-						or isset($reference["@$t"])
634
-					) {
635
-						$type = $t;
636
-						$principal = $reference[$type] ?? $reference["@$type"];
637
-						continue;
638
-					}
639
-				}
640
-			}
641
-		}
642
-		$exposer[$m][$type] = [];
643
-		if ($principal) {
644
-			$principaux = is_array($principal) ? $principal : [$principal];
645
-			foreach ($principaux as $principal) {
646
-				$exposer[$m][$type][$principal] = true;
647
-				if ($type == 'id_mot') {
648
-					if (!$parent) {
649
-						$parent = sql_getfetsel('id_groupe', 'spip_mots', 'id_mot=' . intval($principal), '', '', '', '', $connect);
650
-					}
651
-					if ($parent) {
652
-						$exposer[$m]['id_groupe'][$parent] = true;
653
-					}
654
-				} else {
655
-					if ($type != 'id_groupe') {
656
-						if (!$parent) {
657
-							if ($type == 'id_rubrique') {
658
-								$parent = $principal;
659
-							}
660
-							if ($type == 'id_article') {
661
-								$parent = quete_rubrique($principal, $connect);
662
-							}
663
-						}
664
-						do {
665
-							$exposer[$m]['id_rubrique'][$parent] = true;
666
-						} while ($parent = quete_parent($parent, $connect));
667
-					}
668
-				}
669
-			}
670
-		}
671
-	}
672
-
673
-	// And the winner is...
674
-	return isset($exposer[$m][$prim]) ? isset($exposer[$m][$prim][$id]) : '';
615
+    static $exposer = [];
616
+
617
+    // Que faut-il exposer ? Tous les elements de $reference
618
+    // ainsi que leur hierarchie ; on ne fait donc ce calcul
619
+    // qu'une fois (par squelette) et on conserve le resultat
620
+    // en static.
621
+    if (!isset($exposer[$m = md5(serialize($reference))][$prim])) {
622
+        $principal = $reference[$type] ?? $reference["@$type"] ?? '';
623
+        // le parent fournit en argument est le parent de $id, pas celui de $principal
624
+        // il n'est donc pas utile
625
+        $parent = 0;
626
+        if (!$principal) { // regarder si un enfant est dans le contexte, auquel cas il expose peut etre le parent courant
627
+            $enfants = ['id_rubrique' => ['id_article'], 'id_groupe' => ['id_mot']];
628
+            if (isset($enfants[$type])) {
629
+                foreach ($enfants[$type] as $t) {
630
+                    if (
631
+                        isset($reference[$t])
632
+                        // cas de la reference donnee dynamiquement par la pagination
633
+                        or isset($reference["@$t"])
634
+                    ) {
635
+                        $type = $t;
636
+                        $principal = $reference[$type] ?? $reference["@$type"];
637
+                        continue;
638
+                    }
639
+                }
640
+            }
641
+        }
642
+        $exposer[$m][$type] = [];
643
+        if ($principal) {
644
+            $principaux = is_array($principal) ? $principal : [$principal];
645
+            foreach ($principaux as $principal) {
646
+                $exposer[$m][$type][$principal] = true;
647
+                if ($type == 'id_mot') {
648
+                    if (!$parent) {
649
+                        $parent = sql_getfetsel('id_groupe', 'spip_mots', 'id_mot=' . intval($principal), '', '', '', '', $connect);
650
+                    }
651
+                    if ($parent) {
652
+                        $exposer[$m]['id_groupe'][$parent] = true;
653
+                    }
654
+                } else {
655
+                    if ($type != 'id_groupe') {
656
+                        if (!$parent) {
657
+                            if ($type == 'id_rubrique') {
658
+                                $parent = $principal;
659
+                            }
660
+                            if ($type == 'id_article') {
661
+                                $parent = quete_rubrique($principal, $connect);
662
+                            }
663
+                        }
664
+                        do {
665
+                            $exposer[$m]['id_rubrique'][$parent] = true;
666
+                        } while ($parent = quete_parent($parent, $connect));
667
+                    }
668
+                }
669
+            }
670
+        }
671
+    }
672
+
673
+    // And the winner is...
674
+    return isset($exposer[$m][$prim]) ? isset($exposer[$m][$prim][$id]) : '';
675 675
 }
676 676
 
677 677
 /**
@@ -686,23 +686,23 @@  discard block
 block discarded – undo
686 686
  * @return int
687 687
  */
688 688
 function quete_debut_pagination($primary, $valeur, $pas, $iter) {
689
-	// on ne devrait pas arriver ici si la cle primaire est inexistante
690
-	// ou composee, mais verifions
691
-	if (!$primary or preg_match('/[,\s]/', $primary)) {
692
-		return 0;
693
-	}
694
-
695
-	$pos = 0;
696
-	while ($row = $iter->fetch() and $row[$primary] != $valeur) {
697
-		$pos++;
698
-	}
699
-	// si on a pas trouve
700
-	if (!$row or $row[$primary] != $valeur) {
701
-		return 0;
702
-	}
703
-
704
-	// sinon, calculer le bon numero de page
705
-	return floor($pos / $pas) * $pas;
689
+    // on ne devrait pas arriver ici si la cle primaire est inexistante
690
+    // ou composee, mais verifions
691
+    if (!$primary or preg_match('/[,\s]/', $primary)) {
692
+        return 0;
693
+    }
694
+
695
+    $pos = 0;
696
+    while ($row = $iter->fetch() and $row[$primary] != $valeur) {
697
+        $pos++;
698
+    }
699
+    // si on a pas trouve
700
+    if (!$row or $row[$primary] != $valeur) {
701
+        return 0;
702
+    }
703
+
704
+    // sinon, calculer le bon numero de page
705
+    return floor($pos / $pas) * $pas;
706 706
 }
707 707
 
708 708
 /**
@@ -713,11 +713,11 @@  discard block
 block discarded – undo
713 713
  * @return boolean
714 714
  */
715 715
 function is_whereable($value): bool {
716
-	if (is_array($value) && count($value)) {
717
-		return true;
718
-	}
719
-	if (is_scalar($value) && strlen($value)) {
720
-		return true;
721
-	}
722
-	return false;
716
+    if (is_array($value) && count($value)) {
717
+        return true;
718
+    }
719
+    if (is_scalar($value) && strlen($value)) {
720
+        return true;
721
+    }
722
+    return false;
723 723
 }
Please login to merge, or discard this patch.
ecrire/public/criteres.php 1 patch
Indentation   +1709 added lines, -1709 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
  **/
18 18
 
19 19
 if (!defined('_ECRIRE_INC_VERSION')) {
20
-	return;
20
+    return;
21 21
 }
22 22
 
23 23
 /**
@@ -43,12 +43,12 @@  discard block
 block discarded – undo
43 43
  **/
44 44
 function critere_racine_dist($idb, &$boucles, $crit) {
45 45
 
46
-	$not = $crit->not;
47
-	$boucle = &$boucles[$idb];
48
-	$id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
46
+    $not = $crit->not;
47
+    $boucle = &$boucles[$idb];
48
+    $id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
49 49
 
50
-	$c = ["'='", "'$boucle->id_table." . "$id_parent'", 0];
51
-	$boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
50
+    $c = ["'='", "'$boucle->id_table." . "$id_parent'", 0];
51
+    $boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
52 52
 }
53 53
 
54 54
 
@@ -65,15 +65,15 @@  discard block
 block discarded – undo
65 65
  * @return void
66 66
  **/
67 67
 function critere_exclus_dist($idb, &$boucles, $crit) {
68
-	$not = $crit->not;
69
-	$boucle = &$boucles[$idb];
70
-	$id = $boucle->primary;
71
-
72
-	if ($not or !$id) {
73
-		return (['zbug_critere_inconnu', ['critere' => $not . $crit->op]]);
74
-	}
75
-	$arg = kwote(calculer_argument_precedent($idb, $id, $boucles));
76
-	$boucle->where[] = ["'!='", "'$boucle->id_table." . "$id'", $arg];
68
+    $not = $crit->not;
69
+    $boucle = &$boucles[$idb];
70
+    $id = $boucle->primary;
71
+
72
+    if ($not or !$id) {
73
+        return (['zbug_critere_inconnu', ['critere' => $not . $crit->op]]);
74
+    }
75
+    $arg = kwote(calculer_argument_precedent($idb, $id, $boucles));
76
+    $boucle->where[] = ["'!='", "'$boucle->id_table." . "$id'", $arg];
77 77
 }
78 78
 
79 79
 
@@ -93,73 +93,73 @@  discard block
 block discarded – undo
93 93
  * @return void
94 94
  **/
95 95
 function critere_doublons_dist($idb, &$boucles, $crit) {
96
-	$boucle = &$boucles[$idb];
97
-	$primary = $boucle->primary;
98
-
99
-	// la table nécessite une clé primaire, non composée
100
-	if (!$primary or strpos($primary, ',')) {
101
-		return (['zbug_doublon_sur_table_sans_cle_primaire']);
102
-	}
103
-
104
-	$not = ($crit->not ? '' : 'NOT');
105
-
106
-	// le doublon s'applique sur un type de boucle (article)
107
-	$nom = "'" . $boucle->type_requete . "'";
108
-
109
-	// compléter le nom avec un nom précisé {doublons nom}
110
-	// on obtient $nom = "'article' . 'nom'"
111
-	if (isset($crit->param[0])) {
112
-		$nom .= '.' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
113
-	}
114
-
115
-	// code qui déclarera l'index du stockage de nos doublons (pour éviter une notice PHP)
116
-	$init_comment = "\n\n\t// Initialise le(s) critère(s) doublons\n";
117
-	$init_code = "\tif (!isset(\$doublons[\$d = $nom])) { \$doublons[\$d] = ''; }\n";
118
-
119
-	// on crée un sql_in avec la clé primaire de la table
120
-	// et la collection des doublons déjà emmagasinés dans le tableau
121
-	// $doublons et son index, ici $nom
122
-
123
-	// debut du code "sql_in('articles.id_article', "
124
-	$debut_in = "sql_in('" . $boucle->id_table . '.' . $primary . "', ";
125
-	// lecture des données du doublon "$doublons[$doublon_index[] = "
126
-	// Attention : boucle->doublons désigne une variable qu'on affecte
127
-	$debut_doub = '$doublons[' . (!$not ? '' : ($boucle->doublons . '[]= '));
128
-
129
-	// le debut complet du code des doublons
130
-	$debut_doub = $debut_in . $debut_doub;
131
-
132
-	// nom du doublon "('article' . 'nom')]"
133
-	$fin_doub = "($nom)]";
134
-
135
-	// si on trouve un autre critère doublon,
136
-	// on fusionne pour avoir un seul IN, et on s'en va !
137
-	foreach ($boucle->where as $k => $w) {
138
-		if (strpos($w[0], $debut_doub) === 0) {
139
-			// fusionner le sql_in (du where)
140
-			$boucle->where[$k][0] = $debut_doub . $fin_doub . ' . ' . substr($w[0], strlen($debut_in));
141
-			// fusionner l'initialisation (du hash) pour faire plus joli
142
-			$x = strpos($boucle->hash, $init_comment);
143
-			$len = strlen($init_comment);
144
-			$boucle->hash =
145
-				substr($boucle->hash, 0, $x + $len) . $init_code . substr($boucle->hash, $x + $len);
146
-
147
-			return;
148
-		}
149
-	}
150
-
151
-	// mettre l'ensemble dans un tableau pour que ce ne soit pas vu comme une constante
152
-	$boucle->where[] = [$debut_doub . $fin_doub . ", '" . $not . "')"];
153
-
154
-	// déclarer le doublon s'il n'existe pas encore
155
-	$boucle->hash .= $init_comment . $init_code;
156
-
157
-
158
-	# la ligne suivante avait l'intention d'eviter une collecte deja faite
159
-	# mais elle fait planter une boucle a 2 critere doublons:
160
-	# {!doublons A}{doublons B}
161
-	# (de http://article.gmane.org/gmane.comp.web.spip.devel/31034)
162
-	#	if ($crit->not) $boucle->doublons = "";
96
+    $boucle = &$boucles[$idb];
97
+    $primary = $boucle->primary;
98
+
99
+    // la table nécessite une clé primaire, non composée
100
+    if (!$primary or strpos($primary, ',')) {
101
+        return (['zbug_doublon_sur_table_sans_cle_primaire']);
102
+    }
103
+
104
+    $not = ($crit->not ? '' : 'NOT');
105
+
106
+    // le doublon s'applique sur un type de boucle (article)
107
+    $nom = "'" . $boucle->type_requete . "'";
108
+
109
+    // compléter le nom avec un nom précisé {doublons nom}
110
+    // on obtient $nom = "'article' . 'nom'"
111
+    if (isset($crit->param[0])) {
112
+        $nom .= '.' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
113
+    }
114
+
115
+    // code qui déclarera l'index du stockage de nos doublons (pour éviter une notice PHP)
116
+    $init_comment = "\n\n\t// Initialise le(s) critère(s) doublons\n";
117
+    $init_code = "\tif (!isset(\$doublons[\$d = $nom])) { \$doublons[\$d] = ''; }\n";
118
+
119
+    // on crée un sql_in avec la clé primaire de la table
120
+    // et la collection des doublons déjà emmagasinés dans le tableau
121
+    // $doublons et son index, ici $nom
122
+
123
+    // debut du code "sql_in('articles.id_article', "
124
+    $debut_in = "sql_in('" . $boucle->id_table . '.' . $primary . "', ";
125
+    // lecture des données du doublon "$doublons[$doublon_index[] = "
126
+    // Attention : boucle->doublons désigne une variable qu'on affecte
127
+    $debut_doub = '$doublons[' . (!$not ? '' : ($boucle->doublons . '[]= '));
128
+
129
+    // le debut complet du code des doublons
130
+    $debut_doub = $debut_in . $debut_doub;
131
+
132
+    // nom du doublon "('article' . 'nom')]"
133
+    $fin_doub = "($nom)]";
134
+
135
+    // si on trouve un autre critère doublon,
136
+    // on fusionne pour avoir un seul IN, et on s'en va !
137
+    foreach ($boucle->where as $k => $w) {
138
+        if (strpos($w[0], $debut_doub) === 0) {
139
+            // fusionner le sql_in (du where)
140
+            $boucle->where[$k][0] = $debut_doub . $fin_doub . ' . ' . substr($w[0], strlen($debut_in));
141
+            // fusionner l'initialisation (du hash) pour faire plus joli
142
+            $x = strpos($boucle->hash, $init_comment);
143
+            $len = strlen($init_comment);
144
+            $boucle->hash =
145
+                substr($boucle->hash, 0, $x + $len) . $init_code . substr($boucle->hash, $x + $len);
146
+
147
+            return;
148
+        }
149
+    }
150
+
151
+    // mettre l'ensemble dans un tableau pour que ce ne soit pas vu comme une constante
152
+    $boucle->where[] = [$debut_doub . $fin_doub . ", '" . $not . "')"];
153
+
154
+    // déclarer le doublon s'il n'existe pas encore
155
+    $boucle->hash .= $init_comment . $init_code;
156
+
157
+
158
+    # la ligne suivante avait l'intention d'eviter une collecte deja faite
159
+    # mais elle fait planter une boucle a 2 critere doublons:
160
+    # {!doublons A}{doublons B}
161
+    # (de http://article.gmane.org/gmane.comp.web.spip.devel/31034)
162
+    #	if ($crit->not) $boucle->doublons = "";
163 163
 }
164 164
 
165 165
 
@@ -180,14 +180,14 @@  discard block
 block discarded – undo
180 180
  * @return void
181 181
  **/
182 182
 function critere_lang_select_dist($idb, &$boucles, $crit) {
183
-	if (!isset($crit->param[1][0]) or !($param = $crit->param[1][0]->texte)) {
184
-		$param = 'oui';
185
-	}
186
-	if ($crit->not) {
187
-		$param = ($param == 'oui') ? 'non' : 'oui';
188
-	}
189
-	$boucle = &$boucles[$idb];
190
-	$boucle->lang_select = $param;
183
+    if (!isset($crit->param[1][0]) or !($param = $crit->param[1][0]->texte)) {
184
+        $param = 'oui';
185
+    }
186
+    if ($crit->not) {
187
+        $param = ($param == 'oui') ? 'non' : 'oui';
188
+    }
189
+    $boucle = &$boucles[$idb];
190
+    $boucle->lang_select = $param;
191 191
 }
192 192
 
193 193
 
@@ -209,15 +209,15 @@  discard block
 block discarded – undo
209 209
  * @return void
210 210
  **/
211 211
 function critere_debut_dist($idb, &$boucles, $crit) {
212
-	[$un, $deux] = $crit->param;
213
-	$un = $un[0]->texte;
214
-	$deux = $deux[0]->texte;
215
-	if ($deux) {
216
-		$boucles[$idb]->limit = 
217
-			'intval($Pile[0]["debut' . $un . '"]) . ",' . $deux . '"';
218
-	} else {
219
-		calculer_critere_DEFAUT_dist($idb, $boucles, $crit);
220
-	}
212
+    [$un, $deux] = $crit->param;
213
+    $un = $un[0]->texte;
214
+    $deux = $deux[0]->texte;
215
+    if ($deux) {
216
+        $boucles[$idb]->limit = 
217
+            'intval($Pile[0]["debut' . $un . '"]) . ",' . $deux . '"';
218
+    } else {
219
+        calculer_critere_DEFAUT_dist($idb, $boucles, $crit);
220
+    }
221 221
 }
222 222
 
223 223
 
@@ -251,58 +251,58 @@  discard block
 block discarded – undo
251 251
  **/
252 252
 function critere_pagination_dist($idb, &$boucles, $crit) {
253 253
 
254
-	$boucle = &$boucles[$idb];
255
-	// definition de la taille de la page
256
-	$pas = !isset($crit->param[0][0]) ? "''"
257
-		: calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
258
-
259
-	if (!preg_match(_CODE_QUOTE, $pas, $r)) {
260
-		$pas = "((\$a = intval($pas)) ? \$a : 10)";
261
-	} else {
262
-		$r = intval($r[2]);
263
-		$pas = strval($r ?: 10);
264
-	}
265
-
266
-	// Calcul du nommage de la pagination si il existe.
267
-	// La nouvelle syntaxe {pagination 20, nom} est prise en compte et privilégiée mais on reste
268
-	// compatible avec l'ancienne car certains cas fonctionnent correctement
269
-	$type = "'$idb'";
270
-	// Calcul d'un nommage spécifique de la pagination si précisé.
271
-	// Syntaxe {pagination 20, nom}
272
-	if (isset($crit->param[0][1])) {
273
-		$type = calculer_liste([$crit->param[0][1]], $idb, $boucles, $boucle->id_parent);
274
-	} // Ancienne syntaxe {pagination 20 nom} pour compatibilité
275
-	elseif (isset($crit->param[1][0])) {
276
-		$type = calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
277
-	}
278
-
279
-	$debut = ($type[0] !== "'") ? "'debut'.$type" : ("'debut" . substr($type, 1));
280
-	$boucle->modificateur['debut_nom'] = $type;
281
-	$partie =
282
-		// tester si le numero de page demande est de la forme '@yyy'
283
-		'isset($Pile[0][' . $debut . ']) ? $Pile[0][' . $debut . '] : _request(' . $debut . ");\n"
284
-		. "\tif (\$debut_boucle && \$debut_boucle[0] === '@') {\n"
285
-		. "\t\t" . '$debut_boucle = $Pile[0][' . $debut . '] = quete_debut_pagination(\'' . $boucle->primary . '\',$Pile[0][\'@' . $boucle->primary . '\'] = substr($debut_boucle,1),' . $pas . ',$iter);' . "\n"
286
-		. "\t\t" . '$iter->seek(0);' . "\n"
287
-		. "\t}\n"
288
-		. "\t" . '$debut_boucle = intval($debut_boucle)';
289
-
290
-	$boucle->hash .= '
254
+    $boucle = &$boucles[$idb];
255
+    // definition de la taille de la page
256
+    $pas = !isset($crit->param[0][0]) ? "''"
257
+        : calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
258
+
259
+    if (!preg_match(_CODE_QUOTE, $pas, $r)) {
260
+        $pas = "((\$a = intval($pas)) ? \$a : 10)";
261
+    } else {
262
+        $r = intval($r[2]);
263
+        $pas = strval($r ?: 10);
264
+    }
265
+
266
+    // Calcul du nommage de la pagination si il existe.
267
+    // La nouvelle syntaxe {pagination 20, nom} est prise en compte et privilégiée mais on reste
268
+    // compatible avec l'ancienne car certains cas fonctionnent correctement
269
+    $type = "'$idb'";
270
+    // Calcul d'un nommage spécifique de la pagination si précisé.
271
+    // Syntaxe {pagination 20, nom}
272
+    if (isset($crit->param[0][1])) {
273
+        $type = calculer_liste([$crit->param[0][1]], $idb, $boucles, $boucle->id_parent);
274
+    } // Ancienne syntaxe {pagination 20 nom} pour compatibilité
275
+    elseif (isset($crit->param[1][0])) {
276
+        $type = calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
277
+    }
278
+
279
+    $debut = ($type[0] !== "'") ? "'debut'.$type" : ("'debut" . substr($type, 1));
280
+    $boucle->modificateur['debut_nom'] = $type;
281
+    $partie =
282
+        // tester si le numero de page demande est de la forme '@yyy'
283
+        'isset($Pile[0][' . $debut . ']) ? $Pile[0][' . $debut . '] : _request(' . $debut . ");\n"
284
+        . "\tif (\$debut_boucle && \$debut_boucle[0] === '@') {\n"
285
+        . "\t\t" . '$debut_boucle = $Pile[0][' . $debut . '] = quete_debut_pagination(\'' . $boucle->primary . '\',$Pile[0][\'@' . $boucle->primary . '\'] = substr($debut_boucle,1),' . $pas . ',$iter);' . "\n"
286
+        . "\t\t" . '$iter->seek(0);' . "\n"
287
+        . "\t}\n"
288
+        . "\t" . '$debut_boucle = intval($debut_boucle)';
289
+
290
+    $boucle->hash .= '
291 291
 	$command[\'pagination\'] = array((isset($Pile[0][' . $debut . ']) ? $Pile[0][' . $debut . '] : null), ' . $pas . ');';
292 292
 
293
-	$boucle->total_parties = $pas;
294
-	calculer_parties($boucles, $idb, $partie, 'p+');
295
-	// ajouter la cle primaire dans le select pour pouvoir gerer la pagination referencee par @id
296
-	// sauf si pas de primaire, ou si primaire composee
297
-	// dans ce cas, on ne sait pas gerer une pagination indirecte
298
-	$t = $boucle->id_table . '.' . $boucle->primary;
299
-	if (
300
-		$boucle->primary
301
-		and !preg_match('/[,\s]/', $boucle->primary)
302
-		and !in_array($t, $boucle->select)
303
-	) {
304
-		$boucle->select[] = $t;
305
-	}
293
+    $boucle->total_parties = $pas;
294
+    calculer_parties($boucles, $idb, $partie, 'p+');
295
+    // ajouter la cle primaire dans le select pour pouvoir gerer la pagination referencee par @id
296
+    // sauf si pas de primaire, ou si primaire composee
297
+    // dans ce cas, on ne sait pas gerer une pagination indirecte
298
+    $t = $boucle->id_table . '.' . $boucle->primary;
299
+    if (
300
+        $boucle->primary
301
+        and !preg_match('/[,\s]/', $boucle->primary)
302
+        and !in_array($t, $boucle->select)
303
+    ) {
304
+        $boucle->select[] = $t;
305
+    }
306 306
 }
307 307
 
308 308
 
@@ -324,24 +324,24 @@  discard block
 block discarded – undo
324 324
  **/
325 325
 function critere_recherche_dist($idb, &$boucles, $crit) {
326 326
 
327
-	$boucle = &$boucles[$idb];
327
+    $boucle = &$boucles[$idb];
328 328
 
329
-	if (!$boucle->primary or strpos($boucle->primary, ',')) {
330
-		erreur_squelette(_T('zbug_critere_sur_table_sans_cle_primaire', ['critere' => 'recherche']), $boucle);
329
+    if (!$boucle->primary or strpos($boucle->primary, ',')) {
330
+        erreur_squelette(_T('zbug_critere_sur_table_sans_cle_primaire', ['critere' => 'recherche']), $boucle);
331 331
 
332
-		return;
333
-	}
332
+        return;
333
+    }
334 334
 
335
-	if (isset($crit->param[0])) {
336
-		$quoi = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
337
-	} else {
338
-		$quoi = '(isset($Pile[0]["recherche"])?$Pile[0]["recherche"]:(isset($GLOBALS["recherche"])?$GLOBALS["recherche"]:""))';
339
-	}
335
+    if (isset($crit->param[0])) {
336
+        $quoi = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
337
+    } else {
338
+        $quoi = '(isset($Pile[0]["recherche"])?$Pile[0]["recherche"]:(isset($GLOBALS["recherche"])?$GLOBALS["recherche"]:""))';
339
+    }
340 340
 
341
-	$_modificateur = var_export($boucle->modificateur, true);
342
-	$boucle->hash .= '
341
+    $_modificateur = var_export($boucle->modificateur, true);
342
+    $boucle->hash .= '
343 343
 	// RECHERCHE'
344
-		. ($crit->cond ? '
344
+        . ($crit->cond ? '
345 345
 	if (!strlen(' . $quoi . ')){
346 346
 		list($rech_select, $rech_where) = array("0 as points","");
347 347
 	} else' : '') . '
@@ -352,21 +352,21 @@  discard block
 block discarded – undo
352 352
 	';
353 353
 
354 354
 
355
-	$t = $boucle->id_table . '.' . $boucle->primary;
356
-	if (!in_array($t, $boucles[$idb]->select)) {
357
-		$boucle->select[] = $t;
358
-	} # pour postgres, neuneu ici
359
-	// jointure uniquement sur le serveur principal
360
-	// (on ne peut joindre une table d'un serveur distant avec la table des resultats du serveur principal)
361
-	if (!$boucle->sql_serveur) {
362
-		$boucle->join['resultats'] = ["'" . $boucle->id_table . "'", "'id'", "'" . $boucle->primary . "'"];
363
-		$boucle->from['resultats'] = 'spip_resultats';
364
-	}
365
-	$boucle->select[] = '$rech_select';
366
-	//$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";
367
-
368
-	// et la recherche trouve
369
-	$boucle->where[] = '$rech_where?$rech_where:\'\'';
355
+    $t = $boucle->id_table . '.' . $boucle->primary;
356
+    if (!in_array($t, $boucles[$idb]->select)) {
357
+        $boucle->select[] = $t;
358
+    } # pour postgres, neuneu ici
359
+    // jointure uniquement sur le serveur principal
360
+    // (on ne peut joindre une table d'un serveur distant avec la table des resultats du serveur principal)
361
+    if (!$boucle->sql_serveur) {
362
+        $boucle->join['resultats'] = ["'" . $boucle->id_table . "'", "'id'", "'" . $boucle->primary . "'"];
363
+        $boucle->from['resultats'] = 'spip_resultats';
364
+    }
365
+    $boucle->select[] = '$rech_select';
366
+    //$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";
367
+
368
+    // et la recherche trouve
369
+    $boucle->where[] = '$rech_where?$rech_where:\'\'';
370 370
 }
371 371
 
372 372
 /**
@@ -383,25 +383,25 @@  discard block
 block discarded – undo
383 383
  * @return void
384 384
  **/
385 385
 function critere_traduction_dist($idb, &$boucles, $crit) {
386
-	$boucle = &$boucles[$idb];
387
-	$prim = $boucle->primary;
388
-	$table = $boucle->id_table;
389
-	$arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles));
390
-	$dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles));
391
-	$boucle->where[] =
392
-		[
393
-			"'OR'",
394
-			[
395
-				"'AND'",
396
-				["'='", "'$table.id_trad'", 0],
397
-				["'='", "'$table.$prim'", $dprim]
398
-			],
399
-			[
400
-				"'AND'",
401
-				["'>'", "'$table.id_trad'", 0],
402
-				["'='", "'$table.id_trad'", $arg]
403
-			]
404
-		];
386
+    $boucle = &$boucles[$idb];
387
+    $prim = $boucle->primary;
388
+    $table = $boucle->id_table;
389
+    $arg = kwote(calculer_argument_precedent($idb, 'id_trad', $boucles));
390
+    $dprim = kwote(calculer_argument_precedent($idb, $prim, $boucles));
391
+    $boucle->where[] =
392
+        [
393
+            "'OR'",
394
+            [
395
+                "'AND'",
396
+                ["'='", "'$table.id_trad'", 0],
397
+                ["'='", "'$table.$prim'", $dprim]
398
+            ],
399
+            [
400
+                "'AND'",
401
+                ["'>'", "'$table.id_trad'", 0],
402
+                ["'='", "'$table.id_trad'", $arg]
403
+            ]
404
+        ];
405 405
 }
406 406
 
407 407
 
@@ -419,17 +419,17 @@  discard block
 block discarded – undo
419 419
  * @return void
420 420
  **/
421 421
 function critere_origine_traduction_dist($idb, &$boucles, $crit) {
422
-	$boucle = &$boucles[$idb];
423
-	$prim = $boucle->primary;
424
-	$table = $boucle->id_table;
425
-
426
-	$c =
427
-		[
428
-			"'OR'",
429
-			["'='", "'$table." . "id_trad'", "'$table.$prim'"],
430
-			["'='", "'$table.id_trad'", "'0'"]
431
-		];
432
-	$boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
422
+    $boucle = &$boucles[$idb];
423
+    $prim = $boucle->primary;
424
+    $table = $boucle->id_table;
425
+
426
+    $c =
427
+        [
428
+            "'OR'",
429
+            ["'='", "'$table." . "id_trad'", "'$table.$prim'"],
430
+            ["'='", "'$table.id_trad'", "'0'"]
431
+        ];
432
+    $boucle->where[] = ($crit->not ? ["'NOT'", $c] : $c);
433 433
 }
434 434
 
435 435
 
@@ -446,17 +446,17 @@  discard block
 block discarded – undo
446 446
  **/
447 447
 function critere_meme_parent_dist($idb, &$boucles, $crit) {
448 448
 
449
-	$boucle = &$boucles[$idb];
450
-	$arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
451
-	$id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
452
-	$mparent = $boucle->id_table . '.' . $id_parent;
453
-
454
-	if ($boucle->type_requete == 'rubriques' or isset($GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'])) {
455
-		$boucle->where[] = ["'='", "'$mparent'", $arg];
456
-	} // le cas FORUMS est gere dans le plugin forum, dans la fonction critere_FORUMS_meme_parent_dist()
457
-	else {
458
-		return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $boucle->type_requete]]);
459
-	}
449
+    $boucle = &$boucles[$idb];
450
+    $arg = kwote(calculer_argument_precedent($idb, 'id_parent', $boucles));
451
+    $id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
452
+    $mparent = $boucle->id_table . '.' . $id_parent;
453
+
454
+    if ($boucle->type_requete == 'rubriques' or isset($GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'])) {
455
+        $boucle->where[] = ["'='", "'$mparent'", $arg];
456
+    } // le cas FORUMS est gere dans le plugin forum, dans la fonction critere_FORUMS_meme_parent_dist()
457
+    else {
458
+        return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $boucle->type_requete]]);
459
+    }
460 460
 }
461 461
 
462 462
 
@@ -487,37 +487,37 @@  discard block
 block discarded – undo
487 487
  **/
488 488
 function critere_branche_dist($idb, &$boucles, $crit) {
489 489
 
490
-	$not = $crit->not;
491
-	$boucle = &$boucles[$idb];
492
-	// prendre en priorite un identifiant en parametre {branche XX}
493
-	if (isset($crit->param[0])) {
494
-		$arg = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
495
-		// sinon on le prend chez une boucle parente
496
-	} else {
497
-		$arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles), $boucle->sql_serveur, 'int NOT NULL');
498
-	}
499
-
500
-	//Trouver une jointure
501
-	$champ = 'id_rubrique';
502
-	$desc = $boucle->show;
503
-	//Seulement si necessaire
504
-	if (!array_key_exists($champ, $desc['field'])) {
505
-		$cle = trouver_jointure_champ($champ, $boucle);
506
-		$trouver_table = charger_fonction('trouver_table', 'base');
507
-		$desc = $trouver_table($boucle->from[$cle]);
508
-		if (count(trouver_champs_decomposes($champ, $desc)) > 1) {
509
-			$decompose = decompose_champ_id_objet($champ);
510
-			$champ = array_shift($decompose);
511
-			$boucle->where[] = ["'='", _q($cle . '.' . reset($decompose)), '"' . sql_quote(end($decompose)) . '"'];
512
-		}
513
-	} else {
514
-		$cle = $boucle->id_table;
515
-	}
516
-
517
-	$c = "sql_in('$cle" . ".$champ', calcul_branche_in($arg)"
518
-		. ($not ? ", 'NOT'" : '') . ')';
519
-	$boucle->where[] = !$crit->cond ? $c :
520
-		("($arg ? $c : " . ($not ? "'0=1'" : "'1=1'") . ')');
490
+    $not = $crit->not;
491
+    $boucle = &$boucles[$idb];
492
+    // prendre en priorite un identifiant en parametre {branche XX}
493
+    if (isset($crit->param[0])) {
494
+        $arg = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
495
+        // sinon on le prend chez une boucle parente
496
+    } else {
497
+        $arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles), $boucle->sql_serveur, 'int NOT NULL');
498
+    }
499
+
500
+    //Trouver une jointure
501
+    $champ = 'id_rubrique';
502
+    $desc = $boucle->show;
503
+    //Seulement si necessaire
504
+    if (!array_key_exists($champ, $desc['field'])) {
505
+        $cle = trouver_jointure_champ($champ, $boucle);
506
+        $trouver_table = charger_fonction('trouver_table', 'base');
507
+        $desc = $trouver_table($boucle->from[$cle]);
508
+        if (count(trouver_champs_decomposes($champ, $desc)) > 1) {
509
+            $decompose = decompose_champ_id_objet($champ);
510
+            $champ = array_shift($decompose);
511
+            $boucle->where[] = ["'='", _q($cle . '.' . reset($decompose)), '"' . sql_quote(end($decompose)) . '"'];
512
+        }
513
+    } else {
514
+        $cle = $boucle->id_table;
515
+    }
516
+
517
+    $c = "sql_in('$cle" . ".$champ', calcul_branche_in($arg)"
518
+        . ($not ? ", 'NOT'" : '') . ')';
519
+    $boucle->where[] = !$crit->cond ? $c :
520
+        ("($arg ? $c : " . ($not ? "'0=1'" : "'1=1'") . ')');
521 521
 }
522 522
 
523 523
 /**
@@ -533,15 +533,15 @@  discard block
 block discarded – undo
533 533
  **/
534 534
 function critere_logo_dist($idb, &$boucles, $crit) {
535 535
 
536
-	$boucle = &$boucles[$idb];
537
-	$not = ($crit->not ? 'NOT' : '');
538
-	$serveur = $boucle->sql_serveur;
536
+    $boucle = &$boucles[$idb];
537
+    $not = ($crit->not ? 'NOT' : '');
538
+    $serveur = $boucle->sql_serveur;
539 539
 
540
-	$c = "sql_in('" .
541
-		$boucle->id_table . '.' . $boucle->primary
542
-		. "', lister_objets_avec_logos('" . $boucle->primary . "'), '$not', '$serveur')";
540
+    $c = "sql_in('" .
541
+        $boucle->id_table . '.' . $boucle->primary
542
+        . "', lister_objets_avec_logos('" . $boucle->primary . "'), '$not', '$serveur')";
543 543
 
544
-	$boucle->where[] = $c;
544
+    $boucle->where[] = $c;
545 545
 }
546 546
 
547 547
 
@@ -563,31 +563,31 @@  discard block
 block discarded – undo
563 563
  * @return void
564 564
  **/
565 565
 function critere_fusion_dist($idb, &$boucles, $crit) {
566
-	if ($t = isset($crit->param[0])) {
567
-		$t = $crit->param[0];
568
-		if ($t[0]->type == 'texte') {
569
-			$t = $t[0]->texte;
570
-			if (preg_match('/^(.*)\.(.*)$/', $t, $r)) {
571
-				$t = table_objet_sql($r[1]);
572
-				$t = array_search($t, $boucles[$idb]->from);
573
-				if ($t) {
574
-					$t .= '.' . $r[2];
575
-				}
576
-			}
577
-		} else {
578
-			$t = '".'
579
-				. calculer_critere_arg_dynamique($idb, $boucles, $t)
580
-				. '."';
581
-		}
582
-	}
583
-	if ($t) {
584
-		$boucles[$idb]->group[] = $t;
585
-		if (!in_array($t, $boucles[$idb]->select)) {
586
-			$boucles[$idb]->select[] = $t;
587
-		}
588
-	} else {
589
-		return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']]);
590
-	}
566
+    if ($t = isset($crit->param[0])) {
567
+        $t = $crit->param[0];
568
+        if ($t[0]->type == 'texte') {
569
+            $t = $t[0]->texte;
570
+            if (preg_match('/^(.*)\.(.*)$/', $t, $r)) {
571
+                $t = table_objet_sql($r[1]);
572
+                $t = array_search($t, $boucles[$idb]->from);
573
+                if ($t) {
574
+                    $t .= '.' . $r[2];
575
+                }
576
+            }
577
+        } else {
578
+            $t = '".'
579
+                . calculer_critere_arg_dynamique($idb, $boucles, $t)
580
+                . '."';
581
+        }
582
+    }
583
+    if ($t) {
584
+        $boucles[$idb]->group[] = $t;
585
+        if (!in_array($t, $boucles[$idb]->select)) {
586
+            $boucles[$idb]->select[] = $t;
587
+        }
588
+    } else {
589
+        return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']]);
590
+    }
591 591
 }
592 592
 
593 593
 /**
@@ -607,7 +607,7 @@  discard block
 block discarded – undo
607 607
  * @return void
608 608
  **/
609 609
 function critere_fusion_supprimer_dist($idb, &$boucles, $crit) {
610
-	$boucles[$idb]->group = [];
610
+    $boucles[$idb]->group = [];
611 611
 }
612 612
 
613 613
 /**
@@ -644,45 +644,45 @@  discard block
 block discarded – undo
644 644
  * @param Critere $crit Paramètres du critère dans cette boucle
645 645
  */
646 646
 function critere_collecte_dist($idb, &$boucles, $crit) {
647
-	if (isset($crit->param[0])) {
648
-		$_coll = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
649
-		$boucle = $boucles[$idb];
650
-		$boucle->modificateur['collate'] = "($_coll ?' COLLATE '.$_coll:'')";
651
-		$n = is_countable($boucle->order) ? count($boucle->order) : 0;
652
-		if ($n && (strpos($boucle->order[$n - 1], 'COLLATE') === false)) {
653
-			// l'instruction COLLATE doit être placée avant ASC ou DESC
654
-			// notamment lors de l'utilisation `{!par xxx}{collate yyy}`
655
-			if (
656
-				(false !== $i = strpos($boucle->order[$n - 1], 'ASC'))
657
-				or (false !== $i = strpos($boucle->order[$n - 1], 'DESC'))
658
-			) {
659
-				$boucle->order[$n - 1] = substr_replace($boucle->order[$n - 1], "' . " . $boucle->modificateur['collate'] . " . ' ", $i, 0);
660
-			} else {
661
-				$boucle->order[$n - 1] .= ' . ' . $boucle->modificateur['collate'];
662
-			}
663
-		}
664
-	} else {
665
-		return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . (is_countable($boucles[$idb]->order) ? count($boucles[$idb]->order) : 0)]]);
666
-	}
647
+    if (isset($crit->param[0])) {
648
+        $_coll = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
649
+        $boucle = $boucles[$idb];
650
+        $boucle->modificateur['collate'] = "($_coll ?' COLLATE '.$_coll:'')";
651
+        $n = is_countable($boucle->order) ? count($boucle->order) : 0;
652
+        if ($n && (strpos($boucle->order[$n - 1], 'COLLATE') === false)) {
653
+            // l'instruction COLLATE doit être placée avant ASC ou DESC
654
+            // notamment lors de l'utilisation `{!par xxx}{collate yyy}`
655
+            if (
656
+                (false !== $i = strpos($boucle->order[$n - 1], 'ASC'))
657
+                or (false !== $i = strpos($boucle->order[$n - 1], 'DESC'))
658
+            ) {
659
+                $boucle->order[$n - 1] = substr_replace($boucle->order[$n - 1], "' . " . $boucle->modificateur['collate'] . " . ' ", $i, 0);
660
+            } else {
661
+                $boucle->order[$n - 1] .= ' . ' . $boucle->modificateur['collate'];
662
+            }
663
+        }
664
+    } else {
665
+        return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . (is_countable($boucles[$idb]->order) ? count($boucles[$idb]->order) : 0)]]);
666
+    }
667 667
 }
668 668
 
669 669
 // https://code.spip.net/@calculer_critere_arg_dynamique
670 670
 function calculer_critere_arg_dynamique($idb, &$boucles, $crit, $suffix = '') {
671
-	$boucle = $boucles[$idb];
672
-	$alt = "('" . $boucle->id_table . '.\' . $x' . $suffix . ')';
673
-	$var = '$champs_' . $idb;
674
-	$desc = (strpos($boucle->in, (string) "static $var =") !== false);
675
-	if (!$desc) {
676
-		$desc = $boucle->show['field'];
677
-		$desc = implode(',', array_map('_q', array_keys($desc)));
678
-		$boucles[$idb]->in .= "\n\tstatic $var = array(" . $desc . ');';
679
-	}
680
-	if ($desc) {
681
-		$alt = "(in_array(\$x, $var)  ? $alt :(\$x$suffix))";
682
-	}
683
-	$arg = calculer_liste($crit, $idb, $boucles, $boucle->id_parent);
684
-
685
-	return "((\$x = preg_replace(\"/\\W/\",'', $arg)) ? $alt : '')";
671
+    $boucle = $boucles[$idb];
672
+    $alt = "('" . $boucle->id_table . '.\' . $x' . $suffix . ')';
673
+    $var = '$champs_' . $idb;
674
+    $desc = (strpos($boucle->in, (string) "static $var =") !== false);
675
+    if (!$desc) {
676
+        $desc = $boucle->show['field'];
677
+        $desc = implode(',', array_map('_q', array_keys($desc)));
678
+        $boucles[$idb]->in .= "\n\tstatic $var = array(" . $desc . ');';
679
+    }
680
+    if ($desc) {
681
+        $alt = "(in_array(\$x, $var)  ? $alt :(\$x$suffix))";
682
+    }
683
+    $arg = calculer_liste($crit, $idb, $boucles, $boucle->id_parent);
684
+
685
+    return "((\$x = preg_replace(\"/\\W/\",'', $arg)) ? $alt : '')";
686 686
 }
687 687
 
688 688
 /**
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
  * @param Critere $crit Paramètres du critère dans cette boucle
722 722
  */
723 723
 function critere_par_dist($idb, &$boucles, $crit) {
724
-	return critere_parinverse($idb, $boucles, $crit);
724
+    return critere_parinverse($idb, $boucles, $crit);
725 725
 }
726 726
 
727 727
 /**
@@ -743,93 +743,93 @@  discard block
 block discarded – undo
743 743
  * @param Critere $crit Paramètres du critère dans cette boucle
744 744
  */
745 745
 function critere_parinverse($idb, &$boucles, $crit) {
746
-	$boucle = &$boucles[$idb];
747
-
748
-	$sens = $collecte = '';
749
-	if ($crit->not) {
750
-		$sens = " . ' DESC'";
751
-	}
752
-	if (isset($boucle->modificateur['collate'])) {
753
-		$collecte = ' . ' . $boucle->modificateur['collate'];
754
-	}
755
-
756
-	// Pour chaque paramètre du critère
757
-	foreach ($crit->param as $tri) {
758
-		$order = $fct = '';
759
-		// tris specifiés dynamiquement {par #ENV{tri}}
760
-		if ($tri[0]->type != 'texte') {
761
-			// calculer le order dynamique qui verifie les champs
762
-			$order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
763
-			// ajouter 'hasard' comme possibilité de tri dynamique
764
-			calculer_critere_par_hasard($idb, $boucles, $crit);
765
-		}
766
-		// tris textuels {par titre}
767
-		else {
768
-			$par = array_shift($tri);
769
-			$par = $par->texte;
770
-
771
-			// tris de la forme {par expression champ} tel que {par num titre} ou {par multi titre}
772
-			if (preg_match(',^(\w+)[\s]+(.*)$,', $par, $m)) {
773
-				$expression = trim($m[1]);
774
-				$champ = trim($m[2]);
775
-				if (function_exists($f = 'calculer_critere_par_expression_' . $expression)) {
776
-					$order = $f($idb, $boucles, $crit, $tri, $champ);
777
-				} else {
778
-					return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
779
-				}
780
-
781
-			// tris de la forme {par champ} ou {par FONCTION(champ)}
782
-			} elseif (preg_match(',^' . CHAMP_SQL_PLUS_FONC . '$,is', $par, $match)) {
783
-				// {par FONCTION(champ)}
784
-				if (count($match) > 2) {
785
-					$par = substr($match[2], 1, -1);
786
-					$fct = $match[1];
787
-				}
788
-				// quelques cas spécifiques {par hasard}, {par date}
789
-				if ($par == 'hasard') {
790
-					$order = calculer_critere_par_hasard($idb, $boucles, $crit);
791
-				} elseif ($par == 'date' and !empty($boucle->show['date'])) {
792
-					$order = "'" . $boucle->id_table . '.' . $boucle->show['date'] . "'";
793
-				} else {
794
-					// cas général {par champ}, {par table.champ}, ...
795
-					$order = calculer_critere_par_champ($idb, $boucles, $crit, $par);
796
-				}
797
-			}
798
-
799
-			// on ne sait pas traiter…
800
-			else {
801
-				return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
802
-			}
803
-
804
-			// En cas d'erreur de squelette retournée par une fonction
805
-			if (is_array($order)) {
806
-				return $order;
807
-			}
808
-		}
809
-
810
-		if (preg_match('/^\'([^"]*)\'$/', $order, $m)) {
811
-			$t = $m[1];
812
-			if (strpos($t, '.') and !in_array($t, $boucle->select)) {
813
-				$boucle->select[] = $t;
814
-			}
815
-		} else {
816
-			$sens = '';
817
-		}
818
-
819
-		if ($fct) {
820
-			if (preg_match("/^\s*'(.*)'\s*$/", $order, $r)) {
821
-				$order = "'$fct(" . $r[1] . ")'";
822
-			} else {
823
-				$order = "'$fct(' . $order . ')'";
824
-			}
825
-		}
826
-		$t = $order . $collecte . $sens;
827
-		if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
828
-			$t = $r[1] . $r[2];
829
-		}
830
-
831
-		$boucle->order[] = $t;
832
-	}
746
+    $boucle = &$boucles[$idb];
747
+
748
+    $sens = $collecte = '';
749
+    if ($crit->not) {
750
+        $sens = " . ' DESC'";
751
+    }
752
+    if (isset($boucle->modificateur['collate'])) {
753
+        $collecte = ' . ' . $boucle->modificateur['collate'];
754
+    }
755
+
756
+    // Pour chaque paramètre du critère
757
+    foreach ($crit->param as $tri) {
758
+        $order = $fct = '';
759
+        // tris specifiés dynamiquement {par #ENV{tri}}
760
+        if ($tri[0]->type != 'texte') {
761
+            // calculer le order dynamique qui verifie les champs
762
+            $order = calculer_critere_arg_dynamique($idb, $boucles, $tri, $sens);
763
+            // ajouter 'hasard' comme possibilité de tri dynamique
764
+            calculer_critere_par_hasard($idb, $boucles, $crit);
765
+        }
766
+        // tris textuels {par titre}
767
+        else {
768
+            $par = array_shift($tri);
769
+            $par = $par->texte;
770
+
771
+            // tris de la forme {par expression champ} tel que {par num titre} ou {par multi titre}
772
+            if (preg_match(',^(\w+)[\s]+(.*)$,', $par, $m)) {
773
+                $expression = trim($m[1]);
774
+                $champ = trim($m[2]);
775
+                if (function_exists($f = 'calculer_critere_par_expression_' . $expression)) {
776
+                    $order = $f($idb, $boucles, $crit, $tri, $champ);
777
+                } else {
778
+                    return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
779
+                }
780
+
781
+            // tris de la forme {par champ} ou {par FONCTION(champ)}
782
+            } elseif (preg_match(',^' . CHAMP_SQL_PLUS_FONC . '$,is', $par, $match)) {
783
+                // {par FONCTION(champ)}
784
+                if (count($match) > 2) {
785
+                    $par = substr($match[2], 1, -1);
786
+                    $fct = $match[1];
787
+                }
788
+                // quelques cas spécifiques {par hasard}, {par date}
789
+                if ($par == 'hasard') {
790
+                    $order = calculer_critere_par_hasard($idb, $boucles, $crit);
791
+                } elseif ($par == 'date' and !empty($boucle->show['date'])) {
792
+                    $order = "'" . $boucle->id_table . '.' . $boucle->show['date'] . "'";
793
+                } else {
794
+                    // cas général {par champ}, {par table.champ}, ...
795
+                    $order = calculer_critere_par_champ($idb, $boucles, $crit, $par);
796
+                }
797
+            }
798
+
799
+            // on ne sait pas traiter…
800
+            else {
801
+                return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
802
+            }
803
+
804
+            // En cas d'erreur de squelette retournée par une fonction
805
+            if (is_array($order)) {
806
+                return $order;
807
+            }
808
+        }
809
+
810
+        if (preg_match('/^\'([^"]*)\'$/', $order, $m)) {
811
+            $t = $m[1];
812
+            if (strpos($t, '.') and !in_array($t, $boucle->select)) {
813
+                $boucle->select[] = $t;
814
+            }
815
+        } else {
816
+            $sens = '';
817
+        }
818
+
819
+        if ($fct) {
820
+            if (preg_match("/^\s*'(.*)'\s*$/", $order, $r)) {
821
+                $order = "'$fct(" . $r[1] . ")'";
822
+            } else {
823
+                $order = "'$fct(' . $order . ')'";
824
+            }
825
+        }
826
+        $t = $order . $collecte . $sens;
827
+        if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
828
+            $t = $r[1] . $r[2];
829
+        }
830
+
831
+        $boucle->order[] = $t;
832
+    }
833 833
 }
834 834
 
835 835
 /**
@@ -843,13 +843,13 @@  discard block
 block discarded – undo
843 843
  * @return string Clause pour le Order by
844 844
  */
845 845
 function calculer_critere_par_hasard($idb, &$boucles, $crit) {
846
-	$boucle = &$boucles[$idb];
847
-	// Si ce n'est fait, ajouter un champ 'hasard' dans le select
848
-	$parha = 'rand() AS hasard';
849
-	if (!in_array($parha, $boucle->select)) {
850
-		$boucle->select[] = $parha;
851
-	}
852
-	return "'hasard'";
846
+    $boucle = &$boucles[$idb];
847
+    // Si ce n'est fait, ajouter un champ 'hasard' dans le select
848
+    $parha = 'rand() AS hasard';
849
+    if (!in_array($parha, $boucle->select)) {
850
+        $boucle->select[] = $parha;
851
+    }
852
+    return "'hasard'";
853 853
 }
854 854
 
855 855
 /**
@@ -873,24 +873,24 @@  discard block
 block discarded – undo
873 873
  * @return string Clause pour le Order by
874 874
  */
875 875
 function calculer_critere_par_expression_num($idb, &$boucles, $crit, $tri, $champ) {
876
-	$_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
877
-	if (is_array($_champ)) {
878
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . " num $champ"]];
879
-	}
880
-	$boucle = &$boucles[$idb];
881
-	$texte = '0+' . $_champ;
882
-	$suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
883
-	if ($suite !== "''") {
884
-		$texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
885
-	}
886
-	$asnum = 'num' . ($boucle->order ? count($boucle->order) : '');
887
-	$boucle->select[] = $texte . " AS $asnum";
888
-
889
-	$orderassinum = calculer_critere_par_expression_sinum($idb, $boucles, $crit, $tri, $champ);
890
-	$orderassinum = trim($orderassinum, "'");
891
-
892
-	$order = "'$orderassinum, $asnum'";
893
-	return $order;
876
+    $_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
877
+    if (is_array($_champ)) {
878
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . " num $champ"]];
879
+    }
880
+    $boucle = &$boucles[$idb];
881
+    $texte = '0+' . $_champ;
882
+    $suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
883
+    if ($suite !== "''") {
884
+        $texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
885
+    }
886
+    $asnum = 'num' . ($boucle->order ? count($boucle->order) : '');
887
+    $boucle->select[] = $texte . " AS $asnum";
888
+
889
+    $orderassinum = calculer_critere_par_expression_sinum($idb, $boucles, $crit, $tri, $champ);
890
+    $orderassinum = trim($orderassinum, "'");
891
+
892
+    $order = "'$orderassinum, $asnum'";
893
+    return $order;
894 894
 }
895 895
 
896 896
 /**
@@ -911,35 +911,35 @@  discard block
 block discarded – undo
911 911
  * @return string Clause pour le Order by
912 912
  */
913 913
 function calculer_critere_par_expression_sinum($idb, &$boucles, $crit, $tri, $champ) {
914
-	$_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
915
-	if (is_array($_champ)) {
916
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . " sinum $champ"]];
917
-	}
918
-	$boucle = &$boucles[$idb];
919
-	$texte = '0+' . $_champ;
920
-	$suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
921
-	if ($suite !== "''") {
922
-		$texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
923
-	}
924
-
925
-	$as = false;
926
-	$select = "CASE ( $texte ) WHEN 0 THEN 1 ELSE 0 END AS ";
927
-	foreach ($boucle->select as $s) {
928
-		if (strpos($s, $select) === 0) {
929
-			$as = trim(substr($s, strlen($select)));
930
-			if (!preg_match(',\W,', $as)) {
931
-				break;
932
-			}
933
-			$as = false;
934
-		}
935
-	}
936
-
937
-	if (!$as) {
938
-		$as = 'sinum' . ($boucle->order ? count($boucle->order) : '');
939
-		$boucle->select[] = $select . $as;
940
-	}
941
-	$order = "'$as'";
942
-	return $order;
914
+    $_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
915
+    if (is_array($_champ)) {
916
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . " sinum $champ"]];
917
+    }
918
+    $boucle = &$boucles[$idb];
919
+    $texte = '0+' . $_champ;
920
+    $suite = calculer_liste($tri, $idb, $boucles, $boucle->id_parent);
921
+    if ($suite !== "''") {
922
+        $texte = "\" . ((\$x = $suite) ? ('$texte' . \$x) : '0')" . ' . "';
923
+    }
924
+
925
+    $as = false;
926
+    $select = "CASE ( $texte ) WHEN 0 THEN 1 ELSE 0 END AS ";
927
+    foreach ($boucle->select as $s) {
928
+        if (strpos($s, $select) === 0) {
929
+            $as = trim(substr($s, strlen($select)));
930
+            if (!preg_match(',\W,', $as)) {
931
+                break;
932
+            }
933
+            $as = false;
934
+        }
935
+    }
936
+
937
+    if (!$as) {
938
+        $as = 'sinum' . ($boucle->order ? count($boucle->order) : '');
939
+        $boucle->select[] = $select . $as;
940
+    }
941
+    $order = "'$as'";
942
+    return $order;
943 943
 }
944 944
 
945 945
 
@@ -959,14 +959,14 @@  discard block
 block discarded – undo
959 959
  * @return string Clause pour le Order by
960 960
  */
961 961
 function calculer_critere_par_expression_multi($idb, &$boucles, $crit, $tri, $champ) {
962
-	$_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
963
-	if (is_array($_champ)) {
964
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . " multi $champ"]];
965
-	}
966
-	$boucle = &$boucles[$idb];
967
-	$boucle->select[] = "\".sql_multi('" . $_champ . "', \$GLOBALS['spip_lang']).\"";
968
-	$order = "'multi'";
969
-	return $order;
962
+    $_champ = calculer_critere_par_champ($idb, $boucles, $crit, $champ, true);
963
+    if (is_array($_champ)) {
964
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . " multi $champ"]];
965
+    }
966
+    $boucle = &$boucles[$idb];
967
+    $boucle->select[] = "\".sql_multi('" . $_champ . "', \$GLOBALS['spip_lang']).\"";
968
+    $order = "'multi'";
969
+    return $order;
970 970
 }
971 971
 
972 972
 /**
@@ -985,56 +985,56 @@  discard block
 block discarded – undo
985 985
  * @return array|string
986 986
  */
987 987
 function calculer_critere_par_champ($idb, &$boucles, $crit, $par, $raw = false) {
988
-	$boucle = &$boucles[$idb];
989
-	$desc = $boucle->show;
990
-
991
-	// le champ existe dans la table, pas de souci (le plus commun)
992
-	if (isset($desc['field'][$par])) {
993
-		$par = $boucle->id_table . '.' . $par;
994
-	}
995
-	// le champ est peut être une jointure
996
-	else {
997
-		$table = $table_alias = false; // toutes les tables de jointure possibles
998
-		$champ = $par;
999
-
1000
-		// le champ demandé est une exception de jointure {par titre_mot}
1001
-		if (isset($GLOBALS['exceptions_des_jointures'][$par])) {
1002
-			[$table, $champ] = $GLOBALS['exceptions_des_jointures'][$par];
1003
-		} // la table de jointure est explicitement indiquée {par truc.muche}
1004
-		elseif (preg_match('/^([^,]*)\.(.*)$/', $par, $r)) {
1005
-			[, $table, $champ] = $r;
1006
-			$table_alias = $table; // c'est peut-être un alias de table {par L1.titre}
1007
-			$table = table_objet_sql($table);
1008
-		}
1009
-
1010
-		// Si on connait la table d'arrivée, on la demande donc explicitement
1011
-		// Sinon on cherche le champ dans les tables possibles de jointures
1012
-		// Si la table est déjà dans le from, on la réutilise.
1013
-		if ($infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $table)) {
1014
-			$par = $infos['alias'] . '.' . $champ;
1015
-		} elseif (
1016
-			$boucle->jointures_explicites
1017
-			and $alias = trouver_jointure_champ($champ, $boucle, explode(' ', $boucle->jointures_explicites), false, $table)
1018
-		) {
1019
-			$par = $alias . '.' . $champ;
1020
-		} elseif ($alias = trouver_jointure_champ($champ, $boucle, $boucle->jointures, false, $table)) {
1021
-			$par = $alias . '.' . $champ;
1022
-		// en spécifiant directement l'alias {par L2.titre} (situation hasardeuse tout de même)
1023
-		} elseif (
1024
-			$table_alias
1025
-			and isset($boucle->from[$table_alias])
1026
-			and $infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $boucle->from[$table_alias])
1027
-		) {
1028
-			$par = $infos['alias'] . '.' . $champ;
1029
-		} elseif ($table) {
1030
-			// On avait table + champ, mais on ne les a pas trouvés
1031
-			return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
1032
-		} else {
1033
-			// Sinon tant pis, ca doit etre un champ synthetise (cf points)
1034
-		}
1035
-	}
1036
-
1037
-	return $raw ? $par : "'$par'";
988
+    $boucle = &$boucles[$idb];
989
+    $desc = $boucle->show;
990
+
991
+    // le champ existe dans la table, pas de souci (le plus commun)
992
+    if (isset($desc['field'][$par])) {
993
+        $par = $boucle->id_table . '.' . $par;
994
+    }
995
+    // le champ est peut être une jointure
996
+    else {
997
+        $table = $table_alias = false; // toutes les tables de jointure possibles
998
+        $champ = $par;
999
+
1000
+        // le champ demandé est une exception de jointure {par titre_mot}
1001
+        if (isset($GLOBALS['exceptions_des_jointures'][$par])) {
1002
+            [$table, $champ] = $GLOBALS['exceptions_des_jointures'][$par];
1003
+        } // la table de jointure est explicitement indiquée {par truc.muche}
1004
+        elseif (preg_match('/^([^,]*)\.(.*)$/', $par, $r)) {
1005
+            [, $table, $champ] = $r;
1006
+            $table_alias = $table; // c'est peut-être un alias de table {par L1.titre}
1007
+            $table = table_objet_sql($table);
1008
+        }
1009
+
1010
+        // Si on connait la table d'arrivée, on la demande donc explicitement
1011
+        // Sinon on cherche le champ dans les tables possibles de jointures
1012
+        // Si la table est déjà dans le from, on la réutilise.
1013
+        if ($infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $table)) {
1014
+            $par = $infos['alias'] . '.' . $champ;
1015
+        } elseif (
1016
+            $boucle->jointures_explicites
1017
+            and $alias = trouver_jointure_champ($champ, $boucle, explode(' ', $boucle->jointures_explicites), false, $table)
1018
+        ) {
1019
+            $par = $alias . '.' . $champ;
1020
+        } elseif ($alias = trouver_jointure_champ($champ, $boucle, $boucle->jointures, false, $table)) {
1021
+            $par = $alias . '.' . $champ;
1022
+        // en spécifiant directement l'alias {par L2.titre} (situation hasardeuse tout de même)
1023
+        } elseif (
1024
+            $table_alias
1025
+            and isset($boucle->from[$table_alias])
1026
+            and $infos = chercher_champ_dans_tables($champ, $boucle->from, $boucle->sql_serveur, $boucle->from[$table_alias])
1027
+        ) {
1028
+            $par = $infos['alias'] . '.' . $champ;
1029
+        } elseif ($table) {
1030
+            // On avait table + champ, mais on ne les a pas trouvés
1031
+            return ['zbug_critere_inconnu', ['critere' => $crit->op . " $par"]];
1032
+        } else {
1033
+            // Sinon tant pis, ca doit etre un champ synthetise (cf points)
1034
+        }
1035
+    }
1036
+
1037
+    return $raw ? $par : "'$par'";
1038 1038
 }
1039 1039
 
1040 1040
 /**
@@ -1048,11 +1048,11 @@  discard block
 block discarded – undo
1048 1048
  * @return string Champ pour le compilateur si trouvé, tel que "'alias.champ'", sinon vide.
1049 1049
  */
1050 1050
 function critere_par_joint($table, $champ, &$boucle) {
1051
-	$t = array_search($table, $boucle->from);
1052
-	if (!$t) {
1053
-		$t = trouver_jointure_champ($champ, $boucle);
1054
-	}
1055
-	return !$t ? '' : ("'" . $t . '.' . $champ . "'");
1051
+    $t = array_search($table, $boucle->from);
1052
+    if (!$t) {
1053
+        $t = trouver_jointure_champ($champ, $boucle);
1054
+    }
1055
+    return !$t ? '' : ("'" . $t . '.' . $champ . "'");
1056 1056
 }
1057 1057
 
1058 1058
 /**
@@ -1077,33 +1077,33 @@  discard block
 block discarded – undo
1077 1077
  */
1078 1078
 function critere_inverse_dist($idb, &$boucles, $crit) {
1079 1079
 
1080
-	$boucle = &$boucles[$idb];
1081
-	// Classement par ordre inverse
1082
-	if ($crit->not) {
1083
-		critere_parinverse($idb, $boucles, $crit);
1084
-	} else {
1085
-		$order = "' DESC'";
1086
-		// Classement par ordre inverse fonction eventuelle de #ENV{...}
1087
-		if (isset($crit->param[0])) {
1088
-			$critere = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
1089
-			$order = "(($critere)?' DESC':'')";
1090
-		}
1091
-
1092
-		$n = is_countable($boucle->order) ? count($boucle->order) : 0;
1093
-		if (!$n) {
1094
-			if (isset($boucle->default_order[0])) {
1095
-				$boucle->default_order[0] .= ' . " DESC"';
1096
-			} else {
1097
-				$boucle->default_order[] = ' DESC';
1098
-			}
1099
-		} else {
1100
-			$t = $boucle->order[$n - 1] . " . $order";
1101
-			if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
1102
-				$t = $r[1] . $r[2];
1103
-			}
1104
-			$boucle->order[$n - 1] = $t;
1105
-		}
1106
-	}
1080
+    $boucle = &$boucles[$idb];
1081
+    // Classement par ordre inverse
1082
+    if ($crit->not) {
1083
+        critere_parinverse($idb, $boucles, $crit);
1084
+    } else {
1085
+        $order = "' DESC'";
1086
+        // Classement par ordre inverse fonction eventuelle de #ENV{...}
1087
+        if (isset($crit->param[0])) {
1088
+            $critere = calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent);
1089
+            $order = "(($critere)?' DESC':'')";
1090
+        }
1091
+
1092
+        $n = is_countable($boucle->order) ? count($boucle->order) : 0;
1093
+        if (!$n) {
1094
+            if (isset($boucle->default_order[0])) {
1095
+                $boucle->default_order[0] .= ' . " DESC"';
1096
+            } else {
1097
+                $boucle->default_order[] = ' DESC';
1098
+            }
1099
+        } else {
1100
+            $t = $boucle->order[$n - 1] . " . $order";
1101
+            if (preg_match("/^(.*)'\s*\.\s*'([^']*')$/", $t, $r)) {
1102
+                $t = $r[1] . $r[2];
1103
+            }
1104
+            $boucle->order[$n - 1] = $t;
1105
+        }
1106
+    }
1107 1107
 }
1108 1108
 
1109 1109
 /**
@@ -1114,138 +1114,138 @@  discard block
 block discarded – undo
1114 1114
  * @return array|string
1115 1115
  */
1116 1116
 function critere_par_ordre_liste_dist($idb, &$boucles, $crit) {
1117
-	$boucle = &$boucles[$idb];
1117
+    $boucle = &$boucles[$idb];
1118 1118
 
1119
-	$sens = $collecte = '';
1120
-	if ($crit->not) {
1121
-		$sens = " . ' DESC'";
1122
-	}
1119
+    $sens = $collecte = '';
1120
+    if ($crit->not) {
1121
+        $sens = " . ' DESC'";
1122
+    }
1123 1123
 
1124
-	$crit2 = clone $crit;
1125
-	$crit2->not = false;
1126
-	$crit2->param = [reset($crit->param)];
1127
-	$res = critere_parinverse($idb, $boucles, $crit2);
1124
+    $crit2 = clone $crit;
1125
+    $crit2->not = false;
1126
+    $crit2->param = [reset($crit->param)];
1127
+    $res = critere_parinverse($idb, $boucles, $crit2);
1128 1128
 
1129
-	// erreur ?
1130
-	if (is_array($res)) {
1131
-		return $res;
1132
-	}
1129
+    // erreur ?
1130
+    if (is_array($res)) {
1131
+        return $res;
1132
+    }
1133 1133
 
1134
-	$_order = array_pop($boucle->order);
1134
+    $_order = array_pop($boucle->order);
1135 1135
 
1136
-	$_liste = calculer_liste($crit->param[1], [], $boucles, $boucles[$idb]->id_parent);
1137
-	$boucle->order[] = "'FIELD(' . $_order . ',' . ((\$zl=formate_liste_critere_par_ordre_liste($_liste,'" . $boucle->sql_serveur . "')) ? \$zl : '0').')'$sens";
1136
+    $_liste = calculer_liste($crit->param[1], [], $boucles, $boucles[$idb]->id_parent);
1137
+    $boucle->order[] = "'FIELD(' . $_order . ',' . ((\$zl=formate_liste_critere_par_ordre_liste($_liste,'" . $boucle->sql_serveur . "')) ? \$zl : '0').')'$sens";
1138 1138
 }
1139 1139
 
1140 1140
 
1141 1141
 // https://code.spip.net/@critere_agenda_dist
1142 1142
 function critere_agenda_dist($idb, &$boucles, $crit) {
1143
-	$params = $crit->param;
1144
-
1145
-	if ((is_countable($params) ? count($params) : 0) < 1) {
1146
-		return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
1147
-	}
1148
-
1149
-	$boucle = &$boucles[$idb];
1150
-	$parent = $boucle->id_parent;
1151
-	$fields = $boucle->show['field'];
1152
-
1153
-	$date = array_shift($params);
1154
-	$type = array_shift($params);
1155
-
1156
-	// la valeur $type doit etre connue a la compilation
1157
-	// donc etre forcement reduite a un litteral unique dans le source
1158
-	$type = is_object($type[0]) ? $type[0]->texte : null;
1159
-
1160
-	// La valeur date doit designer un champ de la table SQL.
1161
-	// Si c'est un litteral unique dans le source, verifier a la compil,
1162
-	// sinon synthetiser le test de verif pour execution ulterieure
1163
-	// On prendra arbitrairement le premier champ si test negatif.
1164
-	if (((is_countable($date) ? count($date) : 0) == 1) and ($date[0]->type == 'texte')) {
1165
-		$date = $date[0]->texte;
1166
-		if (!isset($fields[$date])) {
1167
-			return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $date]];
1168
-		}
1169
-	} else {
1170
-		$a = calculer_liste($date, $idb, $boucles, $parent);
1171
-		$noms = array_keys($fields);
1172
-		$defaut = $noms[0];
1173
-		$noms = join(' ', $noms);
1174
-		# bien laisser 2 espaces avant $nom pour que strpos<>0
1175
-		$cond = "(\$a=strval($a))AND\nstrpos(\"  $noms \",\" \$a \")";
1176
-		$date = "'.(($cond)\n?\$a:\"$defaut\").'";
1177
-	}
1178
-	$annee = $params ? array_shift($params) : '';
1179
-	$annee = "\n" . 'sprintf("%04d", ($x = ' .
1180
-		calculer_liste($annee, $idb, $boucles, $parent) .
1181
-		') ? $x : date("Y"))';
1182
-
1183
-	$mois = $params ? array_shift($params) : '';
1184
-	$mois = "\n" . 'sprintf("%02d", ($x = ' .
1185
-		calculer_liste($mois, $idb, $boucles, $parent) .
1186
-		') ? $x : date("m"))';
1187
-
1188
-	$jour = $params ? array_shift($params) : '';
1189
-	$jour = "\n" . 'sprintf("%02d", ($x = ' .
1190
-		calculer_liste($jour, $idb, $boucles, $parent) .
1191
-		') ? $x : date("d"))';
1192
-
1193
-	$annee2 = $params ? array_shift($params) : '';
1194
-	$annee2 = "\n" . 'sprintf("%04d", ($x = ' .
1195
-		calculer_liste($annee2, $idb, $boucles, $parent) .
1196
-		') ? $x : date("Y"))';
1197
-
1198
-	$mois2 = $params ? array_shift($params) : '';
1199
-	$mois2 = "\n" . 'sprintf("%02d", ($x = ' .
1200
-		calculer_liste($mois2, $idb, $boucles, $parent) .
1201
-		') ? $x : date("m"))';
1202
-
1203
-	$jour2 = $params ? array_shift($params) : '';
1204
-	$jour2 = "\n" . 'sprintf("%02d", ($x = ' .
1205
-		calculer_liste($jour2, $idb, $boucles, $parent) .
1206
-		') ? $x : date("d"))';
1207
-
1208
-	$date = $boucle->id_table . ".$date";
1209
-
1210
-	$quote_end = ",'" . $boucle->sql_serveur . "','text'";
1211
-	if ($type == 'jour') {
1212
-		$boucle->where[] = [
1213
-			"'='",
1214
-			"'DATE_FORMAT($date, \'%Y%m%d\')'",
1215
-			("sql_quote($annee . $mois . $jour$quote_end)")
1216
-		];
1217
-	} elseif ($type == 'mois') {
1218
-		$boucle->where[] = [
1219
-			"'='",
1220
-			"'DATE_FORMAT($date, \'%Y%m\')'",
1221
-			("sql_quote($annee . $mois$quote_end)")
1222
-		];
1223
-	} elseif ($type == 'semaine') {
1224
-		$boucle->where[] = [
1225
-			"'AND'",
1226
-			[
1227
-				"'>='",
1228
-				"'DATE_FORMAT($date, \'%Y%m%d\')'",
1229
-				("date_debut_semaine($annee, $mois, $jour)")
1230
-			],
1231
-			[
1232
-				"'<='",
1233
-				"'DATE_FORMAT($date, \'%Y%m%d\')'",
1234
-				("date_fin_semaine($annee, $mois, $jour)")
1235
-			]
1236
-		];
1237
-	} elseif ((is_countable($crit->param) ? count($crit->param) : 0) > 2) {
1238
-		$boucle->where[] = [
1239
-			"'AND'",
1240
-			[
1241
-				"'>='",
1242
-				"'DATE_FORMAT($date, \'%Y%m%d\')'",
1243
-				("sql_quote($annee . $mois . $jour$quote_end)")
1244
-			],
1245
-			["'<='", "'DATE_FORMAT($date, \'%Y%m%d\')'", ("sql_quote($annee2 . $mois2 . $jour2$quote_end)")]
1246
-		];
1247
-	}
1248
-	// sinon on prend tout
1143
+    $params = $crit->param;
1144
+
1145
+    if ((is_countable($params) ? count($params) : 0) < 1) {
1146
+        return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']];
1147
+    }
1148
+
1149
+    $boucle = &$boucles[$idb];
1150
+    $parent = $boucle->id_parent;
1151
+    $fields = $boucle->show['field'];
1152
+
1153
+    $date = array_shift($params);
1154
+    $type = array_shift($params);
1155
+
1156
+    // la valeur $type doit etre connue a la compilation
1157
+    // donc etre forcement reduite a un litteral unique dans le source
1158
+    $type = is_object($type[0]) ? $type[0]->texte : null;
1159
+
1160
+    // La valeur date doit designer un champ de la table SQL.
1161
+    // Si c'est un litteral unique dans le source, verifier a la compil,
1162
+    // sinon synthetiser le test de verif pour execution ulterieure
1163
+    // On prendra arbitrairement le premier champ si test negatif.
1164
+    if (((is_countable($date) ? count($date) : 0) == 1) and ($date[0]->type == 'texte')) {
1165
+        $date = $date[0]->texte;
1166
+        if (!isset($fields[$date])) {
1167
+            return ['zbug_critere_inconnu', ['critere' => $crit->op . ' ' . $date]];
1168
+        }
1169
+    } else {
1170
+        $a = calculer_liste($date, $idb, $boucles, $parent);
1171
+        $noms = array_keys($fields);
1172
+        $defaut = $noms[0];
1173
+        $noms = join(' ', $noms);
1174
+        # bien laisser 2 espaces avant $nom pour que strpos<>0
1175
+        $cond = "(\$a=strval($a))AND\nstrpos(\"  $noms \",\" \$a \")";
1176
+        $date = "'.(($cond)\n?\$a:\"$defaut\").'";
1177
+    }
1178
+    $annee = $params ? array_shift($params) : '';
1179
+    $annee = "\n" . 'sprintf("%04d", ($x = ' .
1180
+        calculer_liste($annee, $idb, $boucles, $parent) .
1181
+        ') ? $x : date("Y"))';
1182
+
1183
+    $mois = $params ? array_shift($params) : '';
1184
+    $mois = "\n" . 'sprintf("%02d", ($x = ' .
1185
+        calculer_liste($mois, $idb, $boucles, $parent) .
1186
+        ') ? $x : date("m"))';
1187
+
1188
+    $jour = $params ? array_shift($params) : '';
1189
+    $jour = "\n" . 'sprintf("%02d", ($x = ' .
1190
+        calculer_liste($jour, $idb, $boucles, $parent) .
1191
+        ') ? $x : date("d"))';
1192
+
1193
+    $annee2 = $params ? array_shift($params) : '';
1194
+    $annee2 = "\n" . 'sprintf("%04d", ($x = ' .
1195
+        calculer_liste($annee2, $idb, $boucles, $parent) .
1196
+        ') ? $x : date("Y"))';
1197
+
1198
+    $mois2 = $params ? array_shift($params) : '';
1199
+    $mois2 = "\n" . 'sprintf("%02d", ($x = ' .
1200
+        calculer_liste($mois2, $idb, $boucles, $parent) .
1201
+        ') ? $x : date("m"))';
1202
+
1203
+    $jour2 = $params ? array_shift($params) : '';
1204
+    $jour2 = "\n" . 'sprintf("%02d", ($x = ' .
1205
+        calculer_liste($jour2, $idb, $boucles, $parent) .
1206
+        ') ? $x : date("d"))';
1207
+
1208
+    $date = $boucle->id_table . ".$date";
1209
+
1210
+    $quote_end = ",'" . $boucle->sql_serveur . "','text'";
1211
+    if ($type == 'jour') {
1212
+        $boucle->where[] = [
1213
+            "'='",
1214
+            "'DATE_FORMAT($date, \'%Y%m%d\')'",
1215
+            ("sql_quote($annee . $mois . $jour$quote_end)")
1216
+        ];
1217
+    } elseif ($type == 'mois') {
1218
+        $boucle->where[] = [
1219
+            "'='",
1220
+            "'DATE_FORMAT($date, \'%Y%m\')'",
1221
+            ("sql_quote($annee . $mois$quote_end)")
1222
+        ];
1223
+    } elseif ($type == 'semaine') {
1224
+        $boucle->where[] = [
1225
+            "'AND'",
1226
+            [
1227
+                "'>='",
1228
+                "'DATE_FORMAT($date, \'%Y%m%d\')'",
1229
+                ("date_debut_semaine($annee, $mois, $jour)")
1230
+            ],
1231
+            [
1232
+                "'<='",
1233
+                "'DATE_FORMAT($date, \'%Y%m%d\')'",
1234
+                ("date_fin_semaine($annee, $mois, $jour)")
1235
+            ]
1236
+        ];
1237
+    } elseif ((is_countable($crit->param) ? count($crit->param) : 0) > 2) {
1238
+        $boucle->where[] = [
1239
+            "'AND'",
1240
+            [
1241
+                "'>='",
1242
+                "'DATE_FORMAT($date, \'%Y%m%d\')'",
1243
+                ("sql_quote($annee . $mois . $jour$quote_end)")
1244
+            ],
1245
+            ["'<='", "'DATE_FORMAT($date, \'%Y%m%d\')'", ("sql_quote($annee2 . $mois2 . $jour2$quote_end)")]
1246
+        ];
1247
+    }
1248
+    // sinon on prend tout
1249 1249
 }
1250 1250
 
1251 1251
 
@@ -1270,33 +1270,33 @@  discard block
 block discarded – undo
1270 1270
  * @return void
1271 1271
  **/
1272 1272
 function calculer_critere_parties($idb, &$boucles, $crit) {
1273
-	$boucle = &$boucles[$idb];
1274
-	$a1 = $crit->param[0];
1275
-	$a2 = $crit->param[1];
1276
-	$op = $crit->op;
1277
-
1278
-	[$a11, $a12] = calculer_critere_parties_aux($idb, $boucles, $a1);
1279
-	[$a21, $a22] = calculer_critere_parties_aux($idb, $boucles, $a2);
1280
-
1281
-	if (($op == ',') && (is_numeric($a11) && (is_numeric($a21)))) {
1282
-		$boucle->limit = $a11 . ',' . $a21;
1283
-	} else {
1284
-		// 3 dans {1/3}, {2,3} ou {1,n-3}
1285
-		$boucle->total_parties = ($a21 != 'n') ? $a21 : $a22;
1286
-		// 2 dans {2/3}, {2,5}, {n-2,1}
1287
-		$partie = ($a11 != 'n') ? $a11 : $a12;
1288
-		$mode = (($op == '/') ? '/' :
1289
-			(($a11 == 'n') ? '-' : '+') . (($a21 == 'n') ? '-' : '+'));
1290
-		// cas simple {0,#ENV{truc}} compilons le en LIMIT :
1291
-		if ($a11 !== 'n' and $a21 !== 'n' and $mode == '++' and $op == ',') {
1292
-			$boucle->limit =
1293
-				(is_numeric($a11) ? "'$a11'" : $a11)
1294
-				. ".','."
1295
-				. (is_numeric($a21) ? "'$a21'" : $a21);
1296
-		} else {
1297
-			calculer_parties($boucles, $idb, $partie, $mode);
1298
-		}
1299
-	}
1273
+    $boucle = &$boucles[$idb];
1274
+    $a1 = $crit->param[0];
1275
+    $a2 = $crit->param[1];
1276
+    $op = $crit->op;
1277
+
1278
+    [$a11, $a12] = calculer_critere_parties_aux($idb, $boucles, $a1);
1279
+    [$a21, $a22] = calculer_critere_parties_aux($idb, $boucles, $a2);
1280
+
1281
+    if (($op == ',') && (is_numeric($a11) && (is_numeric($a21)))) {
1282
+        $boucle->limit = $a11 . ',' . $a21;
1283
+    } else {
1284
+        // 3 dans {1/3}, {2,3} ou {1,n-3}
1285
+        $boucle->total_parties = ($a21 != 'n') ? $a21 : $a22;
1286
+        // 2 dans {2/3}, {2,5}, {n-2,1}
1287
+        $partie = ($a11 != 'n') ? $a11 : $a12;
1288
+        $mode = (($op == '/') ? '/' :
1289
+            (($a11 == 'n') ? '-' : '+') . (($a21 == 'n') ? '-' : '+'));
1290
+        // cas simple {0,#ENV{truc}} compilons le en LIMIT :
1291
+        if ($a11 !== 'n' and $a21 !== 'n' and $mode == '++' and $op == ',') {
1292
+            $boucle->limit =
1293
+                (is_numeric($a11) ? "'$a11'" : $a11)
1294
+                . ".','."
1295
+                . (is_numeric($a21) ? "'$a21'" : $a21);
1296
+        } else {
1297
+            calculer_parties($boucles, $idb, $partie, $mode);
1298
+        }
1299
+    }
1300 1300
 }
1301 1301
 
1302 1302
 /**
@@ -1324,63 +1324,63 @@  discard block
 block discarded – undo
1324 1324
  * @return void
1325 1325
  **/
1326 1326
 function calculer_parties(&$boucles, $id_boucle, $debut, $mode) {
1327
-	$total_parties = $boucles[$id_boucle]->total_parties;
1328
-
1329
-	preg_match(',([+-/p])([+-/])?,', $mode, $regs);
1330
-	[, $op1, $op2] = array_pad($regs, 3, null);
1331
-	$nombre_boucle = "\$Numrows['$id_boucle']['total']";
1332
-	// {1/3}
1333
-	if ($op1 == '/') {
1334
-		$pmoins1 = is_numeric($debut) ? ($debut - 1) : "($debut-1)";
1335
-		$totpos = is_numeric($total_parties) ? ($total_parties) :
1336
-			"($total_parties ? $total_parties : 1)";
1337
-		$fin = "ceil(($nombre_boucle * $debut )/$totpos) - 1";
1338
-		$debut = !$pmoins1 ? 0 : "ceil(($nombre_boucle * $pmoins1)/$totpos);";
1339
-	} else {
1340
-		// cas {n-1,x}
1341
-		if ($op1 == '-') {
1342
-			$debut = "$nombre_boucle - $debut;";
1343
-		}
1344
-
1345
-		// cas {x,n-1}
1346
-		if ($op2 == '-') {
1347
-			$fin = '$debut_boucle + ' . $nombre_boucle . ' - '
1348
-				. (is_numeric($total_parties) ? ($total_parties + 1) :
1349
-					($total_parties . ' - 1'));
1350
-		} else {
1351
-			// {x,1} ou {pagination}
1352
-			$fin = '$debut_boucle'
1353
-				. (is_numeric($total_parties) ?
1354
-					(($total_parties == 1) ? '' : (' + ' . ($total_parties - 1))) :
1355
-					('+' . $total_parties . ' - 1'));
1356
-		}
1357
-
1358
-		// {pagination}, gerer le debut_xx=-1 pour tout voir
1359
-		if ($op1 == 'p') {
1360
-			$debut .= ";\n	\$debut_boucle = ((\$tout=(\$debut_boucle == -1))?0:(\$debut_boucle))";
1361
-			$debut .= ";\n	\$debut_boucle = max(0,min(\$debut_boucle,floor(($nombre_boucle-1)/($total_parties))*($total_parties)))";
1362
-			$fin = "(\$tout ? $nombre_boucle : $fin)";
1363
-		}
1364
-	}
1365
-
1366
-	// Notes :
1367
-	// $debut_boucle et $fin_boucle sont les indices SQL du premier
1368
-	// et du dernier demandes dans la boucle : 0 pour le premier,
1369
-	// n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
1370
-	// Utiliser min pour rabattre $fin_boucle sur total_boucle.
1371
-
1372
-	$boucles[$id_boucle]->mode_partie = "\n\t"
1373
-		. '$debut_boucle = ' . $debut . ";\n	"
1374
-		. "\$debut_boucle = intval(\$debut_boucle);\n	"
1375
-		. '$fin_boucle = min(' . $fin . ", \$Numrows['$id_boucle']['total'] - 1);\n	"
1376
-		. '$Numrows[\'' . $id_boucle . "']['grand_total'] = \$Numrows['$id_boucle']['total'];\n	"
1377
-		. '$Numrows[\'' . $id_boucle . '\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);'
1378
-		. "\n\tif (\$debut_boucle>0"
1379
-		. " AND \$debut_boucle < \$Numrows['$id_boucle']['grand_total']"
1380
-		. " AND \$iter->seek(\$debut_boucle,'continue'))"
1381
-		. "\n\t\t\$Numrows['$id_boucle']['compteur_boucle'] = \$debut_boucle;\n\t";
1382
-
1383
-	$boucles[$id_boucle]->partie = "
1327
+    $total_parties = $boucles[$id_boucle]->total_parties;
1328
+
1329
+    preg_match(',([+-/p])([+-/])?,', $mode, $regs);
1330
+    [, $op1, $op2] = array_pad($regs, 3, null);
1331
+    $nombre_boucle = "\$Numrows['$id_boucle']['total']";
1332
+    // {1/3}
1333
+    if ($op1 == '/') {
1334
+        $pmoins1 = is_numeric($debut) ? ($debut - 1) : "($debut-1)";
1335
+        $totpos = is_numeric($total_parties) ? ($total_parties) :
1336
+            "($total_parties ? $total_parties : 1)";
1337
+        $fin = "ceil(($nombre_boucle * $debut )/$totpos) - 1";
1338
+        $debut = !$pmoins1 ? 0 : "ceil(($nombre_boucle * $pmoins1)/$totpos);";
1339
+    } else {
1340
+        // cas {n-1,x}
1341
+        if ($op1 == '-') {
1342
+            $debut = "$nombre_boucle - $debut;";
1343
+        }
1344
+
1345
+        // cas {x,n-1}
1346
+        if ($op2 == '-') {
1347
+            $fin = '$debut_boucle + ' . $nombre_boucle . ' - '
1348
+                . (is_numeric($total_parties) ? ($total_parties + 1) :
1349
+                    ($total_parties . ' - 1'));
1350
+        } else {
1351
+            // {x,1} ou {pagination}
1352
+            $fin = '$debut_boucle'
1353
+                . (is_numeric($total_parties) ?
1354
+                    (($total_parties == 1) ? '' : (' + ' . ($total_parties - 1))) :
1355
+                    ('+' . $total_parties . ' - 1'));
1356
+        }
1357
+
1358
+        // {pagination}, gerer le debut_xx=-1 pour tout voir
1359
+        if ($op1 == 'p') {
1360
+            $debut .= ";\n	\$debut_boucle = ((\$tout=(\$debut_boucle == -1))?0:(\$debut_boucle))";
1361
+            $debut .= ";\n	\$debut_boucle = max(0,min(\$debut_boucle,floor(($nombre_boucle-1)/($total_parties))*($total_parties)))";
1362
+            $fin = "(\$tout ? $nombre_boucle : $fin)";
1363
+        }
1364
+    }
1365
+
1366
+    // Notes :
1367
+    // $debut_boucle et $fin_boucle sont les indices SQL du premier
1368
+    // et du dernier demandes dans la boucle : 0 pour le premier,
1369
+    // n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
1370
+    // Utiliser min pour rabattre $fin_boucle sur total_boucle.
1371
+
1372
+    $boucles[$id_boucle]->mode_partie = "\n\t"
1373
+        . '$debut_boucle = ' . $debut . ";\n	"
1374
+        . "\$debut_boucle = intval(\$debut_boucle);\n	"
1375
+        . '$fin_boucle = min(' . $fin . ", \$Numrows['$id_boucle']['total'] - 1);\n	"
1376
+        . '$Numrows[\'' . $id_boucle . "']['grand_total'] = \$Numrows['$id_boucle']['total'];\n	"
1377
+        . '$Numrows[\'' . $id_boucle . '\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);'
1378
+        . "\n\tif (\$debut_boucle>0"
1379
+        . " AND \$debut_boucle < \$Numrows['$id_boucle']['grand_total']"
1380
+        . " AND \$iter->seek(\$debut_boucle,'continue'))"
1381
+        . "\n\t\t\$Numrows['$id_boucle']['compteur_boucle'] = \$debut_boucle;\n\t";
1382
+
1383
+    $boucles[$id_boucle]->partie = "
1384 1384
 		if (\$Numrows['$id_boucle']['compteur_boucle'] <= \$debut_boucle) continue;
1385 1385
 		if (\$Numrows['$id_boucle']['compteur_boucle']-1 > \$fin_boucle) break;";
1386 1386
 }
@@ -1397,26 +1397,26 @@  discard block
 block discarded – undo
1397 1397
  * @return array          Valeur de l'élément (peut être une expression PHP), Nombre soustrait
1398 1398
  **/
1399 1399
 function calculer_critere_parties_aux($idb, &$boucles, $param) {
1400
-	if ($param[0]->type != 'texte') {
1401
-		$a1 = calculer_liste([$param[0]], $idb, $boucles, $boucles[$idb]->id_parent);
1402
-		if (isset($param[1]->texte)) {
1403
-			preg_match(',^ *(-([0-9]+))? *$,', $param[1]->texte, $m);
1404
-
1405
-			return ["intval($a1)", ((isset($m[2]) and $m[2]) ? $m[2] : 0)];
1406
-		} else {
1407
-			return ["intval($a1)", 0];
1408
-		}
1409
-	} else {
1410
-		preg_match(',^ *(([0-9]+)|n) *(- *([0-9]+)? *)?$,', $param[0]->texte, $m);
1411
-		$a1 = $m[1];
1412
-		if (empty($m[3])) {
1413
-			return [$a1, 0];
1414
-		} elseif (!empty($m[4])) {
1415
-			return [$a1, $m[4]];
1416
-		} else {
1417
-			return [$a1, calculer_liste([$param[1]], $idb, $boucles, $boucles[$idb]->id_parent)];
1418
-		}
1419
-	}
1400
+    if ($param[0]->type != 'texte') {
1401
+        $a1 = calculer_liste([$param[0]], $idb, $boucles, $boucles[$idb]->id_parent);
1402
+        if (isset($param[1]->texte)) {
1403
+            preg_match(',^ *(-([0-9]+))? *$,', $param[1]->texte, $m);
1404
+
1405
+            return ["intval($a1)", ((isset($m[2]) and $m[2]) ? $m[2] : 0)];
1406
+        } else {
1407
+            return ["intval($a1)", 0];
1408
+        }
1409
+    } else {
1410
+        preg_match(',^ *(([0-9]+)|n) *(- *([0-9]+)? *)?$,', $param[0]->texte, $m);
1411
+        $a1 = $m[1];
1412
+        if (empty($m[3])) {
1413
+            return [$a1, 0];
1414
+        } elseif (!empty($m[4])) {
1415
+            return [$a1, $m[4]];
1416
+        } else {
1417
+            return [$a1, calculer_liste([$param[1]], $idb, $boucles, $boucles[$idb]->id_parent)];
1418
+        }
1419
+    }
1420 1420
 }
1421 1421
 
1422 1422
 
@@ -1443,47 +1443,47 @@  discard block
 block discarded – undo
1443 1443
  *     array : Erreur sur un des critères
1444 1444
  **/
1445 1445
 function calculer_criteres($idb, &$boucles) {
1446
-	$msg = '';
1447
-	$boucle = $boucles[$idb];
1448
-	$table = strtoupper($boucle->type_requete);
1449
-	$serveur = strtolower($boucle->sql_serveur);
1450
-
1451
-	$defaut = charger_fonction('DEFAUT', 'calculer_critere');
1452
-	// s'il y avait une erreur de syntaxe, propager cette info
1453
-	if (!is_array($boucle->criteres)) {
1454
-		return [];
1455
-	}
1456
-
1457
-	foreach ($boucle->criteres as $crit) {
1458
-		$critere = $crit->op;
1459
-		// critere personnalise ?
1460
-		if (
1461
-			(!$serveur or
1462
-				((!function_exists($f = 'critere_' . $serveur . '_' . $table . '_' . $critere))
1463
-					and (!function_exists($f = $f . '_dist'))
1464
-					and (!function_exists($f = 'critere_' . $serveur . '_' . $critere))
1465
-					and (!function_exists($f = $f . '_dist'))
1466
-				)
1467
-			)
1468
-			and (!function_exists($f = 'critere_' . $table . '_' . $critere))
1469
-			and (!function_exists($f = $f . '_dist'))
1470
-			and (!function_exists($f = 'critere_' . $critere))
1471
-			and (!function_exists($f = $f . '_dist'))
1472
-		) {
1473
-			// fonction critere standard
1474
-			$f = $defaut;
1475
-		}
1476
-		// compile le critere
1477
-		$res = $f($idb, $boucles, $crit);
1478
-
1479
-		// Gestion centralisee des erreurs pour pouvoir propager
1480
-		if (is_array($res)) {
1481
-			$msg = $res;
1482
-			erreur_squelette($msg, $boucle);
1483
-		}
1484
-	}
1485
-
1486
-	return $msg;
1446
+    $msg = '';
1447
+    $boucle = $boucles[$idb];
1448
+    $table = strtoupper($boucle->type_requete);
1449
+    $serveur = strtolower($boucle->sql_serveur);
1450
+
1451
+    $defaut = charger_fonction('DEFAUT', 'calculer_critere');
1452
+    // s'il y avait une erreur de syntaxe, propager cette info
1453
+    if (!is_array($boucle->criteres)) {
1454
+        return [];
1455
+    }
1456
+
1457
+    foreach ($boucle->criteres as $crit) {
1458
+        $critere = $crit->op;
1459
+        // critere personnalise ?
1460
+        if (
1461
+            (!$serveur or
1462
+                ((!function_exists($f = 'critere_' . $serveur . '_' . $table . '_' . $critere))
1463
+                    and (!function_exists($f = $f . '_dist'))
1464
+                    and (!function_exists($f = 'critere_' . $serveur . '_' . $critere))
1465
+                    and (!function_exists($f = $f . '_dist'))
1466
+                )
1467
+            )
1468
+            and (!function_exists($f = 'critere_' . $table . '_' . $critere))
1469
+            and (!function_exists($f = $f . '_dist'))
1470
+            and (!function_exists($f = 'critere_' . $critere))
1471
+            and (!function_exists($f = $f . '_dist'))
1472
+        ) {
1473
+            // fonction critere standard
1474
+            $f = $defaut;
1475
+        }
1476
+        // compile le critere
1477
+        $res = $f($idb, $boucles, $crit);
1478
+
1479
+        // Gestion centralisee des erreurs pour pouvoir propager
1480
+        if (is_array($res)) {
1481
+            $msg = $res;
1482
+            erreur_squelette($msg, $boucle);
1483
+        }
1484
+    }
1485
+
1486
+    return $msg;
1487 1487
 }
1488 1488
 
1489 1489
 /**
@@ -1500,11 +1500,11 @@  discard block
 block discarded – undo
1500 1500
  * @return string         Code compilé rééchappé
1501 1501
  */
1502 1502
 function kwote($lisp, $serveur = '', $type = '') {
1503
-	if (preg_match(_CODE_QUOTE, $lisp, $r)) {
1504
-		return $r[1] . '"' . sql_quote(str_replace(["\\'", '\\\\'], ["'", '\\'], $r[2]), $serveur, $type) . '"';
1505
-	} else {
1506
-		return "sql_quote($lisp, '$serveur', '" . str_replace("'", "\\'", $type) . "')";
1507
-	}
1503
+    if (preg_match(_CODE_QUOTE, $lisp, $r)) {
1504
+        return $r[1] . '"' . sql_quote(str_replace(["\\'", '\\\\'], ["'", '\\'], $r[2]), $serveur, $type) . '"';
1505
+    } else {
1506
+        return "sql_quote($lisp, '$serveur', '" . str_replace("'", "\\'", $type) . "')";
1507
+    }
1508 1508
 }
1509 1509
 
1510 1510
 
@@ -1523,82 +1523,82 @@  discard block
 block discarded – undo
1523 1523
  * @return void
1524 1524
  **/
1525 1525
 function critere_IN_dist($idb, &$boucles, $crit) {
1526
-	$r = calculer_critere_infixe($idb, $boucles, $crit);
1527
-	if (!$r) {
1528
-		return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']]);
1529
-	}
1530
-	[$arg, $op, $val, $col, $where_complement] = $r;
1531
-
1532
-	$in = critere_IN_cas($idb, $boucles, $crit->not ? 'NOT' : ($crit->exclus ? 'exclus' : ''), $arg, $op, $val, $col);
1533
-
1534
-	//	inserer la condition; exemple: {id_mot ?IN (66, 62, 64)}
1535
-	$where = $in;
1536
-	if ($crit->cond) {
1537
-		$pred = calculer_argument_precedent($idb, $col, $boucles);
1538
-		$where = ["'?'", $pred, $where, "''"];
1539
-		if ($where_complement) { // condition annexe du type "AND (objet='article')"
1540
-		$where_complement = ["'?'", $pred, $where_complement, "''"];
1541
-		}
1542
-	}
1543
-	if ($crit->exclus) {
1544
-		if (!preg_match(',^L[0-9]+[.],', $arg)) {
1545
-			$where = ["'NOT'", $where];
1546
-		} else // un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1547
-			// c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1548
-		{
1549
-			$where = [
1550
-				"'NOT'",
1551
-				[
1552
-					"'IN'",
1553
-					"'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1554
-					["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1555
-				]
1556
-			];
1557
-		}
1558
-	}
1559
-
1560
-	$boucles[$idb]->where[] = $where;
1561
-	if ($where_complement) { // condition annexe du type "AND (objet='article')"
1562
-	$boucles[$idb]->where[] = $where_complement;
1563
-	}
1526
+    $r = calculer_critere_infixe($idb, $boucles, $crit);
1527
+    if (!$r) {
1528
+        return (['zbug_critere_inconnu', ['critere' => $crit->op . ' ?']]);
1529
+    }
1530
+    [$arg, $op, $val, $col, $where_complement] = $r;
1531
+
1532
+    $in = critere_IN_cas($idb, $boucles, $crit->not ? 'NOT' : ($crit->exclus ? 'exclus' : ''), $arg, $op, $val, $col);
1533
+
1534
+    //	inserer la condition; exemple: {id_mot ?IN (66, 62, 64)}
1535
+    $where = $in;
1536
+    if ($crit->cond) {
1537
+        $pred = calculer_argument_precedent($idb, $col, $boucles);
1538
+        $where = ["'?'", $pred, $where, "''"];
1539
+        if ($where_complement) { // condition annexe du type "AND (objet='article')"
1540
+        $where_complement = ["'?'", $pred, $where_complement, "''"];
1541
+        }
1542
+    }
1543
+    if ($crit->exclus) {
1544
+        if (!preg_match(',^L[0-9]+[.],', $arg)) {
1545
+            $where = ["'NOT'", $where];
1546
+        } else // un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1547
+            // c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1548
+        {
1549
+            $where = [
1550
+                "'NOT'",
1551
+                [
1552
+                    "'IN'",
1553
+                    "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1554
+                    ["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1555
+                ]
1556
+            ];
1557
+        }
1558
+    }
1559
+
1560
+    $boucles[$idb]->where[] = $where;
1561
+    if ($where_complement) { // condition annexe du type "AND (objet='article')"
1562
+    $boucles[$idb]->where[] = $where_complement;
1563
+    }
1564 1564
 }
1565 1565
 
1566 1566
 // https://code.spip.net/@critere_IN_cas
1567 1567
 function critere_IN_cas($idb, &$boucles, $crit2, $arg, $op, $val, $col) {
1568
-	static $num = [];
1569
-	$descr = $boucles[$idb]->descr;
1570
-	$cpt = &$num[$descr['nom']][$descr['gram']][$idb];
1571
-
1572
-	$var = '$in' . $cpt++;
1573
-	$x = "\n\t$var = array();";
1574
-	foreach ($val as $k => $v) {
1575
-		if (preg_match(",^(\n//.*\n)?'(.*)'$,", $v, $r)) {
1576
-			// optimiser le traitement des constantes
1577
-			if (is_numeric($r[2])) {
1578
-				$x .= "\n\t$var" . "[]= $r[2];";
1579
-			} else {
1580
-				$x .= "\n\t$var" . '[]= ' . sql_quote($r[2]) . ';';
1581
-			}
1582
-		} else {
1583
-			// Pour permettre de passer des tableaux de valeurs
1584
-			// on repere l'utilisation brute de #ENV**{X},
1585
-			// c'est-a-dire sa  traduction en ($PILE[0][X]).
1586
-			// et on deballe mais en rajoutant l'anti XSS
1587
-			$x .= "\n\tif (!(is_array(\$a = ($v))))\n\t\t$var" . "[]= \$a;\n\telse $var = array_merge($var, \$a);";
1588
-		}
1589
-	}
1590
-
1591
-	$boucles[$idb]->in .= $x;
1592
-
1593
-	// inserer le tri par defaut selon les ordres du IN ...
1594
-	// avec une ecriture de type FIELD qui degrade les performances (du meme ordre qu'un regexp)
1595
-	// et que l'on limite donc strictement aux cas necessaires :
1596
-	// si ce n'est pas un !IN, et si il n'y a pas d'autre order dans la boucle
1597
-	if (!$crit2) {
1598
-		$boucles[$idb]->default_order[] = "((!\$zqv=sql_quote($var) OR \$zqv===\"''\") ? 0 : ('FIELD($arg,' . \$zqv . ')'))";
1599
-	}
1600
-
1601
-	return "sql_in('$arg', $var" . ($crit2 == 'NOT' ? ",'NOT'" : '') . ')';
1568
+    static $num = [];
1569
+    $descr = $boucles[$idb]->descr;
1570
+    $cpt = &$num[$descr['nom']][$descr['gram']][$idb];
1571
+
1572
+    $var = '$in' . $cpt++;
1573
+    $x = "\n\t$var = array();";
1574
+    foreach ($val as $k => $v) {
1575
+        if (preg_match(",^(\n//.*\n)?'(.*)'$,", $v, $r)) {
1576
+            // optimiser le traitement des constantes
1577
+            if (is_numeric($r[2])) {
1578
+                $x .= "\n\t$var" . "[]= $r[2];";
1579
+            } else {
1580
+                $x .= "\n\t$var" . '[]= ' . sql_quote($r[2]) . ';';
1581
+            }
1582
+        } else {
1583
+            // Pour permettre de passer des tableaux de valeurs
1584
+            // on repere l'utilisation brute de #ENV**{X},
1585
+            // c'est-a-dire sa  traduction en ($PILE[0][X]).
1586
+            // et on deballe mais en rajoutant l'anti XSS
1587
+            $x .= "\n\tif (!(is_array(\$a = ($v))))\n\t\t$var" . "[]= \$a;\n\telse $var = array_merge($var, \$a);";
1588
+        }
1589
+    }
1590
+
1591
+    $boucles[$idb]->in .= $x;
1592
+
1593
+    // inserer le tri par defaut selon les ordres du IN ...
1594
+    // avec une ecriture de type FIELD qui degrade les performances (du meme ordre qu'un regexp)
1595
+    // et que l'on limite donc strictement aux cas necessaires :
1596
+    // si ce n'est pas un !IN, et si il n'y a pas d'autre order dans la boucle
1597
+    if (!$crit2) {
1598
+        $boucles[$idb]->default_order[] = "((!\$zqv=sql_quote($var) OR \$zqv===\"''\") ? 0 : ('FIELD($arg,' . \$zqv . ')'))";
1599
+    }
1600
+
1601
+    return "sql_in('$arg', $var" . ($crit2 == 'NOT' ? ",'NOT'" : '') . ')';
1602 1602
 }
1603 1603
 
1604 1604
 /**
@@ -1614,22 +1614,22 @@  discard block
 block discarded – undo
1614 1614
  * @return void
1615 1615
  */
1616 1616
 function critere_where_dist($idb, &$boucles, $crit) {
1617
-	$boucle = &$boucles[$idb];
1618
-	if (isset($crit->param[0])) {
1619
-		$_where = calculer_liste($crit->param[0], $idb, $boucles, $boucle->id_parent);
1620
-	} else {
1621
-		$_where = 'spip_sanitize_from_request(@$Pile[0]["where"],"where","vide")';
1622
-	}
1623
-
1624
-	if ($crit->cond) {
1625
-		$_where = "((\$zzw = $_where) ? \$zzw : '')";
1626
-	}
1627
-
1628
-	if ($crit->not) {
1629
-		$_where = "array('NOT',$_where)";
1630
-	}
1631
-
1632
-	$boucle->where[] = $_where;
1617
+    $boucle = &$boucles[$idb];
1618
+    if (isset($crit->param[0])) {
1619
+        $_where = calculer_liste($crit->param[0], $idb, $boucles, $boucle->id_parent);
1620
+    } else {
1621
+        $_where = 'spip_sanitize_from_request(@$Pile[0]["where"],"where","vide")';
1622
+    }
1623
+
1624
+    if ($crit->cond) {
1625
+        $_where = "((\$zzw = $_where) ? \$zzw : '')";
1626
+    }
1627
+
1628
+    if ($crit->not) {
1629
+        $_where = "array('NOT',$_where)";
1630
+    }
1631
+
1632
+    $boucle->where[] = $_where;
1633 1633
 }
1634 1634
 
1635 1635
 /**
@@ -1657,31 +1657,31 @@  discard block
 block discarded – undo
1657 1657
  * @return void
1658 1658
  */
1659 1659
 function critere_id__dist($idb, &$boucles, $crit) {
1660
-	/** @var Boucle $boucle */
1661
-	$boucle = $boucles[$idb];
1662
-
1663
-	$champs = lister_champs_id_conditionnel(
1664
-		$boucle->show['table'],
1665
-		$boucle->show,
1666
-		$boucle->sql_serveur
1667
-	);
1668
-
1669
-	// ne pas tenir compte des critères identiques déjà présents.
1670
-	if (!empty($boucle->modificateur['criteres'])) {
1671
-		$champs = array_diff($champs, array_keys($boucle->modificateur['criteres']));
1672
-	}
1673
-	// nous aider en mode debug.
1674
-	$boucle->debug[] = 'id_ : ' . implode(', ', $champs);
1675
-	$boucle->modificateur['id_'] = $champs;
1676
-
1677
-	// créer un critère {id_xxx?} de chaque champ retenu
1678
-	foreach ($champs as $champ) {
1679
-		$critere_id_table = new Critere();
1680
-		$critere_id_table->op = $champ;
1681
-		$critere_id_table->cond = '?';
1682
-		$critere_id_table->ligne = $crit->ligne;
1683
-		calculer_critere_DEFAUT_dist($idb, $boucles, $critere_id_table);
1684
-	}
1660
+    /** @var Boucle $boucle */
1661
+    $boucle = $boucles[$idb];
1662
+
1663
+    $champs = lister_champs_id_conditionnel(
1664
+        $boucle->show['table'],
1665
+        $boucle->show,
1666
+        $boucle->sql_serveur
1667
+    );
1668
+
1669
+    // ne pas tenir compte des critères identiques déjà présents.
1670
+    if (!empty($boucle->modificateur['criteres'])) {
1671
+        $champs = array_diff($champs, array_keys($boucle->modificateur['criteres']));
1672
+    }
1673
+    // nous aider en mode debug.
1674
+    $boucle->debug[] = 'id_ : ' . implode(', ', $champs);
1675
+    $boucle->modificateur['id_'] = $champs;
1676
+
1677
+    // créer un critère {id_xxx?} de chaque champ retenu
1678
+    foreach ($champs as $champ) {
1679
+        $critere_id_table = new Critere();
1680
+        $critere_id_table->op = $champ;
1681
+        $critere_id_table->cond = '?';
1682
+        $critere_id_table->ligne = $crit->ligne;
1683
+        calculer_critere_DEFAUT_dist($idb, $boucles, $critere_id_table);
1684
+    }
1685 1685
 }
1686 1686
 
1687 1687
 /**
@@ -1701,75 +1701,75 @@  discard block
 block discarded – undo
1701 1701
  * @return array Liste de nom de champs (tel que id_article, id_mot, id_parent ...)
1702 1702
  */
1703 1703
 function lister_champs_id_conditionnel($table, $desc = null, $serveur = '') {
1704
-	// calculer la description de la table
1705
-	if (!is_array($desc)) {
1706
-		$desc = description_table($table, $serveur);
1707
-	}
1708
-	if (!$desc) {
1709
-		return [];
1710
-	}
1711
-
1712
-	// Les champs id_xx de la table demandée
1713
-	$champs = array_filter(
1714
-		array_keys($desc['field']),
1715
-		fn($champ) => strpos($champ, 'id_') === 0 or (in_array($champ, ['objet']))
1716
-	);
1717
-
1718
-	// Si le champ id_rubrique appartient à la liste et si id_secteur n'est pas inclus on le rajoute.
1719
-	if (
1720
-		in_array('id_rubrique', $champs)
1721
-		and !in_array('id_secteur', $champs)
1722
-	) {
1723
-		$champs[] = 'id_secteur';
1724
-	}
1725
-
1726
-	// On ne fera pas mieux pour les tables d’un autre serveur
1727
-	if ($serveur) {
1728
-		return $champs;
1729
-	}
1730
-
1731
-	$primary = false;
1732
-	$associable = false;
1733
-	include_spip('action/editer_liens');
1734
-
1735
-	if (isset($desc['type'])) {
1736
-		$primary = id_table_objet($desc['type']);
1737
-		$associable = objet_associable($desc['type']);
1738
-	}
1739
-	if (isset($desc['field']['id_objet']) and isset($desc['field']['objet'])) {
1740
-		$associable = true;
1741
-	}
1742
-
1743
-	// liste de toutes les tables principales, sauf la notre
1744
-	$tables = lister_tables_objets_sql();
1745
-	unset($tables[$table]);
1746
-
1747
-	foreach ($tables as $_table => $_desc) {
1748
-		if (
1749
-			$associable
1750
-			or ($primary and in_array($primary, array_keys($_desc['field'])))
1751
-			or objet_associable($_desc['type'])
1752
-		) {
1753
-			$champs[] = id_table_objet($_table);
1754
-		}
1755
-	}
1756
-	$champs = array_values(array_unique($champs));
1757
-
1758
-	// Exclusions de certains id
1759
-	$exclusions = pipeline(
1760
-		'exclure_id_conditionnel',
1761
-		[
1762
-			'args' => [
1763
-				'table' => $table,
1764
-				'id_table_objet' => $primary,
1765
-				'associable' => $associable,
1766
-			],
1767
-			'data' => [],
1768
-		]
1769
-	);
1770
-	$champs = array_diff($champs, $exclusions);
1771
-
1772
-	return $champs;
1704
+    // calculer la description de la table
1705
+    if (!is_array($desc)) {
1706
+        $desc = description_table($table, $serveur);
1707
+    }
1708
+    if (!$desc) {
1709
+        return [];
1710
+    }
1711
+
1712
+    // Les champs id_xx de la table demandée
1713
+    $champs = array_filter(
1714
+        array_keys($desc['field']),
1715
+        fn($champ) => strpos($champ, 'id_') === 0 or (in_array($champ, ['objet']))
1716
+    );
1717
+
1718
+    // Si le champ id_rubrique appartient à la liste et si id_secteur n'est pas inclus on le rajoute.
1719
+    if (
1720
+        in_array('id_rubrique', $champs)
1721
+        and !in_array('id_secteur', $champs)
1722
+    ) {
1723
+        $champs[] = 'id_secteur';
1724
+    }
1725
+
1726
+    // On ne fera pas mieux pour les tables d’un autre serveur
1727
+    if ($serveur) {
1728
+        return $champs;
1729
+    }
1730
+
1731
+    $primary = false;
1732
+    $associable = false;
1733
+    include_spip('action/editer_liens');
1734
+
1735
+    if (isset($desc['type'])) {
1736
+        $primary = id_table_objet($desc['type']);
1737
+        $associable = objet_associable($desc['type']);
1738
+    }
1739
+    if (isset($desc['field']['id_objet']) and isset($desc['field']['objet'])) {
1740
+        $associable = true;
1741
+    }
1742
+
1743
+    // liste de toutes les tables principales, sauf la notre
1744
+    $tables = lister_tables_objets_sql();
1745
+    unset($tables[$table]);
1746
+
1747
+    foreach ($tables as $_table => $_desc) {
1748
+        if (
1749
+            $associable
1750
+            or ($primary and in_array($primary, array_keys($_desc['field'])))
1751
+            or objet_associable($_desc['type'])
1752
+        ) {
1753
+            $champs[] = id_table_objet($_table);
1754
+        }
1755
+    }
1756
+    $champs = array_values(array_unique($champs));
1757
+
1758
+    // Exclusions de certains id
1759
+    $exclusions = pipeline(
1760
+        'exclure_id_conditionnel',
1761
+        [
1762
+            'args' => [
1763
+                'table' => $table,
1764
+                'id_table_objet' => $primary,
1765
+                'associable' => $associable,
1766
+            ],
1767
+            'data' => [],
1768
+        ]
1769
+    );
1770
+    $champs = array_diff($champs, $exclusions);
1771
+
1772
+    return $champs;
1773 1773
 }
1774 1774
 
1775 1775
 /**
@@ -1824,27 +1824,27 @@  discard block
 block discarded – undo
1824 1824
  * @return void
1825 1825
  */
1826 1826
 function critere_tri_dist($idb, &$boucles, $crit) {
1827
-	$boucle = &$boucles[$idb];
1828
-
1829
-	// definition du champ par defaut
1830
-	$_champ_defaut = !isset($crit->param[0][0]) ? "''"
1831
-		: calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
1832
-	$_sens_defaut = !isset($crit->param[1][0]) ? '1'
1833
-		: calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
1834
-	$_variable = !isset($crit->param[2][0]) ? "'$idb'"
1835
-		: calculer_liste([$crit->param[2][0]], $idb, $boucles, $boucle->id_parent);
1836
-
1837
-	$_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):'')";
1838
-
1839
-	$_sens_defaut = "(is_array(\$s=$_sens_defaut)?(isset(\$s[\$st=$_tri])?\$s[\$st]:reset(\$s)):\$s)";
1840
-	$_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)";
1841
-
1842
-	$boucle->modificateur['tri_champ'] = $_tri;
1843
-	$boucle->modificateur['tri_sens'] = $_sens;
1844
-	$boucle->modificateur['tri_nom'] = $_variable;
1845
-	// faut il inserer un test sur l'existence de $tri parmi les champs de la table ?
1846
-	// evite des erreurs sql, mais peut empecher des tri sur jointure ...
1847
-	$boucle->hash .= "
1827
+    $boucle = &$boucles[$idb];
1828
+
1829
+    // definition du champ par defaut
1830
+    $_champ_defaut = !isset($crit->param[0][0]) ? "''"
1831
+        : calculer_liste([$crit->param[0][0]], $idb, $boucles, $boucle->id_parent);
1832
+    $_sens_defaut = !isset($crit->param[1][0]) ? '1'
1833
+        : calculer_liste([$crit->param[1][0]], $idb, $boucles, $boucle->id_parent);
1834
+    $_variable = !isset($crit->param[2][0]) ? "'$idb'"
1835
+        : calculer_liste([$crit->param[2][0]], $idb, $boucles, $boucle->id_parent);
1836
+
1837
+    $_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):'')";
1838
+
1839
+    $_sens_defaut = "(is_array(\$s=$_sens_defaut)?(isset(\$s[\$st=$_tri])?\$s[\$st]:reset(\$s)):\$s)";
1840
+    $_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)";
1841
+
1842
+    $boucle->modificateur['tri_champ'] = $_tri;
1843
+    $boucle->modificateur['tri_sens'] = $_sens;
1844
+    $boucle->modificateur['tri_nom'] = $_variable;
1845
+    // faut il inserer un test sur l'existence de $tri parmi les champs de la table ?
1846
+    // evite des erreurs sql, mais peut empecher des tri sur jointure ...
1847
+    $boucle->hash .= "
1848 1848
 	\$senstri = '';
1849 1849
 	\$tri = $_tri;
1850 1850
 	if (\$tri){
@@ -1852,8 +1852,8 @@  discard block
 block discarded – undo
1852 1852
 		\$senstri = (\$senstri<0)?' DESC':'';
1853 1853
 	};
1854 1854
 	";
1855
-	$boucle->select[] = '".tri_champ_select($tri)."';
1856
-	$boucle->order[] = "tri_champ_order(\$tri,\$command['from'],\$senstri)";
1855
+    $boucle->select[] = '".tri_champ_select($tri)."';
1856
+    $boucle->order[] = "tri_champ_order(\$tri,\$command['from'],\$senstri)";
1857 1857
 }
1858 1858
 
1859 1859
 # Criteres de comparaison
@@ -1870,20 +1870,20 @@  discard block
 block discarded – undo
1870 1870
  * @return void
1871 1871
  **/
1872 1872
 function calculer_critere_DEFAUT_dist($idb, &$boucles, $crit) {
1873
-	// double cas particulier {0,1} et {1/2} repere a l'analyse lexicale
1874
-	if (($crit->op == ',') or ($crit->op == '/')) {
1875
-		return calculer_critere_parties($idb, $boucles, $crit);
1876
-	}
1877
-
1878
-	$r = calculer_critere_infixe($idb, $boucles, $crit);
1879
-	if (!$r) {
1880
-		#	// on produit une erreur seulement si le critere n'a pas de '?'
1881
-		#	if (!$crit->cond) {
1882
-		return (['zbug_critere_inconnu', ['critere' => $crit->op]]);
1883
-		#	}
1884
-	} else {
1885
-		calculer_critere_DEFAUT_args($idb, $boucles, $crit, $r);
1886
-	}
1873
+    // double cas particulier {0,1} et {1/2} repere a l'analyse lexicale
1874
+    if (($crit->op == ',') or ($crit->op == '/')) {
1875
+        return calculer_critere_parties($idb, $boucles, $crit);
1876
+    }
1877
+
1878
+    $r = calculer_critere_infixe($idb, $boucles, $crit);
1879
+    if (!$r) {
1880
+        #	// on produit une erreur seulement si le critere n'a pas de '?'
1881
+        #	if (!$crit->cond) {
1882
+        return (['zbug_critere_inconnu', ['critere' => $crit->op]]);
1883
+        #	}
1884
+    } else {
1885
+        calculer_critere_DEFAUT_args($idb, $boucles, $crit, $r);
1886
+    }
1887 1887
 }
1888 1888
 
1889 1889
 
@@ -1903,62 +1903,62 @@  discard block
 block discarded – undo
1903 1903
  * @return void
1904 1904
  **/
1905 1905
 function calculer_critere_DEFAUT_args($idb, &$boucles, $crit, $args) {
1906
-	[$arg, $op, $val, $col, $where_complement] = $args;
1907
-
1908
-	$where = ["'$op'", "'$arg'", $val[0]];
1909
-
1910
-	// inserer la negation (cf !...)
1911
-
1912
-	if ($crit->not) {
1913
-		$where = ["'NOT'", $where];
1914
-	}
1915
-	if ($crit->exclus) {
1916
-		if (!preg_match(',^L[0-9]+[.],', $arg)) {
1917
-			$where = ["'NOT'", $where];
1918
-		} else {
1919
-			// un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1920
-			// c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1921
-			$where = [
1922
-				"'NOT'",
1923
-				[
1924
-					"'IN'",
1925
-					"'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1926
-					["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1927
-				]
1928
-			];
1929
-		}
1930
-	}
1931
-
1932
-	// inserer la condition (cf {lang?})
1933
-	// traiter a part la date, elle est mise d'office par SPIP,
1934
-	if ($crit->cond) {
1935
-		$pred = calculer_argument_precedent($idb, $col, $boucles);
1936
-		if ($col === 'date' or $col === 'date_redac') {
1937
-			if ($pred === "\$Pile[0]['" . $col . "']") {
1938
-				$pred = "(\$Pile[0]['{$col}_default']?'':$pred)";
1939
-			}
1940
-		}
1941
-
1942
-		if ($op === '=' and !$crit->not) {
1943
-			$where = [
1944
-				"'?'",
1945
-				"(is_array($pred))",
1946
-				critere_IN_cas($idb, $boucles, 'COND', $arg, $op, [$pred], $col),
1947
-				$where
1948
-			];
1949
-		}
1950
-		$where = ["'?'", "!is_whereable($pred)", "''", $where];
1951
-		if ($where_complement) { 
1952
-			// condition annexe du type "AND (objet='article')"
1953
-			$where_complement = ["'?'", "!is_whereable($pred)", "''", $where_complement];
1954
-		}
1955
-	}
1956
-
1957
-	$boucles[$idb]->where[] = $where;
1958
-	if ($where_complement) {
1959
-		// condition annexe du type "AND (objet='article')"
1960
-		$boucles[$idb]->where[] = $where_complement;
1961
-	}
1906
+    [$arg, $op, $val, $col, $where_complement] = $args;
1907
+
1908
+    $where = ["'$op'", "'$arg'", $val[0]];
1909
+
1910
+    // inserer la negation (cf !...)
1911
+
1912
+    if ($crit->not) {
1913
+        $where = ["'NOT'", $where];
1914
+    }
1915
+    if ($crit->exclus) {
1916
+        if (!preg_match(',^L[0-9]+[.],', $arg)) {
1917
+            $where = ["'NOT'", $where];
1918
+        } else {
1919
+            // un not sur un critere de jointure se traduit comme un NOT IN avec une sous requete
1920
+            // c'est une sous requete identique a la requete principale sous la forme (SELF,$select,$where) avec $select et $where qui surchargent
1921
+            $where = [
1922
+                "'NOT'",
1923
+                [
1924
+                    "'IN'",
1925
+                    "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'",
1926
+                    ["'SELF'", "'" . $boucles[$idb]->id_table . '.' . $boucles[$idb]->primary . "'", $where]
1927
+                ]
1928
+            ];
1929
+        }
1930
+    }
1931
+
1932
+    // inserer la condition (cf {lang?})
1933
+    // traiter a part la date, elle est mise d'office par SPIP,
1934
+    if ($crit->cond) {
1935
+        $pred = calculer_argument_precedent($idb, $col, $boucles);
1936
+        if ($col === 'date' or $col === 'date_redac') {
1937
+            if ($pred === "\$Pile[0]['" . $col . "']") {
1938
+                $pred = "(\$Pile[0]['{$col}_default']?'':$pred)";
1939
+            }
1940
+        }
1941
+
1942
+        if ($op === '=' and !$crit->not) {
1943
+            $where = [
1944
+                "'?'",
1945
+                "(is_array($pred))",
1946
+                critere_IN_cas($idb, $boucles, 'COND', $arg, $op, [$pred], $col),
1947
+                $where
1948
+            ];
1949
+        }
1950
+        $where = ["'?'", "!is_whereable($pred)", "''", $where];
1951
+        if ($where_complement) { 
1952
+            // condition annexe du type "AND (objet='article')"
1953
+            $where_complement = ["'?'", "!is_whereable($pred)", "''", $where_complement];
1954
+        }
1955
+    }
1956
+
1957
+    $boucles[$idb]->where[] = $where;
1958
+    if ($where_complement) {
1959
+        // condition annexe du type "AND (objet='article')"
1960
+        $boucles[$idb]->where[] = $where_complement;
1961
+    }
1962 1962
 }
1963 1963
 
1964 1964
 
@@ -1999,165 +1999,165 @@  discard block
 block discarded – undo
1999 1999
  **/
2000 2000
 function calculer_critere_infixe($idb, &$boucles, $crit) {
2001 2001
 
2002
-	$boucle = &$boucles[$idb];
2003
-	$type = $boucle->type_requete;
2004
-	$table = $boucle->id_table ?? '';
2005
-	$desc = $boucle->show;
2006
-	$col_vraie = null;
2007
-
2008
-	[$fct, $col, $op, $val, $args_sql] =
2009
-		calculer_critere_infixe_ops($idb, $boucles, $crit);
2010
-
2011
-	$col_alias = $col;
2012
-	$where_complement = false;
2013
-
2014
-	// Cas particulier : id_enfant => utiliser la colonne id_objet
2015
-	if ($col == 'id_enfant') {
2016
-		$col = $boucle->primary;
2017
-	}
2018
-
2019
-	// Cas particulier : id_parent => verifier les exceptions de tables
2020
-	if (
2021
-		(in_array($col, ['id_parent', 'id_secteur']) and isset($GLOBALS['exceptions_des_tables'][$table][$col]))
2022
-		or (isset($GLOBALS['exceptions_des_tables'][$table][$col]) and is_string($GLOBALS['exceptions_des_tables'][$table][$col]))
2023
-	) {
2024
-		$col = $GLOBALS['exceptions_des_tables'][$table][$col];
2025
-	} // et possibilite de gerer un critere secteur sur des tables de plugins (ie forums)
2026
-	else {
2027
-		if (($col == 'id_secteur') and ($critere_secteur = charger_fonction("critere_secteur_$type", 'public', true))) {
2028
-			$table = $critere_secteur($idb, $boucles, $val, $crit);
2029
-		}
2030
-
2031
-		// cas id_article=xx qui se mappe en id_objet=xx AND objet=article
2032
-		// sauf si exception declaree : sauter cette etape
2033
-		else {
2034
-			if (
2035
-				!isset($GLOBALS['exceptions_des_jointures'][table_objet_sql($table)][$col])
2036
-				and !isset($GLOBALS['exceptions_des_jointures'][$col])
2037
-				and count(trouver_champs_decomposes($col, $desc)) > 1
2038
-			) {
2039
-				$e = decompose_champ_id_objet($col);
2040
-				$col = array_shift($e);
2041
-				$where_complement = primary_doublee($e, $table);
2042
-			} // Cas particulier : expressions de date
2043
-			else {
2044
-				if ($c = calculer_critere_infixe_date($idb, $boucles, $col)) {
2045
-					[$col, $col_vraie] = $c;
2046
-					$table = '';
2047
-				} // table explicitée {mots.titre}
2048
-				else {
2049
-					if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2050
-						[, $table, $col] = $r;
2051
-						$col_alias = $col;
2052
-
2053
-						$trouver_table = charger_fonction('trouver_table', 'base');
2054
-						if (
2055
-							$desc = $trouver_table($table, $boucle->sql_serveur)
2056
-							and isset($desc['field'][$col])
2057
-							and $cle = array_search($desc['table'], $boucle->from)
2058
-						) {
2059
-							$table = $cle;
2060
-						} else {
2061
-							$table = trouver_jointure_champ($col, $boucle, [$table], ($crit->cond or $op != '='));
2062
-						}
2063
-						#$table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op!='='), true);
2064
-						if (!$table) {
2065
-							return '';
2066
-						}
2067
-					}
2068
-					// si le champ n'est pas trouvé dans la table,
2069
-					// on cherche si une jointure peut l'obtenir
2070
-					elseif (@!array_key_exists($col, $desc['field'])) {
2071
-						// Champ joker * des iterateurs DATA qui accepte tout
2072
-						if (@array_key_exists('*', $desc['field'])) {
2073
-							$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
2074
-						}
2075
-						else {
2076
-							$r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table);
2077
-							if (!$r) {
2078
-								return '';
2079
-							}
2080
-							[$col, $col_alias, $table, $where_complement, $desc] = $r;
2081
-						}
2082
-					}
2083
-				}
2084
-			}
2085
-		}
2086
-	}
2087
-
2088
-	$col_vraie = ($col_vraie ?: $col);
2089
-	// Dans tous les cas,
2090
-	// virer les guillemets eventuels autour d'un int (qui sont refuses par certains SQL)
2091
-	// et passer dans sql_quote avec le type si connu
2092
-	// et int sinon si la valeur est numerique
2093
-	// sinon introduire le vrai type du champ si connu dans le sql_quote (ou int NOT NULL sinon)
2094
-	// Ne pas utiliser intval, PHP tronquant les Bigint de SQL
2095
-	if ($op == '=' or in_array($op, $GLOBALS['table_criteres_infixes'])) {
2096
-		$type_cast_quote = ($desc['field'][$col_vraie] ?? 'int NOT NULL');
2097
-		// defaire le quote des int et les passer dans sql_quote avec le bon type de champ si on le connait, int sinon
2098
-		// prendre en compte le debug ou la valeur arrive avec un commentaire PHP en debut
2099
-		if (preg_match(",^\\A(\s*//.*?$\s*)?\"'(-?\d+)'\"\\z,ms", $val[0], $r)) {
2100
-			$val[0] = $r[1] . '"' . sql_quote($r[2], $boucle->sql_serveur, $type_cast_quote) . '"';
2101
-		}
2102
-		// sinon expliciter les
2103
-		// sql_quote(truc) en sql_quote(truc,'',type)
2104
-		// sql_quote(truc,serveur) en sql_quote(truc,serveur,type)
2105
-		// sql_quote(truc,serveur,'') en sql_quote(truc,serveur,type)
2106
-		// sans toucher aux
2107
-		// sql_quote(truc,'','varchar(10) DEFAULT \'oui\' COLLATE NOCASE')
2108
-		// sql_quote(truc,'','varchar')
2109
-		elseif (
2110
-			preg_match('/\Asql_quote[(](.*?)(,[^)]*?)?(,[^)]*(?:\(\d+\)[^)]*)?)?[)]\s*\z/ms', $val[0], $r)
2111
-			// si pas deja un type
2112
-			and (!isset($r[3]) or !$r[3] or !trim($r[3], ", '"))
2113
-		) {
2114
-			$r = $r[1]
2115
-				. ((isset($r[2]) and $r[2]) ? $r[2] : ",''")
2116
-				. ",'" . addslashes($type_cast_quote) . "'";
2117
-			$val[0] = "sql_quote($r)";
2118
-		}
2119
-		elseif (
2120
-			strpos($val[0], '@@defaultcast@@') !== false
2121
-			and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2122
-		) {
2123
-			$val[0] = substr($val[0], 0, -strlen($r[0])) . "'" . addslashes($type_cast_quote) . "')";
2124
-		}
2125
-	}
2126
-
2127
-	if (
2128
-		strpos($val[0], '@@defaultcast@@') !== false
2129
-		and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2130
-	) {
2131
-		$val[0] = substr($val[0], 0, -strlen($r[0])) . "'char')";
2132
-	}
2133
-
2134
-	// Indicateur pour permettre aux fonctionx boucle_X de modifier
2135
-	// leurs requetes par defaut, notamment le champ statut
2136
-	// Ne pas confondre champs de la table principale et des jointures
2137
-	if ($table === $boucle->id_table) {
2138
-		$boucles[$idb]->modificateur['criteres'][$col_vraie] = true;
2139
-		if ($col_alias != $col_vraie) {
2140
-			$boucles[$idb]->modificateur['criteres'][$col_alias] = true;
2141
-		}
2142
-	}
2143
-
2144
-	// inserer le nom de la table SQL devant le nom du champ
2145
-	if ($table) {
2146
-		if ($col[0] == '`') {
2147
-			$arg = "$table." . substr($col, 1, -1);
2148
-		} else {
2149
-			$arg = "$table.$col";
2150
-		}
2151
-	} else {
2152
-		$arg = $col;
2153
-	}
2154
-
2155
-	// inserer la fonction SQL
2156
-	if ($fct) {
2157
-		$arg = "$fct($arg$args_sql)";
2158
-	}
2159
-
2160
-	return [$arg, $op, $val, $col_alias, $where_complement];
2002
+    $boucle = &$boucles[$idb];
2003
+    $type = $boucle->type_requete;
2004
+    $table = $boucle->id_table ?? '';
2005
+    $desc = $boucle->show;
2006
+    $col_vraie = null;
2007
+
2008
+    [$fct, $col, $op, $val, $args_sql] =
2009
+        calculer_critere_infixe_ops($idb, $boucles, $crit);
2010
+
2011
+    $col_alias = $col;
2012
+    $where_complement = false;
2013
+
2014
+    // Cas particulier : id_enfant => utiliser la colonne id_objet
2015
+    if ($col == 'id_enfant') {
2016
+        $col = $boucle->primary;
2017
+    }
2018
+
2019
+    // Cas particulier : id_parent => verifier les exceptions de tables
2020
+    if (
2021
+        (in_array($col, ['id_parent', 'id_secteur']) and isset($GLOBALS['exceptions_des_tables'][$table][$col]))
2022
+        or (isset($GLOBALS['exceptions_des_tables'][$table][$col]) and is_string($GLOBALS['exceptions_des_tables'][$table][$col]))
2023
+    ) {
2024
+        $col = $GLOBALS['exceptions_des_tables'][$table][$col];
2025
+    } // et possibilite de gerer un critere secteur sur des tables de plugins (ie forums)
2026
+    else {
2027
+        if (($col == 'id_secteur') and ($critere_secteur = charger_fonction("critere_secteur_$type", 'public', true))) {
2028
+            $table = $critere_secteur($idb, $boucles, $val, $crit);
2029
+        }
2030
+
2031
+        // cas id_article=xx qui se mappe en id_objet=xx AND objet=article
2032
+        // sauf si exception declaree : sauter cette etape
2033
+        else {
2034
+            if (
2035
+                !isset($GLOBALS['exceptions_des_jointures'][table_objet_sql($table)][$col])
2036
+                and !isset($GLOBALS['exceptions_des_jointures'][$col])
2037
+                and count(trouver_champs_decomposes($col, $desc)) > 1
2038
+            ) {
2039
+                $e = decompose_champ_id_objet($col);
2040
+                $col = array_shift($e);
2041
+                $where_complement = primary_doublee($e, $table);
2042
+            } // Cas particulier : expressions de date
2043
+            else {
2044
+                if ($c = calculer_critere_infixe_date($idb, $boucles, $col)) {
2045
+                    [$col, $col_vraie] = $c;
2046
+                    $table = '';
2047
+                } // table explicitée {mots.titre}
2048
+                else {
2049
+                    if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2050
+                        [, $table, $col] = $r;
2051
+                        $col_alias = $col;
2052
+
2053
+                        $trouver_table = charger_fonction('trouver_table', 'base');
2054
+                        if (
2055
+                            $desc = $trouver_table($table, $boucle->sql_serveur)
2056
+                            and isset($desc['field'][$col])
2057
+                            and $cle = array_search($desc['table'], $boucle->from)
2058
+                        ) {
2059
+                            $table = $cle;
2060
+                        } else {
2061
+                            $table = trouver_jointure_champ($col, $boucle, [$table], ($crit->cond or $op != '='));
2062
+                        }
2063
+                        #$table = calculer_critere_externe_init($boucle, array($table), $col, $desc, ($crit->cond OR $op!='='), true);
2064
+                        if (!$table) {
2065
+                            return '';
2066
+                        }
2067
+                    }
2068
+                    // si le champ n'est pas trouvé dans la table,
2069
+                    // on cherche si une jointure peut l'obtenir
2070
+                    elseif (@!array_key_exists($col, $desc['field'])) {
2071
+                        // Champ joker * des iterateurs DATA qui accepte tout
2072
+                        if (@array_key_exists('*', $desc['field'])) {
2073
+                            $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
2074
+                        }
2075
+                        else {
2076
+                            $r = calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table);
2077
+                            if (!$r) {
2078
+                                return '';
2079
+                            }
2080
+                            [$col, $col_alias, $table, $where_complement, $desc] = $r;
2081
+                        }
2082
+                    }
2083
+                }
2084
+            }
2085
+        }
2086
+    }
2087
+
2088
+    $col_vraie = ($col_vraie ?: $col);
2089
+    // Dans tous les cas,
2090
+    // virer les guillemets eventuels autour d'un int (qui sont refuses par certains SQL)
2091
+    // et passer dans sql_quote avec le type si connu
2092
+    // et int sinon si la valeur est numerique
2093
+    // sinon introduire le vrai type du champ si connu dans le sql_quote (ou int NOT NULL sinon)
2094
+    // Ne pas utiliser intval, PHP tronquant les Bigint de SQL
2095
+    if ($op == '=' or in_array($op, $GLOBALS['table_criteres_infixes'])) {
2096
+        $type_cast_quote = ($desc['field'][$col_vraie] ?? 'int NOT NULL');
2097
+        // defaire le quote des int et les passer dans sql_quote avec le bon type de champ si on le connait, int sinon
2098
+        // prendre en compte le debug ou la valeur arrive avec un commentaire PHP en debut
2099
+        if (preg_match(",^\\A(\s*//.*?$\s*)?\"'(-?\d+)'\"\\z,ms", $val[0], $r)) {
2100
+            $val[0] = $r[1] . '"' . sql_quote($r[2], $boucle->sql_serveur, $type_cast_quote) . '"';
2101
+        }
2102
+        // sinon expliciter les
2103
+        // sql_quote(truc) en sql_quote(truc,'',type)
2104
+        // sql_quote(truc,serveur) en sql_quote(truc,serveur,type)
2105
+        // sql_quote(truc,serveur,'') en sql_quote(truc,serveur,type)
2106
+        // sans toucher aux
2107
+        // sql_quote(truc,'','varchar(10) DEFAULT \'oui\' COLLATE NOCASE')
2108
+        // sql_quote(truc,'','varchar')
2109
+        elseif (
2110
+            preg_match('/\Asql_quote[(](.*?)(,[^)]*?)?(,[^)]*(?:\(\d+\)[^)]*)?)?[)]\s*\z/ms', $val[0], $r)
2111
+            // si pas deja un type
2112
+            and (!isset($r[3]) or !$r[3] or !trim($r[3], ", '"))
2113
+        ) {
2114
+            $r = $r[1]
2115
+                . ((isset($r[2]) and $r[2]) ? $r[2] : ",''")
2116
+                . ",'" . addslashes($type_cast_quote) . "'";
2117
+            $val[0] = "sql_quote($r)";
2118
+        }
2119
+        elseif (
2120
+            strpos($val[0], '@@defaultcast@@') !== false
2121
+            and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2122
+        ) {
2123
+            $val[0] = substr($val[0], 0, -strlen($r[0])) . "'" . addslashes($type_cast_quote) . "')";
2124
+        }
2125
+    }
2126
+
2127
+    if (
2128
+        strpos($val[0], '@@defaultcast@@') !== false
2129
+        and preg_match("/'@@defaultcast@@'\s*\)\s*\z/ms", $val[0], $r)
2130
+    ) {
2131
+        $val[0] = substr($val[0], 0, -strlen($r[0])) . "'char')";
2132
+    }
2133
+
2134
+    // Indicateur pour permettre aux fonctionx boucle_X de modifier
2135
+    // leurs requetes par defaut, notamment le champ statut
2136
+    // Ne pas confondre champs de la table principale et des jointures
2137
+    if ($table === $boucle->id_table) {
2138
+        $boucles[$idb]->modificateur['criteres'][$col_vraie] = true;
2139
+        if ($col_alias != $col_vraie) {
2140
+            $boucles[$idb]->modificateur['criteres'][$col_alias] = true;
2141
+        }
2142
+    }
2143
+
2144
+    // inserer le nom de la table SQL devant le nom du champ
2145
+    if ($table) {
2146
+        if ($col[0] == '`') {
2147
+            $arg = "$table." . substr($col, 1, -1);
2148
+        } else {
2149
+            $arg = "$table.$col";
2150
+        }
2151
+    } else {
2152
+        $arg = $col;
2153
+    }
2154
+
2155
+    // inserer la fonction SQL
2156
+    if ($fct) {
2157
+        $arg = "$fct($arg$args_sql)";
2158
+    }
2159
+
2160
+    return [$arg, $op, $val, $col_alias, $where_complement];
2161 2161
 }
2162 2162
 
2163 2163
 
@@ -2186,77 +2186,77 @@  discard block
 block discarded – undo
2186 2186
  **/
2187 2187
 function calculer_critere_infixe_externe($boucle, $crit, $op, $desc, $col, $col_alias, $table) {
2188 2188
 
2189
-	$where = '';
2190
-
2191
-	$calculer_critere_externe = 'calculer_critere_externe_init';
2192
-	// gestion par les plugins des jointures tordues
2193
-	// pas automatiques mais necessaires
2194
-	$table_sql = table_objet_sql($table);
2195
-	if (
2196
-		isset($GLOBALS['exceptions_des_jointures'][$table_sql])
2197
-		and is_array($GLOBALS['exceptions_des_jointures'][$table_sql])
2198
-		and
2199
-		(
2200
-			isset($GLOBALS['exceptions_des_jointures'][$table_sql][$col])
2201
-			or
2202
-			isset($GLOBALS['exceptions_des_jointures'][$table_sql][''])
2203
-		)
2204
-	) {
2205
-		$t = $GLOBALS['exceptions_des_jointures'][$table_sql];
2206
-		$index = $t[$col] ?? $t[''] ?? [];
2207
-
2208
-		if ((is_countable($index) ? count($index) : 0) == 3) {
2209
-			[$t, $col, $calculer_critere_externe] = $index;
2210
-		} elseif ((is_countable($index) ? count($index) : 0) == 2) {
2211
-			[$t, $col] = $t[$col];
2212
-		} elseif ((is_countable($index) ? count($index) : 0) == 1) {
2213
-			[$calculer_critere_externe] = $index;
2214
-			$t = $table;
2215
-		} else {
2216
-			$t = '';
2217
-		} // jointure non declaree. La trouver.
2218
-	} elseif (isset($GLOBALS['exceptions_des_jointures'][$col])) {
2219
-		[$t, $col] = $GLOBALS['exceptions_des_jointures'][$col];
2220
-	} else {
2221
-		$t = '';
2222
-	} // jointure non declaree. La trouver.
2223
-
2224
-	// ici on construit le from pour fournir $col en piochant dans les jointures
2225
-
2226
-	// si des jointures explicites sont fournies, on cherche d'abord dans celles ci
2227
-	// permet de forcer une table de lien quand il y a ambiguite
2228
-	// <BOUCLE_(DOCUMENTS documents_liens){id_mot}>
2229
-	// alors que <BOUCLE_(DOCUMENTS){id_mot}> produit la meme chose que <BOUCLE_(DOCUMENTS mots_liens){id_mot}>
2230
-	$table = '';
2231
-	if ($boucle->jointures_explicites) {
2232
-		$jointures_explicites = explode(' ', $boucle->jointures_explicites);
2233
-		$table = $calculer_critere_externe($boucle, $jointures_explicites, $col, $desc, ($crit->cond or $op != '='), $t);
2234
-	}
2235
-
2236
-	// et sinon on cherche parmi toutes les jointures declarees
2237
-	if (!$table) {
2238
-		$table = $calculer_critere_externe($boucle, $boucle->jointures, $col, $desc, ($crit->cond or $op != '='), $t);
2239
-	}
2240
-
2241
-	if (!$table) {
2242
-		return '';
2243
-	}
2244
-
2245
-	// il ne reste plus qu'a trouver le champ dans les from
2246
-	[$nom, $desc, $cle] = trouver_champ_exterieur($col, $boucle->from, $boucle);
2247
-
2248
-	if ((is_countable($cle) ? count($cle) : 0) > 1 or reset($cle) !== $col) {
2249
-		$col_alias = $col; // id_article devient juste le nom d'origine
2250
-		if ((is_countable($cle) ? count($cle) : 0) > 1 and reset($cle) == 'id_objet') {
2251
-			$e = decompose_champ_id_objet($col);
2252
-			$col = array_shift($e);
2253
-			$where = primary_doublee($e, $table);
2254
-		} else {
2255
-			$col = reset($cle);
2256
-		}
2257
-	}
2258
-
2259
-	return [$col, $col_alias, $table, $where, $desc];
2189
+    $where = '';
2190
+
2191
+    $calculer_critere_externe = 'calculer_critere_externe_init';
2192
+    // gestion par les plugins des jointures tordues
2193
+    // pas automatiques mais necessaires
2194
+    $table_sql = table_objet_sql($table);
2195
+    if (
2196
+        isset($GLOBALS['exceptions_des_jointures'][$table_sql])
2197
+        and is_array($GLOBALS['exceptions_des_jointures'][$table_sql])
2198
+        and
2199
+        (
2200
+            isset($GLOBALS['exceptions_des_jointures'][$table_sql][$col])
2201
+            or
2202
+            isset($GLOBALS['exceptions_des_jointures'][$table_sql][''])
2203
+        )
2204
+    ) {
2205
+        $t = $GLOBALS['exceptions_des_jointures'][$table_sql];
2206
+        $index = $t[$col] ?? $t[''] ?? [];
2207
+
2208
+        if ((is_countable($index) ? count($index) : 0) == 3) {
2209
+            [$t, $col, $calculer_critere_externe] = $index;
2210
+        } elseif ((is_countable($index) ? count($index) : 0) == 2) {
2211
+            [$t, $col] = $t[$col];
2212
+        } elseif ((is_countable($index) ? count($index) : 0) == 1) {
2213
+            [$calculer_critere_externe] = $index;
2214
+            $t = $table;
2215
+        } else {
2216
+            $t = '';
2217
+        } // jointure non declaree. La trouver.
2218
+    } elseif (isset($GLOBALS['exceptions_des_jointures'][$col])) {
2219
+        [$t, $col] = $GLOBALS['exceptions_des_jointures'][$col];
2220
+    } else {
2221
+        $t = '';
2222
+    } // jointure non declaree. La trouver.
2223
+
2224
+    // ici on construit le from pour fournir $col en piochant dans les jointures
2225
+
2226
+    // si des jointures explicites sont fournies, on cherche d'abord dans celles ci
2227
+    // permet de forcer une table de lien quand il y a ambiguite
2228
+    // <BOUCLE_(DOCUMENTS documents_liens){id_mot}>
2229
+    // alors que <BOUCLE_(DOCUMENTS){id_mot}> produit la meme chose que <BOUCLE_(DOCUMENTS mots_liens){id_mot}>
2230
+    $table = '';
2231
+    if ($boucle->jointures_explicites) {
2232
+        $jointures_explicites = explode(' ', $boucle->jointures_explicites);
2233
+        $table = $calculer_critere_externe($boucle, $jointures_explicites, $col, $desc, ($crit->cond or $op != '='), $t);
2234
+    }
2235
+
2236
+    // et sinon on cherche parmi toutes les jointures declarees
2237
+    if (!$table) {
2238
+        $table = $calculer_critere_externe($boucle, $boucle->jointures, $col, $desc, ($crit->cond or $op != '='), $t);
2239
+    }
2240
+
2241
+    if (!$table) {
2242
+        return '';
2243
+    }
2244
+
2245
+    // il ne reste plus qu'a trouver le champ dans les from
2246
+    [$nom, $desc, $cle] = trouver_champ_exterieur($col, $boucle->from, $boucle);
2247
+
2248
+    if ((is_countable($cle) ? count($cle) : 0) > 1 or reset($cle) !== $col) {
2249
+        $col_alias = $col; // id_article devient juste le nom d'origine
2250
+        if ((is_countable($cle) ? count($cle) : 0) > 1 and reset($cle) == 'id_objet') {
2251
+            $e = decompose_champ_id_objet($col);
2252
+            $col = array_shift($e);
2253
+            $where = primary_doublee($e, $table);
2254
+        } else {
2255
+            $col = reset($cle);
2256
+        }
2257
+    }
2258
+
2259
+    return [$col, $col_alias, $table, $where, $desc];
2260 2260
 }
2261 2261
 
2262 2262
 
@@ -2277,10 +2277,10 @@  discard block
 block discarded – undo
2277 2277
  *     - valeur
2278 2278
  **/
2279 2279
 function primary_doublee($decompose, $table) {
2280
-	$e1 = reset($decompose);
2281
-	$e2 = "sql_quote('" . end($decompose) . "')";
2280
+    $e1 = reset($decompose);
2281
+    $e2 = "sql_quote('" . end($decompose) . "')";
2282 2282
 
2283
-	return ["'='", "'$table." . $e1 . "'", $e2];
2283
+    return ["'='", "'$table." . $e1 . "'", $e2];
2284 2284
 }
2285 2285
 
2286 2286
 /**
@@ -2311,57 +2311,57 @@  discard block
 block discarded – undo
2311 2311
  *     Vide sinon.
2312 2312
  */
2313 2313
 function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $cond, $checkarrivee = false) {
2314
-	// si on demande un truc du genre spip_mots
2315
-	// avec aussi spip_mots_liens dans les jointures dispo
2316
-	// et qu'on est la
2317
-	// il faut privilegier la jointure directe en 2 etapes spip_mots_liens, spip_mots
2318
-	if (
2319
-		$checkarrivee
2320
-		and is_string($checkarrivee)
2321
-		and $a = table_objet($checkarrivee)
2322
-		and in_array($a . '_liens', $joints)
2323
-	) {
2324
-		if ($res = calculer_lien_externe_init($boucle, $joints, $col, $desc, $cond, $checkarrivee)) {
2325
-			return $res;
2326
-		}
2327
-	}
2328
-	foreach ($joints as $joint) {
2329
-		if ($arrivee = trouver_champ_exterieur($col, [$joint], $boucle, $checkarrivee)) {
2330
-			// alias de table dans le from
2331
-			$t = array_search($arrivee[0], $boucle->from);
2332
-			// recuperer la cle id_xx eventuellement decomposee en (id_objet,objet)
2333
-			$cols = $arrivee[2];
2334
-			// mais on ignore la 3eme cle si presente qui correspond alors au point de depart
2335
-			if ((is_countable($cols) ? count($cols) : 0) > 2) {
2336
-				array_pop($cols);
2337
-			}
2338
-			if ($t) {
2339
-				// la table est déjà dans le FROM, on vérifie si le champ est utilisé.
2340
-				$joindre = false;
2341
-				foreach ($cols as $col) {
2342
-					$c = '/\b' . $t . ".$col" . '\b/';
2343
-					if (trouver_champ($c, $boucle->where)) {
2344
-						$joindre = true;
2345
-					} else {
2346
-						// mais ca peut etre dans le FIELD pour le Having
2347
-						$c = "/FIELD.$t" . ".$col,/";
2348
-						if (trouver_champ($c, $boucle->select)) {
2349
-							$joindre = true;
2350
-						}
2351
-					}
2352
-				}
2353
-				if (!$joindre) {
2354
-					return $t;
2355
-				}
2356
-			}
2357
-			array_pop($arrivee);
2358
-			if ($res = calculer_jointure($boucle, [$boucle->id_table, $desc], $arrivee, $cols, $cond, 1)) {
2359
-				return $res;
2360
-			}
2361
-		}
2362
-	}
2363
-
2364
-	return '';
2314
+    // si on demande un truc du genre spip_mots
2315
+    // avec aussi spip_mots_liens dans les jointures dispo
2316
+    // et qu'on est la
2317
+    // il faut privilegier la jointure directe en 2 etapes spip_mots_liens, spip_mots
2318
+    if (
2319
+        $checkarrivee
2320
+        and is_string($checkarrivee)
2321
+        and $a = table_objet($checkarrivee)
2322
+        and in_array($a . '_liens', $joints)
2323
+    ) {
2324
+        if ($res = calculer_lien_externe_init($boucle, $joints, $col, $desc, $cond, $checkarrivee)) {
2325
+            return $res;
2326
+        }
2327
+    }
2328
+    foreach ($joints as $joint) {
2329
+        if ($arrivee = trouver_champ_exterieur($col, [$joint], $boucle, $checkarrivee)) {
2330
+            // alias de table dans le from
2331
+            $t = array_search($arrivee[0], $boucle->from);
2332
+            // recuperer la cle id_xx eventuellement decomposee en (id_objet,objet)
2333
+            $cols = $arrivee[2];
2334
+            // mais on ignore la 3eme cle si presente qui correspond alors au point de depart
2335
+            if ((is_countable($cols) ? count($cols) : 0) > 2) {
2336
+                array_pop($cols);
2337
+            }
2338
+            if ($t) {
2339
+                // la table est déjà dans le FROM, on vérifie si le champ est utilisé.
2340
+                $joindre = false;
2341
+                foreach ($cols as $col) {
2342
+                    $c = '/\b' . $t . ".$col" . '\b/';
2343
+                    if (trouver_champ($c, $boucle->where)) {
2344
+                        $joindre = true;
2345
+                    } else {
2346
+                        // mais ca peut etre dans le FIELD pour le Having
2347
+                        $c = "/FIELD.$t" . ".$col,/";
2348
+                        if (trouver_champ($c, $boucle->select)) {
2349
+                            $joindre = true;
2350
+                        }
2351
+                    }
2352
+                }
2353
+                if (!$joindre) {
2354
+                    return $t;
2355
+                }
2356
+            }
2357
+            array_pop($arrivee);
2358
+            if ($res = calculer_jointure($boucle, [$boucle->id_table, $desc], $arrivee, $cols, $cond, 1)) {
2359
+                return $res;
2360
+            }
2361
+        }
2362
+    }
2363
+
2364
+    return '';
2365 2365
 }
2366 2366
 
2367 2367
 /**
@@ -2387,35 +2387,35 @@  discard block
 block discarded – undo
2387 2387
  *     Alias de la table de jointure (Lx)
2388 2388
  */
2389 2389
 function calculer_lien_externe_init(&$boucle, $joints, $col, $desc, $cond, $checkarrivee = false) {
2390
-	$primary_arrivee = id_table_objet($checkarrivee);
2391
-
2392
-	// [FIXME] $checkarrivee peut-il arriver avec false ????
2393
-	$intermediaire = trouver_champ_exterieur($primary_arrivee, $joints, $boucle, $checkarrivee . '_liens');
2394
-	$arrivee = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee);
2395
-
2396
-	if (!$intermediaire or !$arrivee) {
2397
-		return '';
2398
-	}
2399
-	array_pop($intermediaire); // enlever la cle en 3eme argument
2400
-	array_pop($arrivee); // enlever la cle en 3eme argument
2401
-
2402
-	$res = fabrique_jointures(
2403
-		$boucle,
2404
-		[
2405
-			[
2406
-				$boucle->id_table,
2407
-				$intermediaire,
2408
-				[id_table_objet($desc['table_objet']), 'id_objet', 'objet', $desc['type']]
2409
-			],
2410
-			[reset($intermediaire), $arrivee, $primary_arrivee]
2411
-		],
2412
-		$cond,
2413
-		$desc,
2414
-		$boucle->id_table,
2415
-		[$col]
2416
-	);
2417
-
2418
-	return $res;
2390
+    $primary_arrivee = id_table_objet($checkarrivee);
2391
+
2392
+    // [FIXME] $checkarrivee peut-il arriver avec false ????
2393
+    $intermediaire = trouver_champ_exterieur($primary_arrivee, $joints, $boucle, $checkarrivee . '_liens');
2394
+    $arrivee = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee);
2395
+
2396
+    if (!$intermediaire or !$arrivee) {
2397
+        return '';
2398
+    }
2399
+    array_pop($intermediaire); // enlever la cle en 3eme argument
2400
+    array_pop($arrivee); // enlever la cle en 3eme argument
2401
+
2402
+    $res = fabrique_jointures(
2403
+        $boucle,
2404
+        [
2405
+            [
2406
+                $boucle->id_table,
2407
+                $intermediaire,
2408
+                [id_table_objet($desc['table_objet']), 'id_objet', 'objet', $desc['type']]
2409
+            ],
2410
+            [reset($intermediaire), $arrivee, $primary_arrivee]
2411
+        ],
2412
+        $cond,
2413
+        $desc,
2414
+        $boucle->id_table,
2415
+        [$col]
2416
+    );
2417
+
2418
+    return $res;
2419 2419
 }
2420 2420
 
2421 2421
 
@@ -2432,17 +2432,17 @@  discard block
 block discarded – undo
2432 2432
  *     false sinon.
2433 2433
  **/
2434 2434
 function trouver_champ($champ, $where) {
2435
-	if (!is_array($where)) {
2436
-		return preg_match($champ, $where);
2437
-	} else {
2438
-		foreach ($where as $clause) {
2439
-			if (trouver_champ($champ, $clause)) {
2440
-				return true;
2441
-			}
2442
-		}
2443
-
2444
-		return false;
2445
-	}
2435
+    if (!is_array($where)) {
2436
+        return preg_match($champ, $where);
2437
+    } else {
2438
+        foreach ($where as $clause) {
2439
+            if (trouver_champ($champ, $clause)) {
2440
+                return true;
2441
+            }
2442
+        }
2443
+
2444
+        return false;
2445
+    }
2446 2446
 }
2447 2447
 
2448 2448
 
@@ -2468,130 +2468,130 @@  discard block
 block discarded – undo
2468 2468
  *     - string $args_sql  Suite des arguments du critère. ?
2469 2469
  **/
2470 2470
 function calculer_critere_infixe_ops($idb, &$boucles, $crit) {
2471
-	// cas d'une valeur comparee a elle-meme ou son referent
2472
-	if (count($crit->param) == 0) {
2473
-		$op = '=';
2474
-		$col = $val = $crit->op;
2475
-		if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2476
-			$val = $r[2];
2477
-		}
2478
-		// Cas special {lang} : aller chercher $GLOBALS['spip_lang']
2479
-		if ($val == 'lang') {
2480
-			$val = [kwote('$GLOBALS[\'spip_lang\']')];
2481
-		} else {
2482
-			$defaut = null;
2483
-			if ($val == 'id_parent') {
2484
-				// Si id_parent, comparer l'id_parent avec l'id_objet
2485
-				// de la boucle superieure.... faudrait verifier qu'il existe
2486
-				// pour eviter l'erreur SQL
2487
-				$val = $boucles[$idb]->primary;
2488
-				// mais si pas de boucle superieure, prendre id_parent dans l'env
2489
-				$defaut = "(\$Pile[0]['id_parent'] ?? null)";
2490
-			} elseif ($val == 'id_enfant') {
2491
-				// Si id_enfant, comparer l'id_objet avec l'id_parent
2492
-				// de la boucle superieure
2493
-				$val = 'id_parent';
2494
-			} elseif ($crit->cond and ($col == 'date' or $col == 'date_redac')) {
2495
-				// un critere conditionnel sur date est traite a part
2496
-				// car la date est mise d'office par SPIP,
2497
-				$defaut = "(\$Pile[0]['{$col}_default']?'':\$Pile[0]['" . $col . "'])";
2498
-			}
2499
-
2500
-			$val = calculer_argument_precedent($idb, $val, $boucles, $defaut);
2501
-			$val = [kwote($val)];
2502
-		}
2503
-	} else {
2504
-		// comparaison explicite
2505
-		// le phraseur impose que le premier param soit du texte
2506
-		$params = $crit->param;
2507
-		$op = $crit->op;
2508
-		if ($op == '==') {
2509
-			$op = 'REGEXP';
2510
-		}
2511
-		$col = array_shift($params);
2512
-		$col = $col[0]->texte;
2513
-
2514
-		$val = [];
2515
-		$parent = $boucles[$idb]->id_parent;
2516
-
2517
-		// Dans le cas {x=='#DATE'} etc, defaire le travail du phraseur,
2518
-		// celui ne sachant pas ce qu'est un critere infixe
2519
-		// et a fortiori son 2e operande qu'entoure " ou '
2520
-		if (
2521
-			count($params) == 1
2522
-			and (is_countable($params[0]) ? count($params[0]) : 0) == 3
2523
-			and $params[0][0]->type == 'texte'
2524
-			and $params[0][2]->type == 'texte'
2525
-			and ($p = $params[0][0]->texte) == $params[0][2]->texte
2526
-			and (($p == "'") or ($p == '"'))
2527
-			and $params[0][1]->type == 'champ'
2528
-		) {
2529
-			$val[] = "$p\\$p#" . $params[0][1]->nom_champ . "\\$p$p";
2530
-		} else {
2531
-			foreach ((($op != 'IN') ? $params : calculer_vieux_in($params)) as $p) {
2532
-				$a = calculer_liste($p, $idb, $boucles, $parent);
2533
-				if (strcasecmp($op, 'IN') == 0) {
2534
-					$val[] = $a;
2535
-				} else {
2536
-					$val[] = kwote($a, $boucles[$idb]->sql_serveur, '@@defaultcast@@');
2537
-				} // toujours quoter en char ici
2538
-			}
2539
-		}
2540
-	}
2541
-
2542
-	$fct = $args_sql = '';
2543
-	// fonction SQL ?
2544
-	// chercher FONCTION(champ) tel que CONCAT(titre,descriptif)
2545
-	if (preg_match('/^(.*)' . SQL_ARGS . '$/', $col, $m)) {
2546
-		$fct = $m[1];
2547
-		preg_match('/^\(([^,]*)(.*)\)$/', $m[2], $a);
2548
-		$col = $a[1];
2549
-		if (preg_match('/^(\S*)(\s+AS\s+.*)$/i', $col, $m)) {
2550
-			$col = $m[1];
2551
-			$args_sql = $m[2];
2552
-		}
2553
-		$args_sql .= $a[2];
2554
-	}
2555
-
2556
-	return [$fct, $col, $op, $val, $args_sql];
2471
+    // cas d'une valeur comparee a elle-meme ou son referent
2472
+    if (count($crit->param) == 0) {
2473
+        $op = '=';
2474
+        $col = $val = $crit->op;
2475
+        if (preg_match('/^(.*)\.(.*)$/', $col, $r)) {
2476
+            $val = $r[2];
2477
+        }
2478
+        // Cas special {lang} : aller chercher $GLOBALS['spip_lang']
2479
+        if ($val == 'lang') {
2480
+            $val = [kwote('$GLOBALS[\'spip_lang\']')];
2481
+        } else {
2482
+            $defaut = null;
2483
+            if ($val == 'id_parent') {
2484
+                // Si id_parent, comparer l'id_parent avec l'id_objet
2485
+                // de la boucle superieure.... faudrait verifier qu'il existe
2486
+                // pour eviter l'erreur SQL
2487
+                $val = $boucles[$idb]->primary;
2488
+                // mais si pas de boucle superieure, prendre id_parent dans l'env
2489
+                $defaut = "(\$Pile[0]['id_parent'] ?? null)";
2490
+            } elseif ($val == 'id_enfant') {
2491
+                // Si id_enfant, comparer l'id_objet avec l'id_parent
2492
+                // de la boucle superieure
2493
+                $val = 'id_parent';
2494
+            } elseif ($crit->cond and ($col == 'date' or $col == 'date_redac')) {
2495
+                // un critere conditionnel sur date est traite a part
2496
+                // car la date est mise d'office par SPIP,
2497
+                $defaut = "(\$Pile[0]['{$col}_default']?'':\$Pile[0]['" . $col . "'])";
2498
+            }
2499
+
2500
+            $val = calculer_argument_precedent($idb, $val, $boucles, $defaut);
2501
+            $val = [kwote($val)];
2502
+        }
2503
+    } else {
2504
+        // comparaison explicite
2505
+        // le phraseur impose que le premier param soit du texte
2506
+        $params = $crit->param;
2507
+        $op = $crit->op;
2508
+        if ($op == '==') {
2509
+            $op = 'REGEXP';
2510
+        }
2511
+        $col = array_shift($params);
2512
+        $col = $col[0]->texte;
2513
+
2514
+        $val = [];
2515
+        $parent = $boucles[$idb]->id_parent;
2516
+
2517
+        // Dans le cas {x=='#DATE'} etc, defaire le travail du phraseur,
2518
+        // celui ne sachant pas ce qu'est un critere infixe
2519
+        // et a fortiori son 2e operande qu'entoure " ou '
2520
+        if (
2521
+            count($params) == 1
2522
+            and (is_countable($params[0]) ? count($params[0]) : 0) == 3
2523
+            and $params[0][0]->type == 'texte'
2524
+            and $params[0][2]->type == 'texte'
2525
+            and ($p = $params[0][0]->texte) == $params[0][2]->texte
2526
+            and (($p == "'") or ($p == '"'))
2527
+            and $params[0][1]->type == 'champ'
2528
+        ) {
2529
+            $val[] = "$p\\$p#" . $params[0][1]->nom_champ . "\\$p$p";
2530
+        } else {
2531
+            foreach ((($op != 'IN') ? $params : calculer_vieux_in($params)) as $p) {
2532
+                $a = calculer_liste($p, $idb, $boucles, $parent);
2533
+                if (strcasecmp($op, 'IN') == 0) {
2534
+                    $val[] = $a;
2535
+                } else {
2536
+                    $val[] = kwote($a, $boucles[$idb]->sql_serveur, '@@defaultcast@@');
2537
+                } // toujours quoter en char ici
2538
+            }
2539
+        }
2540
+    }
2541
+
2542
+    $fct = $args_sql = '';
2543
+    // fonction SQL ?
2544
+    // chercher FONCTION(champ) tel que CONCAT(titre,descriptif)
2545
+    if (preg_match('/^(.*)' . SQL_ARGS . '$/', $col, $m)) {
2546
+        $fct = $m[1];
2547
+        preg_match('/^\(([^,]*)(.*)\)$/', $m[2], $a);
2548
+        $col = $a[1];
2549
+        if (preg_match('/^(\S*)(\s+AS\s+.*)$/i', $col, $m)) {
2550
+            $col = $m[1];
2551
+            $args_sql = $m[2];
2552
+        }
2553
+        $args_sql .= $a[2];
2554
+    }
2555
+
2556
+    return [$fct, $col, $op, $val, $args_sql];
2557 2557
 }
2558 2558
 
2559 2559
 // compatibilite ancienne version
2560 2560
 
2561 2561
 // https://code.spip.net/@calculer_vieux_in
2562 2562
 function calculer_vieux_in($params) {
2563
-	$deb = $params[0][0];
2564
-	$k = (is_countable($params) ? count($params) : 0) - 1;
2565
-	$last = $params[$k];
2566
-	$j = (is_countable($last) ? count($last) : 0) - 1;
2567
-	$last = $last[$j];
2568
-	$n = isset($last->texte) ? strlen($last->texte) : 0;
2569
-
2570
-	if (
2571
-		!((isset($deb->texte[0]) and $deb->texte[0] == '(')
2572
-		&& (isset($last->texte[$n - 1]) and $last->texte[$n - 1] == ')'))
2573
-	) {
2574
-		return $params;
2575
-	}
2576
-	$params[0][0]->texte = substr($deb->texte, 1);
2577
-	// attention, on peut avoir k=0,j=0 ==> recalculer
2578
-	$last = $params[$k][$j];
2579
-	$n = strlen($last->texte);
2580
-	$params[$k][$j]->texte = substr($last->texte, 0, $n - 1);
2581
-	$newp = [];
2582
-	foreach ($params as $v) {
2583
-		if ($v[0]->type != 'texte') {
2584
-			$newp[] = $v;
2585
-		} else {
2586
-			foreach (explode(',', $v[0]->texte) as $x) {
2587
-				$t = new Texte();
2588
-				$t->texte = $x;
2589
-				$newp[] = [$t];
2590
-			}
2591
-		}
2592
-	}
2593
-
2594
-	return $newp;
2563
+    $deb = $params[0][0];
2564
+    $k = (is_countable($params) ? count($params) : 0) - 1;
2565
+    $last = $params[$k];
2566
+    $j = (is_countable($last) ? count($last) : 0) - 1;
2567
+    $last = $last[$j];
2568
+    $n = isset($last->texte) ? strlen($last->texte) : 0;
2569
+
2570
+    if (
2571
+        !((isset($deb->texte[0]) and $deb->texte[0] == '(')
2572
+        && (isset($last->texte[$n - 1]) and $last->texte[$n - 1] == ')'))
2573
+    ) {
2574
+        return $params;
2575
+    }
2576
+    $params[0][0]->texte = substr($deb->texte, 1);
2577
+    // attention, on peut avoir k=0,j=0 ==> recalculer
2578
+    $last = $params[$k][$j];
2579
+    $n = strlen($last->texte);
2580
+    $params[$k][$j]->texte = substr($last->texte, 0, $n - 1);
2581
+    $newp = [];
2582
+    foreach ($params as $v) {
2583
+        if ($v[0]->type != 'texte') {
2584
+            $newp[] = $v;
2585
+        } else {
2586
+            foreach (explode(',', $v[0]->texte) as $x) {
2587
+                $t = new Texte();
2588
+                $t->texte = $x;
2589
+                $newp[] = [$t];
2590
+            }
2591
+        }
2592
+    }
2593
+
2594
+    return $newp;
2595 2595
 }
2596 2596
 
2597 2597
 /**
@@ -2610,89 +2610,89 @@  discard block
 block discarded – undo
2610 2610
  *     - nom de la colonne de date (si le calcul n'est pas relatif)
2611 2611
  **/
2612 2612
 function calculer_critere_infixe_date($idb, &$boucles, $col) {
2613
-	if (!preg_match(',^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z_]+)?$,', $col, $regs)) {
2614
-		return '';
2615
-	}
2616
-
2617
-	$boucle = $boucles[$idb];
2618
-	$table = $boucle->show;
2619
-
2620
-	// si c'est une colonne de la table, ne rien faire
2621
-	if (isset($table['field'][$col])) {
2622
-		return '';
2623
-	}
2624
-
2625
-	if (!$table['date'] && !isset($GLOBALS['table_date'][$table['id_table']])) {
2626
-		return '';
2627
-	}
2628
-	$pred = $date_orig = $GLOBALS['table_date'][$table['id_table']] ?? $table['date'];
2629
-
2630
-	$col = $regs[1];
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
-
2635
-		if (isset($table['field']["date$suite"])) {
2636
-			$date_orig = 'date' . $suite;
2637
-		} else {
2638
-			$date_orig = substr($suite, 1);
2639
-		}
2640
-		$pred = $date_orig;
2641
-	} else {
2642
-		if (isset($regs[2]) and $rel = $regs[2]) {
2643
-			$pred = 'date';
2644
-		}
2645
-	}
2646
-
2647
-	$date_compare = "\"' . normaliser_date(" .
2648
-		calculer_argument_precedent($idb, $pred, $boucles) .
2649
-		") . '\"";
2650
-
2651
-	$col_vraie = $date_orig;
2652
-	$date_orig = $boucle->id_table . '.' . $date_orig;
2653
-
2654
-	switch ($col) {
2655
-		case 'date':
2656
-			$col = $date_orig;
2657
-			break;
2658
-		case 'jour':
2659
-			$col = "DAYOFMONTH($date_orig)";
2660
-			break;
2661
-		case 'mois':
2662
-			$col = "MONTH($date_orig)";
2663
-			break;
2664
-		case 'annee':
2665
-			$col = "YEAR($date_orig)";
2666
-			break;
2667
-		case 'heure':
2668
-			$col = "DATE_FORMAT($date_orig, \\'%H:%i\\')";
2669
-			break;
2670
-		case 'age':
2671
-			$col = calculer_param_date("\'' . date('Y-m-d H:i:00') . '\'", $date_orig);
2672
-			$col_vraie = '';// comparer a un int (par defaut)
2673
-			break;
2674
-		case 'age_relatif':
2675
-			$col = calculer_param_date($date_compare, $date_orig);
2676
-			$col_vraie = '';// comparer a un int (par defaut)
2677
-			break;
2678
-		case 'jour_relatif':
2679
-			$col = '(TO_DAYS(' . $date_compare . ')-TO_DAYS(' . $date_orig . '))';
2680
-			$col_vraie = '';// comparer a un int (par defaut)
2681
-			break;
2682
-		case 'mois_relatif':
2683
-			$col = 'MONTH(' . $date_compare . ')-MONTH(' .
2684
-				$date_orig . ')+12*(YEAR(' . $date_compare .
2685
-				')-YEAR(' . $date_orig . '))';
2686
-			$col_vraie = '';// comparer a un int (par defaut)
2687
-			break;
2688
-		case 'annee_relatif':
2689
-			$col = 'YEAR(' . $date_compare . ')-YEAR(' .
2690
-				$date_orig . ')';
2691
-			$col_vraie = '';// comparer a un int (par defaut)
2692
-			break;
2693
-	}
2694
-
2695
-	return [$col, $col_vraie];
2613
+    if (!preg_match(',^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z_]+)?$,', $col, $regs)) {
2614
+        return '';
2615
+    }
2616
+
2617
+    $boucle = $boucles[$idb];
2618
+    $table = $boucle->show;
2619
+
2620
+    // si c'est une colonne de la table, ne rien faire
2621
+    if (isset($table['field'][$col])) {
2622
+        return '';
2623
+    }
2624
+
2625
+    if (!$table['date'] && !isset($GLOBALS['table_date'][$table['id_table']])) {
2626
+        return '';
2627
+    }
2628
+    $pred = $date_orig = $GLOBALS['table_date'][$table['id_table']] ?? $table['date'];
2629
+
2630
+    $col = $regs[1];
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
+
2635
+        if (isset($table['field']["date$suite"])) {
2636
+            $date_orig = 'date' . $suite;
2637
+        } else {
2638
+            $date_orig = substr($suite, 1);
2639
+        }
2640
+        $pred = $date_orig;
2641
+    } else {
2642
+        if (isset($regs[2]) and $rel = $regs[2]) {
2643
+            $pred = 'date';
2644
+        }
2645
+    }
2646
+
2647
+    $date_compare = "\"' . normaliser_date(" .
2648
+        calculer_argument_precedent($idb, $pred, $boucles) .
2649
+        ") . '\"";
2650
+
2651
+    $col_vraie = $date_orig;
2652
+    $date_orig = $boucle->id_table . '.' . $date_orig;
2653
+
2654
+    switch ($col) {
2655
+        case 'date':
2656
+            $col = $date_orig;
2657
+            break;
2658
+        case 'jour':
2659
+            $col = "DAYOFMONTH($date_orig)";
2660
+            break;
2661
+        case 'mois':
2662
+            $col = "MONTH($date_orig)";
2663
+            break;
2664
+        case 'annee':
2665
+            $col = "YEAR($date_orig)";
2666
+            break;
2667
+        case 'heure':
2668
+            $col = "DATE_FORMAT($date_orig, \\'%H:%i\\')";
2669
+            break;
2670
+        case 'age':
2671
+            $col = calculer_param_date("\'' . date('Y-m-d H:i:00') . '\'", $date_orig);
2672
+            $col_vraie = '';// comparer a un int (par defaut)
2673
+            break;
2674
+        case 'age_relatif':
2675
+            $col = calculer_param_date($date_compare, $date_orig);
2676
+            $col_vraie = '';// comparer a un int (par defaut)
2677
+            break;
2678
+        case 'jour_relatif':
2679
+            $col = '(TO_DAYS(' . $date_compare . ')-TO_DAYS(' . $date_orig . '))';
2680
+            $col_vraie = '';// comparer a un int (par defaut)
2681
+            break;
2682
+        case 'mois_relatif':
2683
+            $col = 'MONTH(' . $date_compare . ')-MONTH(' .
2684
+                $date_orig . ')+12*(YEAR(' . $date_compare .
2685
+                ')-YEAR(' . $date_orig . '))';
2686
+            $col_vraie = '';// comparer a un int (par defaut)
2687
+            break;
2688
+        case 'annee_relatif':
2689
+            $col = 'YEAR(' . $date_compare . ')-YEAR(' .
2690
+                $date_orig . ')';
2691
+            $col_vraie = '';// comparer a un int (par defaut)
2692
+            break;
2693
+    }
2694
+
2695
+    return [$col, $col_vraie];
2696 2696
 }
2697 2697
 
2698 2698
 /**
@@ -2711,16 +2711,16 @@  discard block
 block discarded – undo
2711 2711
  *     de colonne SQL et une date.
2712 2712
  **/
2713 2713
 function calculer_param_date($date_compare, $date_orig) {
2714
-	if (preg_match(",'\" *\.(.*)\. *\"',", $date_compare, $r)) {
2715
-		$init = "'\" . (\$x = $r[1]) . \"'";
2716
-		$date_compare = '\'$x\'';
2717
-	} else {
2718
-		$init = $date_compare;
2719
-	}
2720
-
2721
-	return
2722
-		// optimisation : mais prevoir le support SQLite avant
2723
-		"TIMESTAMPDIFF(HOUR,$date_orig,$init)/24";
2714
+    if (preg_match(",'\" *\.(.*)\. *\"',", $date_compare, $r)) {
2715
+        $init = "'\" . (\$x = $r[1]) . \"'";
2716
+        $date_compare = '\'$x\'';
2717
+    } else {
2718
+        $init = $date_compare;
2719
+    }
2720
+
2721
+    return
2722
+        // optimisation : mais prevoir le support SQLite avant
2723
+        "TIMESTAMPDIFF(HOUR,$date_orig,$init)/24";
2724 2724
 }
2725 2725
 
2726 2726
 /**
@@ -2738,20 +2738,20 @@  discard block
 block discarded – undo
2738 2738
  * @param Critere $crit Paramètres du critère dans cette boucle
2739 2739
  */
2740 2740
 function critere_DATA_source_dist($idb, &$boucles, $crit) {
2741
-	$boucle = &$boucles[$idb];
2742
-
2743
-	$args = [];
2744
-	foreach ($crit->param as &$param) {
2745
-		array_push(
2746
-			$args,
2747
-			calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent)
2748
-		);
2749
-	}
2741
+    $boucle = &$boucles[$idb];
2750 2742
 
2751
-	$boucle->hash .= '
2743
+    $args = [];
2744
+    foreach ($crit->param as &$param) {
2745
+        array_push(
2746
+            $args,
2747
+            calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent)
2748
+        );
2749
+    }
2750
+
2751
+    $boucle->hash .= '
2752 2752
 	$command[\'sourcemode\'] = ' . array_shift($args) . ";\n";
2753 2753
 
2754
-	$boucle->hash .= '
2754
+    $boucle->hash .= '
2755 2755
 	$command[\'source\'] = array(' . join(', ', $args) . ");\n";
2756 2756
 }
2757 2757
 
@@ -2769,8 +2769,8 @@  discard block
 block discarded – undo
2769 2769
  * @param Critere $crit Paramètres du critère dans cette boucle
2770 2770
  */
2771 2771
 function critere_DATA_datacache_dist($idb, &$boucles, $crit) {
2772
-	$boucle = &$boucles[$idb];
2773
-	$boucle->hash .= '
2772
+    $boucle = &$boucles[$idb];
2773
+    $boucle->hash .= '
2774 2774
 	$command[\'datacache\'] = ' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent) . ';';
2775 2775
 }
2776 2776
 
@@ -2786,12 +2786,12 @@  discard block
 block discarded – undo
2786 2786
  * @param Critere $crit Paramètres du critère dans cette boucle
2787 2787
  */
2788 2788
 function critere_php_args_dist($idb, &$boucles, $crit) {
2789
-	$boucle = &$boucles[$idb];
2790
-	$boucle->hash .= '$command[\'args\']=array();';
2791
-	foreach ($crit->param as $param) {
2792
-		$boucle->hash .= '
2789
+    $boucle = &$boucles[$idb];
2790
+    $boucle->hash .= '$command[\'args\']=array();';
2791
+    foreach ($crit->param as $param) {
2792
+        $boucle->hash .= '
2793 2793
 			$command[\'args\'][] = ' . calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ';';
2794
-	}
2794
+    }
2795 2795
 }
2796 2796
 
2797 2797
 /**
@@ -2808,16 +2808,16 @@  discard block
 block discarded – undo
2808 2808
  * @param Critere $crit Paramètres du critère dans cette boucle
2809 2809
  */
2810 2810
 function critere_DATA_liste_dist($idb, &$boucles, $crit) {
2811
-	$boucle = &$boucles[$idb];
2812
-	$boucle->hash .= "\n\t" . '$command[\'liste\'] = array();' . "\n";
2813
-	foreach ($crit->param as $param) {
2814
-		$boucle->hash .= "\t" . '$command[\'liste\'][] = ' . calculer_liste(
2815
-			$param,
2816
-			$idb,
2817
-			$boucles,
2818
-			$boucles[$idb]->id_parent
2819
-		) . ";\n";
2820
-	}
2811
+    $boucle = &$boucles[$idb];
2812
+    $boucle->hash .= "\n\t" . '$command[\'liste\'] = array();' . "\n";
2813
+    foreach ($crit->param as $param) {
2814
+        $boucle->hash .= "\t" . '$command[\'liste\'][] = ' . calculer_liste(
2815
+            $param,
2816
+            $idb,
2817
+            $boucles,
2818
+            $boucles[$idb]->id_parent
2819
+        ) . ";\n";
2820
+    }
2821 2821
 }
2822 2822
 
2823 2823
 /**
@@ -2842,16 +2842,16 @@  discard block
 block discarded – undo
2842 2842
  * @param Critere $crit Paramètres du critère dans cette boucle
2843 2843
  */
2844 2844
 function critere_DATA_enum_dist($idb, &$boucles, $crit) {
2845
-	$boucle = &$boucles[$idb];
2846
-	$boucle->hash .= "\n\t" . '$command[\'enum\'] = array();' . "\n";
2847
-	foreach ($crit->param as $param) {
2848
-		$boucle->hash .= "\t" . '$command[\'enum\'][] = ' . calculer_liste(
2849
-			$param,
2850
-			$idb,
2851
-			$boucles,
2852
-			$boucles[$idb]->id_parent
2853
-		) . ";\n";
2854
-	}
2845
+    $boucle = &$boucles[$idb];
2846
+    $boucle->hash .= "\n\t" . '$command[\'enum\'] = array();' . "\n";
2847
+    foreach ($crit->param as $param) {
2848
+        $boucle->hash .= "\t" . '$command[\'enum\'][] = ' . calculer_liste(
2849
+            $param,
2850
+            $idb,
2851
+            $boucles,
2852
+            $boucles[$idb]->id_parent
2853
+        ) . ";\n";
2854
+    }
2855 2855
 }
2856 2856
 
2857 2857
 /**
@@ -2866,11 +2866,11 @@  discard block
 block discarded – undo
2866 2866
  * @param Critere $crit Paramètres du critère dans cette boucle
2867 2867
  */
2868 2868
 function critere_DATA_datapath_dist($idb, &$boucles, $crit) {
2869
-	$boucle = &$boucles[$idb];
2870
-	foreach ($crit->param as $param) {
2871
-		$boucle->hash .= '
2869
+    $boucle = &$boucles[$idb];
2870
+    foreach ($crit->param as $param) {
2871
+        $boucle->hash .= '
2872 2872
 			$command[\'datapath\'][] = ' . calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ';';
2873
-	}
2873
+    }
2874 2874
 }
2875 2875
 
2876 2876
 
@@ -2902,20 +2902,20 @@  discard block
 block discarded – undo
2902 2902
  * @param Critere $crit Paramètres du critère dans cette boucle
2903 2903
  */
2904 2904
 function critere_si_dist($idb, &$boucles, $crit) {
2905
-	$boucle = &$boucles[$idb];
2906
-	// il faut initialiser 1 fois le tableau a chaque appel de la boucle
2907
-	// (par exemple lorsque notre boucle est appelee dans une autre boucle)
2908
-	// mais ne pas l'initialiser n fois si il y a n criteres {si } dans la boucle !
2909
-	$boucle->hash .= "\n\tif (!isset(\$si_init)) { \$command['si'] = array(); \$si_init = true; }\n";
2910
-	if ($crit->param) {
2911
-		foreach ($crit->param as $param) {
2912
-			$boucle->hash .= "\t\$command['si'][] = "
2913
-				. calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ";\n";
2914
-		}
2915
-		// interdire {si 0} aussi !
2916
-	} else {
2917
-		$boucle->hash .= '$command[\'si\'][] = 0;';
2918
-	}
2905
+    $boucle = &$boucles[$idb];
2906
+    // il faut initialiser 1 fois le tableau a chaque appel de la boucle
2907
+    // (par exemple lorsque notre boucle est appelee dans une autre boucle)
2908
+    // mais ne pas l'initialiser n fois si il y a n criteres {si } dans la boucle !
2909
+    $boucle->hash .= "\n\tif (!isset(\$si_init)) { \$command['si'] = array(); \$si_init = true; }\n";
2910
+    if ($crit->param) {
2911
+        foreach ($crit->param as $param) {
2912
+            $boucle->hash .= "\t\$command['si'][] = "
2913
+                . calculer_liste($param, $idb, $boucles, $boucles[$idb]->id_parent) . ";\n";
2914
+        }
2915
+        // interdire {si 0} aussi !
2916
+    } else {
2917
+        $boucle->hash .= '$command[\'si\'][] = 0;';
2918
+    }
2919 2919
 }
2920 2920
 
2921 2921
 /**
@@ -2932,8 +2932,8 @@  discard block
 block discarded – undo
2932 2932
  * @param Critere $crit Paramètres du critère dans cette boucle
2933 2933
  */
2934 2934
 function critere_POUR_tableau_dist($idb, &$boucles, $crit) {
2935
-	$boucle = &$boucles[$idb];
2936
-	$boucle->hash .= '
2935
+    $boucle = &$boucles[$idb];
2936
+    $boucle->hash .= '
2937 2937
 	$command[\'source\'] = array(' . calculer_liste($crit->param[0], $idb, $boucles, $boucles[$idb]->id_parent) . ');
2938 2938
 	$command[\'sourcemode\'] = \'table\';';
2939 2939
 }
@@ -2954,27 +2954,27 @@  discard block
 block discarded – undo
2954 2954
  */
2955 2955
 function critere_noeud_dist($idb, &$boucles, $crit) {
2956 2956
 
2957
-	$not = $crit->not;
2958
-	$boucle = &$boucles[$idb];
2959
-	$primary = $boucle->primary;
2957
+    $not = $crit->not;
2958
+    $boucle = &$boucles[$idb];
2959
+    $primary = $boucle->primary;
2960 2960
 
2961
-	if (!$primary or strpos($primary, ',')) {
2962
-		erreur_squelette(_T('zbug_doublon_sur_table_sans_cle_primaire'), $boucle);
2961
+    if (!$primary or strpos($primary, ',')) {
2962
+        erreur_squelette(_T('zbug_doublon_sur_table_sans_cle_primaire'), $boucle);
2963 2963
 
2964
-		return;
2965
-	}
2966
-	$table = $boucle->type_requete;
2967
-	$table_sql = table_objet_sql(objet_type($table));
2964
+        return;
2965
+    }
2966
+    $table = $boucle->type_requete;
2967
+    $table_sql = table_objet_sql(objet_type($table));
2968 2968
 
2969
-	$id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
2969
+    $id_parent = $GLOBALS['exceptions_des_tables'][$boucle->id_table]['id_parent'] ?? 'id_parent';
2970 2970
 
2971
-	$in = 'IN';
2972
-	$where = ["'IN'", "'$boucle->id_table." . "$primary'", "'('.sql_get_select('$id_parent', '$table_sql').')'"];
2973
-	if ($not) {
2974
-		$where = ["'NOT'", $where];
2975
-	}
2971
+    $in = 'IN';
2972
+    $where = ["'IN'", "'$boucle->id_table." . "$primary'", "'('.sql_get_select('$id_parent', '$table_sql').')'"];
2973
+    if ($not) {
2974
+        $where = ["'NOT'", $where];
2975
+    }
2976 2976
 
2977
-	$boucle->where[] = $where;
2977
+    $boucle->where[] = $where;
2978 2978
 }
2979 2979
 
2980 2980
 /**
@@ -2990,8 +2990,8 @@  discard block
 block discarded – undo
2990 2990
  * @param Critere $crit Paramètres du critère dans cette boucle
2991 2991
  */
2992 2992
 function critere_feuille_dist($idb, &$boucles, $crit) {
2993
-	$not = $crit->not;
2994
-	$crit->not = $not ? false : true;
2995
-	critere_noeud_dist($idb, $boucles, $crit);
2996
-	$crit->not = $not;
2993
+    $not = $crit->not;
2994
+    $crit->not = $not ? false : true;
2995
+    critere_noeud_dist($idb, $boucles, $crit);
2996
+    $crit->not = $not;
2997 2997
 }
Please login to merge, or discard this patch.
ecrire/public/format_html.php 1 patch
Indentation   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -11,127 +11,127 @@
 block discarded – undo
11 11
 \***************************************************************************/
12 12
 
13 13
 if (!defined('_ECRIRE_INC_VERSION')) {
14
-	return;
14
+    return;
15 15
 }
16 16
 
17 17
 function format_boucle_html($preaff, $avant, $nom, $type, $crit, $corps, $apres, $altern, $postaff, $prof) {
18
-	$preaff = $preaff ? "<BB$nom>$preaff" : '';
19
-	$avant = $avant ? "<B$nom>$avant" : '';
20
-	$apres = $apres ? "$apres</B$nom>" : '';
21
-	$altern = $altern ? "$altern<//B$nom>" : '';
22
-	$postaff = $postaff ? "$postaff</BB$nom>" : '';
23
-	if (!$corps) {
24
-		$corps = ' />';
25
-	} else {
26
-		$corps = ">$corps</BOUCLE$nom>";
27
-	}
28
-
29
-	return "$preaff$avant<BOUCLE$nom($type)$crit$corps$apres$altern$postaff";
18
+    $preaff = $preaff ? "<BB$nom>$preaff" : '';
19
+    $avant = $avant ? "<B$nom>$avant" : '';
20
+    $apres = $apres ? "$apres</B$nom>" : '';
21
+    $altern = $altern ? "$altern<//B$nom>" : '';
22
+    $postaff = $postaff ? "$postaff</BB$nom>" : '';
23
+    if (!$corps) {
24
+        $corps = ' />';
25
+    } else {
26
+        $corps = ">$corps</BOUCLE$nom>";
27
+    }
28
+
29
+    return "$preaff$avant<BOUCLE$nom($type)$crit$corps$apres$altern$postaff";
30 30
 }
31 31
 
32 32
 function format_inclure_html($file, $args, $prof) {
33
-	if (strpos($file, '#') === false) {
34
-		$t = $file ? ('(' . $file . ')') : '';
35
-	} else {
36
-		$t = '{fond=' . $file . '}';
37
-	}
38
-	$args = !$args ? '' : ('{' . join(', ', $args) . '}');
39
-
40
-	return ('<INCLURE' . $t . $args . '>');
33
+    if (strpos($file, '#') === false) {
34
+        $t = $file ? ('(' . $file . ')') : '';
35
+    } else {
36
+        $t = '{fond=' . $file . '}';
37
+    }
38
+    $args = !$args ? '' : ('{' . join(', ', $args) . '}');
39
+
40
+    return ('<INCLURE' . $t . $args . '>');
41 41
 }
42 42
 
43 43
 function format_polyglotte_html($args, $prof) {
44
-	$contenu = [];
45
-	foreach ($args as $l => $t) {
46
-		$contenu[] = ($l ? "[$l]" : '') . $t;
47
-	}
44
+    $contenu = [];
45
+    foreach ($args as $l => $t) {
46
+        $contenu[] = ($l ? "[$l]" : '') . $t;
47
+    }
48 48
 
49
-	return ('<multi>' . join(' ', $contenu) . '</multi>');
49
+    return ('<multi>' . join(' ', $contenu) . '</multi>');
50 50
 }
51 51
 
52 52
 function format_idiome_html($nom, $module, $args, $filtres, $prof) {
53
-	foreach ($args as $k => $v) {
54
-		$args[$k] = "$k=$v";
55
-	}
56
-	$args = (!$args ? '' : ('{' . join(',', $args) . '}'));
53
+    foreach ($args as $k => $v) {
54
+        $args[$k] = "$k=$v";
55
+    }
56
+    $args = (!$args ? '' : ('{' . join(',', $args) . '}'));
57 57
 
58
-	return ('<:' . ($module ? "$module:" : '') . $nom . $args . $filtres . ':>');
58
+    return ('<:' . ($module ? "$module:" : '') . $nom . $args . $filtres . ':>');
59 59
 }
60 60
 
61 61
 function format_champ_html($nom, $boucle, $etoile, $avant, $apres, $args, $filtres, $prof) {
62
-	$nom = '#'
63
-		. ($boucle ? ($boucle . ':') : '')
64
-		. $nom
65
-		. $etoile
66
-		. $args
67
-		. $filtres;
62
+    $nom = '#'
63
+        . ($boucle ? ($boucle . ':') : '')
64
+        . $nom
65
+        . $etoile
66
+        . $args
67
+        . $filtres;
68 68
 
69
-	// Determiner si c'est un champ etendu,
69
+    // Determiner si c'est un champ etendu,
70 70
 
71
-	$s = ($avant or $apres or $filtres
72
-		or (strpos($args, '(#') !== false));
71
+    $s = ($avant or $apres or $filtres
72
+        or (strpos($args, '(#') !== false));
73 73
 
74
-	return ($s ? "[$avant($nom)$apres]" : $nom);
74
+    return ($s ? "[$avant($nom)$apres]" : $nom);
75 75
 }
76 76
 
77 77
 function format_critere_html($critere) {
78
-	foreach ($critere as $k => $crit) {
79
-		$crit_s = '';
80
-		foreach ($crit as $operande) {
81
-			[$type, $valeur] = $operande;
82
-			if ($type == 'champ' and $valeur[0] == '[') {
83
-				$valeur = substr($valeur, 1, -1);
84
-				if (preg_match(',^[(](#[^|]*)[)]$,sS', $valeur)) {
85
-					$valeur = substr($valeur, 1, -1);
86
-				}
87
-			}
88
-			$crit_s .= $valeur;
89
-		}
90
-		$critere[$k] = $crit_s;
91
-	}
92
-
93
-	return (!$critere ? '' : ('{' . join(',', $critere) . '}'));
78
+    foreach ($critere as $k => $crit) {
79
+        $crit_s = '';
80
+        foreach ($crit as $operande) {
81
+            [$type, $valeur] = $operande;
82
+            if ($type == 'champ' and $valeur[0] == '[') {
83
+                $valeur = substr($valeur, 1, -1);
84
+                if (preg_match(',^[(](#[^|]*)[)]$,sS', $valeur)) {
85
+                    $valeur = substr($valeur, 1, -1);
86
+                }
87
+            }
88
+            $crit_s .= $valeur;
89
+        }
90
+        $critere[$k] = $crit_s;
91
+    }
92
+
93
+    return (!$critere ? '' : ('{' . join(',', $critere) . '}'));
94 94
 }
95 95
 
96 96
 function format_liste_html($fonc, $args, $prof) {
97
-	return ((($fonc !== '') ? "|$fonc" : $fonc)
98
-		. (!$args ? '' : ('{' . join(',', $args) . '}')));
97
+    return ((($fonc !== '') ? "|$fonc" : $fonc)
98
+        . (!$args ? '' : ('{' . join(',', $args) . '}')));
99 99
 }
100 100
 
101 101
 // Concatenation sans separateur: verifier qu'on ne cree pas de faux lexemes
102 102
 function format_suite_html($args) {
103
-	for ($i = 0; $i < (is_countable($args) ? count($args) : 0) - 1; $i++) {
104
-		[$texte, $type] = $args[$i];
105
-		[$texte2, $type2] = $args[$i + 1];
106
-		if (!$texte or !$texte2) {
107
-			continue;
108
-		}
109
-		$c1 = substr($texte, -1);
110
-		if ($type2 !== 'texte') {
111
-			// si un texte se termine par ( et est suivi d'un champ
112
-			// ou assimiles, forcer la notation pleine
113
-			if ($c1 == '(' and substr($texte2, 0, 1) == '#') {
114
-				$args[$i + 1][0] = '[(' . $texte2 . ')]';
115
-			}
116
-		} else {
117
-			if ($type == 'texte') {
118
-				continue;
119
-			}
120
-			// si un champ ou assimiles est suivi d'un texte
121
-			// et si celui-ci commence par un caractere de champ
122
-			// forcer la notation pleine
123
-			if (
124
-				($c1 == '}' and substr(ltrim($texte2), 0, 1) == '|')
125
-				or (preg_match('/[\w\d_*]/', $c1) and preg_match('/^[\w\d_*{|]/', $texte2))
126
-			) {
127
-				$args[$i][0] = '[(' . $texte . ')]';
128
-			}
129
-		}
130
-	}
131
-
132
-	return join('', array_map(fn($arg) => reset($arg), $args));
103
+    for ($i = 0; $i < (is_countable($args) ? count($args) : 0) - 1; $i++) {
104
+        [$texte, $type] = $args[$i];
105
+        [$texte2, $type2] = $args[$i + 1];
106
+        if (!$texte or !$texte2) {
107
+            continue;
108
+        }
109
+        $c1 = substr($texte, -1);
110
+        if ($type2 !== 'texte') {
111
+            // si un texte se termine par ( et est suivi d'un champ
112
+            // ou assimiles, forcer la notation pleine
113
+            if ($c1 == '(' and substr($texte2, 0, 1) == '#') {
114
+                $args[$i + 1][0] = '[(' . $texte2 . ')]';
115
+            }
116
+        } else {
117
+            if ($type == 'texte') {
118
+                continue;
119
+            }
120
+            // si un champ ou assimiles est suivi d'un texte
121
+            // et si celui-ci commence par un caractere de champ
122
+            // forcer la notation pleine
123
+            if (
124
+                ($c1 == '}' and substr(ltrim($texte2), 0, 1) == '|')
125
+                or (preg_match('/[\w\d_*]/', $c1) and preg_match('/^[\w\d_*{|]/', $texte2))
126
+            ) {
127
+                $args[$i][0] = '[(' . $texte . ')]';
128
+            }
129
+        }
130
+    }
131
+
132
+    return join('', array_map(fn($arg) => reset($arg), $args));
133 133
 }
134 134
 
135 135
 function format_texte_html($texte) {
136
-	return $texte;
136
+    return $texte;
137 137
 }
Please login to merge, or discard this patch.