Completed
Push — master ( 117d82...bd6ae7 )
by cam
04:12
created

balises.php ➔ balise_NOOP_dist()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/***************************************************************************\
4
 *  SPIP, Système de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright © avec tendresse depuis 2001                                 *
7
 *  Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James  *
8
 *                                                                         *
9
 *  Ce programme est un logiciel libre distribué sous licence GNU/GPL.     *
10
 *  Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne.   *
11
\***************************************************************************/
12
13
/**
14
 * Ce fichier regroupe la quasi totalité des définitions de `#BALISES` de SPIP.
15
 *
16
 * Pour chaque balise, il est possible de surcharger, dans son fichier
17
 * mes_fonctions.php, la fonction `balise_TOTO_dist()` par une fonction
18
 * `balise_TOTO()` respectant la même API : elle reçoit en entrée un objet
19
 * de classe `Champ`, le modifie et le retourne. Cette classe est définie
20
 * dans public/interfaces.
21
 *
22
 * Des balises dites «dynamiques» sont également déclarées dans le
23
 * répertoire ecrire/balise/
24
 *
25
 * @package SPIP\Core\Compilateur\Balises
26
 **/
27
28
if (!defined('_ECRIRE_INC_VERSION')) {
29
	return;
30
}
31
32
/**
33
 * Retourne le code PHP d'un argument de balise s'il est présent
34
 *
35
 * @uses calculer_liste()
36
 * @example
37
 *     ```
38
 *     // Retourne le premier argument de la balise
39
 *     // #BALISE{premier,deuxieme}
40
 *     $arg = interprete_argument_balise(1,$p);
41
 *     ```
42
 *
43
 * @param int $n
44
 *     Numéro de l'argument
45
 * @param Champ $p
46
 *     Pile au niveau de la balise
47
 * @return string|null
48
 *     Code PHP si cet argument est présent, sinon null
49
 **/
50
function interprete_argument_balise($n, $p) {
51
	if (($p->param) && (!$p->param[0][0]) && (count($p->param[0]) > $n)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->param of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
52
		return calculer_liste($p->param[0][$n],
53
			$p->descr,
54
			$p->boucles,
55
			$p->id_boucle);
56
	} else {
57
		return null;
58
	}
59
}
60
61
62
//
63
// Définition des balises
64
//
65
66
/**
67
 * Compile la balise `#NOM_SITE_SPIP` retournant le nom du site
68
 *
69
 * @balise
70
 * @link https://www.spip.net/4622
71
 *
72
 * @param Champ $p
73
 *     Pile au niveau de la balise
74
 * @return Champ
75
 *     Pile complétée par le code à générer
76
 **/
77
function balise_NOM_SITE_SPIP_dist($p) {
78
	$p->code = "\$GLOBALS['meta']['nom_site']";
79
80
	#$p->interdire_scripts = true;
81
	return $p;
82
}
83
84
/**
85
 * Compile la balise `#EMAIL_WEBMASTER` retournant l'adresse courriel
86
 * du webmestre
87
 *
88
 * @balise
89
 * @link https://www.spip.net/4586
90
 *
91
 * @param Champ $p
92
 *     Pile au niveau de la balise
93
 * @return Champ
94
 *     Pile complétée par le code à générer
95
 **/
96
function balise_EMAIL_WEBMASTER_dist($p) {
97
	$p->code = "\$GLOBALS['meta']['email_webmaster']";
98
99
	#$p->interdire_scripts = true;
100
	return $p;
101
}
102
103
/**
104
 * Compile la balise `#DESCRIPTIF_SITE_SPIP` qui retourne le descriptif
105
 * du site !
106
 *
107
 * @balise
108
 * @link https://www.spip.net/4338
109
 *
110
 * @param Champ $p
111
 *     Pile au niveau de la balise
112
 * @return Champ
113
 *     Pile complétée par le code à générer
114
 **/
115
function balise_DESCRIPTIF_SITE_SPIP_dist($p) {
116
	$p->code = "\$GLOBALS['meta']['descriptif_site']";
117
118
	#$p->interdire_scripts = true;
119
	return $p;
120
}
121
122
123
/**
124
 * Compile la balise `#CHARSET` qui retourne le nom du jeu de caractères
125
 * utilisé par le site tel que `utf-8`
126
 *
127
 * @balise
128
 * @link https://www.spip.net/4331
129
 * @example
130
 *     ```
131
 *     <meta http-equiv="Content-Type" content="text/html; charset=#CHARSET" />
132
 *     ```
133
 *
134
 * @param Champ $p
135
 *     Pile au niveau de la balise
136
 * @return Champ
137
 *     Pile complétée par le code à générer
138
 **/
139
function balise_CHARSET_dist($p) {
140
	$p->code = "\$GLOBALS['meta']['charset']";
141
142
	#$p->interdire_scripts = true;
143
	return $p;
144
}
145
146
/**
147
 * Compile la balise `#LANG_LEFT` retournant 'left' si la langue s'écrit
148
 * de gauche à droite, sinon 'right'
149
 *
150
 * @note
151
 *     Peut servir à l'écriture de code CSS dans un squelette, mais
152
 *     pour inclure un fichier css, il vaut mieux utiliser le filtre
153
 *     `direction_css` si on le souhaite sensible à la langue utilisé.
154
 *
155
 * @balise
156
 * @link https://www.spip.net/4625
157
 * @see lang_dir()
158
 * @see balise_LANG_RIGHT_dist()
159
 * @see balise_LANG_DIR_dist()
160
 * @see direction_css()
161
 *
162
 * @param Champ $p
163
 *     Pile au niveau de la balise
164
 * @return Champ
165
 *     Pile complétée par le code à générer
166
 **/
167 View Code Duplication
function balise_LANG_LEFT_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
	$_lang = champ_sql('lang', $p);
169
	$p->code = "lang_dir($_lang, 'left','right')";
170
	$p->interdire_scripts = false;
171
172
	return $p;
173
}
174
175
/**
176
 * Compile la balise `#LANG_RIGHT` retournant 'right' si la langue s'écrit
177
 * de gauche à droite, sinon 'left'
178
 *
179
 * @balise
180
 * @link https://www.spip.net/4625
181
 * @see lang_dir()
182
 * @see balise_LANG_LEFT_dist()
183
 * @see balise_LANG_DIR_dist()
184
 * @see direction_css()
185
 *
186
 * @param Champ $p
187
 *     Pile au niveau de la balise
188
 * @return Champ
189
 *     Pile complétée par le code à générer
190
 **/
191 View Code Duplication
function balise_LANG_RIGHT_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
192
	$_lang = champ_sql('lang', $p);
193
	$p->code = "lang_dir($_lang, 'right','left')";
194
	$p->interdire_scripts = false;
195
196
	return $p;
197
}
198
199
/**
200
 * Compile la balise `#LANG_DIR` retournant 'ltr' si la langue s'écrit
201
 * de gauche à droite, sinon 'rtl'
202
 *
203
 * @balise
204
 * @link https://www.spip.net/4625
205
 * @see lang_dir()
206
 * @see balise_LANG_LEFT_dist()
207
 * @see balise_LANG_RIGHT_dist()
208
 * @example
209
 *     ```
210
 *     <html dir="#LANG_DIR" lang="#LANG"
211
 *         xmlns="http://www.w3.org/1999/xhtml"
212
 *         xml:lang="#LANG" class="[(#LANG_DIR)][ (#LANG)] no-js">
213
 *     ```
214
 *
215
 * @param Champ $p
216
 *     Pile au niveau de la balise
217
 * @return Champ
218
 *     Pile complétée par le code à générer
219
 **/
220 View Code Duplication
function balise_LANG_DIR_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
	$_lang = champ_sql('lang', $p);
222
	$p->code = "lang_dir($_lang, 'ltr','rtl')";
223
	$p->interdire_scripts = false;
224
225
	return $p;
226
}
227
228
229
/**
230
 * Compile la balise `#PUCE` affichant une puce
231
 *
232
 * @balise
233
 * @link https://www.spip.net/4628
234
 * @see definir_puce()
235
 *
236
 * @param Champ $p
237
 *     Pile au niveau de la balise
238
 * @return Champ
239
 *     Pile complétée par le code à générer
240
 **/
241
function balise_PUCE_dist($p) {
242
	$p->code = "definir_puce()";
243
	$p->interdire_scripts = false;
244
245
	return $p;
246
}
247
248
249
/**
250
 * Compile la balise `#DATE` qui retourne la date de mise en ligne
251
 *
252
 * Cette balise retourne soit le champ `date` d'une table si elle est
253
 * utilisée dans une boucle, sinon la date de calcul du squelette.
254
 *
255
 * @balise
256
 * @link https://www.spip.net/4336 Balise DATE
257
 * @link https://www.spip.net/1971 La gestion des dates
258
 * @example
259
 *     ```
260
 *     <td>[(#DATE|affdate_jourcourt)]</td>
261
 *     ```
262
 *
263
 * @param Champ $p
264
 *     Pile au niveau de la balise.
265
 * @return Champ
266
 *     Pile completée du code PHP d'exécution de la balise
267
 */
268
function balise_DATE_dist($p) {
269
	$d = champ_sql('date', $p);
270
#	if ($d === "@\$Pile[0]['date']")
271
#		$d = "isset(\$Pile[0]['date']) ? $d : time()";
272
	$p->code = $d;
273
274
	return $p;
275
}
276
277
278
/**
279
 * Compile la balise `#DATE_REDAC` qui retourne la date de première publication
280
 *
281
 * Cette balise retourne le champ `date_redac` d'une table
282
 *
283
 * @balise
284
 * @link https://www.spip.net/3858 Balises DATE_MODIF et DATE_REDAC
285
 * @link https://www.spip.net/1971 La gestion des dates
286
 * @see balise_DATE_MODIF_dist()
287
 *
288
 * @param Champ $p
289
 *     Pile au niveau de la balise.
290
 * @return Champ
291
 *     Pile completée du code PHP d'exécution de la balise
292
 */
293
function balise_DATE_REDAC_dist($p) {
294
	$d = champ_sql('date_redac', $p);
295
#	if ($d === "@\$Pile[0]['date_redac']")
296
#		$d = "isset(\$Pile[0]['date_redac']) ? $d : time()";
297
	$p->code = $d;
298
	$p->interdire_scripts = false;
299
300
	return $p;
301
}
302
303
/**
304
 * Compile la balise `#DATE_MODIF` qui retourne la date de dernière modification
305
 *
306
 * Cette balise retourne le champ `date_modif` d'une table
307
 *
308
 * @balise
309
 * @link https://www.spip.net/3858 Balises DATE_MODIF et DATE_REDAC
310
 * @link https://www.spip.net/1971 La gestion des dates
311
 * @see balise_DATE_REDAC_dist()
312
 *
313
 * @param Champ $p
314
 *     Pile au niveau de la balise.
315
 * @return Champ
316
 *     Pile completée du code PHP d'exécution de la balise
317
 */
318
function balise_DATE_MODIF_dist($p) {
319
	$p->code = champ_sql('date_modif', $p);
320
	$p->interdire_scripts = false;
321
322
	return $p;
323
}
324
325
/**
326
 * Compile la balise `#DATE_NOUVEAUTES` indiquant la date de dernier envoi
327
 * du mail de nouveautés
328
 *
329
 * @balise
330
 * @link https://www.spip.net/4337 Balise DATE_NOUVEAUTES
331
 * @link https://www.spip.net/1971 La gestion des dates
332
 * @see balise_DATE_REDAC_dist()
333
 *
334
 * @param Champ $p
335
 *     Pile au niveau de la balise.
336
 * @return Champ
337
 *     Pile completée du code PHP d'exécution de la balise
338
 */
339
function balise_DATE_NOUVEAUTES_dist($p) {
340
	$p->code = "((\$GLOBALS['meta']['quoi_de_neuf'] == 'oui'
341
	AND isset(\$GLOBALS['meta']['dernier_envoi_neuf'])) ?
342
	\$GLOBALS['meta']['dernier_envoi_neuf'] :
343
	\"'0000-00-00'\")";
344
	$p->interdire_scripts = false;
345
346
	return $p;
347
}
348
349
/**
350
 * Compile la balise `#SQUELETTE` retournant le chemin du squelette courant
351
 *
352
 * @balise
353
 * @link https://www.spip.net/4027
354
 *
355
 * @param Champ $p
356
 *     Pile au niveau de la balise.
357
 * @return Champ
358
 *     Pile completée du code PHP d'exécution de la balise
359
 */
360
function balise_SQUELETTE_dist($p) {
361
	$code = addslashes($p->descr['sourcefile']);
362
	$p->code = "'$code'" .
363
		$p->interdire_scripts = false;
364
365
	return $p;
366
}
367
368
/**
369
 * Compile la balise `#SPIP_VERSION` qui affiche la version de SPIP
370
 *
371
 * @balise
372
 * @see spip_version()
373
 * @example
374
 *     ```
375
 *     <meta name="generator" content="SPIP[ (#SPIP_VERSION)]" />
376
 *     ```
377
 *
378
 * @param Champ $p
379
 *     Pile au niveau de la balise.
380
 * @return Champ
381
 *     Pile completée du code PHP d'exécution de la balise
382
 */
383
function balise_SPIP_VERSION_dist($p) {
384
	$p->code = "spip_version()";
385
	$p->interdire_scripts = false;
386
387
	return $p;
388
}
389
390
391
/**
392
 * Compile la balise `#NOM_SITE` qui affiche le nom du site.
393
 *
394
 * Affiche le nom du site ou sinon l'URL ou le titre de l'objet
395
 * Utiliser `#NOM_SITE*` pour avoir le nom du site ou rien.
396
 *
397
 * Cette balise interroge les colonnes `nom_site` ou `url_site`
398
 * dans la boucle la plus proche.
399
 *
400
 * @balise
401
 * @see calculer_url()
402
 * @example
403
 *     ```
404
 *     <a href="#URL_SITE">#NOM_SITE</a>
405
 *     ```
406
 *
407
 * @param Champ $p
408
 *     Pile au niveau de la balise
409
 * @return Champ
410
 *     Pile complétée par le code à générer
411
 **/
412
function balise_NOM_SITE_dist($p) {
413
	if (!$p->etoile) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->etoile of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
414
		$p->code = "supprimer_numero(calculer_url(" .
415
			champ_sql('url_site', $p) . "," .
416
			champ_sql('nom_site', $p) .
417
			", 'titre', \$connect, false))";
418
	} else {
419
		$p->code = champ_sql('nom_site', $p);
420
	}
421
422
	$p->interdire_scripts = true;
423
424
	return $p;
425
}
426
427
428
/**
429
 * Compile la balise `#NOTE` qui affiche les notes de bas de page
430
 *
431
 * @balise
432
 * @link https://www.spip.net/3964
433
 * @see calculer_notes()
434
 *
435
 * @param Champ $p
436
 *     Pile au niveau de la balise
437
 * @return Champ
438
 *     Pile complétée par le code à générer
439
 **/
440
function balise_NOTES_dist($p) {
441
	// Recuperer les notes
442
	$p->code = 'calculer_notes()';
443
444
	#$p->interdire_scripts = true;
445
	return $p;
446
}
447
448
449
/**
450
 * Compile la balise `#RECHERCHE` qui retourne le terme de recherche demandé
451
 *
452
 * Retourne un terme demandé en recherche, en le prenant dans _request()
453
 * sous la clé `recherche`.
454
 *
455
 * @balise
456
 * @example
457
 *     ```
458
 *     <h3>Recherche de : #RECHERCHE</h3>
459
 *     ```
460
 *
461
 * @param Champ $p
462
 *     Pile au niveau de la balise
463
 * @return Champ
464
 *     Pile complétée par le code à générer
465
 **/
466
function balise_RECHERCHE_dist($p) {
467
	$p->code = 'entites_html(_request("recherche"))';
468
	$p->interdire_scripts = false;
469
470
	return $p;
471
}
472
473
474
/**
475
 * Compile la balise `#COMPTEUR_BOUCLE` qui retourne le numéro de l’itération
476
 * actuelle de la boucle
477
 *
478
 * @balise
479
 * @link https://www.spip.net/4333
480
 * @see balise_TOTAL_BOUCLE_dist()
481
 *
482
 * @param Champ $p
483
 *     Pile au niveau de la balise
484
 * @return Champ
0 ignored issues
show
Documentation introduced by
Should the return type not be Champ|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
485
 *     Pile complétée par le code à générer
486
 **/
487 View Code Duplication
function balise_COMPTEUR_BOUCLE_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
488
	$b = index_boucle_mere($p);
489
	if ($b === '') {
490
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
491
		erreur_squelette($msg, $p);
492
	} else {
493
		$p->code = "\$Numrows['$b']['compteur_boucle']";
494
		$p->boucles[$b]->cptrows = true;
495
		$p->interdire_scripts = false;
496
497
		return $p;
498
	}
499
}
500
501
/**
502
 * Compile la balise `#TOTAL_BOUCLE` qui retourne le nombre de résultats
503
 * affichés par la boucle
504
 *
505
 * @balise
506
 * @link https://www.spip.net/4334
507
 * @see balise_COMPTEUR_BOUCLE_dist()
508
 * @see balise_GRAND_TOTAL_dist()
509
 *
510
 * @param Champ $p
511
 *     Pile au niveau de la balise
512
 * @return Champ
513
 *     Pile complétée par le code à générer
514
 **/
515 View Code Duplication
function balise_TOTAL_BOUCLE_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
516
	$b = index_boucle_mere($p);
517
	if ($b === '') {
518
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
519
		erreur_squelette($msg, $p);
520
	} else {
521
		$p->code = "\$Numrows['$b']['total']";
522
		$p->boucles[$b]->numrows = true;
523
		$p->interdire_scripts = false;
524
	}
525
526
	return $p;
527
}
528
529
530
/**
531
 * Compile la balise `#POINTS` qui affiche la pertinence des résultats
532
 *
533
 * Retourne le calcul `points` réalisé par le critère `recherche`.
534
 * Cette balise nécessite donc la présence de ce critère.
535
 *
536
 * @balise
537
 * @link https://www.spip.net/903 Boucles et balises de recherche
538
 * @see critere_recherche_dist()
539
 *
540
 * @param Champ $p
541
 *     Pile au niveau de la balise
542
 * @return Champ
543
 *     Pile complétée par le code à générer
544
 **/
545
function balise_POINTS_dist($p) {
546
	return rindex_pile($p, 'points', 'recherche');
547
}
548
549
550
/**
551
 * Compile la balise `#POPULARITE_ABSOLUE` qui affiche la popularité absolue
552
 *
553
 * Cela correspond à la popularité quotidienne de l'article
554
 *
555
 * @balise
556
 * @link https://www.spip.net/1846 La popularité
557
 * @see balise_POPULARITE_dist()
558
 * @see balise_POPULARITE_MAX_dist()
559
 * @see balise_POPULARITE_SITE_dist()
560
 *
561
 * @param Champ $p
562
 *     Pile au niveau de la balise
563
 * @return Champ
564
 *     Pile complétée par le code à générer
565
 **/
566
function balise_POPULARITE_ABSOLUE_dist($p) {
567
	$p->code = 'ceil(' .
568
		champ_sql('popularite', $p) .
569
		')';
570
	$p->interdire_scripts = false;
571
572
	return $p;
573
}
574
575
/**
576
 * Compile la balise `#POPULARITE_SITE` qui affiche la popularité du site
577
 *
578
 * La popularité du site est la somme de toutes les popularités absolues.
579
 *
580
 * @balise
581
 * @link https://www.spip.net/1846 La popularité
582
 * @see balise_POPULARITE_ABSOLUE_dist()
583
 * @see balise_POPULARITE_dist()
584
 * @see balise_POPULARITE_MAX_dist()
585
 *
586
 * @param Champ $p
587
 *     Pile au niveau de la balise
588
 * @return Champ
589
 *     Pile complétée par le code à générer
590
 **/
591
function balise_POPULARITE_SITE_dist($p) {
592
	$p->code = 'ceil($GLOBALS["meta"][\'popularite_total\'])';
593
	$p->interdire_scripts = false;
594
595
	return $p;
596
}
597
598
/**
599
 * Compile la balise `#POPULARITE_MAX` qui affiche la popularité maximum
600
 * parmis les popularités des articles
601
 *
602
 * Cela correspond à la popularité quotidienne de l'article
603
 *
604
 * @balise
605
 * @link https://www.spip.net/1846 La popularité
606
 * @see balise_POPULARITE_ABSOLUE_dist()
607
 * @see balise_POPULARITE_dist()
608
 * @see balise_POPULARITE_SITE_dist()
609
 *
610
 * @param Champ $p
611
 *     Pile au niveau de la balise
612
 * @return Champ
613
 *     Pile complétée par le code à générer
614
 **/
615
function balise_POPULARITE_MAX_dist($p) {
616
	$p->code = 'ceil($GLOBALS["meta"][\'popularite_max\'])';
617
	$p->interdire_scripts = false;
618
619
	return $p;
620
}
621
622
623
/**
624
 * Compile la balise `#VALEUR` retournant le champ `valeur`
625
 *
626
 * Utile dans une boucle DATA pour retourner une valeur.
627
 *
628
 * @balise
629
 * @link https://www.spip.net/5546 #CLE et #VALEUR
630
 * @see table_valeur()
631
 * @example
632
 *     ```
633
 *     #VALEUR renvoie le champ valeur
634
 *     #VALEUR{x} renvoie #VALEUR|table_valeur{x},
635
 *        équivalent à #X (si X n'est pas une balise spécifique à SPIP)
636
 *     #VALEUR{a/b} renvoie #VALEUR|table_valeur{a/b}
637
 *     ```
638
 *
639
 * @param Champ $p
640
 *     Pile au niveau de la balise
641
 * @return Champ
642
 *     Pile complétée par le code à générer
643
 **/
644
function balise_VALEUR_dist($p) {
645
	$b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
646
	$p->code = index_pile($p->id_boucle, 'valeur', $p->boucles, $b);;
647
	if (($v = interprete_argument_balise(1, $p)) !== null) {
648
		$p->code = 'table_valeur(' . $p->code . ', ' . $v . ')';
649
	}
650
	$p->interdire_scripts = true;
651
652
	return $p;
653
}
654
655
/**
656
 * Compile la balise `#EXPOSE` qui met en évidence l'élément sur lequel
657
 * la page se trouve
658
 *
659
 * Expose dans une boucle l'élément de la page sur laquelle on se trouve,
660
 * en retournant `on` si l'élément correspond à la page, une chaîne vide sinon.
661
 *
662
 * On peut passer les paramètres à faire retourner par la balise.
663
 *
664
 * @example
665
 *     ```
666
 *     <a href="#URL_ARTICLE"[ class="(#EXPOSE)"]>
667
 *     <a href="#URL_ARTICLE"[ class="(#EXPOSE{actif})"]>
668
 *     <a href="#URL_ARTICLE"[ class="(#EXPOSE{on,off})"]>
669
 *     ```
670
 *
671
 * @balise
672
 * @link https://www.spip.net/2319 Exposer un article
673
 * @uses calculer_balise_expose()
674
 *
675
 * @param Champ $p
676
 *     Pile au niveau de la balise
677
 * @return Champ
678
 *     Pile complétée par le code à générer
679
 **/
680
function balise_EXPOSE_dist($p) {
681
	$on = "'on'";
682
	$off = "''";
683
	if (($v = interprete_argument_balise(1, $p)) !== null) {
684
		$on = $v;
685
		if (($v = interprete_argument_balise(2, $p)) !== null) {
686
			$off = $v;
687
		}
688
689
	}
690
691
	return calculer_balise_expose($p, $on, $off);
692
}
693
694
/**
695
 * Calcul de la balise expose
696
 *
697
 * @see calcul_exposer()
698
 *
699
 * @param Champ $p
700
 *     Pile au niveau de la balise
701
 * @param string $on
702
 *     Texte à afficher si l'élément est exposé (code à écrire tel que "'on'")
703
 * @param string $off
704
 *     Texte à afficher si l'élément n'est pas exposé (code à écrire tel que "''")
705
 * @return Champ
706
 *     Pile complétée par le code à générer
707
 **/
708
function calculer_balise_expose($p, $on, $off) {
709
	$b = index_boucle($p);
710
	if (empty($p->boucles[$b]->primary)) {
711
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
712
		erreur_squelette($msg, $p);
713
	} else {
714
715
		$key = $p->boucles[$b]->primary;
716
		$type = $p->boucles[$p->id_boucle]->primary;
717
		$desc = $p->boucles[$b]->show;
718
		$connect = sql_quote($p->boucles[$b]->sql_serveur);
719
720
		// Ne pas utiliser champ_sql, on jongle avec le nom boucle explicite
721
		$c = index_pile($p->id_boucle, $type, $p->boucles);
722
723
		if (isset($desc['field']['id_parent'])) {
724
			$parent = 0; // pour if (!$parent) dans calculer_expose
725
		} elseif (isset($desc['field']['id_rubrique'])) {
726
			$parent = index_pile($p->id_boucle, 'id_rubrique', $p->boucles, $b);
727
		} elseif (isset($desc['field']['id_groupe'])) {
728
			$parent = index_pile($p->id_boucle, 'id_groupe', $p->boucles, $b);
729
		} else {
730
			$parent = "''";
731
		}
732
733
		$p->code = "(calcul_exposer($c, '$type', \$Pile[0], $parent, '$key', $connect) ? $on : $off)";
734
	}
735
736
	$p->interdire_scripts = false;
737
738
	return $p;
739
}
740
741
742
/**
743
 * Compile la balise `#INTRODUCTION`
744
 *
745
 * Retourne une introduction d'un objet éditorial, c'est à dire les 600
746
 * premiers caractères environ du champ 'texte' de l'objet ou le contenu
747
 * indiqué entre `<intro>` et `</intro>` de ce même champ.
748
 *
749
 * Pour les articles, l'introduction utilisée est celle du champ `descriptif`
750
 * s'il est renseigné, sinon il est pris dans les champs `chapo` et `texte` et
751
 * est par défaut limité à 500 caractères.
752
 *
753
 * Pour les rubriques, l'introduction utilisée est celle du champ `descriptif`
754
 * s'il est renseigné, sinon du champ texte.
755
 *
756
 * La balise accèpte 1 paramètre indiquant la longueur en nombre de caractères
757
 * de l'introduction.
758
 *
759
 * @see filtre_introduction_dist()
760
 * @example
761
 *     ```
762
 *     #INTRODUCTION
763
 *     #INTRODUCTION{300}
764
 *     ```
765
 *
766
 * @balise
767
 * @link https://www.spip.net/@introduction
768
 *
769
 * @param Champ $p
770
 *     Pile au niveau de la balise
771
 * @return Champ
772
 *     Pile complétée par le code à générer
773
 **/
774
function balise_INTRODUCTION_dist($p) {
775
776
	$type = $p->type_requete;
777
778
	$_texte = champ_sql('texte', $p);
779
	$trouver_table = charger_fonction('trouver_table', 'base');
780
	$desc = $trouver_table(table_objet_sql($type));
781
	$_descriptif = "''";
782
	if ($desc and isset($desc['field']['descriptif'])) {
783
		// notamment articles et rubriques mais aussi tout nouvel objet concerne
784
		$_descriptif = champ_sql('descriptif', $p);
785
	}
786
787
	// notamment les articles mais aussi tout nouvel objet concerne
788
	if ($desc and isset($desc['field']['chapo'])) {
789
		$_chapo = champ_sql('chapo', $p);
790
		$_texte = "(strlen($_descriptif))
791
		? ''
792
		: $_chapo . \"\\n\\n\" . $_texte";
793
	}
794
795
	// longueur en parametre, ou valeur par defaut
796
	$longueur_defaut = objet_info($type, 'introduction_longueur');
797
	if (!$longueur_defaut) {
798
		$longueur_defaut = 600;
799
	}
800
801
	$_suite = 'null';
802
	$_longueur = $longueur_defaut;
803
	if (($v = interprete_argument_balise(1, $p)) !== null) {
804
		$_longueur = 'is_numeric(' . $v . ')?intval(' . $v . '):' . $longueur_defaut;
805
		$_suite = '!is_numeric(' . $v . ')?' . $v . ':null';
806
	}
807
	if (($v2 = interprete_argument_balise(2, $p)) !== null) {
808
		$_suite = $v2;
809
	}
810
811
	$f = chercher_filtre('introduction');
812
	$p->code = "$f($_descriptif, $_texte, $_longueur, \$connect, $_suite)";
813
814
	#$p->interdire_scripts = true;
815
	$p->etoile = '*'; // propre est deja fait dans le calcul de l'intro
816
	return $p;
817
}
818
819
820
/**
821
 * Compile la balise `#LANG` qui affiche la langue de l'objet (ou d'une boucle supérieure),
822
 * et à defaut la langue courante
823
 *
824
 * La langue courante est celle du site ou celle qui a été passée dans l'URL par le visiteur.
825
 * L'étoile `#LANG*` n'affiche rien si aucune langue n'est trouvée dans le SQL ou le contexte.
826
 *
827
 * @balise
828
 * @link https://www.spip.net/3864
829
 *
830
 * @param Champ $p
831
 *     Pile au niveau de la balise
832
 * @return Champ
833
 *     Pile complétée par le code à générer
834
 **/
835
function balise_LANG_dist($p) {
836
	$_lang = champ_sql('lang', $p);
837
	if (!$p->etoile) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->etoile of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
838
		$p->code = "spip_htmlentities($_lang ? $_lang : \$GLOBALS['spip_lang'])";
839
	} else {
840
		$p->code = "spip_htmlentities($_lang)";
841
	}
842
	$p->interdire_scripts = false;
843
844
	return $p;
845
}
846
847
/**
848
 * Compile la balise `#LESAUTEURS` chargée d'afficher la liste des auteurs d'un objet
849
 *
850
 * - Soit le champ `lesauteurs` existe dans la table et à ce moment là,
851
 *   la balise retourne son contenu,
852
 * - soit la balise appelle le modele `lesauteurs.html` en lui passant
853
 *   le couple `objet` et `id_objet` dans son environnement.
854
 *
855
 * @balise
856
 * @link https://www.spip.net/3966 Description de la balise
857
 * @link https://www.spip.net/902 Description de la boucle ARTICLES
858
 * @link https://www.spip.net/911 Description de la boucle SYNDIC_ARTICLES
859
 *
860
 * @param Champ $p
861
 *     Pile au niveau de la balise
862
 * @return Champ
863
 *     Pile complétée par le code à générer
864
 */
865
function balise_LESAUTEURS_dist($p) {
866
	// Cherche le champ 'lesauteurs' dans la pile
867
	$_lesauteurs = champ_sql('lesauteurs', $p, false);
868
869
	// Si le champ n'existe pas (cas de spip_articles), on applique
870
	// le modele lesauteurs.html en passant id_article dans le contexte;
871
	// dans le cas contraire on prend le champ 'lesauteurs'
872
	// (cf extension sites/)
873
	if ($_lesauteurs
874
		and $_lesauteurs != '@$Pile[0][\'lesauteurs\']'
875
	) {
876
		$p->code = "safehtml($_lesauteurs)";
877
		// $p->interdire_scripts = true;
878
	} else {
879
		if (!$p->id_boucle) {
880
			$connect = '';
881
			$objet = 'article';
882
			$id_table_objet = 'id_article';
883
		} else {
884
			$b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
885
			$connect = $p->boucles[$b]->sql_serveur;
886
			$type_boucle = $p->boucles[$b]->type_requete;
887
			$objet = objet_type($type_boucle);
888
			$id_table_objet = id_table_objet($type_boucle);
889
		}
890
		$c = memoriser_contexte_compil($p);
891
892
		$p->code = sprintf(CODE_RECUPERER_FOND, "'modeles/lesauteurs'",
893
			"array('objet'=>'" . $objet .
894
			"','id_objet' => " . champ_sql($id_table_objet, $p) .
895
			",'$id_table_objet' => " . champ_sql($id_table_objet, $p) .
896
			($objet == 'article' ? "" : ",'id_article' => " . champ_sql('id_article', $p)) .
897
			")",
898
			"'trim'=>true, 'compil'=>array($c)",
899
			_q($connect));
900
		$p->interdire_scripts = false; // securite apposee par recuperer_fond()
901
	}
902
903
	return $p;
904
}
905
906
907
/**
908
 * Compile la balise `#RANG` chargée d'afficher le numéro de l'objet
909
 *
910
 * Affiche le « numero de l'objet ». Soit `1` quand on a un titre `1. Premier article`.
911
 *
912
 * Ceci est transitoire afin de préparer une migration vers un vrai système de
913
 * tri des articles dans une rubrique (et plus si affinités).
914
 * La balise permet d'extraire le numero masqué par le filtre `supprimer_numero`.
915
 *
916
 * La balise recupère le champ declaré dans la définition `table_titre`
917
 * de l'objet, ou à defaut du champ `titre`
918
 *
919
 * Si un champ `rang` existe, il est pris en priorité.
920
 *
921
 * @balise
922
 * @link https://www.spip.net/5495
923
 *
924
 * @param Champ $p
925
 *     Pile au niveau de la balise
926
 * @return Champ
927
 *     Pile complétée par le code à générer
928
 */
929
function balise_RANG_dist($p) {
930
	$b = index_boucle($p);
931
	if ($b === '') {
932
		$msg = array(
933
			'zbug_champ_hors_boucle',
934
			array('champ' => '#RANG')
935
		);
936
		erreur_squelette($msg, $p);
937
	} else {
938
		// chercher d'abord un champ sql rang (mais pas dans le env : defaut '' si on trouve pas de champ sql)
939
		// dans la boucle immediatement englobante uniquement
940
		// sinon on compose le champ calcule
941
		$_rang = champ_sql('rang', $p, '', false);
942
943
		// si pas trouve de champ sql rang :
944
		if (!$_rang or $_rang == "''") {
945
			$boucle = &$p->boucles[$b];
946
947
			// on gere le cas ou #RANG est une extraction du numero dans le titre
948
			$trouver_table = charger_fonction('trouver_table', 'base');
949
			$desc = $trouver_table($boucle->id_table);
950
			$_titre = ''; # où extraire le numero ?
951
			
952
			if (isset($desc['titre'])) {
953
				$t = $desc['titre'];
954
				if (
955
					// Soit on trouve avec la déclaration de la lang AVANT
956
					preg_match(';(?:lang\s*,)\s*(.*?titre)\s*(,|$);', $t, $m)
957
					// Soit on prend depuis le début
958
					or preg_match(';^(.*?titre)\s*(,|$);', $t, $m)
959
				) {
960
					$m = preg_replace(',as\s+titre$,i', '', $m[1]);
961
					$m = trim($m);
962
					if ($m != "''") {
963
						if (!preg_match(",\W,", $m)) {
964
							$m = $boucle->id_table . ".$m";
965
						}
966
						
967
						$m .= " AS titre_rang";
968
969
						$boucle->select[] = $m;
970
						$_titre = '$Pile[$SP][\'titre_rang\']';
971
					}
972
				}
973
			}
974
975
			// si on n'a rien trouvé, on utilise le champ titre classique
976
			if (!$_titre) {
977
				$_titre = champ_sql('titre', $p);
978
			}
979
980
			// et on recupere aussi les infos de liaison si on est en train d'editer les liens justement
981
			// cas des formulaires xxx_lies utilises par #FORMULAIRE_EDITER_LIENS
982
			$type_boucle = $boucle->type_requete;
983
			$objet = objet_type($type_boucle);
984
			$id_table_objet = id_table_objet($type_boucle);
985
			$_primary = champ_sql($id_table_objet, $p, '', false);
986
			$_env = '$Pile[0]';
987
988
			if (!$_titre) {$_titre = "''";}
989
			if (!$_primary) {$_primary = "''";}
990
			$_rang = "calculer_rang_smart($_titre, '$objet', $_primary, $_env)";
991
992
		}
993
		
994
		$p->code = $_rang;
995
		$p->interdire_scripts = false;
996
	}
997
	
998
	return $p;
999
}
1000
1001
1002
/**
1003
 * Compile la balise `#POPULARITE` qui affiche la popularité relative.
1004
 *
1005
 * C'est à dire le pourcentage de la fréquentation de l'article
1006
 * (la popularité absolue) par rapport à la popularité maximum.
1007
 *
1008
 * @balise
1009
 * @link https://www.spip.net/1846 La popularité
1010
 * @see balise_POPULARITE_ABSOLUE_dist()
1011
 * @see balise_POPULARITE_MAX_dist()
1012
 * @see balise_POPULARITE_SITE_dist()
1013
 *
1014
 * @param Champ $p
1015
 *     Pile au niveau de la balise
1016
 * @return Champ
1017
 *     Pile complétée par le code à générer
1018
 **/
1019
function balise_POPULARITE_dist($p) {
1020
	$_popularite = champ_sql('popularite', $p);
1021
	$p->code = "(ceil(min(100, 100 * $_popularite
1022
	/ max(1 , 0 + \$GLOBALS['meta']['popularite_max']))))";
1023
	$p->interdire_scripts = false;
1024
1025
	return $p;
1026
}
1027
1028
/**
1029
 * Code de compilation pour la balise `#PAGINATION`
1030
 *
1031
 * Le code produit est trompeur, car les modèles ne fournissent pas Pile[0].
1032
 * On produit un appel à `_request` si on ne l'a pas, mais c'est inexact:
1033
 * l'absence peut-être due à une faute de frappe dans le contexte inclus.
1034
 */
1035
define('CODE_PAGINATION',
1036
'%s($Numrows["%s"]["grand_total"],
1037
 		%s,
1038
		isset($Pile[0][%4$s])?$Pile[0][%4$s]:intval(_request(%4$s)),
1039
		%5$s, %6$s, %7$s, %8$s, array(%9$s))');
1040
1041
/**
1042
 * Compile la balise `#PAGINATION` chargée d'afficher une pagination
1043
 *
1044
 * Elle charge le modèle `pagination.html` (par défaut), mais un paramètre
1045
 * permet d'indiquer d'autres modèles. `#PAGINATION{nom}` utilisera le
1046
 * modèle `pagination_nom.html`.
1047
 *
1048
 * Cette balise nécessite le critère `pagination` sur la boucle où elle
1049
 * est utilisée.
1050
 *
1051
 * @balise
1052
 * @link https://www.spip.net/3367 Le système de pagination
1053
 * @see filtre_pagination_dist()
1054
 * @see critere_pagination_dist()
1055
 * @see balise_ANCRE_PAGINATION_dist()
1056
 * @example
1057
 *    ```
1058
 *    [<nav role="navigation" class="pagination">(#PAGINATION{prive})</nav>]
1059
 *    ```
1060
 *
1061
 * @param Champ $p
1062
 *     Pile au niveau de la balise
1063
 * @param string $liste
1064
 *     Afficher ou non les liens de pagination (variable de type `string`
1065
 *     car code à faire écrire au compilateur) :
1066
 *     - `true` pour les afficher
1067
 *     - `false` pour afficher uniquement l'ancre.
1068
 * @return Champ
1069
 *     Pile complétée par le code à générer
1070
 */
1071
function balise_PAGINATION_dist($p, $liste = 'true') {
1072
	$b = index_boucle_mere($p);
1073
1074
	// s'il n'y a pas de nom de boucle, on ne peut pas paginer
1075
	if ($b === '') {
1076
		$msg = array(
1077
			'zbug_champ_hors_boucle',
1078
			array('champ' => $liste ? 'PAGINATION' : 'ANCRE_PAGINATION')
1079
		);
1080
		erreur_squelette($msg, $p);
1081
1082
		return $p;
1083
	}
1084
1085
	// s'il n'y a pas de mode_partie, c'est qu'on se trouve
1086
	// dans un boucle recursive ou qu'on a oublie le critere {pagination}
1087
	if (!$p->boucles[$b]->mode_partie) {
1088
		if (!$p->boucles[$b]->table_optionnelle) {
1089
			$msg = array(
1090
				'zbug_pagination_sans_critere',
1091
				array('champ' => '#PAGINATION')
1092
			);
1093
			erreur_squelette($msg, $p);
1094
		}
1095
1096
		return $p;
1097
	}
1098
1099
	// a priori true
1100
	// si false, le compilo va bloquer sur des syntaxes avec un filtre sans argument qui suit la balise
1101
	// si true, les arguments simples (sans truc=chose) vont degager
1102
	$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false, false);
1103
	if (count($_contexte)) {
1104
		$key = key($_contexte);
1105
		if (is_numeric($key)) {
1106
			array_shift($_contexte);
1107
			$__modele = interprete_argument_balise(1, $p);
1108
		}
1109
	}
1110
1111
	if (count($_contexte)) {
1112
		$code_contexte = implode(',', $_contexte);
1113
	} else {
1114
		$code_contexte = '';
1115
	}
1116
1117
	$connect = $p->boucles[$b]->sql_serveur;
1118
	$pas = $p->boucles[$b]->total_parties;
1119
	$f_pagination = chercher_filtre('pagination');
1120
	$type = $p->boucles[$b]->modificateur['debut_nom'];
1121
	$modif = ($type[0] !== "'") ? "'debut'.$type"
1122
		: ("'debut" . substr($type, 1));
1123
1124
	$p->code = sprintf(CODE_PAGINATION, $f_pagination, $b, $type, $modif, $pas, $liste,
1125
		((isset($__modele) and $__modele) ? $__modele : "''"), _q($connect), $code_contexte);
1126
1127
	$p->boucles[$b]->numrows = true;
1128
	$p->interdire_scripts = false;
1129
1130
	return $p;
1131
}
1132
1133
1134
/**
1135
 * Compile la balise `#ANCRE_PAGINATION` chargée d'afficher l'ancre
1136
 * de la pagination
1137
 *
1138
 * Cette ancre peut ainsi être placée au-dessus la liste des éléments
1139
 * de la boucle alors qu'on mettra les liens de pagination en-dessous de
1140
 * cette liste paginée.
1141
 *
1142
 * Cette balise nécessite le critère `pagination` sur la boucle où elle
1143
 * est utilisée.
1144
 *
1145
 * @balise
1146
 * @link https://www.spip.net/3367 Le système de pagination
1147
 * @link https://www.spip.net/4328 Balise ANCRE_PAGINATION
1148
 * @see critere_pagination_dist()
1149
 * @see balise_PAGINATION_dist()
1150
 *
1151
 * @param Champ $p
1152
 *     Pile au niveau de la balise
1153
 * @return Champ
1154
 *     Pile complétée par le code à générer
1155
 **/
1156
function balise_ANCRE_PAGINATION_dist($p) {
1157
	if ($f = charger_fonction('PAGINATION', 'balise', true)) {
1158
		return $f($p, $liste = 'false');
1159
	} else {
1160
		return null;
1161
	} // ou une erreur ?
1162
}
1163
1164
1165
/**
1166
 * Compile la balise `#GRAND_TOTAL` qui retourne le nombre total de résultats
1167
 * d'une boucle
1168
 *
1169
 * Cette balise set équivalente à `#TOTAL_BOUCLE` sauf pour les boucles paginées.
1170
 * Dans ce cas elle indique le nombre total d'éléments répondant aux critères
1171
 * hors pagination.
1172
 *
1173
 * @balise
1174
 * @see balise_GRAND_TOTAL_dist()
1175
 *
1176
 * @param Champ $p
1177
 *     Pile au niveau de la balise
1178
 * @return Champ
1179
 *     Pile complétée par le code à générer
1180
 **/
1181 View Code Duplication
function balise_GRAND_TOTAL_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1182
	$b = index_boucle_mere($p);
1183
	if ($b === '') {
1184
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
1185
		erreur_squelette($msg, $p);
1186
	} else {
1187
		$p->code = "(isset(\$Numrows['$b']['grand_total'])
1188
			? \$Numrows['$b']['grand_total'] : \$Numrows['$b']['total'])";
1189
		$p->boucles[$b]->numrows = true;
1190
		$p->interdire_scripts = false;
1191
	}
1192
1193
	return $p;
1194
}
1195
1196
1197
/**
1198
 * Compile la balise `#SELF` qui retourne l’URL de la page appelée.
1199
 *
1200
 * Cette URL est nettoyée des variables propres à l’exécution de SPIP
1201
 * tel que `var_mode`.
1202
 *
1203
 * @note
1204
 *     Attention dans un `INCLURE()` ou une balise dynamique, on n'a pas le droit de
1205
 *     mettre en cache `#SELF` car il peut correspondre à une autre page (attaque XSS)
1206
 *     (Dans ce cas faire <INCLURE{self=#SELF}> pour différencier les caches.)
1207
 *
1208
 * @balise
1209
 * @link https://www.spip.net/4574
1210
 * @example
1211
 *     ```
1212
 *     <a href="[(#SELF|parametre_url{id_mot,#ID_MOT})]">...
1213
 *     ```
1214
 *
1215
 * @param Champ $p
1216
 *     Pile au niveau de la balise
1217
 * @return Champ
1218
 *     Pile complétée par le code à générer
1219
 **/
1220
function balise_SELF_dist($p) {
1221
	$p->code = 'self()';
1222
	$p->interdire_scripts = false;
1223
1224
	return $p;
1225
}
1226
1227
1228
/**
1229
 * Compile la balise `#CHEMIN` qui cherche un fichier dans les chemins
1230
 * connus de SPIP et retourne son chemin complet depuis la racine
1231
 *
1232
 * Signature : `#CHEMIN{chemin/vers/fichier.ext}`
1233
 *
1234
 * Retourne une chaîne vide si le fichier n'est pas trouvé.
1235
 *
1236
 * @balise
1237
 * @link https://www.spip.net/4332
1238
 * @see find_in_path() Recherche de chemin
1239
 * @example
1240
 *     ```
1241
 *     [<script type="text/javascript" src="(#CHEMIN{javascript/jquery.flot.js})"></script>]
1242
 *     [<link rel="stylesheet" href="(#CHEMIN{css/perso.css}|direction_css)" type="text/css" />]
1243
 *     ```
1244
 *
1245
 * @param Champ $p
1246
 *     Pile au niveau de la balise
1247
 * @return Champ
1248
 *     Pile complétée par le code à générer
1249
 **/
1250 View Code Duplication
function balise_CHEMIN_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1251
	$arg = interprete_argument_balise(1, $p);
1252
	if (!$arg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arg of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1253
		$msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN'));
1254
		erreur_squelette($msg, $p);
1255
	} else {
1256
		$p->code = 'find_in_path(' . $arg . ')';
1257
	}
1258
1259
	$p->interdire_scripts = false;
1260
1261
	return $p;
1262
}
1263
1264
/**
1265
 * Compile la balise `#CHEMIN_IMAGE` qui cherche une image dans le thème
1266
 * de l'espace privé utilisé par SPIP et retourne son chemin complet depuis
1267
 * la racine
1268
 *
1269
 * Signature : `#CHEMIN_IMAGE{image.png}`
1270
 *
1271
 * Retourne une chaîne vide si le fichier n'est pas trouvé.
1272
 *
1273
 * @balise
1274
 * @see chemin_image()
1275
 * @example
1276
 *     ```
1277
 *     #CHEMIN_IMAGE{article-24.png}
1278
 *     ```
1279
 *
1280
 * @param Champ $p
1281
 *     Pile au niveau de la balise
1282
 * @return Champ
1283
 *     Pile complétée par le code à générer
1284
 **/
1285 View Code Duplication
function balise_CHEMIN_IMAGE_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1286
	$arg = interprete_argument_balise(1, $p);
1287
	if (!$arg) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arg of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1288
		$msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN_IMAGE'));
1289
		erreur_squelette($msg, $p);
1290
	} else {
1291
		$p->code = 'chemin_image(' . $arg . ')';
1292
	}
1293
1294
	$p->interdire_scripts = false;
1295
	return $p;
1296
}
1297
1298
1299
/**
1300
 * Compile la balise `#ENV` qui permet de récupérer le contexte d'environnement
1301
 * transmis à un squelette.
1302
 *
1303
 * La syntaxe `#ENV{toto, valeur par defaut}`
1304
 * renverra `valeur par defaut` si `$toto` est vide.
1305
 *
1306
 * La recherche de la clé s'appuyant sur la fonction `table_valeur`
1307
 * il est possible de demander un sous élément d'un tableau :
1308
 * `#ENV{toto/sous/element, valeur par defaut}` retournera l'équivalent de
1309
 * `#ENV{toto}|table_valeur{sous/element}` c'est-à-dire en quelque sorte
1310
 * `$env['toto']['sous']['element']` s'il existe, sinon la valeur par défaut.
1311
 *
1312
 * Si le tableau est vide on renvoie `''` (utile pour `#SESSION`)
1313
 *
1314
 * Enfin, la balise utilisée seule `#ENV` retourne le tableau complet
1315
 * de l'environnement. À noter que ce tableau est retourné sérialisé.
1316
 *
1317
 * En standard est appliqué le filtre `entites_html`, mais si l'étoile est
1318
 * utilisée pour désactiver les filtres par défaut, par exemple avec
1319
 * `[(#ENV*{toto})]` , il *faut* s'assurer de la sécurité
1320
 * anti-javascript, par exemple en filtrant avec `safehtml` : `[(#ENV*{toto}|safehtml)]`
1321
 *
1322
 *
1323
 * @param Champ $p
1324
 *     Pile ; arbre de syntaxe abstrait positionné au niveau de la balise.
1325
 * @param array $src
0 ignored issues
show
Documentation introduced by
Should the type for parameter $src not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1326
 *     Tableau dans lequel chercher la clé demandée en paramètre de la balise.
1327
 *     Par defaut prend dans le contexte du squelette.
1328
 * @return Champ
1329
 *     Pile completée du code PHP d'exécution de la balise
1330
 **/
1331
function balise_ENV_dist($p, $src = null) {
1332
1333
	// cle du tableau desiree
1334
	$_nom = interprete_argument_balise(1, $p);
1335
	// valeur par defaut
1336
	$_sinon = interprete_argument_balise(2, $p);
1337
1338
	// $src est un tableau de donnees sources eventuellement transmis
1339
	// en absence, on utilise l'environnement du squelette $Pile[0]
1340
1341
	if (!$_nom) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_nom of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1342
		// cas de #ENV sans argument : on retourne le serialize() du tableau
1343
		// une belle fonction [(#ENV|affiche_env)] serait pratique
1344
		if ($src) {
1345
			$p->code = '(is_array($a = (' . $src . ')) ? serialize($a) : "")';
1346
		} else {
1347
			$p->code = '@serialize($Pile[0])';
1348
		}
1349
	} else {
1350
		if (!$src) {
1351
			$src = '@$Pile[0]';
1352
		}
1353
		if ($_sinon) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_sinon of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1354
			$p->code = "sinon(table_valeur($src, (string)$_nom, null), $_sinon)";
1355
		} else {
1356
			$p->code = "table_valeur($src, (string)$_nom, null)";
1357
		}
1358
	}
1359
1360
	#$p->interdire_scripts = true;
1361
1362
	return $p;
1363
}
1364
1365
/**
1366
 * Compile la balise `#CONFIG` qui retourne une valeur de configuration
1367
 *
1368
 * Cette balise appelle la fonction `lire_config()` pour obtenir les
1369
 * configurations du site.
1370
 *
1371
 * Par exemple `#CONFIG{gerer_trad}` donne 'oui ou 'non' selon le réglage.
1372
 *
1373
 * Le 3ème argument permet de contrôler la sérialisation du résultat
1374
 * (mais ne sert que pour le dépot `meta`) qui doit parfois désérialiser,
1375
 * par exemple avec `|in_array{#CONFIG{toto,#ARRAY,1}}`. Ceci n'affecte
1376
 * pas d'autres dépots et `|in_array{#CONFIG{toto/,#ARRAY}}` sera
1377
 * équivalent.
1378
 *
1379
 * Òn peut appeler d'autres tables que `spip_meta` avec un
1380
 * `#CONFIG{/infos/champ,defaut}` qui lit la valeur de `champ`
1381
 * dans une table des meta qui serait `spip_infos`
1382
 *
1383
 * @balise
1384
 * @link https://www.spip.net/4335
1385
 *
1386
 * @param Champ $p
1387
 *     Pile au niveau de la balise.
1388
 * @return Champ
1389
 *     Pile completée du code PHP d'exécution de la balise
1390
 */
1391
function balise_CONFIG_dist($p) {
1392
	if (!$arg = interprete_argument_balise(1, $p)) {
1393
		$arg = "''";
1394
	}
1395
	$_sinon = interprete_argument_balise(2, $p);
1396
	$_unserialize = sinon(interprete_argument_balise(3, $p), "false");
1397
1398
	$p->code = '(include_spip(\'inc/config\')?lire_config(' . $arg . ',' .
1399
		($_sinon && $_sinon != "''" ? $_sinon : 'null') . ',' . $_unserialize . "):'')";
0 ignored issues
show
Bug Best Practice introduced by
The expression $_sinon of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1400
1401
	return $p;
1402
}
1403
1404
1405
/**
1406
 * Compile la balise `#CONNECT` qui retourne le nom du connecteur
1407
 * de base de données
1408
 *
1409
 * Retourne le nom du connecteur de base de données utilisé (le nom
1410
 * du fichier `config/xx.php` sans l'extension, utilisé pour calculer
1411
 * les données du squelette).
1412
 *
1413
 * Retourne `NULL` si le connecteur utilisé est celui par défaut de SPIP
1414
 * (connect.php), sinon retourne son nom.
1415
 *
1416
 * @balise
1417
 *
1418
 * @param Champ $p
1419
 *     Pile au niveau de la balise.
1420
 * @return Champ
1421
 *     Pile completée du code PHP d'exécution de la balise
1422
 */
1423
function balise_CONNECT_dist($p) {
1424
	$p->code = '($connect ? $connect : NULL)';
1425
	$p->interdire_scripts = false;
1426
1427
	return $p;
1428
}
1429
1430
1431
/**
1432
 * Compile la balise `#SESSION` qui permet d’accéder aux informations
1433
 * liées au visiteur authentifié et de différencier automatiquement
1434
 * le cache en fonction du visiteur.
1435
 *
1436
 * Cette balise est un tableau des données du visiteur (nom, email etc).
1437
 * Si elle est invoquée, elle lève un drapeau dans le fichier cache, qui
1438
 * permet à public/cacher de créer un cache différent par visiteur
1439
 *
1440
 * @balise
1441
 * @link https://www.spip.net/3979
1442
 * @see balise_AUTORISER_dist()
1443
 * @see balise_SESSION_SET_dist()
1444
 * @example
1445
 *     ```
1446
 *     #SESSION{nom}
1447
 *     ```
1448
 *
1449
 * @param Champ $p
1450
 *     Pile au niveau de la balise.
1451
 * @return Champ
1452
 *     Pile completée du code PHP d'exécution de la balise
1453
 **/
1454
function balise_SESSION_dist($p) {
1455
	$p->descr['session'] = true;
1456
1457
	$f = function_exists('balise_ENV')
1458
		? 'balise_ENV'
1459
		: 'balise_ENV_dist';
1460
1461
	$p = $f($p, '$GLOBALS["visiteur_session"]');
1462
1463
	return $p;
1464
}
1465
1466
1467
/**
1468
 * Compile la balise `#SESSION_SET` qui d’insérer dans la session
1469
 * des données supplémentaires
1470
 *
1471
 * @balise
1472
 * @link https://www.spip.net/3984
1473
 * @see balise_AUTORISER_dist()
1474
 * @see balise_SESSION_SET_dist()
1475
 * @example
1476
 *     ```
1477
 *     #SESSION_SET{x,y} ajoute x=y dans la session du visiteur
1478
 *     ```
1479
 *
1480
 * @param Champ $p
1481
 *     Pile au niveau de la balise.
1482
 * @return Champ
1483
 *     Pile completée du code PHP d'exécution de la balise
1484
 **/
1485
function balise_SESSION_SET_dist($p) {
1486
	$_nom = interprete_argument_balise(1, $p);
1487
	$_val = interprete_argument_balise(2, $p);
1488
	if (!$_nom or !$_val) {
1489
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SESSION_SET'));
1490
		erreur_squelette($err_b_s_a, $p);
1491
	} else {
1492
		$p->code = '(include_spip("inc/session") AND session_set(' . $_nom . ',' . $_val . '))';
1493
	}
1494
1495
	$p->interdire_scripts = false;
1496
1497
	return $p;
1498
}
1499
1500
1501
/**
1502
 * Compile la balise `#EVAL` qui évalue un code PHP
1503
 *
1504
 * À utiliser avec précautions !
1505
 *
1506
 * @balise
1507
 * @link https://www.spip.net/4587
1508
 * @example
1509
 *     ```
1510
 *     #EVAL{6+9}
1511
 *     #EVAL{'date("Y-m-d")'}
1512
 *     #EVAL{$_SERVER['REQUEST_URI']}
1513
 *     #EVAL{'str_replace("r","z", "roger")'}  (attention les "'" sont interdits)
1514
 *     ```
1515
 *
1516
 * @note
1517
 *     `#EVAL{code}` produit `eval('return code;')`
1518
 *      mais si le code est une expression sans balise, on se dispense
1519
 *      de passer par une construction si compliquée, et le code est
1520
 *      passé tel quel (entre parenthèses, et protégé par interdire_scripts)
1521
 *
1522
 * @param Champ $p
1523
 *     Pile au niveau de la balise.
1524
 * @return Champ
1525
 *     Pile completée du code PHP d'exécution de la balise
1526
 **/
1527
function balise_EVAL_dist($p) {
1528
	$php = interprete_argument_balise(1, $p);
1529
	if ($php) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $php of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1530
		# optimisation sur les #EVAL{une expression sans #BALISE}
1531
		# attention au commentaire "// x signes" qui precede
1532 View Code Duplication
		if (preg_match(",^([[:space:]]*//[^\n]*\n)'([^']+)'$,ms",
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1533
			$php, $r)) {
1534
			$p->code = /* $r[1]. */
1535
				'(' . $r[2] . ')';
1536
		} else {
1537
			$p->code = "eval('return '.$php.';')";
1538
		}
1539
	} else {
1540
		$msg = array('zbug_balise_sans_argument', array('balise' => ' EVAL'));
1541
		erreur_squelette($msg, $p);
1542
	}
1543
1544
	#$p->interdire_scripts = true;
1545
1546
	return $p;
1547
}
1548
1549
1550
/**
1551
 * Compile la balise `#CHAMP_SQL` qui renvoie la valeur d'un champ SQL
1552
 *
1553
 * Signature : `#CHAMP_SQL{champ}`
1554
 *
1555
 * Cette balise permet de récupérer par exemple un champ `notes` dans une table
1556
 * SQL externe (impossible avec la balise `#NOTES` qui est une balise calculée).
1557
 *
1558
 * Ne permet pas de passer une expression comme argument, qui ne peut
1559
 * être qu'un texte statique !
1560
 *
1561
 * @balise
1562
 * @link https://www.spip.net/4041
1563
 * @see champ_sql()
1564
 * @example
1565
 *     ```
1566
 *     #CHAMP_SQL{notes}
1567
 *     ```
1568
 *
1569
 * @param Champ $p
1570
 *     Pile au niveau de la balise
1571
 * @return Champ
1572
 *     Pile complétée par le code à générer
1573
 **/
1574
function balise_CHAMP_SQL_dist($p) {
1575
1576
	if ($p->param
1577
		and isset($p->param[0][1][0])
1578
		and $champ = ($p->param[0][1][0]->texte)
1579
	) {
1580
		$p->code = champ_sql($champ, $p);
1581
	} else {
1582
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => ' CHAMP_SQL'));
1583
		erreur_squelette($err_b_s_a, $p);
1584
	}
1585
1586
	#$p->interdire_scripts = true;
1587
	return $p;
1588
}
1589
1590
/**
1591
 * Compile la balise `#VAL` qui retourne simplement le premier argument
1592
 * qui lui est transmis
1593
 *
1594
 * Cela permet d'appliquer un filtre à une chaîne de caractère
1595
 *
1596
 * @balise
1597
 * @link https://www.spip.net/4026
1598
 * @example
1599
 *     ```
1600
 *     #VAL retourne ''
1601
 *     #VAL{x} retourne 'x'
1602
 *     #VAL{1,2} renvoie '1' (2 est considéré comme un autre paramètre)
1603
 *     #VAL{'1,2'} renvoie '1,2'
1604
 *     [(#VAL{a_suivre}|bouton_spip_rss)]
1605
 *     ```
1606
 *
1607
 * @param Champ $p
1608
 *     Pile au niveau de la balise
1609
 * @return Champ
1610
 *     Pile complétée par le code à générer
1611
 **/
1612
function balise_VAL_dist($p) {
1613
	$p->code = interprete_argument_balise(1, $p);
1614
	if (!strlen($p->code)) {
1615
		$p->code = "''";
1616
	}
1617
	$p->interdire_scripts = false;
1618
1619
	return $p;
1620
}
1621
1622
/**
1623
 * Compile la balise `#REM` servant à commenter du texte
1624
 *
1625
 * Retourne toujours une chaîne vide.
1626
 *
1627
 * @balise
1628
 * @link https://www.spip.net/4578
1629
 * @example
1630
 *     ```
1631
 *     [(#REM)
1632
 *       Ceci est une remarque ou un commentaire,
1633
 *       non affiché dans le code généré
1634
 *     ]
1635
 *     ```
1636
 *
1637
 * @note
1638
 *     La balise `#REM` n'empêche pas l'exécution des balises SPIP contenues
1639
 *     dedans (elle ne sert pas à commenter du code pour empêcher son
1640
 *     exécution).
1641
 *
1642
 * @param Champ $p
1643
 *     Pile au niveau de la balise
1644
 * @return Champ
1645
 *     Pile complétée par le code à générer
1646
 **/
1647
function balise_REM_dist($p) {
1648
	$p->code = "''";
1649
	$p->interdire_scripts = false;
1650
1651
	return $p;
1652
}
1653
1654
/**
1655
 * Une balise #NULL quand on a besoin de passer un argument null sur l'appel d'un filtre ou formulaire
1656
 * (evite un #EVAL{null})
1657
 * @param $p
1658
 * @return mixed
1659
 */
1660
function balise_NULL_dist($p) {
1661
	$p->code = "null";
1662
	$p->interdire_scripts = false;
1663
1664
	return $p;
1665
}
1666
1667
1668
/**
1669
 * Compile la balise `#HTTP_HEADER` envoyant des entêtes de retour HTTP
1670
 *
1671
 * Doit être placée en tête de fichier et ne fonctionne pas dans une
1672
 * inclusion.
1673
 *
1674
 * @balise
1675
 * @link https://www.spip.net/4631
1676
 * @example
1677
 *     ```
1678
 *     #HTTP_HEADER{Content-Type: text/csv; charset=#CHARSET}
1679
 *     ```
1680
 *
1681
 * @param Champ $p
1682
 *     Pile au niveau de la balise
1683
 * @return Champ
1684
 *     Pile complétée par le code à générer
1685
 **/
1686 View Code Duplication
function balise_HTTP_HEADER_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1687
1688
	$header = interprete_argument_balise(1, $p);
1689
	if (!$header) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $header of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1690
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'HTTP_HEADER'));
1691
		erreur_squelette($err_b_s_a, $p);
1692
	} else {
1693
		$p->code = "'<'.'?php header(' . _q("
1694
			. $header
1695
			. ") . '); ?'.'>'";
1696
	}
1697
	$p->interdire_scripts = false;
1698
1699
	return $p;
1700
}
1701
1702
1703
/**
1704
 * Compile la balise `#FILTRE` qui exécute un filtre à l'ensemble du squelette
1705
 * une fois calculé.
1706
 *
1707
 * Le filtrage se fait au niveau du squelette, sans s'appliquer aux `<INCLURE>`.
1708
 * Plusieurs filtres peuvent être indiqués, séparés par des barres verticales `|`
1709
 *
1710
 * @balise
1711
 * @link https://www.spip.net/4894
1712
 * @example
1713
 *     ```
1714
 *     #FILTRE{compacte_head}
1715
 *     #FILTRE{supprimer_tags|filtrer_entites|trim}
1716
 *     ```
1717
 *
1718
 * @param Champ $p
1719
 *     Pile au niveau de la balise
1720
 * @return Champ
0 ignored issues
show
Documentation introduced by
Should the return type not be Champ|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1721
 *     Pile complétée par le code à générer
1722
 **/
1723
function balise_FILTRE_dist($p) {
1724
	if ($p->param) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->param of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1725
		$args = array();
1726
		foreach ($p->param as $i => $ignore) {
1727
			$args[] = interprete_argument_balise($i + 1, $p);
1728
		}
1729
		$p->code = "'<' . '"
1730
			. '?php header("X-Spip-Filtre: \'.'
1731
			. join('.\'|\'.', $args)
1732
			. " . '\"); ?'.'>'";
1733
1734
		$p->interdire_scripts = false;
1735
1736
		return $p;
1737
	}
1738
}
1739
1740
1741
/**
1742
 * Compile la balise `#CACHE` definissant la durée de validité du cache du squelette
1743
 *
1744
 * Signature : `#CACHE{duree[,type]}`
1745
 *
1746
 * Le premier argument est la durée en seconde du cache. Le second
1747
 * (par défaut `statique`) indique le type de cache :
1748
 *
1749
 * - `cache-client` autorise gestion du IF_MODIFIED_SINCE
1750
 * - `statique` ne respecte pas l'invalidation par modif de la base
1751
 *   (mais s'invalide tout de même à l'expiration du delai)
1752
 *
1753
 * @balise
1754
 * @see ecrire/public/cacher.php
1755
 * @link https://www.spip.net/4330
1756
 * @example
1757
 *     ```
1758
 *     #CACHE{24*3600}
1759
 *     #CACHE{24*3600, cache-client}
1760
 *     #CACHE{0} pas de cache
1761
 *     ```
1762
 * @note
1763
 *   En absence de cette balise la durée est du cache est donné
1764
 *   par la constante `_DUREE_CACHE_DEFAUT`
1765
 *
1766
 * @param Champ $p
1767
 *     Pile au niveau de la balise
1768
 * @return Champ
1769
 *     Pile complétée par le code à générer
1770
 **/
1771
function balise_CACHE_dist($p) {
1772
1773
	if ($p->param) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->param of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1774
		$duree = valeur_numerique($p->param[0][1][0]->texte);
1775
1776
		// noter la duree du cache dans un entete proprietaire
1777
1778
		$code = "'<'.'" . '?php header("X-Spip-Cache: '
1779
			. $duree
1780
			. '"); ?' . "'.'>'";
1781
1782
		// Remplir le header Cache-Control
1783
		// cas #CACHE{0}
1784
		if ($duree == 0) {
1785
			$code .= ".'<'.'"
1786
				. '?php header("Cache-Control: no-cache, must-revalidate"); ?'
1787
				. "'.'><'.'"
1788
				. '?php header("Pragma: no-cache"); ?'
1789
				. "'.'>'";
1790
		}
1791
1792
		// recuperer les parametres suivants
1793
		$i = 1;
1794
		while (isset($p->param[0][++$i])) {
1795
			$pa = ($p->param[0][$i][0]->texte);
1796
1797
			if ($pa == 'cache-client'
1798
				and $duree > 0
1799
			) {
1800
				$code .= ".'<'.'" . '?php header("Cache-Control: max-age='
1801
					. $duree
1802
					. '"); ?' . "'.'>'";
1803
				// il semble logique, si on cache-client, de ne pas invalider
1804
				$pa = 'statique';
1805
			}
1806
1807
			if ($pa == 'statique'
1808
				and $duree > 0
1809
			) {
1810
				$code .= ".'<'.'" . '?php header("X-Spip-Statique: oui"); ?' . "'.'>'";
1811
			}
1812
		}
1813
	} else {
1814
		$code = "''";
1815
	}
1816
	$p->code = $code;
1817
	$p->interdire_scripts = false;
1818
1819
	return $p;
1820
}
1821
1822
1823
/**
1824
 * Compile la balise `#INSERT_HEAD` permettant d'insérer du contenu dans
1825
 * le `<head>` d'une page HTML
1826
 *
1827
 * La balise permet aux plugins d'insérer des styles, js ou autre
1828
 * dans l'entête sans modification du squelette.
1829
 * Les css doivent être inserées de préférence par `#INSERT_HEAD_CSS`
1830
 * pour en faciliter la surcharge.
1831
 *
1832
 * On insère ici aussi un morceau de PHP qui verifiera à l'exécution
1833
 * que le pipeline `insert_head_css` a bien été vu
1834
 * et dans le cas contraire l'appelera. Ceal permet de ne pas oublier
1835
 * les css de `#INSERT_HEAD_CSS` même si cette balise n'est pas presente.
1836
 *
1837
 * Il faut mettre ce php avant le `insert_head` car le compresseur y mets
1838
 * ensuite un php du meme type pour collecter
1839
 * CSS et JS, et on ne veut pas qu'il rate les css insérées en fallback
1840
 * par `insert_head_css_conditionnel`.
1841
 *
1842
 * @link https://www.spip.net/4629
1843
 * @see balise_INSERT_HEAD_CSS_dist()
1844
 *
1845
 * @param Champ $p
1846
 *     Pile au niveau de la balise
1847
 * @return Champ
1848
 *     Pile complétée par le code à générer
1849
 */
1850
function balise_INSERT_HEAD_dist($p) {
1851
	$p->code = "'<'.'"
1852
		. '?php header("X-Spip-Filtre: insert_head_css_conditionnel"); ?'
1853
		. "'.'>'";
1854
	$p->code .= ". pipeline('insert_head','<!-- insert_head -->')";
1855
	$p->interdire_scripts = false;
1856
1857
	return $p;
1858
}
1859
1860
/**
1861
 * Compile la balise `#INSERT_HEAD_CSS` homologue de `#INSERT_HEAD` pour les CSS
1862
 *
1863
 * Et par extension pour le JS inline qui doit préférentiellement
1864
 * être inséré avant les CSS car bloquant sinon.
1865
 *
1866
 * @link https://www.spip.net/4605
1867
 * @see balise_INSERT_HEAD_dist()
1868
 *
1869
 * @param Champ $p
1870
 *     Pile au niveau de la balise
1871
 * @return Champ
1872
 *     Pile complétée par le code à générer
1873
 */
1874
function balise_INSERT_HEAD_CSS_dist($p) {
1875
	$p->code = "pipeline('insert_head_css','<!-- insert_head_css -->')";
1876
	$p->interdire_scripts = false;
1877
1878
	return $p;
1879
}
1880
1881
/**
1882
 * Compile la balise `#INCLUDE` alias de `#INCLURE`
1883
 *
1884
 * @balise
1885
 * @see balise_INCLURE_dist()
1886
 *
1887
 * @param Champ $p
1888
 *     Pile au niveau de la balise
1889
 * @return Champ
1890
 *     Pile complétée par le code à générer
1891
 **/
1892
function balise_INCLUDE_dist($p) {
1893
	if (function_exists('balise_INCLURE')) {
1894
		return balise_INCLURE($p);
1895
	} else {
1896
		return balise_INCLURE_dist($p);
1897
	}
1898
}
1899
1900
/**
1901
 * Compile la balise `#INCLURE` qui inclut un résultat de squelette
1902
 *
1903
 * Signature : `[(#INCLURE{fond=nom_du_squelette, argument, argument=xx})]`
1904
 *
1905
 * L'argument `env` permet de transmettre tout l'environnement du squelette
1906
 * en cours au squelette inclus.
1907
 *
1908
 * On parle d’inclusion « statique » car le résultat de compilation est
1909
 * ajouté au squelette en cours, dans le même fichier de cache.
1910
 * Cette balise est donc différente d’une inclusion « dynamique » avec
1911
 * `<INCLURE.../>` qui, elle, crée un fichier de cache séparé
1912
 * (avec une durée de cache qui lui est propre).
1913
 *
1914
 * L'inclusion est realisée au calcul du squelette, pas au service
1915
 * ainsi le produit du squelette peut être utilisé en entrée de filtres
1916
 * à suivre. On peut faire un `#INCLURE{fichier}` sans squelette
1917
 * (Incompatible avec les balises dynamiques).
1918
 *
1919
 * @balise
1920
 * @example
1921
 *     ```
1922
 *     [(#INCLURE{fond=inclure/documents,id_article, env})]
1923
 *     ```
1924
 *
1925
 * @param Champ $p
1926
 *     Pile au niveau de la balise
1927
 * @return Champ
1928
 *     Pile complétée par le code à générer
1929
 **/
1930
function balise_INCLURE_dist($p) {
1931
	$id_boucle = $p->id_boucle;
1932
	// la lang n'est pas passe de facon automatique par argumenter
1933
	// mais le sera pas recuperer_fond, sauf si etoile=>true est passe
1934
	// en option
1935
1936
	$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $id_boucle, false, false);
1937
1938
	// erreur de syntaxe = fond absent
1939
	// (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
1940
	if (!$_contexte) {
1941
		$contexte = array();
0 ignored issues
show
Unused Code introduced by
$contexte is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1942
	}
1943
1944
	if (isset($_contexte['fond'])) {
1945
1946
		$f = $_contexte['fond'];
1947
		// toujours vrai :
1948
		if (preg_match('/^.fond.\s*=>(.*)$/s', $f, $r)) {
1949
			$f = $r[1];
1950
			unset($_contexte['fond']);
1951
		} else {
1952
			spip_log("compilation de #INCLURE a revoir");
1953
		}
1954
1955
		// #INCLURE{doublons}
1956
		if (isset($_contexte['doublons'])) {
1957
			$_contexte['doublons'] = "'doublons' => \$doublons";
1958
		}
1959
1960
		// Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
1961
		$flag_env = false;
1962 View Code Duplication
		if (isset($_contexte['env']) or isset($_contexte['self'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1963
			$flag_env = true;
1964
			unset($_contexte['env']);
1965
		}
1966
1967
		$_options = array();
1968 View Code Duplication
		if (isset($_contexte['ajax'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1969
			$_options[] = preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
1970
			unset($_contexte['ajax']);
1971
		}
1972
		if ($p->etoile) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->etoile of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1973
			$_options[] = "'etoile'=>true";
1974
		}
1975
		$_options[] = "'compil'=>array(" . memoriser_contexte_compil($p) . ")";
1976
1977
		$_l = 'array(' . join(",\n\t", $_contexte) . ')';
1978
		if ($flag_env) {
1979
			$_l = "array_merge(\$Pile[0],$_l)";
1980
		}
1981
1982
		$p->code = sprintf(CODE_RECUPERER_FOND, $f, $_l, join(',', $_options), "_request('connect')");
1983
1984
	} elseif (!isset($_contexte[1])) {
1985
		$msg = array('zbug_balise_sans_argument', array('balise' => ' INCLURE'));
1986
		erreur_squelette($msg, $p);
1987
	} else {
1988
		$p->code = 'charge_scripts(' . $_contexte[1] . ',false)';
1989
	}
1990
1991
	$p->interdire_scripts = false; // la securite est assuree par recuperer_fond
1992
	return $p;
1993
}
1994
1995
1996
/**
1997
 * Compile la balise `#MODELE` qui inclut un résultat de squelette de modèle
1998
 *
1999
 * `#MODELE{nom}` insère le résultat d’un squelette contenu dans le
2000
 * répertoire `modeles/`. L’identifiant de la boucle parente est transmis
2001
 * par défaut avec le paramètre `id` à cette inclusion.
2002
 *
2003
 * Des arguments supplémentaires peuvent être transmis :
2004
 * `[(#MODELE{nom, argument=xx, argument})]`
2005
 *
2006
 * @balise
2007
 * @see balise_INCLURE_dist()
2008
 * @example
2009
 *     ```
2010
 *     #MODELE{article_traductions}
2011
 *     ```
2012
 *
2013
 * @param Champ $p
2014
 *     Pile au niveau de la balise
2015
 * @return Champ
2016
 *     Pile complétée par le code à générer
2017
 **/
2018
function balise_MODELE_dist($p) {
2019
2020
	$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false);
2021
2022
	// erreur de syntaxe = fond absent
2023
	// (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
2024
	if (!$_contexte) {
2025
		$_contexte = array();
2026
	}
2027
2028
	if (!isset($_contexte[1])) {
2029
		$msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE'));
2030
		erreur_squelette($msg, $p);
2031
	} else {
2032
		$nom = $_contexte[1];
2033
		unset($_contexte[1]);
2034
2035
		if (preg_match("/^\s*'[^']*'/s", $nom)) {
2036
			$nom = "'modeles/" . substr($nom, 1);
2037
		} else {
2038
			$nom = "'modeles/' . $nom";
2039
		}
2040
2041
		$flag_env = false;
2042
		if (isset($_contexte['env'])) {
2043
			$flag_env = true;
2044
			unset($_contexte['env']);
2045
		}
2046
2047
		// Incoherence dans la syntaxe du contexte. A revoir.
2048
		// Reserver la cle primaire de la boucle courante si elle existe
2049
		if (isset($p->boucles[$p->id_boucle]->primary)) {
2050
			$primary = $p->boucles[$p->id_boucle]->primary;
2051
			if (!strpos($primary, ',')) {
2052
				$id = champ_sql($primary, $p);
2053
				$_contexte[] = "'$primary'=>" . $id;
2054
				$_contexte[] = "'id'=>" . $id;
2055
			}
2056
		}
2057
		$_contexte[] = "'recurs'=>(++\$recurs)";
2058
		$connect = '';
2059
		if (isset($p->boucles[$p->id_boucle])) {
2060
			$connect = $p->boucles[$p->id_boucle]->sql_serveur;
2061
		}
2062
2063
		$_options = memoriser_contexte_compil($p);
2064
		$_options = "'compil'=>array($_options), 'trim'=>true";
2065 View Code Duplication
		if (isset($_contexte['ajax'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2066
			$_options .= ", " . preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
2067
			unset($_contexte['ajax']);
2068
		}
2069
2070
		$_l = 'array(' . join(",\n\t", $_contexte) . ')';
2071
		if ($flag_env) {
2072
			$_l = "array_merge(\$Pile[0],$_l)";
2073
		}
2074
2075
		$page = sprintf(CODE_RECUPERER_FOND, $nom, $_l, $_options, _q($connect));
2076
2077
		$p->code = "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t$page)\n";
2078
2079
		$p->interdire_scripts = false; // securite assuree par le squelette
2080
	}
2081
2082
	return $p;
2083
}
2084
2085
2086
/**
2087
 * Compile la balise `#SET` qui affecte une variable locale au squelette
2088
 *
2089
 * Signature : `#SET{cle,valeur}`
2090
 *
2091
 * @balise
2092
 * @link https://www.spip.net/3990 Balises #SET et #GET
2093
 * @see balise_GET_dist()
2094
 * @example
2095
 *     ```
2096
 *     #SET{nb,5}
2097
 *     #GET{nb} // affiche 5
2098
 *     ```
2099
 *
2100
 * @param Champ $p
2101
 *     Pile au niveau de la balise
2102
 * @return Champ
2103
 *     Pile complétée par le code à générer
2104
 **/
2105 View Code Duplication
function balise_SET_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2106
	$_nom = interprete_argument_balise(1, $p);
2107
	$_val = interprete_argument_balise(2, $p);
2108
2109
	if (!$_nom or !$_val) {
2110
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SET'));
2111
		erreur_squelette($err_b_s_a, $p);
2112
	}
2113
	// affectation $_zzz inutile, mais permet de contourner un bug OpCode cache sous PHP 5.5.4
2114
	// cf https://bugs.php.net/bug.php?id=65845
2115
	else {
2116
		$p->code = "vide(\$Pile['vars'][\$_zzz=(string)$_nom] = $_val)";
2117
	}
2118
2119
	$p->interdire_scripts = false; // la balise ne renvoie rien
2120
	return $p;
2121
}
2122
2123
2124
/**
2125
 * Compile la balise `#GET` qui récupère une variable locale au squelette
2126
 *
2127
 * Signature : `#GET{cle[,defaut]}`
2128
 *
2129
 * La clé peut obtenir des sous clés séparés par des `/`
2130
 *
2131
 * @balise
2132
 * @link https://www.spip.net/3990 Balises #SET et #GET
2133
 * @see balise_SET_dist()
2134
 * @example
2135
 *     ```
2136
 *     #SET{nb,5}
2137
 *     #GET{nb} affiche 5
2138
 *     #GET{nb,3} affiche la valeur de nb, sinon 3
2139
 *
2140
 *     #SET{nb,#ARRAY{boucles,3}}
2141
 *     #GET{nb/boucles} affiche 3, équivalent à #GET{nb}|table_valeur{boucles}
2142
 *     ```
2143
 *
2144
 * @param Champ $p
2145
 *     Pile au niveau de la balise
2146
 * @return Champ
2147
 *     Pile complétée par le code à générer
2148
 **/
2149
function balise_GET_dist($p) {
2150
	$p->interdire_scripts = false; // le contenu vient de #SET, donc il est de confiance
2151
	if (function_exists('balise_ENV')) {
2152
		return balise_ENV($p, '$Pile["vars"]');
2153
	} else {
2154
		return balise_ENV_dist($p, '$Pile["vars"]');
2155
	}
2156
}
2157
2158
2159
/**
2160
 * Compile la balise `#DOUBLONS` qui redonne les doublons enregistrés
2161
 *
2162
 * - `#DOUBLONS{mots}` ou `#DOUBLONS{mots,famille}`
2163
 *   donne l'état des doublons `(MOTS)` à cet endroit
2164
 *   sous forme de tableau d'id_mot comme `array(1,2,3,...)`
2165
 * - `#DOUBLONS` tout seul donne la liste brute de tous les doublons
2166
 * - `#DOUBLONS*{mots}` donne la chaine brute `,1,2,3,...`
2167
 *   (changera si la gestion des doublons evolue)
2168
 *
2169
 * @balise
2170
 * @link https://www.spip.net/4123
2171
 *
2172
 * @param Champ $p
2173
 *     Pile au niveau de la balise
2174
 * @return Champ
2175
 *     Pile complétée par le code à générer
2176
 **/
2177
function balise_DOUBLONS_dist($p) {
2178
	if ($type = interprete_argument_balise(1, $p)) {
2179
		if ($famille = interprete_argument_balise(2, $p)) {
2180
			$type .= '.' . $famille;
2181
		}
2182
		$p->code = '(isset($doublons[' . $type . ']) ? $doublons[' . $type . '] : "")';
2183
		if (!$p->etoile) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $p->etoile of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2184
			$p->code = 'array_filter(array_map("intval",explode(",",'
2185
				. $p->code . ')))';
2186
		}
2187
	} else {
2188
		$p->code = '$doublons';
2189
	}
2190
2191
	$p->interdire_scripts = false;
2192
2193
	return $p;
2194
}
2195
2196
2197
/**
2198
 * Compile la balise `#PIPELINE` pour permettre d'insérer des sorties de
2199
 * pipeline dans un squelette
2200
 *
2201
 * @balise
2202
 * @see pipeline()
2203
 * @example
2204
 *     ```
2205
 *     #PIPELINE{nom}
2206
 *     #PIPELINE{nom,données}
2207
 *     #PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{type,rubrique,id,#ENV{id_rubrique}}}}
2208
 *     ```
2209
 *
2210
 * @param Champ $p
2211
 *     Pile au niveau de la balise
2212
 * @return Champ
2213
 *     Pile complétée par le code à générer
2214
 **/
2215 View Code Duplication
function balise_PIPELINE_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2216
	$_pipe = interprete_argument_balise(1, $p);
2217
	if (!$_pipe) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_pipe of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2218
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'PIPELINE'));
2219
		erreur_squelette($err_b_s_a, $p);
2220
	} else {
2221
		$_flux = interprete_argument_balise(2, $p);
2222
		$_flux = $_flux ? $_flux : "''";
2223
		$p->code = "pipeline( $_pipe , $_flux )";
2224
		$p->interdire_scripts = false;
2225
	}
2226
2227
	return $p;
2228
}
2229
2230
2231
/**
2232
 * Compile la balise `#EDIT` qui ne fait rien dans SPIP
2233
 *
2234
 * Cette balise ne retourne rien mais permet d'indiquer, pour certains plugins
2235
 * qui redéfinissent cette balise, le nom du champ SQL (ou le nom d'un contrôleur)
2236
 * correspondant à ce qui est édité. Cela sert particulièrement au plugin Crayons.
2237
 * Ainsi en absence du plugin, la balise est toujours reconnue (mais n'a aucune action).
2238
 *
2239
 * @balise
2240
 * @link https://www.spip.net/4584
2241
 * @example
2242
 *     ```
2243
 *     [<div class="#EDIT{texte} texte">(#TEXTE)</div>]
2244
 *     ```
2245
 *
2246
 * @param Champ $p
2247
 *     Pile au niveau de la balise
2248
 * @return Champ
2249
 *     Pile complétée par le code à générer
2250
 **/
2251
function balise_EDIT_dist($p) {
2252
	$p->code = "''";
2253
	$p->interdire_scripts = false;
2254
2255
	return $p;
2256
}
2257
2258
2259
/**
2260
 * Compile la balise `#TOTAL_UNIQUE` qui récupère le nombre d'éléments
2261
 * différents affichés par le filtre `unique`
2262
 *
2263
 * @balise
2264
 * @link https://www.spip.net/4374
2265
 * @see unique()
2266
 * @example
2267
 *     ```
2268
 *     #TOTAL_UNIQUE affiche le nombre de #BALISE|unique
2269
 *     #TOTAL_UNIQUE{famille} afiche le nombre de #BALISE|unique{famille}
2270
 *     ```
2271
 *
2272
 * @param Champ $p
2273
 *     Pile au niveau de la balise
2274
 * @return Champ
2275
 *     Pile complétée par le code à générer
2276
 **/
2277
function balise_TOTAL_UNIQUE_dist($p) {
2278
	$_famille = interprete_argument_balise(1, $p);
2279
	$_famille = $_famille ? $_famille : "''";
2280
	$p->code = "unique('', $_famille, true)";
2281
2282
	return $p;
2283
}
2284
2285
/**
2286
 * Compile la balise `#ARRAY` créant un tableau PHP associatif
2287
 *
2288
 * Crée un `array` PHP à partir d'arguments calculés.
2289
 * Chaque paire d'arguments représente la clé et la valeur du tableau.
2290
 *
2291
 * @balise
2292
 * @link https://www.spip.net/4009
2293
 * @example
2294
 *     ```
2295
 *     #ARRAY{key1,val1,key2,val2 ...} retourne
2296
 *     array( key1 => val1, key2 => val2, ...)
2297
 *     ```
2298
 *
2299
 * @param Champ $p
2300
 *     Pile au niveau de la balise
2301
 * @return Champ
2302
 *     Pile complétée par le code à générer
2303
 **/
2304
function balise_ARRAY_dist($p) {
2305
	$_code = array();
2306
	$n = 1;
2307
	do {
2308
		$_key = interprete_argument_balise($n++, $p);
2309
		$_val = interprete_argument_balise($n++, $p);
2310
		if ($_key and $_val) {
2311
			$_code[] = "$_key => $_val";
2312
		}
2313
	} while ($_key && $_val);
0 ignored issues
show
Bug Best Practice introduced by
The expression $_val of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Bug Best Practice introduced by
The expression $_key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2314
	$p->code = 'array(' . join(', ', $_code) . ')';
2315
	$p->interdire_scripts = false;
2316
2317
	return $p;
2318
}
2319
2320
/**
2321
 * Compile la balise `#LISTE` qui crée un tableau PHP avec les valeurs, sans préciser les clés
2322
 *
2323
 * @balise
2324
 * @link https://www.spip.net/5547
2325
 * @example
2326
 *    ```
2327
 *    #LISTE{a,b,c,d,e}
2328
 *    ```
2329
 *
2330
 * @param Champ $p
2331
 *     Pile au niveau de la balise
2332
 * @return Champ
2333
 *     Pile complétée par le code à générer
2334
 */
2335 View Code Duplication
function balise_LISTE_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2336
	$_code = array();
2337
	$n = 1;
2338
	while ($_val = interprete_argument_balise($n++, $p)) {
2339
		$_code[] = $_val;
2340
	}
2341
	$p->code = 'array(' . join(', ', $_code) . ')';
2342
	$p->interdire_scripts = false;
2343
2344
	return $p;
2345
}
2346
2347
2348
/**
2349
 * Compile la balise `#AUTORISER` qui teste une autorisation
2350
 *
2351
 * Appelle la fonction `autoriser()` avec les mêmes arguments,
2352
 * et renvoie un espace ' ' si OK (l'action est autorisée),
2353
 * sinon une chaine vide '' (l'action n'est pas autorisée).
2354
 *
2355
 * Cette balise créée un cache par session.
2356
 *
2357
 * Signature : `#AUTORISER{faire[,type[,id[,auteur[,options]]]}`
2358
 *
2359
 * @note
2360
 *     La priorité des opérateurs exige && plutot que AND
2361
 *
2362
 * @balise
2363
 * @link https://www.spip.net/3896
2364
 * @see autoriser()
2365
 * @see sinon_interdire_acces()
2366
 * @example
2367
 *    ```
2368
 *    [(#AUTORISER{modifier,rubrique,#ID_RUBRIQUE}) ... ]
2369
 *    [(#AUTORISER{voir,rubrique,#ID_RUBRIQUE}|sinon_interdire_acces)]
2370
 *    ```
2371
 *
2372
 * @param Champ $p
2373
 *     Pile au niveau de la balise
2374
 * @return Champ
2375
 *     Pile complétée par le code à générer
2376
 **/
2377 View Code Duplication
function balise_AUTORISER_dist($p) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2378
	$_code = array();
2379
	$p->descr['session'] = true; // faire un cache par session
2380
2381
	$n = 1;
2382
	while ($_v = interprete_argument_balise($n++, $p)) {
2383
		$_code[] = $_v;
2384
	}
2385
2386
	$p->code = '((function_exists("autoriser")||include_spip("inc/autoriser"))&&autoriser(' . join(', ',
2387
			$_code) . ')?" ":"")';
2388
	$p->interdire_scripts = false;
2389
2390
	return $p;
2391
}
2392
2393
2394
/**
2395
 * Compile la balise `#PLUGIN` qui permet d’afficher les informations d'un plugin actif
2396
 *
2397
 * @balise
2398
 * @see filtre_info_plugin_dist()
2399
 * @link https://www.spip.net/4591
2400
 * @example
2401
 *     ```
2402
 *     #PLUGIN Retourne la liste sérialisée des préfixes de plugins actifs
2403
 *     #PLUGIN{prefixe} Renvoie true si le plugin avec ce préfixe est actif
2404
 *     #PLUGIN{prefixe, x} Renvoie l'information x du plugin (s'il est actif)
2405
 *     #PLUGIN{prefixe, tout} Renvoie toutes les informations du plugin (s'il est actif)
2406
 *     ```
2407
 *
2408
 * @param Champ $p
2409
 *     Pile au niveau de la balise
2410
 * @return Champ
2411
 *     Pile complétée par le code à générer
2412
 **/
2413
function balise_PLUGIN_dist($p) {
2414
	$plugin = interprete_argument_balise(1, $p);
2415
	$plugin = isset($plugin) ? str_replace('\'', '"', $plugin) : '""';
2416
	$type_info = interprete_argument_balise(2, $p);
2417
	$type_info = isset($type_info) ? str_replace('\'', '"', $type_info) : '"est_actif"';
2418
2419
	$f = chercher_filtre('info_plugin');
2420
	$p->code = $f . '(' . $plugin . ', ' . $type_info . ')';
2421
2422
	return $p;
2423
}
2424
2425
/**
2426
 * Compile la balise `#AIDER` qui permet d’afficher l’icone de l’aide
2427
 * au sein des squelettes.
2428
 *
2429
 * @balise
2430
 * @see inc_aide_dist()
2431
 * @link https://www.spip.net/4733
2432
 * @example
2433
 *     ```
2434
 *     #AIDER{raccourcis}
2435
 *     ```
2436
 *
2437
 * @param Champ $p
2438
 *     Pile au niveau de la balise
2439
 * @return Champ
2440
 *     Pile complétée par le code à générer
2441
 **/
2442
function balise_AIDER_dist($p) {
2443
	$_motif = interprete_argument_balise(1, $p);
2444
	$p->code = "((\$aider=charger_fonction('aide','inc',true))?\$aider($_motif):'')";
2445
	return $p;
2446
}
2447
2448
/**
2449
 * Compile la balise `#ACTION_FORMULAIRE` qui insère le contexte
2450
 * des formulaires charger / vérifier / traiter avec les hidden de
2451
 * l'URL d'action
2452
 *
2453
 * Accèpte 2 arguments optionnels :
2454
 * - L'url de l'action (par défaut `#ENV{action}`
2455
 * - Le nom du formulaire (par défaut `#ENV{form}`
2456
 *
2457
 * @balise
2458
 * @see form_hidden()
2459
 * @example
2460
 *     ```
2461
 *     <form method='post' action='#ENV{action}'><div>
2462
 *     #ACTION_FORMULAIRE
2463
 *     ```
2464
 *
2465
 * @param Champ $p
2466
 *     Pile au niveau de la balise
2467
 * @return Champ
2468
 *     Pile complétée par le code à générer
2469
 **/
2470
function balise_ACTION_FORMULAIRE($p) {
2471
	if (!$_url = interprete_argument_balise(1, $p)) {
2472
		$_url = "@\$Pile[0]['action']";
2473
	}
2474
	if (!$_form = interprete_argument_balise(2, $p)) {
2475
		$_form = "@\$Pile[0]['form']";
2476
	}
2477
2478
	// envoyer le nom du formulaire que l'on traite
2479
	// transmettre les eventuels args de la balise formulaire
2480
	$p->code = "	'<span class=\"form-hidden\">' .
2481
	form_hidden($_url) .
2482
	'<input name=\'formulaire_action\' type=\'hidden\'
2483
		value=\'' . $_form . '\' />' .
2484
	'<input name=\'formulaire_action_args\' type=\'hidden\'
2485
		value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
2486
	(!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') .
2487
	'</span>'";
2488
2489
	$p->interdire_scripts = false;
2490
2491
	return $p;
2492
}
2493
2494
2495
/**
2496
 * Compile la balise `#BOUTON_ACTION` qui génère un bouton d'action en post, ajaxable
2497
 *
2498
 * Cette balise s'utilise à la place des liens `action_auteur`, sous la forme
2499
 * `#BOUTON_ACTION{libelle[,url[,class[,confirm[,title[,callback]]]]]}`
2500
 *
2501
 * - libelle  : Texte du bouton
2502
 * - url      : URL d’action sécurisée
2503
 * - class    : Classes à ajouter au bouton, à l'exception de `ajax` qui est placé sur le formulaire.
2504
 *              Pour d'autres classes sur le formulaire, utiliser le filtre `ajouter_class`
2505
 * - confirm  : message de confirmation oui/non avant l'action
2506
 * - title    : attribut title à ajouter au bouton
2507
 * - callback : callback js a appeler lors de l'évènement action et avant execution de l'action
2508
 *               (ou après confirmation éventuelle si $confirm est non vide).
2509
 *               Si la callback renvoie false, elle annule le déclenchement de l'action.
2510
 *
2511
 * @balise
2512
 * @uses bouton_action()
2513
 * @link https://www.spip.net/4583
2514
 * @example
2515
 *     ```
2516
 *     [(#AUTORISER{reparer,base}|oui)
2517
 *        [(#BOUTON_ACTION{
2518
 *            <:bouton_tenter_recuperation:>,
2519
 *            #URL_ECRIRE{base_repair},
2520
 *            "ajax btn_large",
2521
 *        })]
2522
 *     ]
2523
 *     ```
2524
 *
2525
 * @param Champ $p
2526
 *     Pile au niveau de la balise
2527
 * @return Champ
2528
 *     Pile complétée par le code à générer
2529
 */
2530
function balise_BOUTON_ACTION_dist($p) {
2531
2532
	$args = array();
2533
	for ($k = 1; $k <= 6; $k++) {
2534
		$_a = interprete_argument_balise($k, $p);
2535
		if (!$_a) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_a of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2536
			$_a = "''";
2537
		}
2538
		$args[] = $_a;
2539
	}
2540
	// supprimer les args vides
2541
	while (end($args) == "''" and count($args) > 2) {
2542
		array_pop($args);
2543
	}
2544
	$args = implode(",", $args);
2545
2546
	$bouton_action = chercher_filtre("bouton_action");
2547
	$p->code = "$bouton_action($args)";
2548
	$p->interdire_scripts = false;
2549
2550
	return $p;
2551
}
2552
2553
2554
/**
2555
 * Compile la balise `#SLOGAN_SITE_SPIP` qui retourne le slogan du site
2556
 *
2557
 * @balise
2558
 * @example
2559
 *     ```
2560
 *     [<p id="slogan">(#SLOGAN_SITE_SPIP)</p>]
2561
 *     ```
2562
 *
2563
 * @param Champ $p
2564
 *     Pile au niveau de la balise
2565
 * @return Champ
2566
 *     Pile complétée par le code à générer
2567
 */
2568
function balise_SLOGAN_SITE_SPIP_dist($p) {
2569
	$p->code = "\$GLOBALS['meta']['slogan_site']";
2570
2571
	#$p->interdire_scripts = true;
2572
	return $p;
2573
}
2574
2575
2576
/**
2577
 * Compile la balise `#HTML5` indiquant si l'espace public peut utiliser du HTML5
2578
 *
2579
 * Renvoie `' '` si le webmestre souhaite que SPIP génère du code (X)HTML5 sur
2580
 * le site public, et `''` si le code doit être strictement compatible HTML4
2581
 *
2582
 * @balise
2583
 * @uses html5_permis()
2584
 * @example
2585
 *     ```
2586
 *     [(#HTML5) required="required"]
2587
 *     <input[ (#HTML5|?{type="email",type="text"})] ... />
2588
 *     ```
2589
 *
2590
 * @param Champ $p
2591
 *     Pile au niveau de la balise
2592
 * @return Champ
2593
 *     Pile complétée par le code à générer
2594
 */
2595
function balise_HTML5_dist($p) {
2596
	$p->code = html5_permis() ? "' '" : "''";
2597
	$p->interdire_scripts = false;
2598
2599
	return $p;
2600
}
2601
2602
2603
/**
2604
 * Compile la balise `#TRI` permettant d'afficher un lien de changement d'ordre de tri
2605
 * d'une colonne de la boucle
2606
 *
2607
 * La balise `#TRI{champ[,libelle]}` champ prend `>` ou `<` pour afficher
2608
 * le lien de changement de sens croissant ou decroissant (`>` `<` indiquent
2609
 * un sens par une flèche)
2610
 *
2611
 * @balise
2612
 * @example
2613
 *     ```
2614
 *     <th>[(#TRI{titre,<:info_titre:>,ajax})]</th>
2615
 *     ```
2616
 *
2617
 * @param Champ $p
2618
 *     Pile au niveau de la balise
2619
 * @param string $liste
2620
 *     Inutilisé
2621
 * @return Champ
2622
 *     Pile complétée par le code à générer
2623
 */
2624
function balise_TRI_dist($p, $liste = 'true') {
0 ignored issues
show
Unused Code introduced by
The parameter $liste is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2625
	$b = index_boucle_mere($p);
2626
	// s'il n'y a pas de nom de boucle, on ne peut pas trier
2627
	if ($b === '') {
2628
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
2629
		erreur_squelette($msg, $p);
2630
		$p->code = "''";
2631
2632
		return $p;
2633
	}
2634
	$boucle = $p->boucles[$b];
2635
2636
	// s'il n'y a pas de tri_champ, c'est qu'on se trouve
2637
	// dans un boucle recursive ou qu'on a oublie le critere {tri}
2638
	if (!isset($boucle->modificateur['tri_champ'])) {
2639
		$msg = array('zbug_champ_hors_critere', array(
2640
			'champ' => zbug_presenter_champ($p),
2641
			'critere' => 'tri'
2642
		));
2643
		erreur_squelette($msg, $p);
2644
		$p->code = "''";
2645
2646
		return $p;
2647
	}
2648
2649
	$_champ = interprete_argument_balise(1, $p);
2650
	// si pas de champ, renvoyer le critere de tri utilise
2651
	if (!$_champ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_champ of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2652
		$p->code = $boucle->modificateur['tri_champ'];
2653
2654
		return $p;
2655
	}
2656
	// forcer la jointure si besoin, et si le champ est statique
2657
	if (preg_match(",^'([\w.]+)'$,i", $_champ, $m)) {
2658
		index_pile($b, $m[1], $p->boucles, '', null, true, false);
2659
	}
2660
2661
	$_libelle = interprete_argument_balise(2, $p);
2662
	$_libelle = $_libelle ? $_libelle : $_champ;
2663
2664
	$_class = interprete_argument_balise(3, $p);
2665
	// si champ = ">" c'est un lien vers le tri croissant : de gauche a droite ==> 1
2666
	// si champ = "<" c'est un lien vers le tri decroissant : (sens inverse) == -1
2667
	$_issens = "in_array($_champ,array('>','<'))";
2668
	$_sens = "(strpos('< >',$_champ)-1)";
2669
2670
	$_variable = "((\$s=$_issens)?'sens':'tri')." . $boucle->modificateur['tri_nom'];
2671
	$_url = "parametre_url(self(),$_variable,\$s?$_sens:$_champ)";
2672
	$_url = "parametre_url($_url,'var_memotri',strncmp(" . $boucle->modificateur['tri_nom'] . ",'session',7)==0?$_variable:'')";
2673
	$_on = "\$s?(" . $boucle->modificateur['tri_sens'] . "==$_sens" . '):(' . $boucle->modificateur['tri_champ'] . "==$_champ)";
2674
2675
	$p->code = "lien_ou_expose($_url,$_libelle,$_on" . ($_class ? ",$_class" : "") . ")";
2676
	//$p->code = "''";
2677
	$p->interdire_scripts = false;
2678
2679
	return $p;
2680
}
2681
2682
2683
/**
2684
 * Compile la balise `#SAUTER{n}` qui permet de sauter en avant n resultats dans une boucle
2685
 *
2686
 * La balise modifie le compteur courant de la boucle, mais pas les autres
2687
 * champs qui restent les valeurs de la boucle avant le saut. Il est donc
2688
 * preferable d'utiliser la balise juste avant la fermeture `</BOUCLE>`
2689
 *
2690
 * L'argument `n` doit être supérieur à zéro sinon la balise ne fait rien
2691
 *
2692
 * @balise
2693
 *
2694
 * @param Champ $p
2695
 *     Pile au niveau de la balise
2696
 * @return Champ
2697
 *     Pile complétée par le code à générer
2698
 */
2699
function balise_SAUTER_dist($p) {
2700
	$id_boucle = $p->id_boucle;
2701
2702
	if (empty($p->boucles[$id_boucle])) {
2703
		$msg = array('zbug_champ_hors_boucle', array('champ' => '#SAUTER'));
2704
		erreur_squelette($msg, $p);
2705
	} else {
2706
		$boucle = $p->boucles[$id_boucle];
0 ignored issues
show
Unused Code introduced by
$boucle is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2707
		$_saut = interprete_argument_balise(1, $p);
2708
		$_compteur = "\$Numrows['$id_boucle']['compteur_boucle']";
2709
		$_total = "\$Numrows['$id_boucle']['total']";
2710
2711
		$p->code = "vide($_compteur=\$iter->skip($_saut,$_total))";
2712
	}
2713
	$p->interdire_scripts = false;
2714
2715
	return $p;
2716
}
2717
2718
2719
/**
2720
 * Compile la balise `#PUBLIE` qui indique si un objet est publié ou non
2721
 *
2722
 * @balise
2723
 * @link https://www.spip.net/5545
2724
 * @see objet_test_si_publie()
2725
 * @example
2726
 *     ```
2727
 *     #PUBLIE : porte sur la boucle en cours
2728
 *     [(#PUBLIE{article, 3}|oui) ... ] : pour l'objet indiqué
2729
 *     ```
2730
 *
2731
 * @param Champ $p
2732
 *     Pile au niveau de la balise
2733
 * @return Champ
2734
 *     Pile complétée par le code à générer
2735
 */
2736
function balise_PUBLIE_dist($p) {
2737
	if (!$_type = interprete_argument_balise(1, $p)) {
2738
		$_type = _q($p->type_requete);
2739
		$_id = champ_sql($p->boucles[$p->id_boucle]->primary, $p);
2740
	} else {
2741
		$_id = interprete_argument_balise(2, $p);
2742
	}
2743
2744
	$connect = '';
2745
	if (isset($p->boucles[$p->id_boucle])) {
2746
		$connect = $p->boucles[$p->id_boucle]->sql_serveur;
2747
	}
2748
2749
	$p->code = "(objet_test_si_publie(" . $_type . ",intval(" . $_id . ")," . _q($connect) . ")?' ':'')";
2750
	$p->interdire_scripts = false;
2751
2752
	return $p;
2753
}
2754
2755
/**
2756
 * Compile la balise `#PRODUIRE` qui génère un fichier statique à partir
2757
 * d'un squelette SPIP
2758
 *
2759
 * Le format du fichier sera extrait de la pre-extension du squelette
2760
 * (typo.css.html, messcripts.js.html)
2761
 * ou par l'argument `format=css` ou `format=js` passé en argument.
2762
 *
2763
 * S'il n'y a pas de format détectable, on utilise `.html`, comme pour les squelettes.
2764
 *
2765
 * La syntaxe de la balise est la même que celle de `#INCLURE`.
2766
 *
2767
 * @balise
2768
 * @see balise_INCLURE_dist()
2769
 * @link https://www.spip.net/5505
2770
 * @example
2771
 *     ```
2772
 *     <link rel="stylesheet" type="text/css" href="#PRODUIRE{fond=css/macss.css,couleur=ffffff}" />
2773
 *     ```
2774
 *
2775
 * @param Champ $p
2776
 *     Pile au niveau de la balise
2777
 * @return Champ
2778
 *     Pile complétée par le code à générer
2779
 */
2780
function balise_PRODUIRE_dist($p) {
2781
	$balise_inclure = charger_fonction('INCLURE', 'balise');
2782
	$p = $balise_inclure($p);
2783
2784
	$p->code = str_replace('recuperer_fond(', 'produire_fond_statique(', $p->code);
2785
2786
	return $p;
2787
}
2788
2789
/**
2790
 * Compile la balise `#LARGEUR_ECRAN` qui définit la largeur d'écran
2791
 * dans l'espace privé
2792
 *
2793
 * @balise
2794
 * @example
2795
 *     ```
2796
 *     #LARGEUR_ECRAN{pleine_largeur}
2797
 *     ```
2798
 *
2799
 * @param Champ $p
2800
 *     Pile au niveau de la balise
2801
 * @return Champ
2802
 *     Pile complétée par le code à générer
2803
 */
2804
function balise_LARGEUR_ECRAN_dist($p) {
2805
	$_class = interprete_argument_balise(1, $p);
2806
	if (!$_class) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $_class of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2807
		$_class = 'null';
2808
	}
2809
	$p->code = "(is_string($_class)?vide(\$GLOBALS['largeur_ecran']=$_class):(isset(\$GLOBALS['largeur_ecran'])?\$GLOBALS['largeur_ecran']:''))";
2810
2811
	return $p;
2812
}
2813
2814
2815
/**
2816
 * Compile la balise `#CONST` qui retourne la valeur de la constante passée en argument
2817
 *
2818
 * @balise
2819
 * @example `#CONST{_DIR_IMG}`
2820
 *
2821
 * @param Champ $p
2822
 *     Pile au niveau de la balise
2823
 * @return Champ
2824
 *     Pile complétée par le code à générer
2825
 **/
2826
function balise_CONST_dist($p) {
2827
	$_const = interprete_argument_balise(1, $p);
2828
	if (!strlen($_const)) {
2829
		$p->code = "''";
2830
	}
2831
	else {
2832
		$p->code = "(defined($_const)?constant($_const):'')";
2833
	}
2834
	$p->interdire_scripts = false;
2835
2836
	return $p;
2837
}
2838