Completed
Push — master ( 4fa0dc...b74578 )
by cam
01:19
created
ecrire/src/Compilateur/Iterateur/Decorator.php 2 patches
Indentation   +554 added lines, -554 removed lines patch added patch discarded remove patch
@@ -8,566 +8,566 @@
 block discarded – undo
8 8
 
9 9
 class Decorator extends FilterIterator
10 10
 {
11
-	/**
12
-	 * Conditions de filtrage
13
-	 * ie criteres de selection.
14
-	 *
15
-	 * @var array
16
-	 */
17
-	protected $filtre = [];
18
-
19
-	/**
20
-	 * Fonction de filtrage compilee a partir des criteres de filtre.
21
-	 *
22
-	 * @var string
23
-	 */
24
-	protected $func_filtre;
25
-
26
-	/**
27
-	 * Critere {offset, limit}.
28
-	 *
29
-	 * @var int
30
-	 * @var int
31
-	 */
32
-	protected $offset;
33
-	protected $limit;
34
-
35
-	/**
36
-	 * nombre d'elements recuperes depuis la position 0,
37
-	 * en tenant compte des filtres.
38
-	 *
39
-	 * @var int
40
-	 */
41
-	protected $fetched = 0;
42
-
43
-	/**
44
-	 * Y a t'il une erreur ?
45
-	 *
46
-	 * @var bool
47
-	 */
48
-	protected $err = false;
49
-
50
-	// Extension SPIP des iterateurs PHP
51
-	/**
52
-	 * type de l'iterateur.
53
-	 *
54
-	 * @var string
55
-	 */
56
-	protected $type;
57
-
58
-	/**
59
-	 * position courante de l'iterateur.
60
-	 *
61
-	 * @var int
62
-	 */
63
-	protected $pos = 0;
64
-
65
-	/**
66
-	 * nombre total resultats dans l'iterateur.
67
-	 *
68
-	 * @var int
69
-	 */
70
-	protected $total;
71
-
72
-	/**
73
-	 * nombre maximal de recherche pour $total
74
-	 * si l'iterateur n'implemente pas de fonction specifique.
75
-	 */
76
-	protected $max = 100000;
77
-
78
-	/**
79
-	 * Liste des champs a inserer dans les $row
80
-	 * retournes par ->fetch().
81
-	 */
82
-	protected $select = [];
83
-	private Iterator $iter;
84
-
85
-	public function __construct(
86
-		Iterator $iter,
87
-		/** Parametres de l'iterateur */
88
-		protected array $command,
89
-		/** Infos du compilateur */
90
-		protected array $info
91
-	) {
92
-		parent::__construct($iter);
93
-		parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
94
-
95
-		// recuperer l'iterateur transmis
96
-		$this->iter = $this->getInnerIterator();
97
-
98
-		// chercher la liste des champs a retourner par
99
-		// fetch si l'objet ne les calcule pas tout seul
100
-		if (!method_exists($this->iter, 'fetch')) {
101
-			$this->calculer_select();
102
-			$this->calculer_filtres();
103
-		}
104
-
105
-		// emptyIterator critere {si} faux n'a pas d'erreur !
106
-		if (property_exists($this->iter, 'err') && $this->iter->err !== null) {
107
-			$this->err = $this->iter->err;
108
-		}
109
-
110
-		// pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
111
-		//$this->total = $this->count();
112
-	}
113
-
114
-	/**
115
-	 * Drapeau a activer en cas d'echec
116
-	 * (select SQL errone, non chargement des DATA, etc).
117
-	 */
118
-	public function err() {
119
-		if (method_exists($this->iter, 'err')) {
120
-			return $this->iter->err();
121
-		}
122
-		if (property_exists($this->iter, 'err')) {
123
-			return $this->iter->err;
124
-		}
125
-
126
-		return false;
127
-	}
128
-
129
-	// recuperer la valeur d'une balise #X
130
-	// en fonction des methodes
131
-	// et proprietes disponibles
132
-	public function get_select($nom) {
133
-		if (is_object($this->iter) && method_exists($this->iter, $nom)) {
134
-			try {
135
-				return $this->iter->{$nom}();
136
-			} catch (Exception) {
137
-				// #GETCHILDREN sur un fichier de DirectoryIterator ...
138
-				spip_log("Methode {$nom} en echec sur " . $this->iter::class);
139
-				spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
140
-
141
-				return '';
142
-			}
143
-		}
144
-		/*
11
+    /**
12
+     * Conditions de filtrage
13
+     * ie criteres de selection.
14
+     *
15
+     * @var array
16
+     */
17
+    protected $filtre = [];
18
+
19
+    /**
20
+     * Fonction de filtrage compilee a partir des criteres de filtre.
21
+     *
22
+     * @var string
23
+     */
24
+    protected $func_filtre;
25
+
26
+    /**
27
+     * Critere {offset, limit}.
28
+     *
29
+     * @var int
30
+     * @var int
31
+     */
32
+    protected $offset;
33
+    protected $limit;
34
+
35
+    /**
36
+     * nombre d'elements recuperes depuis la position 0,
37
+     * en tenant compte des filtres.
38
+     *
39
+     * @var int
40
+     */
41
+    protected $fetched = 0;
42
+
43
+    /**
44
+     * Y a t'il une erreur ?
45
+     *
46
+     * @var bool
47
+     */
48
+    protected $err = false;
49
+
50
+    // Extension SPIP des iterateurs PHP
51
+    /**
52
+     * type de l'iterateur.
53
+     *
54
+     * @var string
55
+     */
56
+    protected $type;
57
+
58
+    /**
59
+     * position courante de l'iterateur.
60
+     *
61
+     * @var int
62
+     */
63
+    protected $pos = 0;
64
+
65
+    /**
66
+     * nombre total resultats dans l'iterateur.
67
+     *
68
+     * @var int
69
+     */
70
+    protected $total;
71
+
72
+    /**
73
+     * nombre maximal de recherche pour $total
74
+     * si l'iterateur n'implemente pas de fonction specifique.
75
+     */
76
+    protected $max = 100000;
77
+
78
+    /**
79
+     * Liste des champs a inserer dans les $row
80
+     * retournes par ->fetch().
81
+     */
82
+    protected $select = [];
83
+    private Iterator $iter;
84
+
85
+    public function __construct(
86
+        Iterator $iter,
87
+        /** Parametres de l'iterateur */
88
+        protected array $command,
89
+        /** Infos du compilateur */
90
+        protected array $info
91
+    ) {
92
+        parent::__construct($iter);
93
+        parent::rewind(); // remettre a la premiere position (bug? connu de FilterIterator)
94
+
95
+        // recuperer l'iterateur transmis
96
+        $this->iter = $this->getInnerIterator();
97
+
98
+        // chercher la liste des champs a retourner par
99
+        // fetch si l'objet ne les calcule pas tout seul
100
+        if (!method_exists($this->iter, 'fetch')) {
101
+            $this->calculer_select();
102
+            $this->calculer_filtres();
103
+        }
104
+
105
+        // emptyIterator critere {si} faux n'a pas d'erreur !
106
+        if (property_exists($this->iter, 'err') && $this->iter->err !== null) {
107
+            $this->err = $this->iter->err;
108
+        }
109
+
110
+        // pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
111
+        //$this->total = $this->count();
112
+    }
113
+
114
+    /**
115
+     * Drapeau a activer en cas d'echec
116
+     * (select SQL errone, non chargement des DATA, etc).
117
+     */
118
+    public function err() {
119
+        if (method_exists($this->iter, 'err')) {
120
+            return $this->iter->err();
121
+        }
122
+        if (property_exists($this->iter, 'err')) {
123
+            return $this->iter->err;
124
+        }
125
+
126
+        return false;
127
+    }
128
+
129
+    // recuperer la valeur d'une balise #X
130
+    // en fonction des methodes
131
+    // et proprietes disponibles
132
+    public function get_select($nom) {
133
+        if (is_object($this->iter) && method_exists($this->iter, $nom)) {
134
+            try {
135
+                return $this->iter->{$nom}();
136
+            } catch (Exception) {
137
+                // #GETCHILDREN sur un fichier de DirectoryIterator ...
138
+                spip_log("Methode {$nom} en echec sur " . $this->iter::class);
139
+                spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
140
+
141
+                return '';
142
+            }
143
+        }
144
+        /*
145 145
 		if (property_exists($this->iter, $nom)) {
146 146
 			return $this->iter->$nom;
147 147
 		}*/
148
-		// cle et valeur par defaut
149
-		// ICI PLANTAGE SI ON NE CONTROLE PAS $nom
150
-		if (
151
-			in_array($nom, ['cle', 'valeur'])
152
-			&& method_exists($this, $nom)
153
-		) {
154
-			return $this->{$nom}();
155
-		}
156
-
157
-		// Par defaut chercher en xpath dans la valeur()
158
-		return table_valeur($this->valeur(), $nom, null);
159
-	}
160
-
161
-	public function next(): void {
162
-		++$this->pos;
163
-		parent::next();
164
-	}
165
-
166
-	/**
167
-	 * revient au depart.
168
-	 */
169
-	public function rewind(): void {
170
-		$this->pos = 0;
171
-		$this->fetched = 0;
172
-		parent::rewind();
173
-	}
174
-
175
-	/**
176
-	 * aller a la position absolue n,
177
-	 * comptee depuis le debut.
178
-	 *
179
-	 * @param int    $n
180
-	 *                         absolute pos
181
-	 * @param string $continue
182
-	 *                         param for sql_ api
183
-	 *
184
-	 * @return bool
185
-	 *              success or fail if not implemented
186
-	 */
187
-	public function seek($n = 0, $continue = null) {
188
-		if ($this->func_filtre || !method_exists($this->iter, 'seek') || !$this->iter->seek($n)) {
189
-			$this->seek_loop($n);
190
-		}
191
-		$this->pos = $n;
192
-		$this->fetched = $n;
193
-
194
-		return true;
195
-	}
196
-
197
-	/**
198
-	 * Avancer de $saut pas.
199
-	 *
200
-	 * @param $saut
201
-	 * @param $max
202
-	 *
203
-	 * @return int
204
-	 */
205
-	public function skip($saut, $max = null) {
206
-		// pas de saut en arriere autorise pour cette fonction
207
-		if (($saut = (int) $saut) <= 0) {
208
-			return $this->pos;
209
-		}
210
-		$seek = $this->pos + $saut;
211
-		// si le saut fait depasser le maxi, on libere la resource
212
-		// et on sort
213
-		if (is_null($max)) {
214
-			$max = $this->count();
215
-		}
216
-
217
-		if ($seek >= $max || $seek >= $this->count()) {
218
-			// sortie plus rapide que de faire next() jusqu'a la fin !
219
-			$this->free();
220
-
221
-			return $max;
222
-		}
223
-
224
-		$this->seek($seek);
225
-
226
-		return $this->pos;
227
-	}
228
-
229
-	/**
230
-	 * Renvoyer un tableau des donnees correspondantes
231
-	 * a la position courante de l'iterateur
232
-	 * en controlant si on respecte le filtre
233
-	 * Appliquer aussi le critere {offset,limit}.
234
-	 *
235
-	 * @return array|bool
236
-	 */
237
-	public function fetch() {
238
-		if (method_exists($this->iter, 'fetch')) {
239
-			return $this->iter->fetch();
240
-		}
241
-		while (
242
-				$this->valid()
243
-				&& (!$this->accept() || $this->offset !== null && $this->fetched++ < $this->offset)
244
-		) {
245
-			$this->next();
246
-		}
247
-
248
-		if (!$this->valid()) {
249
-			return false;
250
-		}
251
-
252
-		if (
253
-				$this->limit !== null
254
-				&& $this->fetched > $this->offset + $this->limit
255
-		) {
256
-			return false;
257
-		}
258
-
259
-		$r = [];
260
-		foreach ($this->select as $nom) {
261
-			$r[$nom] = $this->get_select($nom);
262
-		}
263
-		$this->next();
264
-
265
-		return $r;
266
-	}
267
-
268
-	// retourner la cle pour #CLE
269
-	public function cle() {
270
-		return $this->key();
271
-	}
272
-
273
-	// retourner la valeur pour #VALEUR
274
-	public function valeur() {
275
-		return $this->current();
276
-	}
277
-
278
-	/**
279
-	 * Accepte-t-on l'entree courante lue ?
280
-	 * On execute les filtres pour le savoir.
281
-	 */
282
-	public function accept(): bool {
283
-		if ($f = $this->func_filtre) {
284
-			return $f();
285
-		}
286
-
287
-		return true;
288
-	}
289
-
290
-	/**
291
-	 * liberer la ressource.
292
-	 *
293
-	 * @return bool
294
-	 */
295
-	public function free() {
296
-		if (method_exists($this->iter, 'free')) {
297
-			$this->iter->free();
298
-		}
299
-		$this->pos = $this->total = 0;
300
-
301
-		return true;
302
-	}
303
-
304
-	/**
305
-	 * Compter le nombre total de resultats
306
-	 * pour #TOTAL_BOUCLE.
307
-	 *
308
-	 * @return int
309
-	 */
310
-	public function count() {
311
-		if (is_null($this->total)) {
312
-			if (
313
-				method_exists($this->iter, 'count')
314
-				&& !$this->func_filtre
315
-			) {
316
-				return $this->total = $this->iter->count();
317
-			}
318
-			// compter les lignes et rembobiner
319
-			$total = 0;
320
-			$pos = $this->pos; // sauver la position
321
-			$this->rewind();
322
-			while ($this->fetch() && $total < $this->max) {
323
-				++$total;
324
-			}
325
-			$this->seek($pos);
326
-			$this->total = $total;
327
-		}
328
-
329
-		return $this->total;
330
-	}
331
-
332
-	/**
333
-	 * Assembler le tableau de filtres traduits depuis les conditions SQL
334
-	 * les filtres vides ou null sont ignores.
335
-	 *
336
-	 * @param $filtres
337
-	 * @param string $operateur
338
-	 *
339
-	 * @return null|string
340
-	 */
341
-	protected function assembler_filtres($filtres, $operateur = 'AND') {
342
-		$filtres_string = [];
343
-		foreach ($filtres as $k => $v) {
344
-			// si c'est un tableau de OR/AND + 2 sous-filtres, on recurse pour transformer en chaine
345
-			if (is_array($v) && in_array(reset($v), ['OR', 'AND'])) {
346
-				$op = array_shift($v);
347
-				$v = $this->assembler_filtres($v, $op);
348
-			}
349
-			if (is_null($v) || !is_string($v) || empty($v)) {
350
-				continue;
351
-			}
352
-			$filtres_string[] = $v;
353
-		}
354
-
355
-		if ($filtres_string === []) {
356
-			return null;
357
-		}
358
-
359
-		return '(' . implode(") {$operateur} (", $filtres_string) . ')';
360
-	}
361
-
362
-	/**
363
-	 * Traduire un element du tableau where SQL en un filtre.
364
-	 *
365
-	 * @param $v
366
-	 *
367
-	 * @return null|array|string
368
-	 */
369
-	protected function traduire_condition_sql_en_filtre($v) {
370
-		if (is_array($v)) {
371
-			if ((count($v) >= 2) && ('REGEXP' == $v[0]) && ("'.*'" == $v[2])) {
372
-				return 'true';
373
-			}
374
-			if ((count($v) >= 2) && ('LIKE' == $v[0]) && ("'%'" == $v[2])) {
375
-				return 'true';
376
-			}
377
-			$op = $v[0] ?: $v;
378
-		} else {
379
-			$op = $v;
380
-		}
381
-		if (!$op || 1 == $op || '0=0' == $op) {
382
-			return 'true';
383
-		}
384
-		if ('0=1' === $op) {
385
-			return 'false';
386
-		}
387
-		// traiter {cle IN a,b} ou {valeur !IN a,b}
388
-		if (preg_match(',^\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)$,', $op, $regs)) {
389
-			return $this->composer_filtre($regs[1], 'IN', $regs[3], $regs[2]);
390
-		}
391
-
392
-		// 3 possibilites : count($v) =
393
-		// * 1 : {x y} ; on recoit $v[0] = y
394
-		// * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
395
-		// * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
396
-
397
-		// 1 : forcement traite par un critere, on passe
398
-		if (!$v || !is_array($v) || 1 == count($v)) {
399
-			return null; // sera ignore
400
-		}
401
-		if (2 == count($v) && is_array($v[1])) {
402
-			return $this->composer_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
403
-		}
404
-		if (3 == count($v)) {
405
-			// traiter le OR/AND suivi de 2 valeurs
406
-			if (in_array($op, ['OR', 'AND'])) {
407
-				array_shift($v);
408
-				foreach (array_keys($v) as $k) {
409
-					$v[$k] = $this->traduire_condition_sql_en_filtre($v[$k]);
410
-					if (null === $v[$k]) {
411
-						unset($v[$k]);
412
-					} elseif ('true' === $v[$k]) {
413
-						if ('OR' === $op) {
414
-							return 'true';
415
-						}
416
-						if ('AND' === $op) {
417
-							unset($v[$k]);
418
-						}
419
-					} elseif ('false' === $v[$k]) {
420
-						if ('OR' === $op) {
421
-							unset($v[$k]);
422
-						}
423
-						if ('AND' === $op) {
424
-							return 'false';
425
-						}
426
-					}
427
-				}
428
-				if ($v === []) {
429
-					return null;
430
-				}
431
-				if (1 === count($v)) {
432
-					return reset($v);
433
-				}
434
-				array_unshift($v, $op);
435
-
436
-				return $v;
437
-			}
438
-
439
-			return $this->composer_filtre($v[1], $v[0], $v[2]);
440
-		}
441
-
442
-		return null;  // sera ignore
443
-	}
444
-
445
-	/**
446
-	 * Calculer un filtre sur un champ du tableau.
447
-	 *
448
-	 * @param $cle
449
-	 * @param $op
450
-	 * @param $valeur
451
-	 * @param false $not
452
-	 *
453
-	 * @return null|string
454
-	 */
455
-	protected function composer_filtre($cle, $op, $valeur, $not = false) {
456
-		if (
457
-			method_exists($this->iter, 'exception_des_criteres')
458
-			&& in_array($cle, $this->iter->exception_des_criteres())
459
-		) {
460
-			return null;
461
-		}
462
-		// TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
463
-		// mais c'est normalement deja opere par calculer_critere_infixe()
464
-		// qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
465
-		// ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
466
-		// il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
467
-
468
-		// if (!in_array($cle, array('cle', 'valeur')))
469
-		//	return;
470
-
471
-		$a = '$this->get_select(\'' . $cle . '\')';
472
-
473
-		$filtre = '';
474
-
475
-		if ('REGEXP' == $op) {
476
-			$filtre = 'filtrer("match", ' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
477
-			$op = '';
478
-		} else {
479
-			if ('LIKE' == $op) {
480
-				$valeur = str_replace(['\"', '_', '%'], ['"', '.', '.*'], preg_quote($valeur));
481
-				$filtre = 'filtrer("match", ' . $a . ', ' . $valeur . ')';
482
-				$op = '';
483
-			} else {
484
-				if ('=' == $op) {
485
-					$op = '==';
486
-				} else {
487
-					if ('IN' == $op) {
488
-						$filtre = 'in_array(' . $a . ', array' . $valeur . ')';
489
-						$op = '';
490
-					} else {
491
-						if (!in_array($op, ['<', '<=', '>', '>='])) {
492
-							spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
493
-							$op = '';
494
-						}
495
-					}
496
-				}
497
-			}
498
-		}
499
-
500
-		if ($op) {
501
-			$filtre = $a . $op . str_replace('\"', '"', $valeur);
502
-		}
503
-
504
-		if ($not) {
505
-			$filtre = "!({$filtre})";
506
-		}
507
-
508
-		return $filtre;
509
-	}
510
-
511
-	// calcule les elements a retournes par fetch()
512
-	// enleve les elements inutiles du select()
513
-	//
514
-	private function calculer_select() {
515
-		if ($select = &$this->command['select']) {
516
-			foreach ($select as $s) {
517
-				// /!\ $s = '.nom'
518
-				if ('.' == $s[0]) {
519
-					$s = substr($s, 1);
520
-				}
521
-				$this->select[] = $s;
522
-			}
523
-		}
524
-	}
525
-
526
-	private function calculer_filtres() {
527
-		// Issu de calculer_select() de public/composer L.519
528
-		// TODO: externaliser...
529
-		//
530
-		// retirer les criteres vides:
531
-		// {X ?} avec X absent de l'URL
532
-		// {par #ENV{X}} avec X absent de l'URL
533
-		// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
534
-		if ($where = &$this->command['where']) {
535
-			foreach ($where as $k => $v) {
536
-				$this->filtre[] = $this->traduire_condition_sql_en_filtre($v);
537
-			}
538
-		}
539
-
540
-		// critere {2,7}
541
-		if (isset($this->command['limit']) && $this->command['limit']) {
542
-			$limit = explode(',', $this->command['limit']);
543
-			$this->offset = $limit[0];
544
-			$this->limit = $limit[1];
545
-		}
546
-
547
-		// Creer la fonction de filtrage sur $this
548
-		if ($this->filtre) {
549
-			if ($filtres = $this->assembler_filtres($this->filtre)) {
550
-				$filtres = 'return ' . $filtres . ';';
551
-				$this->func_filtre = fn () => eval($filtres);
552
-			} else {
553
-				$this->func_filtre = null;
554
-			}
555
-		}
556
-	}
557
-
558
-	/*
148
+        // cle et valeur par defaut
149
+        // ICI PLANTAGE SI ON NE CONTROLE PAS $nom
150
+        if (
151
+            in_array($nom, ['cle', 'valeur'])
152
+            && method_exists($this, $nom)
153
+        ) {
154
+            return $this->{$nom}();
155
+        }
156
+
157
+        // Par defaut chercher en xpath dans la valeur()
158
+        return table_valeur($this->valeur(), $nom, null);
159
+    }
160
+
161
+    public function next(): void {
162
+        ++$this->pos;
163
+        parent::next();
164
+    }
165
+
166
+    /**
167
+     * revient au depart.
168
+     */
169
+    public function rewind(): void {
170
+        $this->pos = 0;
171
+        $this->fetched = 0;
172
+        parent::rewind();
173
+    }
174
+
175
+    /**
176
+     * aller a la position absolue n,
177
+     * comptee depuis le debut.
178
+     *
179
+     * @param int    $n
180
+     *                         absolute pos
181
+     * @param string $continue
182
+     *                         param for sql_ api
183
+     *
184
+     * @return bool
185
+     *              success or fail if not implemented
186
+     */
187
+    public function seek($n = 0, $continue = null) {
188
+        if ($this->func_filtre || !method_exists($this->iter, 'seek') || !$this->iter->seek($n)) {
189
+            $this->seek_loop($n);
190
+        }
191
+        $this->pos = $n;
192
+        $this->fetched = $n;
193
+
194
+        return true;
195
+    }
196
+
197
+    /**
198
+     * Avancer de $saut pas.
199
+     *
200
+     * @param $saut
201
+     * @param $max
202
+     *
203
+     * @return int
204
+     */
205
+    public function skip($saut, $max = null) {
206
+        // pas de saut en arriere autorise pour cette fonction
207
+        if (($saut = (int) $saut) <= 0) {
208
+            return $this->pos;
209
+        }
210
+        $seek = $this->pos + $saut;
211
+        // si le saut fait depasser le maxi, on libere la resource
212
+        // et on sort
213
+        if (is_null($max)) {
214
+            $max = $this->count();
215
+        }
216
+
217
+        if ($seek >= $max || $seek >= $this->count()) {
218
+            // sortie plus rapide que de faire next() jusqu'a la fin !
219
+            $this->free();
220
+
221
+            return $max;
222
+        }
223
+
224
+        $this->seek($seek);
225
+
226
+        return $this->pos;
227
+    }
228
+
229
+    /**
230
+     * Renvoyer un tableau des donnees correspondantes
231
+     * a la position courante de l'iterateur
232
+     * en controlant si on respecte le filtre
233
+     * Appliquer aussi le critere {offset,limit}.
234
+     *
235
+     * @return array|bool
236
+     */
237
+    public function fetch() {
238
+        if (method_exists($this->iter, 'fetch')) {
239
+            return $this->iter->fetch();
240
+        }
241
+        while (
242
+                $this->valid()
243
+                && (!$this->accept() || $this->offset !== null && $this->fetched++ < $this->offset)
244
+        ) {
245
+            $this->next();
246
+        }
247
+
248
+        if (!$this->valid()) {
249
+            return false;
250
+        }
251
+
252
+        if (
253
+                $this->limit !== null
254
+                && $this->fetched > $this->offset + $this->limit
255
+        ) {
256
+            return false;
257
+        }
258
+
259
+        $r = [];
260
+        foreach ($this->select as $nom) {
261
+            $r[$nom] = $this->get_select($nom);
262
+        }
263
+        $this->next();
264
+
265
+        return $r;
266
+    }
267
+
268
+    // retourner la cle pour #CLE
269
+    public function cle() {
270
+        return $this->key();
271
+    }
272
+
273
+    // retourner la valeur pour #VALEUR
274
+    public function valeur() {
275
+        return $this->current();
276
+    }
277
+
278
+    /**
279
+     * Accepte-t-on l'entree courante lue ?
280
+     * On execute les filtres pour le savoir.
281
+     */
282
+    public function accept(): bool {
283
+        if ($f = $this->func_filtre) {
284
+            return $f();
285
+        }
286
+
287
+        return true;
288
+    }
289
+
290
+    /**
291
+     * liberer la ressource.
292
+     *
293
+     * @return bool
294
+     */
295
+    public function free() {
296
+        if (method_exists($this->iter, 'free')) {
297
+            $this->iter->free();
298
+        }
299
+        $this->pos = $this->total = 0;
300
+
301
+        return true;
302
+    }
303
+
304
+    /**
305
+     * Compter le nombre total de resultats
306
+     * pour #TOTAL_BOUCLE.
307
+     *
308
+     * @return int
309
+     */
310
+    public function count() {
311
+        if (is_null($this->total)) {
312
+            if (
313
+                method_exists($this->iter, 'count')
314
+                && !$this->func_filtre
315
+            ) {
316
+                return $this->total = $this->iter->count();
317
+            }
318
+            // compter les lignes et rembobiner
319
+            $total = 0;
320
+            $pos = $this->pos; // sauver la position
321
+            $this->rewind();
322
+            while ($this->fetch() && $total < $this->max) {
323
+                ++$total;
324
+            }
325
+            $this->seek($pos);
326
+            $this->total = $total;
327
+        }
328
+
329
+        return $this->total;
330
+    }
331
+
332
+    /**
333
+     * Assembler le tableau de filtres traduits depuis les conditions SQL
334
+     * les filtres vides ou null sont ignores.
335
+     *
336
+     * @param $filtres
337
+     * @param string $operateur
338
+     *
339
+     * @return null|string
340
+     */
341
+    protected function assembler_filtres($filtres, $operateur = 'AND') {
342
+        $filtres_string = [];
343
+        foreach ($filtres as $k => $v) {
344
+            // si c'est un tableau de OR/AND + 2 sous-filtres, on recurse pour transformer en chaine
345
+            if (is_array($v) && in_array(reset($v), ['OR', 'AND'])) {
346
+                $op = array_shift($v);
347
+                $v = $this->assembler_filtres($v, $op);
348
+            }
349
+            if (is_null($v) || !is_string($v) || empty($v)) {
350
+                continue;
351
+            }
352
+            $filtres_string[] = $v;
353
+        }
354
+
355
+        if ($filtres_string === []) {
356
+            return null;
357
+        }
358
+
359
+        return '(' . implode(") {$operateur} (", $filtres_string) . ')';
360
+    }
361
+
362
+    /**
363
+     * Traduire un element du tableau where SQL en un filtre.
364
+     *
365
+     * @param $v
366
+     *
367
+     * @return null|array|string
368
+     */
369
+    protected function traduire_condition_sql_en_filtre($v) {
370
+        if (is_array($v)) {
371
+            if ((count($v) >= 2) && ('REGEXP' == $v[0]) && ("'.*'" == $v[2])) {
372
+                return 'true';
373
+            }
374
+            if ((count($v) >= 2) && ('LIKE' == $v[0]) && ("'%'" == $v[2])) {
375
+                return 'true';
376
+            }
377
+            $op = $v[0] ?: $v;
378
+        } else {
379
+            $op = $v;
380
+        }
381
+        if (!$op || 1 == $op || '0=0' == $op) {
382
+            return 'true';
383
+        }
384
+        if ('0=1' === $op) {
385
+            return 'false';
386
+        }
387
+        // traiter {cle IN a,b} ou {valeur !IN a,b}
388
+        if (preg_match(',^\(([\w/]+)(\s+NOT)?\s+IN\s+(\(.*\))\)$,', $op, $regs)) {
389
+            return $this->composer_filtre($regs[1], 'IN', $regs[3], $regs[2]);
390
+        }
391
+
392
+        // 3 possibilites : count($v) =
393
+        // * 1 : {x y} ; on recoit $v[0] = y
394
+        // * 2 : {x !op y} ; on recoit $v[0] = 'NOT', $v[1] = array() // array du type {x op y}
395
+        // * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
396
+
397
+        // 1 : forcement traite par un critere, on passe
398
+        if (!$v || !is_array($v) || 1 == count($v)) {
399
+            return null; // sera ignore
400
+        }
401
+        if (2 == count($v) && is_array($v[1])) {
402
+            return $this->composer_filtre($v[1][1], $v[1][0], $v[1][2], 'NOT');
403
+        }
404
+        if (3 == count($v)) {
405
+            // traiter le OR/AND suivi de 2 valeurs
406
+            if (in_array($op, ['OR', 'AND'])) {
407
+                array_shift($v);
408
+                foreach (array_keys($v) as $k) {
409
+                    $v[$k] = $this->traduire_condition_sql_en_filtre($v[$k]);
410
+                    if (null === $v[$k]) {
411
+                        unset($v[$k]);
412
+                    } elseif ('true' === $v[$k]) {
413
+                        if ('OR' === $op) {
414
+                            return 'true';
415
+                        }
416
+                        if ('AND' === $op) {
417
+                            unset($v[$k]);
418
+                        }
419
+                    } elseif ('false' === $v[$k]) {
420
+                        if ('OR' === $op) {
421
+                            unset($v[$k]);
422
+                        }
423
+                        if ('AND' === $op) {
424
+                            return 'false';
425
+                        }
426
+                    }
427
+                }
428
+                if ($v === []) {
429
+                    return null;
430
+                }
431
+                if (1 === count($v)) {
432
+                    return reset($v);
433
+                }
434
+                array_unshift($v, $op);
435
+
436
+                return $v;
437
+            }
438
+
439
+            return $this->composer_filtre($v[1], $v[0], $v[2]);
440
+        }
441
+
442
+        return null;  // sera ignore
443
+    }
444
+
445
+    /**
446
+     * Calculer un filtre sur un champ du tableau.
447
+     *
448
+     * @param $cle
449
+     * @param $op
450
+     * @param $valeur
451
+     * @param false $not
452
+     *
453
+     * @return null|string
454
+     */
455
+    protected function composer_filtre($cle, $op, $valeur, $not = false) {
456
+        if (
457
+            method_exists($this->iter, 'exception_des_criteres')
458
+            && in_array($cle, $this->iter->exception_des_criteres())
459
+        ) {
460
+            return null;
461
+        }
462
+        // TODO: analyser le filtre pour refuser ce qu'on ne sait pas traiter ?
463
+        // mais c'est normalement deja opere par calculer_critere_infixe()
464
+        // qui regarde la description 'desc' (en casse reelle d'ailleurs : {isDir=1}
465
+        // ne sera pas vu si l'on a defini desc['field']['isdir'] pour que #ISDIR soit present.
466
+        // il faudrait peut etre definir les 2 champs isDir et isdir... a reflechir...
467
+
468
+        // if (!in_array($cle, array('cle', 'valeur')))
469
+        //	return;
470
+
471
+        $a = '$this->get_select(\'' . $cle . '\')';
472
+
473
+        $filtre = '';
474
+
475
+        if ('REGEXP' == $op) {
476
+            $filtre = 'filtrer("match", ' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
477
+            $op = '';
478
+        } else {
479
+            if ('LIKE' == $op) {
480
+                $valeur = str_replace(['\"', '_', '%'], ['"', '.', '.*'], preg_quote($valeur));
481
+                $filtre = 'filtrer("match", ' . $a . ', ' . $valeur . ')';
482
+                $op = '';
483
+            } else {
484
+                if ('=' == $op) {
485
+                    $op = '==';
486
+                } else {
487
+                    if ('IN' == $op) {
488
+                        $filtre = 'in_array(' . $a . ', array' . $valeur . ')';
489
+                        $op = '';
490
+                    } else {
491
+                        if (!in_array($op, ['<', '<=', '>', '>='])) {
492
+                            spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
493
+                            $op = '';
494
+                        }
495
+                    }
496
+                }
497
+            }
498
+        }
499
+
500
+        if ($op) {
501
+            $filtre = $a . $op . str_replace('\"', '"', $valeur);
502
+        }
503
+
504
+        if ($not) {
505
+            $filtre = "!({$filtre})";
506
+        }
507
+
508
+        return $filtre;
509
+    }
510
+
511
+    // calcule les elements a retournes par fetch()
512
+    // enleve les elements inutiles du select()
513
+    //
514
+    private function calculer_select() {
515
+        if ($select = &$this->command['select']) {
516
+            foreach ($select as $s) {
517
+                // /!\ $s = '.nom'
518
+                if ('.' == $s[0]) {
519
+                    $s = substr($s, 1);
520
+                }
521
+                $this->select[] = $s;
522
+            }
523
+        }
524
+    }
525
+
526
+    private function calculer_filtres() {
527
+        // Issu de calculer_select() de public/composer L.519
528
+        // TODO: externaliser...
529
+        //
530
+        // retirer les criteres vides:
531
+        // {X ?} avec X absent de l'URL
532
+        // {par #ENV{X}} avec X absent de l'URL
533
+        // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
534
+        if ($where = &$this->command['where']) {
535
+            foreach ($where as $k => $v) {
536
+                $this->filtre[] = $this->traduire_condition_sql_en_filtre($v);
537
+            }
538
+        }
539
+
540
+        // critere {2,7}
541
+        if (isset($this->command['limit']) && $this->command['limit']) {
542
+            $limit = explode(',', $this->command['limit']);
543
+            $this->offset = $limit[0];
544
+            $this->limit = $limit[1];
545
+        }
546
+
547
+        // Creer la fonction de filtrage sur $this
548
+        if ($this->filtre) {
549
+            if ($filtres = $this->assembler_filtres($this->filtre)) {
550
+                $filtres = 'return ' . $filtres . ';';
551
+                $this->func_filtre = fn () => eval($filtres);
552
+            } else {
553
+                $this->func_filtre = null;
554
+            }
555
+        }
556
+    }
557
+
558
+    /*
559 559
 	 * aller a la position $n en parcourant
560 560
 	 * un par un tous les elements
561 561
 	 */
562
-	private function seek_loop($n) {
563
-		if ($this->pos > $n) {
564
-			$this->rewind();
565
-		}
562
+    private function seek_loop($n) {
563
+        if ($this->pos > $n) {
564
+            $this->rewind();
565
+        }
566 566
 
567
-		while ($this->pos < $n && $this->valid()) {
568
-			$this->next();
569
-		}
567
+        while ($this->pos < $n && $this->valid()) {
568
+            $this->next();
569
+        }
570 570
 
571
-		return true;
572
-	}
571
+        return true;
572
+    }
573 573
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
 				return $this->iter->{$nom}();
136 136
 			} catch (Exception) {
137 137
 				// #GETCHILDREN sur un fichier de DirectoryIterator ...
138
-				spip_log("Methode {$nom} en echec sur " . $this->iter::class);
138
+				spip_log("Methode {$nom} en echec sur ".$this->iter::class);
139 139
 				spip_log("Cela peut être normal : retour d'une ligne de resultat ne pouvant pas calculer cette methode");
140 140
 
141 141
 				return '';
@@ -356,7 +356,7 @@  discard block
 block discarded – undo
356 356
 			return null;
357 357
 		}
358 358
 
359
-		return '(' . implode(") {$operateur} (", $filtres_string) . ')';
359
+		return '('.implode(") {$operateur} (", $filtres_string).')';
360 360
 	}
361 361
 
362 362
 	/**
@@ -439,7 +439,7 @@  discard block
 block discarded – undo
439 439
 			return $this->composer_filtre($v[1], $v[0], $v[2]);
440 440
 		}
441 441
 
442
-		return null;  // sera ignore
442
+		return null; // sera ignore
443 443
 	}
444 444
 
445 445
 	/**
@@ -468,28 +468,28 @@  discard block
 block discarded – undo
468 468
 		// if (!in_array($cle, array('cle', 'valeur')))
469 469
 		//	return;
470 470
 
471
-		$a = '$this->get_select(\'' . $cle . '\')';
471
+		$a = '$this->get_select(\''.$cle.'\')';
472 472
 
473 473
 		$filtre = '';
474 474
 
475 475
 		if ('REGEXP' == $op) {
476
-			$filtre = 'filtrer("match", ' . $a . ', ' . str_replace('\"', '"', $valeur) . ')';
476
+			$filtre = 'filtrer("match", '.$a.', '.str_replace('\"', '"', $valeur).')';
477 477
 			$op = '';
478 478
 		} else {
479 479
 			if ('LIKE' == $op) {
480 480
 				$valeur = str_replace(['\"', '_', '%'], ['"', '.', '.*'], preg_quote($valeur));
481
-				$filtre = 'filtrer("match", ' . $a . ', ' . $valeur . ')';
481
+				$filtre = 'filtrer("match", '.$a.', '.$valeur.')';
482 482
 				$op = '';
483 483
 			} else {
484 484
 				if ('=' == $op) {
485 485
 					$op = '==';
486 486
 				} else {
487 487
 					if ('IN' == $op) {
488
-						$filtre = 'in_array(' . $a . ', array' . $valeur . ')';
488
+						$filtre = 'in_array('.$a.', array'.$valeur.')';
489 489
 						$op = '';
490 490
 					} else {
491 491
 						if (!in_array($op, ['<', '<=', '>', '>='])) {
492
-							spip_log('operateur non reconnu ' . $op); // [todo] mettre une erreur de squelette
492
+							spip_log('operateur non reconnu '.$op); // [todo] mettre une erreur de squelette
493 493
 							$op = '';
494 494
 						}
495 495
 					}
@@ -498,7 +498,7 @@  discard block
 block discarded – undo
498 498
 		}
499 499
 
500 500
 		if ($op) {
501
-			$filtre = $a . $op . str_replace('\"', '"', $valeur);
501
+			$filtre = $a.$op.str_replace('\"', '"', $valeur);
502 502
 		}
503 503
 
504 504
 		if ($not) {
@@ -547,7 +547,7 @@  discard block
 block discarded – undo
547 547
 		// Creer la fonction de filtrage sur $this
548 548
 		if ($this->filtre) {
549 549
 			if ($filtres = $this->assembler_filtres($this->filtre)) {
550
-				$filtres = 'return ' . $filtres . ';';
550
+				$filtres = 'return '.$filtres.';';
551 551
 				$this->func_filtre = fn () => eval($filtres);
552 552
 			} else {
553 553
 				$this->func_filtre = null;
Please login to merge, or discard this patch.
ecrire/src/Compilateur/Iterateur/Data.php 2 patches
Indentation   +478 added lines, -478 removed lines patch added patch discarded remove patch
@@ -12,486 +12,486 @@
 block discarded – undo
12 12
  */
13 13
 class Data extends AbstractIterateur implements Iterator
14 14
 {
15
-	/** Tableau de données */
16
-	protected array $tableau = [];
17
-
18
-	/**
19
-	 * Conditions de filtrage
20
-	 * ie criteres de selection
21
-	 */
22
-	protected array $filtre = [];
23
-
24
-	/**
25
-	 * Cle courante
26
-	 *
27
-	 * @var scalar
28
-	 */
29
-	protected $cle = null;
30
-
31
-	/**
32
-	 * Valeur courante
33
-	 *
34
-	 * @var mixed
35
-	 */
36
-	protected $valeur = null;
37
-
38
-	/**
39
-	 * Constructeur
40
-	 *
41
-	 * @param  $command
42
-	 * @param array $info
43
-	 */
44
-	public function __construct(array $command, array $info = []) {
45
-		include_spip('iterateur/data');
46
-		$this->type = 'DATA';
47
-		$this->command = $command;
48
-		$this->info = $info;
49
-		$this->select($command);
50
-	}
51
-
52
-	/**
53
-	 * Revenir au depart
54
-	 *
55
-	 * @return void
56
-	 */
57
-	public function rewind(): void {
58
-		reset($this->tableau);
59
-		$this->cle = array_key_first($this->tableau);
60
-		$this->valeur = current($this->tableau);
61
-		next($this->tableau);
62
-	}
63
-
64
-	/**
65
-	 * Déclarer les critères exceptions
66
-	 *
67
-	 * @return array
68
-	 */
69
-	public function exception_des_criteres() {
70
-		return ['tableau'];
71
-	}
72
-
73
-	/**
74
-	 * Récupérer depuis le cache si possible
75
-	 *
76
-	 * @param string $cle
77
-	 * @return mixed
78
-	 */
79
-	protected function cache_get($cle) {
80
-		if (!$cle) {
81
-			return;
82
-		}
83
-		# utiliser memoization si dispo
84
-		if (!function_exists('cache_get')) {
85
-			return;
86
-		}
87
-
88
-		return cache_get($cle);
89
-	}
90
-
91
-	/**
92
-	 * Stocker en cache si possible
93
-	 *
94
-	 * @param string $cle
95
-	 * @param int $ttl
96
-	 * @param null|mixed $valeur
97
-	 * @return bool
98
-	 */
99
-	protected function cache_set($cle, $ttl, $valeur = null) {
100
-		if (!$cle) {
101
-			return;
102
-		}
103
-		if (is_null($valeur)) {
104
-			$valeur = $this->tableau;
105
-		}
106
-		# utiliser memoization si dispo
107
-		if (!function_exists('cache_set')) {
108
-			return;
109
-		}
110
-
111
-		return cache_set(
112
-			$cle,
113
-			[
114
-				'data' => $valeur,
115
-				'time' => time(),
116
-				'ttl' => $ttl
117
-			],
118
-			3600 + $ttl
119
-		);
120
-		# conserver le cache 1h de plus que la validite demandee,
121
-		# pour le cas ou le serveur distant ne reponde plus
122
-	}
123
-
124
-	/**
125
-	 * Aller chercher les données de la boucle DATA
126
-	 *
127
-	 * @throws Exception
128
-	 * @param array $command
129
-	 * @return void
130
-	 */
131
-	protected function select($command) {
132
-
133
-		// l'iterateur DATA peut etre appele en passant (data:type)
134
-		// le type se retrouve dans la commande 'from'
135
-		// dans ce cas la le critere {source}, si present, n'a pas besoin du 1er argument
136
-		if (isset($this->command['from'][0])) {
137
-			if (isset($this->command['source']) && is_array($this->command['source'])) {
138
-				array_unshift($this->command['source'], $this->command['sourcemode']);
139
-			}
140
-			$this->command['sourcemode'] = $this->command['from'][0];
141
-		}
142
-
143
-		// cherchons differents moyens de creer le tableau de donnees
144
-		// les commandes connues pour l'iterateur DATA
145
-		// sont : {tableau #ARRAY} ; {cle=...} ; {valeur=...}
146
-
147
-		// {source format, [URL], [arg2]...}
148
-		if (
149
-			isset($this->command['source'])
150
-			&& isset($this->command['sourcemode'])
151
-		) {
152
-			$this->select_source();
153
-		}
154
-
155
-		// Critere {liste X1, X2, X3}
156
-		if (isset($this->command['liste'])) {
157
-			$this->select_liste();
158
-		}
159
-		if (isset($this->command['enum'])) {
160
-			$this->select_enum();
161
-		}
162
-
163
-		// Si a ce stade on n'a pas de table, il y a un bug
164
-		if (!is_array($this->tableau)) {
165
-			$this->err = true;
166
-			spip_log('erreur datasource ' . var_export($command, true));
167
-		}
168
-
169
-		// {datapath query.results}
170
-		// extraire le chemin "query.results" du tableau de donnees
171
-		if (
172
-			!$this->err
173
-			&& isset($this->command['datapath'])
174
-			&& is_array($this->command['datapath'])
175
-		) {
176
-			$this->select_datapath();
177
-		}
178
-
179
-		// tri {par x}
180
-		if ($this->command['orderby']) {
181
-			$this->select_orderby();
182
-		}
183
-
184
-		// grouper les resultats {fusion /x/y/z} ;
185
-		if ($this->command['groupby']) {
186
-			$this->select_groupby();
187
-		}
188
-
189
-		$this->rewind();
190
-		#var_dump($this->tableau);
191
-	}
192
-
193
-
194
-	/**
195
-	 * Aller chercher les donnees de la boucle DATA
196
-	 * depuis une source
197
-	 * {source format, [URL], [arg2]...}
198
-	 */
199
-	protected function select_source() {
200
-		# un peu crado : avant de charger le cache il faut charger
201
-		# les class indispensables, sinon PHP ne saura pas gerer
202
-		# l'objet en cache ; cf plugins/icalendar
203
-		# perf : pas de fonction table_to_array ! (table est deja un array)
204
-		if (
205
-			isset($this->command['sourcemode'])
206
-			&& !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
207
-		) {
208
-			charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
209
-		}
210
-
211
-		# le premier argument peut etre un array, une URL etc.
212
-		$src = $this->command['source'][0] ?? null;
213
-
214
-		# avons-nous un cache dispo ?
215
-		$cle = null;
216
-		if (is_string($src)) {
217
-			$cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
218
-		}
219
-
220
-		$cache = $this->cache_get($cle);
221
-		if (isset($this->command['datacache'])) {
222
-			$ttl = (int) $this->command['datacache'];
223
-		}
224
-		if (
225
-			$cache
226
-			&& $cache['time'] + ($ttl ?? $cache['ttl']) > time()
227
-			&& !(_request('var_mode') === 'recalcul' && include_spip('inc/autoriser') && autoriser('recalcul'))
228
-		) {
229
-			$this->tableau = $cache['data'];
230
-		} else {
231
-			try {
232
-				if (
233
-					isset($this->command['sourcemode'])
234
-					&& in_array(
235
-						$this->command['sourcemode'],
236
-						['table', 'array', 'tableau']
237
-					)
238
-				) {
239
-					if (
240
-						is_array($a = $src)
241
-						|| is_string($a) && ($a = str_replace('&quot;', '"', $a)) && is_array($a = @unserialize($a))
242
-					) {
243
-						$this->tableau = $a;
244
-					}
245
-				} else {
246
-					$data = $src;
247
-					if (is_string($src)) {
248
-						if (tester_url_absolue($src)) {
249
-							include_spip('inc/distant');
250
-							$data = recuperer_url($src, ['taille_max' => _DATA_SOURCE_MAX_SIZE]);
251
-							$data = $data['page'] ?? '';
252
-							if (!$data) {
253
-								throw new Exception('404');
254
-							}
255
-							if (!isset($ttl)) {
256
-								$ttl = 24 * 3600;
257
-							}
258
-						} elseif (@is_dir($src)) {
259
-							$data = $src;
260
-						} elseif (@is_readable($src) && @is_file($src)) {
261
-							$data = spip_file_get_contents($src);
262
-						}
263
-						if (!isset($ttl)) {
264
-							$ttl = 10;
265
-						}
266
-					}
267
-					if (
268
-						!$this->err
269
-						&& ($data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true))
270
-					) {
271
-						$args = $this->command['source'];
272
-						$args[0] = $data;
273
-						if (is_array($a = $data_to_array(...$args))) {
274
-							$this->tableau = $a;
275
-						}
276
-					}
277
-				}
278
-
279
-				if (!is_array($this->tableau)) {
280
-					$this->err = true;
281
-				}
282
-
283
-				if (!$this->err && isset($ttl) && $ttl > 0) {
284
-					$this->cache_set($cle, $ttl);
285
-				}
286
-			} catch (Exception $e) {
287
-				$e = $e->getMessage();
288
-				$err = sprintf(
289
-					"[%s, %s] $e",
290
-					$src,
291
-					$this->command['sourcemode']
292
-				);
293
-				erreur_squelette([$err, []]);
294
-				$this->err = true;
295
-			}
296
-		}
297
-
298
-		# en cas d'erreur, utiliser le cache si encore dispo
299
-		if ($this->err && $cache) {
300
-			$this->tableau = $cache['data'];
301
-			$this->err = false;
302
-		}
303
-	}
304
-
305
-
306
-	/**
307
-	 * Retourne un tableau donne depuis un critère liste
308
-	 *
309
-	 * Critère `{liste X1, X2, X3}`
310
-	 *
311
-	 * @see critere_DATA_liste_dist()
312
-	 *
313
-	 **/
314
-	protected function select_liste() {
315
-		# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
316
-		if (!isset($this->command['liste'][1])) {
317
-			if (!is_array($this->command['liste'][0])) {
318
-				$this->command['liste'] = explode(',', $this->command['liste'][0]);
319
-			} else {
320
-				$this->command['liste'] = $this->command['liste'][0];
321
-			}
322
-		}
323
-		$this->tableau = $this->command['liste'];
324
-	}
325
-
326
-	/**
327
-	 * Retourne un tableau donne depuis un critere liste
328
-	 * Critere {enum Xmin, Xmax}
329
-	 *
330
-	 **/
331
-	protected function select_enum() {
332
-		# s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
333
-		if (!isset($this->command['enum'][1])) {
334
-			if (!is_array($this->command['enum'][0])) {
335
-				$this->command['enum'] = explode(',', $this->command['enum'][0]);
336
-			} else {
337
-				$this->command['enum'] = $this->command['enum'][0];
338
-			}
339
-		}
340
-		if ((is_countable($this->command['enum']) ? count($this->command['enum']) : 0) >= 3) {
341
-			$enum = range(
342
-				array_shift($this->command['enum']),
343
-				array_shift($this->command['enum']),
344
-				array_shift($this->command['enum'])
345
-			);
346
-		} else {
347
-			$enum = range(array_shift($this->command['enum']), array_shift($this->command['enum']));
348
-		}
349
-		$this->tableau = $enum;
350
-	}
351
-
352
-
353
-	/**
354
-	 * extraire le chemin "query.results" du tableau de donnees
355
-	 * {datapath query.results}
356
-	 *
357
-	 **/
358
-	protected function select_datapath() {
359
-		$base = reset($this->command['datapath']);
360
-		if (strlen($base = ltrim(trim($base), '/'))) {
361
-			$results = table_valeur($this->tableau, $base);
362
-			if (is_array($results)) {
363
-				$this->tableau = $results;
364
-			} else {
365
-				$this->tableau = [];
366
-				$this->err = true;
367
-				spip_log("datapath '$base' absent");
368
-			}
369
-		}
370
-	}
371
-
372
-	/**
373
-	 * Ordonner les resultats
374
-	 * {par x}
375
-	 *
376
-	 **/
377
-	protected function select_orderby() {
378
-		$sortfunc = '';
379
-		$aleas = 0;
380
-		foreach ($this->command['orderby'] as $tri) {
381
-			// virer le / initial pour les criteres de la forme {par /xx}
382
-			if (preg_match(',^\.?([/\w:_-]+)( DESC)?$,iS', ltrim($tri, '/'), $r)) {
383
-				$r = array_pad($r, 3, null);
384
-
385
-				// tri par cle
386
-				if ($r[1] == 'cle') {
387
-					if (isset($r[2]) && $r[2]) {
388
-						krsort($this->tableau);
389
-					} else {
390
-						ksort($this->tableau);
391
-					}
392
-				} # {par hasard}
393
-				else {
394
-					if ($r[1] == 'hasard') {
395
-						$k = array_keys($this->tableau);
396
-						shuffle($k);
397
-						$v = [];
398
-						foreach ($k as $cle) {
399
-							$v[$cle] = $this->tableau[$cle];
400
-						}
401
-						$this->tableau = $v;
402
-					} else {
403
-						# {par valeur} ou {par valeur/xx/yy}
404
-						$tv = $r[1] == 'valeur' ? '%s' : 'table_valeur(%s, ' . var_export($r[1], true) . ')';
405
-						$sortfunc .= '
15
+    /** Tableau de données */
16
+    protected array $tableau = [];
17
+
18
+    /**
19
+     * Conditions de filtrage
20
+     * ie criteres de selection
21
+     */
22
+    protected array $filtre = [];
23
+
24
+    /**
25
+     * Cle courante
26
+     *
27
+     * @var scalar
28
+     */
29
+    protected $cle = null;
30
+
31
+    /**
32
+     * Valeur courante
33
+     *
34
+     * @var mixed
35
+     */
36
+    protected $valeur = null;
37
+
38
+    /**
39
+     * Constructeur
40
+     *
41
+     * @param  $command
42
+     * @param array $info
43
+     */
44
+    public function __construct(array $command, array $info = []) {
45
+        include_spip('iterateur/data');
46
+        $this->type = 'DATA';
47
+        $this->command = $command;
48
+        $this->info = $info;
49
+        $this->select($command);
50
+    }
51
+
52
+    /**
53
+     * Revenir au depart
54
+     *
55
+     * @return void
56
+     */
57
+    public function rewind(): void {
58
+        reset($this->tableau);
59
+        $this->cle = array_key_first($this->tableau);
60
+        $this->valeur = current($this->tableau);
61
+        next($this->tableau);
62
+    }
63
+
64
+    /**
65
+     * Déclarer les critères exceptions
66
+     *
67
+     * @return array
68
+     */
69
+    public function exception_des_criteres() {
70
+        return ['tableau'];
71
+    }
72
+
73
+    /**
74
+     * Récupérer depuis le cache si possible
75
+     *
76
+     * @param string $cle
77
+     * @return mixed
78
+     */
79
+    protected function cache_get($cle) {
80
+        if (!$cle) {
81
+            return;
82
+        }
83
+        # utiliser memoization si dispo
84
+        if (!function_exists('cache_get')) {
85
+            return;
86
+        }
87
+
88
+        return cache_get($cle);
89
+    }
90
+
91
+    /**
92
+     * Stocker en cache si possible
93
+     *
94
+     * @param string $cle
95
+     * @param int $ttl
96
+     * @param null|mixed $valeur
97
+     * @return bool
98
+     */
99
+    protected function cache_set($cle, $ttl, $valeur = null) {
100
+        if (!$cle) {
101
+            return;
102
+        }
103
+        if (is_null($valeur)) {
104
+            $valeur = $this->tableau;
105
+        }
106
+        # utiliser memoization si dispo
107
+        if (!function_exists('cache_set')) {
108
+            return;
109
+        }
110
+
111
+        return cache_set(
112
+            $cle,
113
+            [
114
+                'data' => $valeur,
115
+                'time' => time(),
116
+                'ttl' => $ttl
117
+            ],
118
+            3600 + $ttl
119
+        );
120
+        # conserver le cache 1h de plus que la validite demandee,
121
+        # pour le cas ou le serveur distant ne reponde plus
122
+    }
123
+
124
+    /**
125
+     * Aller chercher les données de la boucle DATA
126
+     *
127
+     * @throws Exception
128
+     * @param array $command
129
+     * @return void
130
+     */
131
+    protected function select($command) {
132
+
133
+        // l'iterateur DATA peut etre appele en passant (data:type)
134
+        // le type se retrouve dans la commande 'from'
135
+        // dans ce cas la le critere {source}, si present, n'a pas besoin du 1er argument
136
+        if (isset($this->command['from'][0])) {
137
+            if (isset($this->command['source']) && is_array($this->command['source'])) {
138
+                array_unshift($this->command['source'], $this->command['sourcemode']);
139
+            }
140
+            $this->command['sourcemode'] = $this->command['from'][0];
141
+        }
142
+
143
+        // cherchons differents moyens de creer le tableau de donnees
144
+        // les commandes connues pour l'iterateur DATA
145
+        // sont : {tableau #ARRAY} ; {cle=...} ; {valeur=...}
146
+
147
+        // {source format, [URL], [arg2]...}
148
+        if (
149
+            isset($this->command['source'])
150
+            && isset($this->command['sourcemode'])
151
+        ) {
152
+            $this->select_source();
153
+        }
154
+
155
+        // Critere {liste X1, X2, X3}
156
+        if (isset($this->command['liste'])) {
157
+            $this->select_liste();
158
+        }
159
+        if (isset($this->command['enum'])) {
160
+            $this->select_enum();
161
+        }
162
+
163
+        // Si a ce stade on n'a pas de table, il y a un bug
164
+        if (!is_array($this->tableau)) {
165
+            $this->err = true;
166
+            spip_log('erreur datasource ' . var_export($command, true));
167
+        }
168
+
169
+        // {datapath query.results}
170
+        // extraire le chemin "query.results" du tableau de donnees
171
+        if (
172
+            !$this->err
173
+            && isset($this->command['datapath'])
174
+            && is_array($this->command['datapath'])
175
+        ) {
176
+            $this->select_datapath();
177
+        }
178
+
179
+        // tri {par x}
180
+        if ($this->command['orderby']) {
181
+            $this->select_orderby();
182
+        }
183
+
184
+        // grouper les resultats {fusion /x/y/z} ;
185
+        if ($this->command['groupby']) {
186
+            $this->select_groupby();
187
+        }
188
+
189
+        $this->rewind();
190
+        #var_dump($this->tableau);
191
+    }
192
+
193
+
194
+    /**
195
+     * Aller chercher les donnees de la boucle DATA
196
+     * depuis une source
197
+     * {source format, [URL], [arg2]...}
198
+     */
199
+    protected function select_source() {
200
+        # un peu crado : avant de charger le cache il faut charger
201
+        # les class indispensables, sinon PHP ne saura pas gerer
202
+        # l'objet en cache ; cf plugins/icalendar
203
+        # perf : pas de fonction table_to_array ! (table est deja un array)
204
+        if (
205
+            isset($this->command['sourcemode'])
206
+            && !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
207
+        ) {
208
+            charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
209
+        }
210
+
211
+        # le premier argument peut etre un array, une URL etc.
212
+        $src = $this->command['source'][0] ?? null;
213
+
214
+        # avons-nous un cache dispo ?
215
+        $cle = null;
216
+        if (is_string($src)) {
217
+            $cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
218
+        }
219
+
220
+        $cache = $this->cache_get($cle);
221
+        if (isset($this->command['datacache'])) {
222
+            $ttl = (int) $this->command['datacache'];
223
+        }
224
+        if (
225
+            $cache
226
+            && $cache['time'] + ($ttl ?? $cache['ttl']) > time()
227
+            && !(_request('var_mode') === 'recalcul' && include_spip('inc/autoriser') && autoriser('recalcul'))
228
+        ) {
229
+            $this->tableau = $cache['data'];
230
+        } else {
231
+            try {
232
+                if (
233
+                    isset($this->command['sourcemode'])
234
+                    && in_array(
235
+                        $this->command['sourcemode'],
236
+                        ['table', 'array', 'tableau']
237
+                    )
238
+                ) {
239
+                    if (
240
+                        is_array($a = $src)
241
+                        || is_string($a) && ($a = str_replace('&quot;', '"', $a)) && is_array($a = @unserialize($a))
242
+                    ) {
243
+                        $this->tableau = $a;
244
+                    }
245
+                } else {
246
+                    $data = $src;
247
+                    if (is_string($src)) {
248
+                        if (tester_url_absolue($src)) {
249
+                            include_spip('inc/distant');
250
+                            $data = recuperer_url($src, ['taille_max' => _DATA_SOURCE_MAX_SIZE]);
251
+                            $data = $data['page'] ?? '';
252
+                            if (!$data) {
253
+                                throw new Exception('404');
254
+                            }
255
+                            if (!isset($ttl)) {
256
+                                $ttl = 24 * 3600;
257
+                            }
258
+                        } elseif (@is_dir($src)) {
259
+                            $data = $src;
260
+                        } elseif (@is_readable($src) && @is_file($src)) {
261
+                            $data = spip_file_get_contents($src);
262
+                        }
263
+                        if (!isset($ttl)) {
264
+                            $ttl = 10;
265
+                        }
266
+                    }
267
+                    if (
268
+                        !$this->err
269
+                        && ($data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true))
270
+                    ) {
271
+                        $args = $this->command['source'];
272
+                        $args[0] = $data;
273
+                        if (is_array($a = $data_to_array(...$args))) {
274
+                            $this->tableau = $a;
275
+                        }
276
+                    }
277
+                }
278
+
279
+                if (!is_array($this->tableau)) {
280
+                    $this->err = true;
281
+                }
282
+
283
+                if (!$this->err && isset($ttl) && $ttl > 0) {
284
+                    $this->cache_set($cle, $ttl);
285
+                }
286
+            } catch (Exception $e) {
287
+                $e = $e->getMessage();
288
+                $err = sprintf(
289
+                    "[%s, %s] $e",
290
+                    $src,
291
+                    $this->command['sourcemode']
292
+                );
293
+                erreur_squelette([$err, []]);
294
+                $this->err = true;
295
+            }
296
+        }
297
+
298
+        # en cas d'erreur, utiliser le cache si encore dispo
299
+        if ($this->err && $cache) {
300
+            $this->tableau = $cache['data'];
301
+            $this->err = false;
302
+        }
303
+    }
304
+
305
+
306
+    /**
307
+     * Retourne un tableau donne depuis un critère liste
308
+     *
309
+     * Critère `{liste X1, X2, X3}`
310
+     *
311
+     * @see critere_DATA_liste_dist()
312
+     *
313
+     **/
314
+    protected function select_liste() {
315
+        # s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
316
+        if (!isset($this->command['liste'][1])) {
317
+            if (!is_array($this->command['liste'][0])) {
318
+                $this->command['liste'] = explode(',', $this->command['liste'][0]);
319
+            } else {
320
+                $this->command['liste'] = $this->command['liste'][0];
321
+            }
322
+        }
323
+        $this->tableau = $this->command['liste'];
324
+    }
325
+
326
+    /**
327
+     * Retourne un tableau donne depuis un critere liste
328
+     * Critere {enum Xmin, Xmax}
329
+     *
330
+     **/
331
+    protected function select_enum() {
332
+        # s'il n'y a qu'une valeur dans la liste, sans doute une #BALISE
333
+        if (!isset($this->command['enum'][1])) {
334
+            if (!is_array($this->command['enum'][0])) {
335
+                $this->command['enum'] = explode(',', $this->command['enum'][0]);
336
+            } else {
337
+                $this->command['enum'] = $this->command['enum'][0];
338
+            }
339
+        }
340
+        if ((is_countable($this->command['enum']) ? count($this->command['enum']) : 0) >= 3) {
341
+            $enum = range(
342
+                array_shift($this->command['enum']),
343
+                array_shift($this->command['enum']),
344
+                array_shift($this->command['enum'])
345
+            );
346
+        } else {
347
+            $enum = range(array_shift($this->command['enum']), array_shift($this->command['enum']));
348
+        }
349
+        $this->tableau = $enum;
350
+    }
351
+
352
+
353
+    /**
354
+     * extraire le chemin "query.results" du tableau de donnees
355
+     * {datapath query.results}
356
+     *
357
+     **/
358
+    protected function select_datapath() {
359
+        $base = reset($this->command['datapath']);
360
+        if (strlen($base = ltrim(trim($base), '/'))) {
361
+            $results = table_valeur($this->tableau, $base);
362
+            if (is_array($results)) {
363
+                $this->tableau = $results;
364
+            } else {
365
+                $this->tableau = [];
366
+                $this->err = true;
367
+                spip_log("datapath '$base' absent");
368
+            }
369
+        }
370
+    }
371
+
372
+    /**
373
+     * Ordonner les resultats
374
+     * {par x}
375
+     *
376
+     **/
377
+    protected function select_orderby() {
378
+        $sortfunc = '';
379
+        $aleas = 0;
380
+        foreach ($this->command['orderby'] as $tri) {
381
+            // virer le / initial pour les criteres de la forme {par /xx}
382
+            if (preg_match(',^\.?([/\w:_-]+)( DESC)?$,iS', ltrim($tri, '/'), $r)) {
383
+                $r = array_pad($r, 3, null);
384
+
385
+                // tri par cle
386
+                if ($r[1] == 'cle') {
387
+                    if (isset($r[2]) && $r[2]) {
388
+                        krsort($this->tableau);
389
+                    } else {
390
+                        ksort($this->tableau);
391
+                    }
392
+                } # {par hasard}
393
+                else {
394
+                    if ($r[1] == 'hasard') {
395
+                        $k = array_keys($this->tableau);
396
+                        shuffle($k);
397
+                        $v = [];
398
+                        foreach ($k as $cle) {
399
+                            $v[$cle] = $this->tableau[$cle];
400
+                        }
401
+                        $this->tableau = $v;
402
+                    } else {
403
+                        # {par valeur} ou {par valeur/xx/yy}
404
+                        $tv = $r[1] == 'valeur' ? '%s' : 'table_valeur(%s, ' . var_export($r[1], true) . ')';
405
+                        $sortfunc .= '
406 406
 					$a = ' . sprintf($tv, '$aa') . ';
407 407
 					$b = ' . sprintf($tv, '$bb') . ';
408 408
 					if ($a <> $b)
409 409
 						return ($a ' . (empty($r[2]) ? '<' : '>') . ' $b) ? -1 : 1;';
410
-					}
411
-				}
412
-			}
413
-		}
414
-
415
-		if ($sortfunc) {
416
-			$sortfunc .= "\n return 0;";
417
-			uasort($this->tableau, fn($aa, $bb) => eval($sortfunc));
418
-		}
419
-	}
420
-
421
-
422
-	/**
423
-	 * Grouper les resultats
424
-	 * {fusion /x/y/z}
425
-	 *
426
-	 **/
427
-	protected function select_groupby() {
428
-		// virer le / initial pour les criteres de la forme {fusion /xx}
429
-		if (strlen($fusion = ltrim($this->command['groupby'][0], '/'))) {
430
-			$vu = [];
431
-			foreach ($this->tableau as $k => $v) {
432
-				$val = table_valeur($v, $fusion);
433
-				if (isset($vu[$val])) {
434
-					unset($this->tableau[$k]);
435
-				} else {
436
-					$vu[$val] = true;
437
-				}
438
-			}
439
-		}
440
-	}
441
-
442
-
443
-	/**
444
-	 * L'iterateur est-il encore valide ?
445
-	 *
446
-	 * @return bool
447
-	 */
448
-	public function valid(): bool {
449
-		return !is_null($this->cle);
450
-	}
451
-
452
-	/**
453
-	 * Retourner la valeur
454
-	 *
455
-	 * @return mixed
456
-	 */
457
-	#[\ReturnTypeWillChange]
458
-	public function current() {
459
-		return $this->valeur;
460
-	}
461
-
462
-	/**
463
-	 * Retourner la cle
464
-	 *
465
-	 * @return mixed
466
-	 */
467
-	#[\ReturnTypeWillChange]
468
-	public function key() {
469
-		return $this->cle;
470
-	}
471
-
472
-	/**
473
-	 * Passer a la valeur suivante
474
-	 *
475
-	 * @return void
476
-	 */
477
-	public function next(): void {
478
-		if ($this->valid()) {
479
-			$this->cle = key($this->tableau);
480
-			$this->valeur = current($this->tableau);
481
-			next($this->tableau);
482
-		}
483
-	}
484
-
485
-	/**
486
-	 * Compter le nombre total de resultats
487
-	 *
488
-	 * @return int
489
-	 */
490
-	public function count() {
491
-		if (is_null($this->total)) {
492
-			$this->total = count($this->tableau);
493
-		}
494
-
495
-		return $this->total;
496
-	}
410
+                    }
411
+                }
412
+            }
413
+        }
414
+
415
+        if ($sortfunc) {
416
+            $sortfunc .= "\n return 0;";
417
+            uasort($this->tableau, fn($aa, $bb) => eval($sortfunc));
418
+        }
419
+    }
420
+
421
+
422
+    /**
423
+     * Grouper les resultats
424
+     * {fusion /x/y/z}
425
+     *
426
+     **/
427
+    protected function select_groupby() {
428
+        // virer le / initial pour les criteres de la forme {fusion /xx}
429
+        if (strlen($fusion = ltrim($this->command['groupby'][0], '/'))) {
430
+            $vu = [];
431
+            foreach ($this->tableau as $k => $v) {
432
+                $val = table_valeur($v, $fusion);
433
+                if (isset($vu[$val])) {
434
+                    unset($this->tableau[$k]);
435
+                } else {
436
+                    $vu[$val] = true;
437
+                }
438
+            }
439
+        }
440
+    }
441
+
442
+
443
+    /**
444
+     * L'iterateur est-il encore valide ?
445
+     *
446
+     * @return bool
447
+     */
448
+    public function valid(): bool {
449
+        return !is_null($this->cle);
450
+    }
451
+
452
+    /**
453
+     * Retourner la valeur
454
+     *
455
+     * @return mixed
456
+     */
457
+    #[\ReturnTypeWillChange]
458
+    public function current() {
459
+        return $this->valeur;
460
+    }
461
+
462
+    /**
463
+     * Retourner la cle
464
+     *
465
+     * @return mixed
466
+     */
467
+    #[\ReturnTypeWillChange]
468
+    public function key() {
469
+        return $this->cle;
470
+    }
471
+
472
+    /**
473
+     * Passer a la valeur suivante
474
+     *
475
+     * @return void
476
+     */
477
+    public function next(): void {
478
+        if ($this->valid()) {
479
+            $this->cle = key($this->tableau);
480
+            $this->valeur = current($this->tableau);
481
+            next($this->tableau);
482
+        }
483
+    }
484
+
485
+    /**
486
+     * Compter le nombre total de resultats
487
+     *
488
+     * @return int
489
+     */
490
+    public function count() {
491
+        if (is_null($this->total)) {
492
+            $this->total = count($this->tableau);
493
+        }
494
+
495
+        return $this->total;
496
+    }
497 497
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 		// Si a ce stade on n'a pas de table, il y a un bug
164 164
 		if (!is_array($this->tableau)) {
165 165
 			$this->err = true;
166
-			spip_log('erreur datasource ' . var_export($command, true));
166
+			spip_log('erreur datasource '.var_export($command, true));
167 167
 		}
168 168
 
169 169
 		// {datapath query.results}
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 			isset($this->command['sourcemode'])
206 206
 			&& !in_array($this->command['sourcemode'], ['table', 'array', 'tableau'])
207 207
 		) {
208
-			charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true);
208
+			charger_fonction($this->command['sourcemode'].'_to_array', 'inc', true);
209 209
 		}
210 210
 
211 211
 		# le premier argument peut etre un array, une URL etc.
@@ -214,7 +214,7 @@  discard block
 block discarded – undo
214 214
 		# avons-nous un cache dispo ?
215 215
 		$cle = null;
216 216
 		if (is_string($src)) {
217
-			$cle = 'datasource_' . md5($this->command['sourcemode'] . ':' . var_export($this->command['source'], true));
217
+			$cle = 'datasource_'.md5($this->command['sourcemode'].':'.var_export($this->command['source'], true));
218 218
 		}
219 219
 
220 220
 		$cache = $this->cache_get($cle);
@@ -266,7 +266,7 @@  discard block
 block discarded – undo
266 266
 					}
267 267
 					if (
268 268
 						!$this->err
269
-						&& ($data_to_array = charger_fonction($this->command['sourcemode'] . '_to_array', 'inc', true))
269
+						&& ($data_to_array = charger_fonction($this->command['sourcemode'].'_to_array', 'inc', true))
270 270
 					) {
271 271
 						$args = $this->command['source'];
272 272
 						$args[0] = $data;
@@ -401,12 +401,12 @@  discard block
 block discarded – undo
401 401
 						$this->tableau = $v;
402 402
 					} else {
403 403
 						# {par valeur} ou {par valeur/xx/yy}
404
-						$tv = $r[1] == 'valeur' ? '%s' : 'table_valeur(%s, ' . var_export($r[1], true) . ')';
404
+						$tv = $r[1] == 'valeur' ? '%s' : 'table_valeur(%s, '.var_export($r[1], true).')';
405 405
 						$sortfunc .= '
406
-					$a = ' . sprintf($tv, '$aa') . ';
407
-					$b = ' . sprintf($tv, '$bb') . ';
406
+					$a = ' . sprintf($tv, '$aa').';
407
+					$b = ' . sprintf($tv, '$bb').';
408 408
 					if ($a <> $b)
409
-						return ($a ' . (empty($r[2]) ? '<' : '>') . ' $b) ? -1 : 1;';
409
+						return ($a ' . (empty($r[2]) ? '<' : '>').' $b) ? -1 : 1;';
410 410
 					}
411 411
 				}
412 412
 			}
Please login to merge, or discard this patch.
ecrire/src/Compilateur/Iterateur/Sql.php 1 patch
Indentation   +182 added lines, -182 removed lines patch added patch discarded remove patch
@@ -11,193 +11,193 @@
 block discarded – undo
11 11
  */
12 12
 class Sql extends AbstractIterateur implements Iterator
13 13
 {
14
-	/**
15
-	 * Ressource sql.
16
-	 *
17
-	 * @var bool|object
18
-	 */
19
-	protected $sqlresult = false;
14
+    /**
15
+     * Ressource sql.
16
+     *
17
+     * @var bool|object
18
+     */
19
+    protected $sqlresult = false;
20 20
 
21
-	/**
22
-	 * row sql courante.
23
-	 *
24
-	 * @var null|array
25
-	 */
26
-	protected $row;
21
+    /**
22
+     * row sql courante.
23
+     *
24
+     * @var null|array
25
+     */
26
+    protected $row;
27 27
 
28
-	protected bool $firstseek = false;
28
+    protected bool $firstseek = false;
29 29
 
30
-	protected int $pos = -1;
30
+    protected int $pos = -1;
31 31
 
32
-	/*
32
+    /*
33 33
 	 * array command: les commandes d'initialisation
34 34
 	 * array info: les infos sur le squelette
35 35
 	 */
36
-	public function __construct(array $command, array $info = []) {
37
-		$this->type = 'SQL';
38
-		parent::__construct($command, $info);
39
-
40
-		$this->select();
41
-	}
42
-
43
-	/**
44
-	 * Rembobiner.
45
-	 *
46
-	 * @return bool
47
-	 */
48
-	public function rewind(): void {
49
-		if ($this->pos > 0) {
50
-			$this->seek(0);
51
-		}
52
-	}
53
-
54
-	/**
55
-	 * Verifier l'etat de l'iterateur.
56
-	 */
57
-	public function valid(): bool {
58
-		if ($this->err) {
59
-			return false;
60
-		}
61
-		if (!$this->firstseek) {
62
-			$this->next();
63
-		}
64
-
65
-		return is_array($this->row);
66
-	}
67
-
68
-	/**
69
-	 * Valeurs sur la position courante.
70
-	 *
71
-	 * @return array
72
-	 */
73
-	#[\ReturnTypeWillChange]
74
-	public function current() {
75
-		return $this->row;
76
-	}
77
-
78
-	#[\ReturnTypeWillChange]
79
-	public function key() {
80
-		return $this->pos;
81
-	}
82
-
83
-	/**
84
-	 * Sauter a une position absolue.
85
-	 *
86
-	 * @param int         $n
87
-	 * @param null|string $continue
88
-	 *
89
-	 * @return bool
90
-	 */
91
-	public function seek($n = 0, $continue = null) {
92
-		if (!sql_seek($this->sqlresult, $n, $this->command['connect'], $continue)) {
93
-			// SQLite ne sait pas seek(), il faut relancer la query
94
-			// si la position courante est apres la position visee
95
-			// il faut relancer la requete
96
-			if ($this->pos > $n) {
97
-				$this->free();
98
-				$this->select();
99
-				$this->valid();
100
-			}
101
-			// et utiliser la methode par defaut pour se deplacer au bon endroit
102
-			// (sera fait en cas d'echec de cette fonction)
103
-			return false;
104
-		}
105
-		$this->row = sql_fetch($this->sqlresult, $this->command['connect']);
106
-		$this->pos = min($n, $this->count());
107
-
108
-		return true;
109
-	}
110
-
111
-	/**
112
-	 * Avancer d'un cran.
113
-	 */
114
-	public function next(): void {
115
-		$this->row = sql_fetch($this->sqlresult, $this->command['connect']);
116
-		++$this->pos;
117
-		$this->firstseek |= true;
118
-	}
119
-
120
-	/**
121
-	 * Avancer et retourner les donnees pour le nouvel element.
122
-	 *
123
-	 * @return null|array|bool
124
-	 */
125
-	public function fetch() {
126
-		if ($this->valid()) {
127
-			$r = $this->current();
128
-			$this->next();
129
-		} else {
130
-			$r = false;
131
-		}
132
-
133
-		return $r;
134
-	}
135
-
136
-	/**
137
-	 * liberer les ressources.
138
-	 *
139
-	 * @return bool
140
-	 */
141
-	public function free() {
142
-		if (!$this->sqlresult) {
143
-			return true;
144
-		}
145
-		$a = sql_free($this->sqlresult, $this->command['connect']);
146
-		$this->sqlresult = null;
147
-
148
-		return $a;
149
-	}
150
-
151
-	/**
152
-	 * Compter le nombre de resultats.
153
-	 *
154
-	 * @return int
155
-	 */
156
-	public function count() {
157
-		if (is_null($this->total)) {
158
-			if (!$this->sqlresult) {
159
-				$this->total = 0;
160
-			} else {
161
-				// cas count(*)
162
-				if (in_array('count(*)', $this->command['select'])) {
163
-					$this->valid();
164
-					$s = $this->current();
165
-					$this->total = $s['count(*)'];
166
-				} else {
167
-					$this->total = sql_count($this->sqlresult, $this->command['connect']);
168
-				}
169
-			}
170
-		}
171
-
172
-		return $this->total;
173
-	}
174
-
175
-	/**
176
-	 * selectionner les donnees, ie faire la requete SQL.
177
-	 */
178
-	protected function select() {
179
-		$this->row = null;
180
-		$v = &$this->command;
181
-		$this->sqlresult = calculer_select(
182
-			$v['select'],
183
-			$v['from'],
184
-			$v['type'],
185
-			$v['where'],
186
-			$v['join'],
187
-			$v['groupby'],
188
-			$v['orderby'],
189
-			$v['limit'],
190
-			$v['having'],
191
-			$v['table'],
192
-			$v['id'],
193
-			$v['connect'],
194
-			$this->info
195
-		);
196
-		$this->err = !$this->sqlresult;
197
-		$this->firstseek = false;
198
-		$this->pos = -1;
199
-
200
-		// pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
201
-		//$this->total = $this->count();
202
-	}
36
+    public function __construct(array $command, array $info = []) {
37
+        $this->type = 'SQL';
38
+        parent::__construct($command, $info);
39
+
40
+        $this->select();
41
+    }
42
+
43
+    /**
44
+     * Rembobiner.
45
+     *
46
+     * @return bool
47
+     */
48
+    public function rewind(): void {
49
+        if ($this->pos > 0) {
50
+            $this->seek(0);
51
+        }
52
+    }
53
+
54
+    /**
55
+     * Verifier l'etat de l'iterateur.
56
+     */
57
+    public function valid(): bool {
58
+        if ($this->err) {
59
+            return false;
60
+        }
61
+        if (!$this->firstseek) {
62
+            $this->next();
63
+        }
64
+
65
+        return is_array($this->row);
66
+    }
67
+
68
+    /**
69
+     * Valeurs sur la position courante.
70
+     *
71
+     * @return array
72
+     */
73
+    #[\ReturnTypeWillChange]
74
+    public function current() {
75
+        return $this->row;
76
+    }
77
+
78
+    #[\ReturnTypeWillChange]
79
+    public function key() {
80
+        return $this->pos;
81
+    }
82
+
83
+    /**
84
+     * Sauter a une position absolue.
85
+     *
86
+     * @param int         $n
87
+     * @param null|string $continue
88
+     *
89
+     * @return bool
90
+     */
91
+    public function seek($n = 0, $continue = null) {
92
+        if (!sql_seek($this->sqlresult, $n, $this->command['connect'], $continue)) {
93
+            // SQLite ne sait pas seek(), il faut relancer la query
94
+            // si la position courante est apres la position visee
95
+            // il faut relancer la requete
96
+            if ($this->pos > $n) {
97
+                $this->free();
98
+                $this->select();
99
+                $this->valid();
100
+            }
101
+            // et utiliser la methode par defaut pour se deplacer au bon endroit
102
+            // (sera fait en cas d'echec de cette fonction)
103
+            return false;
104
+        }
105
+        $this->row = sql_fetch($this->sqlresult, $this->command['connect']);
106
+        $this->pos = min($n, $this->count());
107
+
108
+        return true;
109
+    }
110
+
111
+    /**
112
+     * Avancer d'un cran.
113
+     */
114
+    public function next(): void {
115
+        $this->row = sql_fetch($this->sqlresult, $this->command['connect']);
116
+        ++$this->pos;
117
+        $this->firstseek |= true;
118
+    }
119
+
120
+    /**
121
+     * Avancer et retourner les donnees pour le nouvel element.
122
+     *
123
+     * @return null|array|bool
124
+     */
125
+    public function fetch() {
126
+        if ($this->valid()) {
127
+            $r = $this->current();
128
+            $this->next();
129
+        } else {
130
+            $r = false;
131
+        }
132
+
133
+        return $r;
134
+    }
135
+
136
+    /**
137
+     * liberer les ressources.
138
+     *
139
+     * @return bool
140
+     */
141
+    public function free() {
142
+        if (!$this->sqlresult) {
143
+            return true;
144
+        }
145
+        $a = sql_free($this->sqlresult, $this->command['connect']);
146
+        $this->sqlresult = null;
147
+
148
+        return $a;
149
+    }
150
+
151
+    /**
152
+     * Compter le nombre de resultats.
153
+     *
154
+     * @return int
155
+     */
156
+    public function count() {
157
+        if (is_null($this->total)) {
158
+            if (!$this->sqlresult) {
159
+                $this->total = 0;
160
+            } else {
161
+                // cas count(*)
162
+                if (in_array('count(*)', $this->command['select'])) {
163
+                    $this->valid();
164
+                    $s = $this->current();
165
+                    $this->total = $s['count(*)'];
166
+                } else {
167
+                    $this->total = sql_count($this->sqlresult, $this->command['connect']);
168
+                }
169
+            }
170
+        }
171
+
172
+        return $this->total;
173
+    }
174
+
175
+    /**
176
+     * selectionner les donnees, ie faire la requete SQL.
177
+     */
178
+    protected function select() {
179
+        $this->row = null;
180
+        $v = &$this->command;
181
+        $this->sqlresult = calculer_select(
182
+            $v['select'],
183
+            $v['from'],
184
+            $v['type'],
185
+            $v['where'],
186
+            $v['join'],
187
+            $v['groupby'],
188
+            $v['orderby'],
189
+            $v['limit'],
190
+            $v['having'],
191
+            $v['table'],
192
+            $v['id'],
193
+            $v['connect'],
194
+            $this->info
195
+        );
196
+        $this->err = !$this->sqlresult;
197
+        $this->firstseek = false;
198
+        $this->pos = -1;
199
+
200
+        // pas d'init a priori, le calcul ne sera fait qu'en cas de besoin (provoque une double requete souvent inutile en sqlite)
201
+        //$this->total = $this->count();
202
+    }
203 203
 }
Please login to merge, or discard this patch.
ecrire/src/Compilateur/Iterateur/Factory.php 1 patch
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -12,60 +12,60 @@
 block discarded – undo
12 12
  */
13 13
 class Factory
14 14
 {
15
-	public static function create($iterateur, $command, $info = null) {
16
-		$iter = null;
17
-		// cas des SI {si expression} analises tres tot
18
-		// pour eviter le chargement de tout iterateur
19
-		if (isset($command['si'])) {
20
-			foreach ($command['si'] as $si) {
21
-				if (!$si) {
22
-					// $command pour boucle SQL peut generer des erreurs de compilation
23
-					// s'il est transmis alors qu'on est dans un iterateur vide
24
-					return new Decorator(new EmptyIterator(), [], $info);
25
-				}
26
-			}
27
-		}
15
+    public static function create($iterateur, $command, $info = null) {
16
+        $iter = null;
17
+        // cas des SI {si expression} analises tres tot
18
+        // pour eviter le chargement de tout iterateur
19
+        if (isset($command['si'])) {
20
+            foreach ($command['si'] as $si) {
21
+                if (!$si) {
22
+                    // $command pour boucle SQL peut generer des erreurs de compilation
23
+                    // s'il est transmis alors qu'on est dans un iterateur vide
24
+                    return new Decorator(new EmptyIterator(), [], $info);
25
+                }
26
+            }
27
+        }
28 28
 
29
-		// chercher un iterateur PHP existant (par exemple dans SPL)
30
-		// (il faudrait passer l'argument ->sql_serveur
31
-		// pour etre certain qu'on est sur un "php:")
32
-		if (class_exists($iterateur)) {
33
-			$a = $command['args'] ?? [];
29
+        // chercher un iterateur PHP existant (par exemple dans SPL)
30
+        // (il faudrait passer l'argument ->sql_serveur
31
+        // pour etre certain qu'on est sur un "php:")
32
+        if (class_exists($iterateur)) {
33
+            $a = $command['args'] ?? [];
34 34
 
35
-			// permettre de passer un Iterateur directement {args #ITERATEUR} :
36
-			// si on recoit deja un iterateur en argument, on l'utilise
37
-			if ((is_countable($a) ? count($a) : 0) == 1 && is_object($a[0]) && is_subclass_of($a[0], \Iterator::class)) {
38
-				$iter = $a[0];
39
-			} else {
40
-				// sinon, on cree un iterateur du type donne
41
-				// arguments de creation de l'iterateur...
42
-				try {
43
-					$iter = new $iterateur(...$a);
44
-				} catch (Exception $e) {
45
-					spip_log("Erreur de chargement de l'iterateur {$iterateur}");
46
-					spip_log($e->getMessage());
47
-					$iter = new EmptyIterator();
48
-				}
49
-			}
50
-		} else {
51
-			// chercher la classe d'iterateur Iterateur/XXX
52
-			// definie dans le fichier src/Compilateur/Iterateur/xxx.php
53
-			// FIXME: déclarer quelque part les iterateurs supplémentaires
54
-			$class = __NAMESPACE__ . '\\' . ucfirst(strtolower($iterateur));
55
-			if (!class_exists($class)) {
56
-				// historique
57
-				// Chercher IterateurXXX
58
-				include_spip('iterateur/' . $iterateur);
59
-				$class = 'Iterateur' . $iterateur;
60
-				if (!class_exists($class)) {
61
-					exit("Iterateur {$iterateur} non trouv&#233;");
62
-					// si l'iterateur n'existe pas, on se rabat sur le generique
63
-					// $iter = new EmptyIterator();
64
-				}
65
-			}
66
-			$iter = new $class($command, $info);
67
-		}
35
+            // permettre de passer un Iterateur directement {args #ITERATEUR} :
36
+            // si on recoit deja un iterateur en argument, on l'utilise
37
+            if ((is_countable($a) ? count($a) : 0) == 1 && is_object($a[0]) && is_subclass_of($a[0], \Iterator::class)) {
38
+                $iter = $a[0];
39
+            } else {
40
+                // sinon, on cree un iterateur du type donne
41
+                // arguments de creation de l'iterateur...
42
+                try {
43
+                    $iter = new $iterateur(...$a);
44
+                } catch (Exception $e) {
45
+                    spip_log("Erreur de chargement de l'iterateur {$iterateur}");
46
+                    spip_log($e->getMessage());
47
+                    $iter = new EmptyIterator();
48
+                }
49
+            }
50
+        } else {
51
+            // chercher la classe d'iterateur Iterateur/XXX
52
+            // definie dans le fichier src/Compilateur/Iterateur/xxx.php
53
+            // FIXME: déclarer quelque part les iterateurs supplémentaires
54
+            $class = __NAMESPACE__ . '\\' . ucfirst(strtolower($iterateur));
55
+            if (!class_exists($class)) {
56
+                // historique
57
+                // Chercher IterateurXXX
58
+                include_spip('iterateur/' . $iterateur);
59
+                $class = 'Iterateur' . $iterateur;
60
+                if (!class_exists($class)) {
61
+                    exit("Iterateur {$iterateur} non trouv&#233;");
62
+                    // si l'iterateur n'existe pas, on se rabat sur le generique
63
+                    // $iter = new EmptyIterator();
64
+                }
65
+            }
66
+            $iter = new $class($command, $info);
67
+        }
68 68
 
69
-		return new Decorator($iter, $command, $info);
70
-	}
69
+        return new Decorator($iter, $command, $info);
70
+    }
71 71
 }
Please login to merge, or discard this patch.
ecrire/src/Chiffrer/Chiffrement.php 2 patches
Indentation   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -18,76 +18,76 @@
 block discarded – undo
18 18
  * @link https://www.php.net/manual/fr/book.sodium.php
19 19
  */
20 20
 class Chiffrement {
21
-	/** Chiffre un message en utilisant une clé ou un mot de passe */
22
-	public static function chiffrer(
23
-		string $message,
24
-		#[\SensitiveParameter]
25
-		string $key
26
-	): ?string {
27
-		// create a random salt for key derivation
28
-		$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES);
29
-		$key = self::deriveKeyFromPassword($key, $salt);
30
-		$nonce = random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
31
-		$padded_message = sodium_pad($message, 16);
32
-		$encrypted = sodium_crypto_secretbox($padded_message, $nonce, $key);
33
-		$encoded = base64_encode($salt . $nonce . $encrypted);
34
-		sodium_memzero($key);
35
-		sodium_memzero($nonce);
36
-		sodium_memzero($salt);
37
-		#spip_log("chiffrer($message)=$encoded", 'chiffrer' . _LOG_DEBUG);
38
-		return $encoded;
39
-	}
21
+    /** Chiffre un message en utilisant une clé ou un mot de passe */
22
+    public static function chiffrer(
23
+        string $message,
24
+        #[\SensitiveParameter]
25
+        string $key
26
+    ): ?string {
27
+        // create a random salt for key derivation
28
+        $salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES);
29
+        $key = self::deriveKeyFromPassword($key, $salt);
30
+        $nonce = random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
31
+        $padded_message = sodium_pad($message, 16);
32
+        $encrypted = sodium_crypto_secretbox($padded_message, $nonce, $key);
33
+        $encoded = base64_encode($salt . $nonce . $encrypted);
34
+        sodium_memzero($key);
35
+        sodium_memzero($nonce);
36
+        sodium_memzero($salt);
37
+        #spip_log("chiffrer($message)=$encoded", 'chiffrer' . _LOG_DEBUG);
38
+        return $encoded;
39
+    }
40 40
 
41
-	/** Déchiffre un message en utilisant une clé ou un mot de passe */
42
-	public static function dechiffrer(
43
-		string $encoded,
44
-		#[\SensitiveParameter]
45
-		string $key
46
-	): ?string {
47
-		$decoded = base64_decode($encoded);
48
-		$salt = substr($decoded, 0, \SODIUM_CRYPTO_PWHASH_SALTBYTES);
49
-		$nonce = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES, \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
50
-		$encrypted = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES + \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
51
-		$key = self::deriveKeyFromPassword($key, $salt);
52
-		$padded_message = sodium_crypto_secretbox_open($encrypted, $nonce, $key);
53
-		sodium_memzero($key);
54
-		sodium_memzero($nonce);
55
-		sodium_memzero($salt);
56
-		if ($padded_message === false) {
57
-			spip_log("dechiffrer() chiffre corrompu `$encoded`", 'chiffrer' . _LOG_DEBUG);
58
-			return null;
59
-		}
60
-		return sodium_unpad($padded_message, 16);
61
-	}
41
+    /** Déchiffre un message en utilisant une clé ou un mot de passe */
42
+    public static function dechiffrer(
43
+        string $encoded,
44
+        #[\SensitiveParameter]
45
+        string $key
46
+    ): ?string {
47
+        $decoded = base64_decode($encoded);
48
+        $salt = substr($decoded, 0, \SODIUM_CRYPTO_PWHASH_SALTBYTES);
49
+        $nonce = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES, \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
50
+        $encrypted = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES + \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
51
+        $key = self::deriveKeyFromPassword($key, $salt);
52
+        $padded_message = sodium_crypto_secretbox_open($encrypted, $nonce, $key);
53
+        sodium_memzero($key);
54
+        sodium_memzero($nonce);
55
+        sodium_memzero($salt);
56
+        if ($padded_message === false) {
57
+            spip_log("dechiffrer() chiffre corrompu `$encoded`", 'chiffrer' . _LOG_DEBUG);
58
+            return null;
59
+        }
60
+        return sodium_unpad($padded_message, 16);
61
+    }
62 62
 
63
-	/** Génère une clé de la taille attendue pour le chiffrement */
64
-	public static function keygen(): string {
65
-		return sodium_crypto_secretbox_keygen();
66
-	}
63
+    /** Génère une clé de la taille attendue pour le chiffrement */
64
+    public static function keygen(): string {
65
+        return sodium_crypto_secretbox_keygen();
66
+    }
67 67
 
68
-	/**
69
-	 * Retourne une clé de la taille attendue pour le chiffrement
70
-	 *
71
-	 * Notamment si on utilise un mot de passe comme clé, il faut le hacher
72
-	 * pour servir de clé à la taille correspondante.
73
-	 */
74
-	private static function deriveKeyFromPassword(
75
-		#[\SensitiveParameter]
76
-		string $password,
77
-		string $salt
78
-	): string {
79
-		if (strlen($password) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
80
-			return $password;
81
-		}
82
-		$key = sodium_crypto_pwhash(
83
-			\SODIUM_CRYPTO_SECRETBOX_KEYBYTES,
84
-			$password,
85
-			$salt,
86
-			\SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
87
-			\SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
88
-		);
89
-		sodium_memzero($password);
68
+    /**
69
+     * Retourne une clé de la taille attendue pour le chiffrement
70
+     *
71
+     * Notamment si on utilise un mot de passe comme clé, il faut le hacher
72
+     * pour servir de clé à la taille correspondante.
73
+     */
74
+    private static function deriveKeyFromPassword(
75
+        #[\SensitiveParameter]
76
+        string $password,
77
+        string $salt
78
+    ): string {
79
+        if (strlen($password) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
80
+            return $password;
81
+        }
82
+        $key = sodium_crypto_pwhash(
83
+            \SODIUM_CRYPTO_SECRETBOX_KEYBYTES,
84
+            $password,
85
+            $salt,
86
+            \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
87
+            \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
88
+        );
89
+        sodium_memzero($password);
90 90
 
91
-		return $key;
92
-	}
91
+        return $key;
92
+    }
93 93
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@  discard block
 block discarded – undo
30 30
 		$nonce = random_bytes(\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
31 31
 		$padded_message = sodium_pad($message, 16);
32 32
 		$encrypted = sodium_crypto_secretbox($padded_message, $nonce, $key);
33
-		$encoded = base64_encode($salt . $nonce . $encrypted);
33
+		$encoded = base64_encode($salt.$nonce.$encrypted);
34 34
 		sodium_memzero($key);
35 35
 		sodium_memzero($nonce);
36 36
 		sodium_memzero($salt);
@@ -47,14 +47,14 @@  discard block
 block discarded – undo
47 47
 		$decoded = base64_decode($encoded);
48 48
 		$salt = substr($decoded, 0, \SODIUM_CRYPTO_PWHASH_SALTBYTES);
49 49
 		$nonce = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES, \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
50
-		$encrypted = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES + \SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
50
+		$encrypted = substr($decoded, \SODIUM_CRYPTO_PWHASH_SALTBYTES +\SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
51 51
 		$key = self::deriveKeyFromPassword($key, $salt);
52 52
 		$padded_message = sodium_crypto_secretbox_open($encrypted, $nonce, $key);
53 53
 		sodium_memzero($key);
54 54
 		sodium_memzero($nonce);
55 55
 		sodium_memzero($salt);
56 56
 		if ($padded_message === false) {
57
-			spip_log("dechiffrer() chiffre corrompu `$encoded`", 'chiffrer' . _LOG_DEBUG);
57
+			spip_log("dechiffrer() chiffre corrompu `$encoded`", 'chiffrer'._LOG_DEBUG);
58 58
 			return null;
59 59
 		}
60 60
 		return sodium_unpad($padded_message, 16);
Please login to merge, or discard this patch.
ecrire/src/Chiffrer/Password.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -13,49 +13,49 @@
 block discarded – undo
13 13
 
14 14
 /** Vérification et hachage de mot de passe */
15 15
 class Password {
16
-	/**
17
-	 * verifier qu'un mot de passe en clair est correct a l'aide de son hash
18
-	 *
19
-	 * Le mot de passe est poivre via la cle secret_des_auth
20
-	 */
21
-	public static function verifier(
22
-		#[\SensitiveParameter]
23
-		string $password_clair,
24
-		#[\SensitiveParameter]
25
-		string $password_hash,
26
-		#[\SensitiveParameter]
27
-		?string $key = null
28
-	): bool {
29
-		$key ??= self::getDefaultKey();
30
-		if ($key) {
31
-			$pass_poivre = hash_hmac('sha256', $password_clair, $key);
32
-			return password_verify($pass_poivre, $password_hash);
33
-		}
34
-		spip_log('Aucune clé pour vérifier le mot de passe', 'chiffrer' . _LOG_INFO_IMPORTANTE);
35
-		return false;
36
-	}
16
+    /**
17
+     * verifier qu'un mot de passe en clair est correct a l'aide de son hash
18
+     *
19
+     * Le mot de passe est poivre via la cle secret_des_auth
20
+     */
21
+    public static function verifier(
22
+        #[\SensitiveParameter]
23
+        string $password_clair,
24
+        #[\SensitiveParameter]
25
+        string $password_hash,
26
+        #[\SensitiveParameter]
27
+        ?string $key = null
28
+    ): bool {
29
+        $key ??= self::getDefaultKey();
30
+        if ($key) {
31
+            $pass_poivre = hash_hmac('sha256', $password_clair, $key);
32
+            return password_verify($pass_poivre, $password_hash);
33
+        }
34
+        spip_log('Aucune clé pour vérifier le mot de passe', 'chiffrer' . _LOG_INFO_IMPORTANTE);
35
+        return false;
36
+    }
37 37
 
38
-	/**
39
-	 * Calculer un hash salé du mot de passe
40
-	 */
41
-	public static function hacher(
42
-		#[\SensitiveParameter]
43
-		string $password_clair,
44
-		#[\SensitiveParameter]
45
-		?string $key = null
46
-	): ?string {
47
-		$key ??= self::getDefaultKey();
48
-		// ne pas fournir un hash errone si la cle nous manque
49
-		if ($key) {
50
-			$pass_poivre = hash_hmac('sha256', $password_clair, $key);
51
-			return password_hash($pass_poivre, PASSWORD_DEFAULT);
52
-		}
53
-		spip_log('Aucune clé pour chiffrer le mot de passe', 'chiffrer' . _LOG_INFO_IMPORTANTE);
54
-		return null;
55
-	}
38
+    /**
39
+     * Calculer un hash salé du mot de passe
40
+     */
41
+    public static function hacher(
42
+        #[\SensitiveParameter]
43
+        string $password_clair,
44
+        #[\SensitiveParameter]
45
+        ?string $key = null
46
+    ): ?string {
47
+        $key ??= self::getDefaultKey();
48
+        // ne pas fournir un hash errone si la cle nous manque
49
+        if ($key) {
50
+            $pass_poivre = hash_hmac('sha256', $password_clair, $key);
51
+            return password_hash($pass_poivre, PASSWORD_DEFAULT);
52
+        }
53
+        spip_log('Aucune clé pour chiffrer le mot de passe', 'chiffrer' . _LOG_INFO_IMPORTANTE);
54
+        return null;
55
+    }
56 56
 
57
-	private static function getDefaultKey(): ?string {
58
-		$keys = SpipCles::instance();
59
-		return $keys->getSecretAuth();
60
-	}
57
+    private static function getDefaultKey(): ?string {
58
+        $keys = SpipCles::instance();
59
+        return $keys->getSecretAuth();
60
+    }
61 61
 }
Please login to merge, or discard this patch.
ecrire/src/Chiffrer/Cles.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -13,46 +13,46 @@
 block discarded – undo
13 13
 
14 14
 /** Conteneur de clés (chiffrement, authentification) */
15 15
 class Cles implements \Countable /* , ContainerInterface */ {
16
-	public function __construct(private array $keys) {
17
-	}
18
-
19
-	public function has(string $name): bool {
20
-		return array_key_exists($name, $this->keys);
21
-	}
22
-
23
-	public function get(string $name): ?string {
24
-		return $this->keys[$name] ?? null;
25
-	}
26
-
27
-	public function generate(string $name): string {
28
-		$key = Chiffrement::keygen();
29
-		$this->keys[$name] = $key;
30
-		spip_log("Création de la cle $name", 'chiffrer' . _LOG_INFO_IMPORTANTE);
31
-		return $key;
32
-	}
33
-
34
-	public function set(
35
-		string $name,
36
-		#[\SensitiveParameter]
37
-		string $key
38
-	): void {
39
-		$this->keys[$name] = $key;
40
-	}
41
-
42
-	public function delete(string $name): bool {
43
-		if (isset($this->keys[$name])) {
44
-			unset($this->keys[$name]);
45
-			return true;
46
-		};
47
-		return false;
48
-	}
49
-
50
-	public function count(): int {
51
-		return count($this->keys);
52
-	}
53
-
54
-	public function toJson(): string {
55
-		$json = array_map('base64_encode', $this->keys);
56
-		return \json_encode($json);
57
-	}
16
+    public function __construct(private array $keys) {
17
+    }
18
+
19
+    public function has(string $name): bool {
20
+        return array_key_exists($name, $this->keys);
21
+    }
22
+
23
+    public function get(string $name): ?string {
24
+        return $this->keys[$name] ?? null;
25
+    }
26
+
27
+    public function generate(string $name): string {
28
+        $key = Chiffrement::keygen();
29
+        $this->keys[$name] = $key;
30
+        spip_log("Création de la cle $name", 'chiffrer' . _LOG_INFO_IMPORTANTE);
31
+        return $key;
32
+    }
33
+
34
+    public function set(
35
+        string $name,
36
+        #[\SensitiveParameter]
37
+        string $key
38
+    ): void {
39
+        $this->keys[$name] = $key;
40
+    }
41
+
42
+    public function delete(string $name): bool {
43
+        if (isset($this->keys[$name])) {
44
+            unset($this->keys[$name]);
45
+            return true;
46
+        };
47
+        return false;
48
+    }
49
+
50
+    public function count(): int {
51
+        return count($this->keys);
52
+    }
53
+
54
+    public function toJson(): string {
55
+        $json = array_map('base64_encode', $this->keys);
56
+        return \json_encode($json);
57
+    }
58 58
 }
Please login to merge, or discard this patch.
ecrire/src/Chiffrer/SpipCles.php 2 patches
Indentation   +165 added lines, -165 removed lines patch added patch discarded remove patch
@@ -13,169 +13,169 @@
 block discarded – undo
13 13
 
14 14
 /** Gestion des clés d’authentification / chiffrement de SPIP */
15 15
 final class SpipCles {
16
-	private static array $instances = [];
17
-
18
-	private string $file = _DIR_ETC . 'cles.php';
19
-	private Cles $cles;
20
-
21
-	public static function instance(string $file = ''): self {
22
-		if (empty(self::$instances[$file])) {
23
-			self::$instances[$file] = new self($file);
24
-		}
25
-		return self::$instances[$file];
26
-	}
27
-
28
-	/**
29
-	 * Retourne le secret du site (shorthand)
30
-	 * @uses self::getSecretSite()
31
-	 */
32
-	public static function secret_du_site(): ?string {
33
-		return (self::instance())->getSecretSite();
34
-	}
35
-
36
-	private function __construct(string $file = '') {
37
-		if ($file) {
38
-			$this->file = $file;
39
-		}
40
-		$this->cles = new Cles($this->read());
41
-	}
42
-
43
-	/**
44
-	 * Renvoyer le secret du site
45
-	 *
46
-	 * Le secret du site doit rester aussi secret que possible, et est eternel
47
-	 * On ne doit pas l'exporter
48
-	 *
49
-	 * Le secret est partagé entre une clé disque et une clé bdd
50
-	 *
51
-	 * @return string
52
-	 */
53
-	public function getSecretSite(bool $autoInit = true): ?string {
54
-		$key = $this->getKey('secret_du_site', $autoInit);
55
-		$meta = $this->getMetaKey('secret_du_site', $autoInit);
56
-		// conserve la même longeur.
57
-		return $key ^ $meta;
58
-	}
59
-
60
-	/** Renvoyer le secret des authentifications */
61
-	public function getSecretAuth(bool $autoInit = false): ?string {
62
-		return $this->getKey('secret_des_auth', $autoInit);
63
-	}
64
-	public function save(): bool {
65
-		return ecrire_fichier_securise($this->file, $this->cles->toJson());
66
-	}
67
-
68
-	/**
69
-	 * Fournir une sauvegarde chiffree des cles (a l'aide d'une autre clé, comme le pass d'un auteur)
70
-	 *
71
-	 * @param string $withKey Clé de chiffrage de la sauvegarde
72
-	 * @return string Contenu de la sauvegarde chiffrée générée
73
-	 */
74
-	public function backup(
75
-		#[\SensitiveParameter]
76
-		string $withKey
77
-	): string {
78
-		if (count($this->cles)) {
79
-			return Chiffrement::chiffrer($this->cles->toJson(), $withKey);
80
-		}
81
-		return '';
82
-	}
83
-
84
-	/**
85
-	 * Restaurer les cles manquantes depuis une sauvegarde chiffree des cles
86
-	 * (si la sauvegarde est bien valide)
87
-	 */
88
-	public function restore(
89
-		/** Sauvegarde chiffrée (générée par backup()) */
90
-		string $backup,
91
-		#[\SensitiveParameter]
92
-		string $password_clair,
93
-		#[\SensitiveParameter]
94
-		string $password_hash,
95
-		int $id_auteur
96
-	): bool {
97
-		if (empty($backup)) {
98
-			return false;
99
-		}
100
-
101
-		$sauvegarde = Chiffrement::dechiffrer($backup, $password_clair);
102
-		$json = json_decode($sauvegarde, true);
103
-		if (!$json) {
104
-			return false;
105
-		}
106
-
107
-		// cela semble une sauvegarde valide
108
-		$cles_potentielles = array_map('base64_decode', $json);
109
-
110
-		// il faut faire une double verif sur secret_des_auth
111
-		// pour s'assurer qu'elle permet bien de decrypter le pass de l'auteur qui fournit la sauvegarde
112
-		// et par extension tous les passwords
113
-		if (
114
-			!empty($cles_potentielles['secret_des_auth'])
115
-			&& !Password::verifier($password_clair, $password_hash, $cles_potentielles['secret_des_auth'])
116
-		) {
117
-			spip_log("Restauration de la cle `secret_des_auth` par id_auteur $id_auteur erronnee, on ignore", 'chiffrer' . _LOG_INFO_IMPORTANTE);
118
-			unset($cles_potentielles['secret_des_auth']);
119
-		}
120
-
121
-		// on merge les cles pour recuperer les cles manquantes
122
-		$restauration = false;
123
-		foreach ($cles_potentielles as $name => $key) {
124
-			if (!$this->cles->has($name)) {
125
-				$this->cles->set($name, $key);
126
-				spip_log("Restauration de la cle $name par id_auteur $id_auteur", 'chiffrer' . _LOG_INFO_IMPORTANTE);
127
-				$restauration = true;
128
-			}
129
-		}
130
-		return $restauration;
131
-	}
132
-
133
-	private function getKey(string $name, bool $autoInit): ?string {
134
-		if ($this->cles->has($name)) {
135
-			return $this->cles->get($name);
136
-		}
137
-		if ($autoInit) {
138
-			$this->cles->generate($name);
139
-			// si l'ecriture de fichier a bien marche on peut utiliser la cle
140
-			if ($this->save()) {
141
-				return $this->cles->get($name);
142
-			}
143
-			// sinon loger et annule la cle generee car il ne faut pas l'utiliser
144
-			spip_log('Echec ecriture du fichier cle ' . $this->file . " ; impossible de generer une cle $name", 'chiffrer' . _LOG_ERREUR);
145
-			$this->cles->delete($name);
146
-		}
147
-		return null;
148
-	}
149
-
150
-	private function getMetaKey(string $name, bool $autoInit = true): ?string {
151
-		if (!isset($GLOBALS['meta'][$name])) {
152
-			include_spip('base/abstract_sql');
153
-			$GLOBALS['meta'][$name] = sql_getfetsel('valeur', 'spip_meta', 'nom = ' . sql_quote($name, '', 'string'));
154
-		}
155
-		$key = base64_decode($GLOBALS['meta'][$name] ?? '');
156
-		if (strlen($key) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
157
-			return $key;
158
-		}
159
-		if (!$autoInit) {
160
-			return null;
161
-		}
162
-		$key = Chiffrement::keygen();
163
-		ecrire_meta($name, base64_encode($key), 'non');
164
-		lire_metas(); // au cas ou ecrire_meta() ne fonctionne pas
165
-
166
-		return $key;
167
-	}
168
-
169
-	private function read(): array {
170
-		$json = null;
171
-		lire_fichier_securise($this->file, $json);
172
-		if (
173
-			$json
174
-			&& ($json = \json_decode($json, true))
175
-			&& is_array($json)
176
-		) {
177
-			return array_map('base64_decode', $json);
178
-		}
179
-		return [];
180
-	}
16
+    private static array $instances = [];
17
+
18
+    private string $file = _DIR_ETC . 'cles.php';
19
+    private Cles $cles;
20
+
21
+    public static function instance(string $file = ''): self {
22
+        if (empty(self::$instances[$file])) {
23
+            self::$instances[$file] = new self($file);
24
+        }
25
+        return self::$instances[$file];
26
+    }
27
+
28
+    /**
29
+     * Retourne le secret du site (shorthand)
30
+     * @uses self::getSecretSite()
31
+     */
32
+    public static function secret_du_site(): ?string {
33
+        return (self::instance())->getSecretSite();
34
+    }
35
+
36
+    private function __construct(string $file = '') {
37
+        if ($file) {
38
+            $this->file = $file;
39
+        }
40
+        $this->cles = new Cles($this->read());
41
+    }
42
+
43
+    /**
44
+     * Renvoyer le secret du site
45
+     *
46
+     * Le secret du site doit rester aussi secret que possible, et est eternel
47
+     * On ne doit pas l'exporter
48
+     *
49
+     * Le secret est partagé entre une clé disque et une clé bdd
50
+     *
51
+     * @return string
52
+     */
53
+    public function getSecretSite(bool $autoInit = true): ?string {
54
+        $key = $this->getKey('secret_du_site', $autoInit);
55
+        $meta = $this->getMetaKey('secret_du_site', $autoInit);
56
+        // conserve la même longeur.
57
+        return $key ^ $meta;
58
+    }
59
+
60
+    /** Renvoyer le secret des authentifications */
61
+    public function getSecretAuth(bool $autoInit = false): ?string {
62
+        return $this->getKey('secret_des_auth', $autoInit);
63
+    }
64
+    public function save(): bool {
65
+        return ecrire_fichier_securise($this->file, $this->cles->toJson());
66
+    }
67
+
68
+    /**
69
+     * Fournir une sauvegarde chiffree des cles (a l'aide d'une autre clé, comme le pass d'un auteur)
70
+     *
71
+     * @param string $withKey Clé de chiffrage de la sauvegarde
72
+     * @return string Contenu de la sauvegarde chiffrée générée
73
+     */
74
+    public function backup(
75
+        #[\SensitiveParameter]
76
+        string $withKey
77
+    ): string {
78
+        if (count($this->cles)) {
79
+            return Chiffrement::chiffrer($this->cles->toJson(), $withKey);
80
+        }
81
+        return '';
82
+    }
83
+
84
+    /**
85
+     * Restaurer les cles manquantes depuis une sauvegarde chiffree des cles
86
+     * (si la sauvegarde est bien valide)
87
+     */
88
+    public function restore(
89
+        /** Sauvegarde chiffrée (générée par backup()) */
90
+        string $backup,
91
+        #[\SensitiveParameter]
92
+        string $password_clair,
93
+        #[\SensitiveParameter]
94
+        string $password_hash,
95
+        int $id_auteur
96
+    ): bool {
97
+        if (empty($backup)) {
98
+            return false;
99
+        }
100
+
101
+        $sauvegarde = Chiffrement::dechiffrer($backup, $password_clair);
102
+        $json = json_decode($sauvegarde, true);
103
+        if (!$json) {
104
+            return false;
105
+        }
106
+
107
+        // cela semble une sauvegarde valide
108
+        $cles_potentielles = array_map('base64_decode', $json);
109
+
110
+        // il faut faire une double verif sur secret_des_auth
111
+        // pour s'assurer qu'elle permet bien de decrypter le pass de l'auteur qui fournit la sauvegarde
112
+        // et par extension tous les passwords
113
+        if (
114
+            !empty($cles_potentielles['secret_des_auth'])
115
+            && !Password::verifier($password_clair, $password_hash, $cles_potentielles['secret_des_auth'])
116
+        ) {
117
+            spip_log("Restauration de la cle `secret_des_auth` par id_auteur $id_auteur erronnee, on ignore", 'chiffrer' . _LOG_INFO_IMPORTANTE);
118
+            unset($cles_potentielles['secret_des_auth']);
119
+        }
120
+
121
+        // on merge les cles pour recuperer les cles manquantes
122
+        $restauration = false;
123
+        foreach ($cles_potentielles as $name => $key) {
124
+            if (!$this->cles->has($name)) {
125
+                $this->cles->set($name, $key);
126
+                spip_log("Restauration de la cle $name par id_auteur $id_auteur", 'chiffrer' . _LOG_INFO_IMPORTANTE);
127
+                $restauration = true;
128
+            }
129
+        }
130
+        return $restauration;
131
+    }
132
+
133
+    private function getKey(string $name, bool $autoInit): ?string {
134
+        if ($this->cles->has($name)) {
135
+            return $this->cles->get($name);
136
+        }
137
+        if ($autoInit) {
138
+            $this->cles->generate($name);
139
+            // si l'ecriture de fichier a bien marche on peut utiliser la cle
140
+            if ($this->save()) {
141
+                return $this->cles->get($name);
142
+            }
143
+            // sinon loger et annule la cle generee car il ne faut pas l'utiliser
144
+            spip_log('Echec ecriture du fichier cle ' . $this->file . " ; impossible de generer une cle $name", 'chiffrer' . _LOG_ERREUR);
145
+            $this->cles->delete($name);
146
+        }
147
+        return null;
148
+    }
149
+
150
+    private function getMetaKey(string $name, bool $autoInit = true): ?string {
151
+        if (!isset($GLOBALS['meta'][$name])) {
152
+            include_spip('base/abstract_sql');
153
+            $GLOBALS['meta'][$name] = sql_getfetsel('valeur', 'spip_meta', 'nom = ' . sql_quote($name, '', 'string'));
154
+        }
155
+        $key = base64_decode($GLOBALS['meta'][$name] ?? '');
156
+        if (strlen($key) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
157
+            return $key;
158
+        }
159
+        if (!$autoInit) {
160
+            return null;
161
+        }
162
+        $key = Chiffrement::keygen();
163
+        ecrire_meta($name, base64_encode($key), 'non');
164
+        lire_metas(); // au cas ou ecrire_meta() ne fonctionne pas
165
+
166
+        return $key;
167
+    }
168
+
169
+    private function read(): array {
170
+        $json = null;
171
+        lire_fichier_securise($this->file, $json);
172
+        if (
173
+            $json
174
+            && ($json = \json_decode($json, true))
175
+            && is_array($json)
176
+        ) {
177
+            return array_map('base64_decode', $json);
178
+        }
179
+        return [];
180
+    }
181 181
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -15,7 +15,7 @@  discard block
 block discarded – undo
15 15
 final class SpipCles {
16 16
 	private static array $instances = [];
17 17
 
18
-	private string $file = _DIR_ETC . 'cles.php';
18
+	private string $file = _DIR_ETC.'cles.php';
19 19
 	private Cles $cles;
20 20
 
21 21
 	public static function instance(string $file = ''): self {
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
 			!empty($cles_potentielles['secret_des_auth'])
115 115
 			&& !Password::verifier($password_clair, $password_hash, $cles_potentielles['secret_des_auth'])
116 116
 		) {
117
-			spip_log("Restauration de la cle `secret_des_auth` par id_auteur $id_auteur erronnee, on ignore", 'chiffrer' . _LOG_INFO_IMPORTANTE);
117
+			spip_log("Restauration de la cle `secret_des_auth` par id_auteur $id_auteur erronnee, on ignore", 'chiffrer'._LOG_INFO_IMPORTANTE);
118 118
 			unset($cles_potentielles['secret_des_auth']);
119 119
 		}
120 120
 
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
 		foreach ($cles_potentielles as $name => $key) {
124 124
 			if (!$this->cles->has($name)) {
125 125
 				$this->cles->set($name, $key);
126
-				spip_log("Restauration de la cle $name par id_auteur $id_auteur", 'chiffrer' . _LOG_INFO_IMPORTANTE);
126
+				spip_log("Restauration de la cle $name par id_auteur $id_auteur", 'chiffrer'._LOG_INFO_IMPORTANTE);
127 127
 				$restauration = true;
128 128
 			}
129 129
 		}
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
 				return $this->cles->get($name);
142 142
 			}
143 143
 			// sinon loger et annule la cle generee car il ne faut pas l'utiliser
144
-			spip_log('Echec ecriture du fichier cle ' . $this->file . " ; impossible de generer une cle $name", 'chiffrer' . _LOG_ERREUR);
144
+			spip_log('Echec ecriture du fichier cle '.$this->file." ; impossible de generer une cle $name", 'chiffrer'._LOG_ERREUR);
145 145
 			$this->cles->delete($name);
146 146
 		}
147 147
 		return null;
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
 	private function getMetaKey(string $name, bool $autoInit = true): ?string {
151 151
 		if (!isset($GLOBALS['meta'][$name])) {
152 152
 			include_spip('base/abstract_sql');
153
-			$GLOBALS['meta'][$name] = sql_getfetsel('valeur', 'spip_meta', 'nom = ' . sql_quote($name, '', 'string'));
153
+			$GLOBALS['meta'][$name] = sql_getfetsel('valeur', 'spip_meta', 'nom = '.sql_quote($name, '', 'string'));
154 154
 		}
155 155
 		$key = base64_decode($GLOBALS['meta'][$name] ?? '');
156 156
 		if (strlen($key) === \SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
Please login to merge, or discard this patch.
ecrire/src/Admin/Bouton.php 2 patches
Indentation   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -7,32 +7,32 @@
 block discarded – undo
7 7
  * privée ou dans un de ses sous menus
8 8
  */
9 9
 class Bouton {
10
-	/** Sous-barre de boutons / onglets */
11
-	public array $sousmenu = [];
10
+    /** Sous-barre de boutons / onglets */
11
+    public array $sousmenu = [];
12 12
 
13
-	/** Position dans le menu */
14
-	public int $position = 0;
13
+    /** Position dans le menu */
14
+    public int $position = 0;
15 15
 
16
-	/** Entrée favorite (sa position dans les favoris) ? */
17
-	public int $favori = 0;
16
+    /** Entrée favorite (sa position dans les favoris) ? */
17
+    public int $favori = 0;
18 18
 
19 19
 
20
-	/**
21
-	 * Définit un bouton
22
-	 */
23
-	public function __construct(
24
-		/** L'icone à mettre dans le bouton */
25
-		public string $icone,
26
-		/** Le nom de l'entrée d'i18n associé */
27
-		public string $libelle,
28
-		/** L'URL de la page (null => ?exec=nom) */
29
-		public ?string $url = null,
30
-		/** Arguments supplémentaires de l'URL */
31
-		public string|array|null $urlArg = null,
32
-		/** URL du javascript */
33
-		public ?string $url2 = null,
34
-		/** Pour ouvrir une fenêtre à part */
35
-		public ?string $target = null
36
-	) {
37
-	}
20
+    /**
21
+     * Définit un bouton
22
+     */
23
+    public function __construct(
24
+        /** L'icone à mettre dans le bouton */
25
+        public string $icone,
26
+        /** Le nom de l'entrée d'i18n associé */
27
+        public string $libelle,
28
+        /** L'URL de la page (null => ?exec=nom) */
29
+        public ?string $url = null,
30
+        /** Arguments supplémentaires de l'URL */
31
+        public string|array|null $urlArg = null,
32
+        /** URL du javascript */
33
+        public ?string $url2 = null,
34
+        /** Pour ouvrir une fenêtre à part */
35
+        public ?string $target = null
36
+    ) {
37
+    }
38 38
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -28,7 +28,7 @@
 block discarded – undo
28 28
 		/** L'URL de la page (null => ?exec=nom) */
29 29
 		public ?string $url = null,
30 30
 		/** Arguments supplémentaires de l'URL */
31
-		public string|array|null $urlArg = null,
31
+		public string | array | null $urlArg = null,
32 32
 		/** URL du javascript */
33 33
 		public ?string $url2 = null,
34 34
 		/** Pour ouvrir une fenêtre à part */
Please login to merge, or discard this patch.