Completed
Push — master ( e4c4a7...6512a2 )
by cam
04:43
created

balises.php ➔ balise_DOSSIER_SQUELETTE_dist()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 7
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
/**
351
 * Compile la balise `#DOSSIER_SQUELETTE` retournant le chemin vers le
352
 * répertoire du fichier squelette dans lequel elle est appelee
353
 * (comme __DIR__ en php)
354
 *
355
 * @balise
356
 * @link https://www.spip.net/4627
357
 *
358
 * @param Champ $p
359
 *     Pile au niveau de la balise.
360
 * @return Champ
361
 *     Pile completée du code PHP d'exécution de la balise
362
 */
363
function balise_DOSSIER_SQUELETTE_dist($p) {
364
	$code = substr(addslashes(dirname($p->descr['sourcefile'])), strlen(_DIR_RACINE));
365
	$p->code = "_DIR_RACINE . '$code'" .
366
		$p->interdire_scripts = false;
367
368
	return $p;
369
}
370
371
/**
372
 * Compile la balise `#SQUELETTE` retournant le chemin du squelette courant
373
 *
374
 * @balise
375
 * @link https://www.spip.net/4027
376
 *
377
 * @param Champ $p
378
 *     Pile au niveau de la balise.
379
 * @return Champ
380
 *     Pile completée du code PHP d'exécution de la balise
381
 */
382
function balise_SQUELETTE_dist($p) {
383
	$code = addslashes($p->descr['sourcefile']);
384
	$p->code = "'$code'" .
385
		$p->interdire_scripts = false;
386
387
	return $p;
388
}
389
390
/**
391
 * Compile la balise `#SPIP_VERSION` qui affiche la version de SPIP
392
 *
393
 * @balise
394
 * @see spip_version()
395
 * @example
396
 *     ```
397
 *     <meta name="generator" content="SPIP[ (#SPIP_VERSION)]" />
398
 *     ```
399
 *
400
 * @param Champ $p
401
 *     Pile au niveau de la balise.
402
 * @return Champ
403
 *     Pile completée du code PHP d'exécution de la balise
404
 */
405
function balise_SPIP_VERSION_dist($p) {
406
	$p->code = "spip_version()";
407
	$p->interdire_scripts = false;
408
409
	return $p;
410
}
411
412
413
/**
414
 * Compile la balise `#NOM_SITE` qui affiche le nom du site.
415
 *
416
 * Affiche le nom du site ou sinon l'URL ou le titre de l'objet
417
 * Utiliser `#NOM_SITE*` pour avoir le nom du site ou rien.
418
 *
419
 * Cette balise interroge les colonnes `nom_site` ou `url_site`
420
 * dans la boucle la plus proche.
421
 *
422
 * @balise
423
 * @see calculer_url()
424
 * @example
425
 *     ```
426
 *     <a href="#URL_SITE">#NOM_SITE</a>
427
 *     ```
428
 *
429
 * @param Champ $p
430
 *     Pile au niveau de la balise
431
 * @return Champ
432
 *     Pile complétée par le code à générer
433
 **/
434
function balise_NOM_SITE_dist($p) {
435
	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...
436
		$p->code = "supprimer_numero(calculer_url(" .
437
			champ_sql('url_site', $p) . "," .
438
			champ_sql('nom_site', $p) .
439
			", 'titre', \$connect, false))";
440
	} else {
441
		$p->code = champ_sql('nom_site', $p);
442
	}
443
444
	$p->interdire_scripts = true;
445
446
	return $p;
447
}
448
449
450
/**
451
 * Compile la balise `#NOTE` qui affiche les notes de bas de page
452
 *
453
 * @balise
454
 * @link https://www.spip.net/3964
455
 * @see calculer_notes()
456
 *
457
 * @param Champ $p
458
 *     Pile au niveau de la balise
459
 * @return Champ
460
 *     Pile complétée par le code à générer
461
 **/
462
function balise_NOTES_dist($p) {
463
	// Recuperer les notes
464
	$p->code = 'calculer_notes()';
465
466
	#$p->interdire_scripts = true;
467
	return $p;
468
}
469
470
471
/**
472
 * Compile la balise `#RECHERCHE` qui retourne le terme de recherche demandé
473
 *
474
 * Retourne un terme demandé en recherche, en le prenant dans _request()
475
 * sous la clé `recherche`.
476
 *
477
 * @balise
478
 * @example
479
 *     ```
480
 *     <h3>Recherche de : #RECHERCHE</h3>
481
 *     ```
482
 *
483
 * @param Champ $p
484
 *     Pile au niveau de la balise
485
 * @return Champ
486
 *     Pile complétée par le code à générer
487
 **/
488
function balise_RECHERCHE_dist($p) {
489
	$p->code = 'entites_html(_request("recherche"))';
490
	$p->interdire_scripts = false;
491
492
	return $p;
493
}
494
495
496
/**
497
 * Compile la balise `#COMPTEUR_BOUCLE` qui retourne le numéro de l’itération
498
 * actuelle de la boucle
499
 *
500
 * @balise
501
 * @link https://www.spip.net/4333
502
 * @see balise_TOTAL_BOUCLE_dist()
503
 *
504
 * @param Champ $p
505
 *     Pile au niveau de la balise
506
 * @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...
507
 *     Pile complétée par le code à générer
508
 **/
509 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...
510
	$b = index_boucle_mere($p);
511
	if ($b === '') {
512
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
513
		erreur_squelette($msg, $p);
514
	} else {
515
		$p->code = "\$Numrows['$b']['compteur_boucle']";
516
		$p->boucles[$b]->cptrows = true;
517
		$p->interdire_scripts = false;
518
519
		return $p;
520
	}
521
}
522
523
/**
524
 * Compile la balise `#TOTAL_BOUCLE` qui retourne le nombre de résultats
525
 * affichés par la boucle
526
 *
527
 * @balise
528
 * @link https://www.spip.net/4334
529
 * @see balise_COMPTEUR_BOUCLE_dist()
530
 * @see balise_GRAND_TOTAL_dist()
531
 *
532
 * @param Champ $p
533
 *     Pile au niveau de la balise
534
 * @return Champ
535
 *     Pile complétée par le code à générer
536
 **/
537 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...
538
	$b = index_boucle_mere($p);
539
	if ($b === '') {
540
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
541
		erreur_squelette($msg, $p);
542
	} else {
543
		$p->code = "\$Numrows['$b']['total']";
544
		$p->boucles[$b]->numrows = true;
545
		$p->interdire_scripts = false;
546
	}
547
548
	return $p;
549
}
550
551
552
/**
553
 * Compile la balise `#POINTS` qui affiche la pertinence des résultats
554
 *
555
 * Retourne le calcul `points` réalisé par le critère `recherche`.
556
 * Cette balise nécessite donc la présence de ce critère.
557
 *
558
 * @balise
559
 * @link https://www.spip.net/903 Boucles et balises de recherche
560
 * @see critere_recherche_dist()
561
 *
562
 * @param Champ $p
563
 *     Pile au niveau de la balise
564
 * @return Champ
565
 *     Pile complétée par le code à générer
566
 **/
567
function balise_POINTS_dist($p) {
568
	return rindex_pile($p, 'points', 'recherche');
569
}
570
571
572
/**
573
 * Compile la balise `#POPULARITE_ABSOLUE` qui affiche la popularité absolue
574
 *
575
 * Cela correspond à la popularité quotidienne de l'article
576
 *
577
 * @balise
578
 * @link https://www.spip.net/1846 La popularité
579
 * @see balise_POPULARITE_dist()
580
 * @see balise_POPULARITE_MAX_dist()
581
 * @see balise_POPULARITE_SITE_dist()
582
 *
583
 * @param Champ $p
584
 *     Pile au niveau de la balise
585
 * @return Champ
586
 *     Pile complétée par le code à générer
587
 **/
588
function balise_POPULARITE_ABSOLUE_dist($p) {
589
	$p->code = 'ceil(' .
590
		champ_sql('popularite', $p) .
591
		')';
592
	$p->interdire_scripts = false;
593
594
	return $p;
595
}
596
597
/**
598
 * Compile la balise `#POPULARITE_SITE` qui affiche la popularité du site
599
 *
600
 * La popularité du site est la somme de toutes les popularités absolues.
601
 *
602
 * @balise
603
 * @link https://www.spip.net/1846 La popularité
604
 * @see balise_POPULARITE_ABSOLUE_dist()
605
 * @see balise_POPULARITE_dist()
606
 * @see balise_POPULARITE_MAX_dist()
607
 *
608
 * @param Champ $p
609
 *     Pile au niveau de la balise
610
 * @return Champ
611
 *     Pile complétée par le code à générer
612
 **/
613
function balise_POPULARITE_SITE_dist($p) {
614
	$p->code = 'ceil($GLOBALS["meta"][\'popularite_total\'])';
615
	$p->interdire_scripts = false;
616
617
	return $p;
618
}
619
620
/**
621
 * Compile la balise `#POPULARITE_MAX` qui affiche la popularité maximum
622
 * parmis les popularités des articles
623
 *
624
 * Cela correspond à la popularité quotidienne de l'article
625
 *
626
 * @balise
627
 * @link https://www.spip.net/1846 La popularité
628
 * @see balise_POPULARITE_ABSOLUE_dist()
629
 * @see balise_POPULARITE_dist()
630
 * @see balise_POPULARITE_SITE_dist()
631
 *
632
 * @param Champ $p
633
 *     Pile au niveau de la balise
634
 * @return Champ
635
 *     Pile complétée par le code à générer
636
 **/
637
function balise_POPULARITE_MAX_dist($p) {
638
	$p->code = 'ceil($GLOBALS["meta"][\'popularite_max\'])';
639
	$p->interdire_scripts = false;
640
641
	return $p;
642
}
643
644
645
/**
646
 * Compile la balise `#VALEUR` retournant le champ `valeur`
647
 *
648
 * Utile dans une boucle DATA pour retourner une valeur.
649
 *
650
 * @balise
651
 * @link https://www.spip.net/5546 #CLE et #VALEUR
652
 * @see table_valeur()
653
 * @example
654
 *     ```
655
 *     #VALEUR renvoie le champ valeur
656
 *     #VALEUR{x} renvoie #VALEUR|table_valeur{x},
657
 *        équivalent à #X (si X n'est pas une balise spécifique à SPIP)
658
 *     #VALEUR{a/b} renvoie #VALEUR|table_valeur{a/b}
659
 *     ```
660
 *
661
 * @param Champ $p
662
 *     Pile au niveau de la balise
663
 * @return Champ
664
 *     Pile complétée par le code à générer
665
 **/
666
function balise_VALEUR_dist($p) {
667
	$b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
668
	$p->code = index_pile($p->id_boucle, 'valeur', $p->boucles, $b);;
669
	if (($v = interprete_argument_balise(1, $p)) !== null) {
670
		$p->code = 'table_valeur(' . $p->code . ', ' . $v . ')';
671
	}
672
	$p->interdire_scripts = true;
673
674
	return $p;
675
}
676
677
/**
678
 * Compile la balise `#EXPOSE` qui met en évidence l'élément sur lequel
679
 * la page se trouve
680
 *
681
 * Expose dans une boucle l'élément de la page sur laquelle on se trouve,
682
 * en retournant `on` si l'élément correspond à la page, une chaîne vide sinon.
683
 *
684
 * On peut passer les paramètres à faire retourner par la balise.
685
 *
686
 * @example
687
 *     ```
688
 *     <a href="#URL_ARTICLE"[ class="(#EXPOSE)"]>
689
 *     <a href="#URL_ARTICLE"[ class="(#EXPOSE{actif})"]>
690
 *     <a href="#URL_ARTICLE"[ class="(#EXPOSE{on,off})"]>
691
 *     ```
692
 *
693
 * @balise
694
 * @link https://www.spip.net/2319 Exposer un article
695
 * @uses calculer_balise_expose()
696
 *
697
 * @param Champ $p
698
 *     Pile au niveau de la balise
699
 * @return Champ
700
 *     Pile complétée par le code à générer
701
 **/
702
function balise_EXPOSE_dist($p) {
703
	$on = "'on'";
704
	$off = "''";
705
	if (($v = interprete_argument_balise(1, $p)) !== null) {
706
		$on = $v;
707
		if (($v = interprete_argument_balise(2, $p)) !== null) {
708
			$off = $v;
709
		}
710
711
	}
712
713
	return calculer_balise_expose($p, $on, $off);
714
}
715
716
/**
717
 * Calcul de la balise expose
718
 *
719
 * @see calcul_exposer()
720
 *
721
 * @param Champ $p
722
 *     Pile au niveau de la balise
723
 * @param string $on
724
 *     Texte à afficher si l'élément est exposé (code à écrire tel que "'on'")
725
 * @param string $off
726
 *     Texte à afficher si l'élément n'est pas exposé (code à écrire tel que "''")
727
 * @return Champ
728
 *     Pile complétée par le code à générer
729
 **/
730
function calculer_balise_expose($p, $on, $off) {
731
	$b = index_boucle($p);
732
	if (empty($p->boucles[$b]->primary)) {
733
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
734
		erreur_squelette($msg, $p);
735
	} else {
736
737
		$key = $p->boucles[$b]->primary;
738
		$type = $p->boucles[$p->id_boucle]->primary;
739
		$desc = $p->boucles[$b]->show;
740
		$connect = sql_quote($p->boucles[$b]->sql_serveur);
741
742
		// Ne pas utiliser champ_sql, on jongle avec le nom boucle explicite
743
		$c = index_pile($p->id_boucle, $type, $p->boucles);
744
745
		if (isset($desc['field']['id_parent'])) {
746
			$parent = 0; // pour if (!$parent) dans calculer_expose
747
		} elseif (isset($desc['field']['id_rubrique'])) {
748
			$parent = index_pile($p->id_boucle, 'id_rubrique', $p->boucles, $b);
749
		} elseif (isset($desc['field']['id_groupe'])) {
750
			$parent = index_pile($p->id_boucle, 'id_groupe', $p->boucles, $b);
751
		} else {
752
			$parent = "''";
753
		}
754
755
		$p->code = "(calcul_exposer($c, '$type', \$Pile[0], $parent, '$key', $connect) ? $on : $off)";
756
	}
757
758
	$p->interdire_scripts = false;
759
760
	return $p;
761
}
762
763
764
/**
765
 * Compile la balise `#INTRODUCTION`
766
 *
767
 * Retourne une introduction d'un objet éditorial, c'est à dire les 600
768
 * premiers caractères environ du champ 'texte' de l'objet ou le contenu
769
 * indiqué entre `<intro>` et `</intro>` de ce même champ.
770
 *
771
 * Pour les articles, l'introduction utilisée est celle du champ `descriptif`
772
 * s'il est renseigné, sinon il est pris dans les champs `chapo` et `texte` et
773
 * est par défaut limité à 500 caractères.
774
 *
775
 * Pour les rubriques, l'introduction utilisée est celle du champ `descriptif`
776
 * s'il est renseigné, sinon du champ texte.
777
 *
778
 * La balise accèpte 1 paramètre indiquant la longueur en nombre de caractères
779
 * de l'introduction.
780
 *
781
 * @see filtre_introduction_dist()
782
 * @example
783
 *     ```
784
 *     #INTRODUCTION
785
 *     #INTRODUCTION{300}
786
 *     ```
787
 *
788
 * @balise
789
 * @link https://www.spip.net/@introduction
790
 *
791
 * @param Champ $p
792
 *     Pile au niveau de la balise
793
 * @return Champ
794
 *     Pile complétée par le code à générer
795
 **/
796
function balise_INTRODUCTION_dist($p) {
797
798
	$type = $p->type_requete;
799
800
	$_texte = champ_sql('texte', $p);
801
	$trouver_table = charger_fonction('trouver_table', 'base');
802
	$desc = $trouver_table(table_objet_sql($type));
803
	$_descriptif = "''";
804
	if ($desc and isset($desc['field']['descriptif'])) {
805
		// notamment articles et rubriques mais aussi tout nouvel objet concerne
806
		$_descriptif = champ_sql('descriptif', $p);
807
	}
808
809
	// notamment les articles mais aussi tout nouvel objet concerne
810
	if ($desc and isset($desc['field']['chapo'])) {
811
		$_chapo = champ_sql('chapo', $p);
812
		$_texte = "(strlen($_descriptif))
813
		? ''
814
		: $_chapo . \"\\n\\n\" . $_texte";
815
	}
816
817
	// longueur en parametre, ou valeur par defaut
818
	$longueur_defaut = objet_info($type, 'introduction_longueur');
819
	if (!$longueur_defaut) {
820
		$longueur_defaut = 600;
821
	}
822
823
	$_suite = 'null';
824
	$_longueur = $longueur_defaut;
825
	if (($v = interprete_argument_balise(1, $p)) !== null) {
826
		$_longueur = 'is_numeric(' . $v . ')?intval(' . $v . '):' . $longueur_defaut;
827
		$_suite = '!is_numeric(' . $v . ')?' . $v . ':null';
828
	}
829
	if (($v2 = interprete_argument_balise(2, $p)) !== null) {
830
		$_suite = $v2;
831
	}
832
833
	$f = chercher_filtre('introduction');
834
	$p->code = "$f($_descriptif, $_texte, $_longueur, \$connect, $_suite)";
835
836
	#$p->interdire_scripts = true;
837
	$p->etoile = '*'; // propre est deja fait dans le calcul de l'intro
838
	return $p;
839
}
840
841
842
/**
843
 * Compile la balise `#LANG` qui affiche la langue de l'objet (ou d'une boucle supérieure),
844
 * et à defaut la langue courante
845
 *
846
 * La langue courante est celle du site ou celle qui a été passée dans l'URL par le visiteur.
847
 * L'étoile `#LANG*` n'affiche rien si aucune langue n'est trouvée dans le SQL ou le contexte.
848
 *
849
 * @balise
850
 * @link https://www.spip.net/3864
851
 *
852
 * @param Champ $p
853
 *     Pile au niveau de la balise
854
 * @return Champ
855
 *     Pile complétée par le code à générer
856
 **/
857
function balise_LANG_dist($p) {
858
	$_lang = champ_sql('lang', $p);
859
	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...
860
		$p->code = "spip_htmlentities($_lang ? $_lang : \$GLOBALS['spip_lang'])";
861
	} else {
862
		$p->code = "spip_htmlentities($_lang)";
863
	}
864
	$p->interdire_scripts = false;
865
866
	return $p;
867
}
868
869
/**
870
 * Compile la balise `#LESAUTEURS` chargée d'afficher la liste des auteurs d'un objet
871
 *
872
 * - Soit le champ `lesauteurs` existe dans la table et à ce moment là,
873
 *   la balise retourne son contenu,
874
 * - soit la balise appelle le modele `lesauteurs.html` en lui passant
875
 *   le couple `objet` et `id_objet` dans son environnement.
876
 *
877
 * @balise
878
 * @link https://www.spip.net/3966 Description de la balise
879
 * @link https://www.spip.net/902 Description de la boucle ARTICLES
880
 * @link https://www.spip.net/911 Description de la boucle SYNDIC_ARTICLES
881
 *
882
 * @param Champ $p
883
 *     Pile au niveau de la balise
884
 * @return Champ
885
 *     Pile complétée par le code à générer
886
 */
887
function balise_LESAUTEURS_dist($p) {
888
	// Cherche le champ 'lesauteurs' dans la pile
889
	$_lesauteurs = champ_sql('lesauteurs', $p, false);
890
891
	// Si le champ n'existe pas (cas de spip_articles), on applique
892
	// le modele lesauteurs.html en passant id_article dans le contexte;
893
	// dans le cas contraire on prend le champ 'lesauteurs'
894
	// (cf extension sites/)
895
	if ($_lesauteurs
896
		and $_lesauteurs != '@$Pile[0][\'lesauteurs\']'
897
	) {
898
		$p->code = "safehtml($_lesauteurs)";
899
		// $p->interdire_scripts = true;
900
	} else {
901
		if (!$p->id_boucle) {
902
			$connect = '';
903
			$objet = 'article';
904
			$id_table_objet = 'id_article';
905
		} else {
906
			$b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
907
			$connect = $p->boucles[$b]->sql_serveur;
908
			$type_boucle = $p->boucles[$b]->type_requete;
909
			$objet = objet_type($type_boucle);
910
			$id_table_objet = id_table_objet($type_boucle);
911
		}
912
		$c = memoriser_contexte_compil($p);
913
914
		$p->code = sprintf(CODE_RECUPERER_FOND, "'modeles/lesauteurs'",
915
			"array('objet'=>'" . $objet .
916
			"','id_objet' => " . champ_sql($id_table_objet, $p) .
917
			",'$id_table_objet' => " . champ_sql($id_table_objet, $p) .
918
			($objet == 'article' ? "" : ",'id_article' => " . champ_sql('id_article', $p)) .
919
			")",
920
			"'trim'=>true, 'compil'=>array($c)",
921
			_q($connect));
922
		$p->interdire_scripts = false; // securite apposee par recuperer_fond()
923
	}
924
925
	return $p;
926
}
927
928
929
/**
930
 * Compile la balise `#RANG` chargée d'afficher le numéro de l'objet
931
 *
932
 * Affiche le « numero de l'objet ». Soit `1` quand on a un titre `1. Premier article`.
933
 *
934
 * Ceci est transitoire afin de préparer une migration vers un vrai système de
935
 * tri des articles dans une rubrique (et plus si affinités).
936
 * La balise permet d'extraire le numero masqué par le filtre `supprimer_numero`.
937
 *
938
 * La balise recupère le champ declaré dans la définition `table_titre`
939
 * de l'objet, ou à defaut du champ `titre`
940
 *
941
 * Si un champ `rang` existe, il est pris en priorité.
942
 *
943
 * @balise
944
 * @link https://www.spip.net/5495
945
 *
946
 * @param Champ $p
947
 *     Pile au niveau de la balise
948
 * @return Champ
949
 *     Pile complétée par le code à générer
950
 */
951
function balise_RANG_dist($p) {
952
	$b = index_boucle($p);
953
	if ($b === '') {
954
		$msg = array(
955
			'zbug_champ_hors_boucle',
956
			array('champ' => '#RANG')
957
		);
958
		erreur_squelette($msg, $p);
959
	} else {
960
		// chercher d'abord un champ sql rang (mais pas dans le env : defaut '' si on trouve pas de champ sql)
961
		// dans la boucle immediatement englobante uniquement
962
		// sinon on compose le champ calcule
963
		$_rang = champ_sql('rang', $p, '', false);
964
965
		// si pas trouve de champ sql rang :
966
		if (!$_rang or $_rang == "''") {
967
			$boucle = &$p->boucles[$b];
968
969
			// on gere le cas ou #RANG est une extraction du numero dans le titre
970
			$trouver_table = charger_fonction('trouver_table', 'base');
971
			$desc = $trouver_table($boucle->id_table);
972
			$_titre = ''; # où extraire le numero ?
973
			
974
			if (isset($desc['titre'])) {
975
				$t = $desc['titre'];
976
				if (
977
					// Soit on trouve avec la déclaration de la lang AVANT
978
					preg_match(';(?:lang\s*,)\s*(.*?titre)\s*(,|$);', $t, $m)
979
					// Soit on prend depuis le début
980
					or preg_match(';^(.*?titre)\s*(,|$);', $t, $m)
981
				) {
982
					$m = preg_replace(',as\s+titre$,i', '', $m[1]);
983
					$m = trim($m);
984
					if ($m != "''") {
985
						if (!preg_match(",\W,", $m)) {
986
							$m = $boucle->id_table . ".$m";
987
						}
988
						
989
						$m .= " AS titre_rang";
990
991
						$boucle->select[] = $m;
992
						$_titre = '$Pile[$SP][\'titre_rang\']';
993
					}
994
				}
995
			}
996
997
			// si on n'a rien trouvé, on utilise le champ titre classique
998
			if (!$_titre) {
999
				$_titre = champ_sql('titre', $p);
1000
			}
1001
1002
			// et on recupere aussi les infos de liaison si on est en train d'editer les liens justement
1003
			// cas des formulaires xxx_lies utilises par #FORMULAIRE_EDITER_LIENS
1004
			$type_boucle = $boucle->type_requete;
1005
			$objet = objet_type($type_boucle);
1006
			$id_table_objet = id_table_objet($type_boucle);
1007
			$_primary = champ_sql($id_table_objet, $p, '', false);
1008
			$_env = '$Pile[0]';
1009
1010
			if (!$_titre) {$_titre = "''";}
1011
			if (!$_primary) {$_primary = "''";}
1012
			$_rang = "calculer_rang_smart($_titre, '$objet', $_primary, $_env)";
1013
1014
		}
1015
		
1016
		$p->code = $_rang;
1017
		$p->interdire_scripts = false;
1018
	}
1019
	
1020
	return $p;
1021
}
1022
1023
1024
/**
1025
 * Compile la balise `#POPULARITE` qui affiche la popularité relative.
1026
 *
1027
 * C'est à dire le pourcentage de la fréquentation de l'article
1028
 * (la popularité absolue) par rapport à la popularité maximum.
1029
 *
1030
 * @balise
1031
 * @link https://www.spip.net/1846 La popularité
1032
 * @see balise_POPULARITE_ABSOLUE_dist()
1033
 * @see balise_POPULARITE_MAX_dist()
1034
 * @see balise_POPULARITE_SITE_dist()
1035
 *
1036
 * @param Champ $p
1037
 *     Pile au niveau de la balise
1038
 * @return Champ
1039
 *     Pile complétée par le code à générer
1040
 **/
1041
function balise_POPULARITE_dist($p) {
1042
	$_popularite = champ_sql('popularite', $p);
1043
	$p->code = "(ceil(min(100, 100 * $_popularite
1044
	/ max(1 , 0 + \$GLOBALS['meta']['popularite_max']))))";
1045
	$p->interdire_scripts = false;
1046
1047
	return $p;
1048
}
1049
1050
/**
1051
 * Code de compilation pour la balise `#PAGINATION`
1052
 *
1053
 * Le code produit est trompeur, car les modèles ne fournissent pas Pile[0].
1054
 * On produit un appel à `_request` si on ne l'a pas, mais c'est inexact:
1055
 * l'absence peut-être due à une faute de frappe dans le contexte inclus.
1056
 */
1057
define('CODE_PAGINATION',
1058
'%s($Numrows["%s"]["grand_total"],
1059
 		%s,
1060
		isset($Pile[0][%4$s])?$Pile[0][%4$s]:intval(_request(%4$s)),
1061
		%5$s, %6$s, %7$s, %8$s, array(%9$s))');
1062
1063
/**
1064
 * Compile la balise `#PAGINATION` chargée d'afficher une pagination
1065
 *
1066
 * Elle charge le modèle `pagination.html` (par défaut), mais un paramètre
1067
 * permet d'indiquer d'autres modèles. `#PAGINATION{nom}` utilisera le
1068
 * modèle `pagination_nom.html`.
1069
 *
1070
 * Cette balise nécessite le critère `pagination` sur la boucle où elle
1071
 * est utilisée.
1072
 *
1073
 * @balise
1074
 * @link https://www.spip.net/3367 Le système de pagination
1075
 * @see filtre_pagination_dist()
1076
 * @see critere_pagination_dist()
1077
 * @see balise_ANCRE_PAGINATION_dist()
1078
 * @example
1079
 *    ```
1080
 *    [<nav role="navigation" class="pagination">(#PAGINATION{prive})</nav>]
1081
 *    ```
1082
 *
1083
 * @param Champ $p
1084
 *     Pile au niveau de la balise
1085
 * @param string $liste
1086
 *     Afficher ou non les liens de pagination (variable de type `string`
1087
 *     car code à faire écrire au compilateur) :
1088
 *     - `true` pour les afficher
1089
 *     - `false` pour afficher uniquement l'ancre.
1090
 * @return Champ
1091
 *     Pile complétée par le code à générer
1092
 */
1093
function balise_PAGINATION_dist($p, $liste = 'true') {
1094
	$b = index_boucle_mere($p);
1095
1096
	// s'il n'y a pas de nom de boucle, on ne peut pas paginer
1097
	if ($b === '') {
1098
		$msg = array(
1099
			'zbug_champ_hors_boucle',
1100
			array('champ' => $liste ? 'PAGINATION' : 'ANCRE_PAGINATION')
1101
		);
1102
		erreur_squelette($msg, $p);
1103
1104
		return $p;
1105
	}
1106
1107
	// s'il n'y a pas de mode_partie, c'est qu'on se trouve
1108
	// dans un boucle recursive ou qu'on a oublie le critere {pagination}
1109
	if (!$p->boucles[$b]->mode_partie) {
1110
		if (!$p->boucles[$b]->table_optionnelle) {
1111
			$msg = array(
1112
				'zbug_pagination_sans_critere',
1113
				array('champ' => '#PAGINATION')
1114
			);
1115
			erreur_squelette($msg, $p);
1116
		}
1117
1118
		return $p;
1119
	}
1120
1121
	// a priori true
1122
	// si false, le compilo va bloquer sur des syntaxes avec un filtre sans argument qui suit la balise
1123
	// si true, les arguments simples (sans truc=chose) vont degager
1124
	$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false, false);
1125
	if (count($_contexte)) {
1126
		$key = key($_contexte);
1127
		if (is_numeric($key)) {
1128
			array_shift($_contexte);
1129
			$__modele = interprete_argument_balise(1, $p);
1130
		}
1131
	}
1132
1133
	if (count($_contexte)) {
1134
		$code_contexte = implode(',', $_contexte);
1135
	} else {
1136
		$code_contexte = '';
1137
	}
1138
1139
	$connect = $p->boucles[$b]->sql_serveur;
1140
	$pas = $p->boucles[$b]->total_parties;
1141
	$f_pagination = chercher_filtre('pagination');
1142
	$type = $p->boucles[$b]->modificateur['debut_nom'];
1143
	$modif = ($type[0] !== "'") ? "'debut'.$type"
1144
		: ("'debut" . substr($type, 1));
1145
1146
	$p->code = sprintf(CODE_PAGINATION, $f_pagination, $b, $type, $modif, $pas, $liste,
1147
		((isset($__modele) and $__modele) ? $__modele : "''"), _q($connect), $code_contexte);
1148
1149
	$p->boucles[$b]->numrows = true;
1150
	$p->interdire_scripts = false;
1151
1152
	return $p;
1153
}
1154
1155
1156
/**
1157
 * Compile la balise `#ANCRE_PAGINATION` chargée d'afficher l'ancre
1158
 * de la pagination
1159
 *
1160
 * Cette ancre peut ainsi être placée au-dessus la liste des éléments
1161
 * de la boucle alors qu'on mettra les liens de pagination en-dessous de
1162
 * cette liste paginée.
1163
 *
1164
 * Cette balise nécessite le critère `pagination` sur la boucle où elle
1165
 * est utilisée.
1166
 *
1167
 * @balise
1168
 * @link https://www.spip.net/3367 Le système de pagination
1169
 * @link https://www.spip.net/4328 Balise ANCRE_PAGINATION
1170
 * @see critere_pagination_dist()
1171
 * @see balise_PAGINATION_dist()
1172
 *
1173
 * @param Champ $p
1174
 *     Pile au niveau de la balise
1175
 * @return Champ
1176
 *     Pile complétée par le code à générer
1177
 **/
1178
function balise_ANCRE_PAGINATION_dist($p) {
1179
	if ($f = charger_fonction('PAGINATION', 'balise', true)) {
1180
		return $f($p, $liste = 'false');
1181
	} else {
1182
		return null;
1183
	} // ou une erreur ?
1184
}
1185
1186
1187
/**
1188
 * Compile la balise `#GRAND_TOTAL` qui retourne le nombre total de résultats
1189
 * d'une boucle
1190
 *
1191
 * Cette balise set équivalente à `#TOTAL_BOUCLE` sauf pour les boucles paginées.
1192
 * Dans ce cas elle indique le nombre total d'éléments répondant aux critères
1193
 * hors pagination.
1194
 *
1195
 * @balise
1196
 * @see balise_GRAND_TOTAL_dist()
1197
 *
1198
 * @param Champ $p
1199
 *     Pile au niveau de la balise
1200
 * @return Champ
1201
 *     Pile complétée par le code à générer
1202
 **/
1203 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...
1204
	$b = index_boucle_mere($p);
1205
	if ($b === '') {
1206
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
1207
		erreur_squelette($msg, $p);
1208
	} else {
1209
		$p->code = "(isset(\$Numrows['$b']['grand_total'])
1210
			? \$Numrows['$b']['grand_total'] : \$Numrows['$b']['total'])";
1211
		$p->boucles[$b]->numrows = true;
1212
		$p->interdire_scripts = false;
1213
	}
1214
1215
	return $p;
1216
}
1217
1218
1219
/**
1220
 * Compile la balise `#SELF` qui retourne l’URL de la page appelée.
1221
 *
1222
 * Cette URL est nettoyée des variables propres à l’exécution de SPIP
1223
 * tel que `var_mode`.
1224
 *
1225
 * @note
1226
 *     Attention dans un `INCLURE()` ou une balise dynamique, on n'a pas le droit de
1227
 *     mettre en cache `#SELF` car il peut correspondre à une autre page (attaque XSS)
1228
 *     (Dans ce cas faire <INCLURE{self=#SELF}> pour différencier les caches.)
1229
 *
1230
 * @balise
1231
 * @link https://www.spip.net/4574
1232
 * @example
1233
 *     ```
1234
 *     <a href="[(#SELF|parametre_url{id_mot,#ID_MOT})]">...
1235
 *     ```
1236
 *
1237
 * @param Champ $p
1238
 *     Pile au niveau de la balise
1239
 * @return Champ
1240
 *     Pile complétée par le code à générer
1241
 **/
1242
function balise_SELF_dist($p) {
1243
	$p->code = 'self()';
1244
	$p->interdire_scripts = false;
1245
1246
	return $p;
1247
}
1248
1249
1250
/**
1251
 * Compile la balise `#CHEMIN` qui cherche un fichier dans les chemins
1252
 * connus de SPIP et retourne son chemin complet depuis la racine
1253
 *
1254
 * Signature : `#CHEMIN{chemin/vers/fichier.ext}`
1255
 *
1256
 * Retourne une chaîne vide si le fichier n'est pas trouvé.
1257
 *
1258
 * @balise
1259
 * @link https://www.spip.net/4332
1260
 * @see find_in_path() Recherche de chemin
1261
 * @example
1262
 *     ```
1263
 *     [<script type="text/javascript" src="(#CHEMIN{javascript/jquery.flot.js})"></script>]
1264
 *     [<link rel="stylesheet" href="(#CHEMIN{css/perso.css}|direction_css)" type="text/css" />]
1265
 *     ```
1266
 *
1267
 * @param Champ $p
1268
 *     Pile au niveau de la balise
1269
 * @return Champ
1270
 *     Pile complétée par le code à générer
1271
 **/
1272 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...
1273
	$arg = interprete_argument_balise(1, $p);
1274
	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...
1275
		$msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN'));
1276
		erreur_squelette($msg, $p);
1277
	} else {
1278
		$p->code = 'find_in_path(' . $arg . ')';
1279
	}
1280
1281
	$p->interdire_scripts = false;
1282
1283
	return $p;
1284
}
1285
1286
/**
1287
 * Compile la balise `#CHEMIN_IMAGE` qui cherche une image dans le thème
1288
 * de l'espace privé utilisé par SPIP et retourne son chemin complet depuis
1289
 * la racine
1290
 *
1291
 * Signature : `#CHEMIN_IMAGE{image.png}`
1292
 *
1293
 * Retourne une chaîne vide si le fichier n'est pas trouvé.
1294
 *
1295
 * @balise
1296
 * @see chemin_image()
1297
 * @example
1298
 *     ```
1299
 *     #CHEMIN_IMAGE{article-24.png}
1300
 *     ```
1301
 *
1302
 * @param Champ $p
1303
 *     Pile au niveau de la balise
1304
 * @return Champ
1305
 *     Pile complétée par le code à générer
1306
 **/
1307 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...
1308
	$arg = interprete_argument_balise(1, $p);
1309
	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...
1310
		$msg = array('zbug_balise_sans_argument', array('balise' => ' CHEMIN_IMAGE'));
1311
		erreur_squelette($msg, $p);
1312
	} else {
1313
		$p->code = 'chemin_image(' . $arg . ')';
1314
	}
1315
1316
	$p->interdire_scripts = false;
1317
	return $p;
1318
}
1319
1320
1321
/**
1322
 * Compile la balise `#ENV` qui permet de récupérer le contexte d'environnement
1323
 * transmis à un squelette.
1324
 *
1325
 * La syntaxe `#ENV{toto, valeur par defaut}`
1326
 * renverra `valeur par defaut` si `$toto` est vide.
1327
 *
1328
 * La recherche de la clé s'appuyant sur la fonction `table_valeur`
1329
 * il est possible de demander un sous élément d'un tableau :
1330
 * `#ENV{toto/sous/element, valeur par defaut}` retournera l'équivalent de
1331
 * `#ENV{toto}|table_valeur{sous/element}` c'est-à-dire en quelque sorte
1332
 * `$env['toto']['sous']['element']` s'il existe, sinon la valeur par défaut.
1333
 *
1334
 * Si le tableau est vide on renvoie `''` (utile pour `#SESSION`)
1335
 *
1336
 * Enfin, la balise utilisée seule `#ENV` retourne le tableau complet
1337
 * de l'environnement. À noter que ce tableau est retourné sérialisé.
1338
 *
1339
 * En standard est appliqué le filtre `entites_html`, mais si l'étoile est
1340
 * utilisée pour désactiver les filtres par défaut, par exemple avec
1341
 * `[(#ENV*{toto})]` , il *faut* s'assurer de la sécurité
1342
 * anti-javascript, par exemple en filtrant avec `safehtml` : `[(#ENV*{toto}|safehtml)]`
1343
 *
1344
 *
1345
 * @param Champ $p
1346
 *     Pile ; arbre de syntaxe abstrait positionné au niveau de la balise.
1347
 * @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...
1348
 *     Tableau dans lequel chercher la clé demandée en paramètre de la balise.
1349
 *     Par defaut prend dans le contexte du squelette.
1350
 * @return Champ
1351
 *     Pile completée du code PHP d'exécution de la balise
1352
 **/
1353
function balise_ENV_dist($p, $src = null) {
1354
1355
	// cle du tableau desiree
1356
	$_nom = interprete_argument_balise(1, $p);
1357
	// valeur par defaut
1358
	$_sinon = interprete_argument_balise(2, $p);
1359
1360
	// $src est un tableau de donnees sources eventuellement transmis
1361
	// en absence, on utilise l'environnement du squelette $Pile[0]
1362
1363
	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...
1364
		// cas de #ENV sans argument : on retourne le serialize() du tableau
1365
		// une belle fonction [(#ENV|affiche_env)] serait pratique
1366
		if ($src) {
1367
			$p->code = '(is_array($a = (' . $src . ')) ? serialize($a) : "")';
1368
		} else {
1369
			$p->code = '@serialize($Pile[0])';
1370
		}
1371
	} else {
1372
		if (!$src) {
1373
			$src = '@$Pile[0]';
1374
		}
1375
		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...
1376
			$p->code = "sinon(table_valeur($src, (string)$_nom, null), $_sinon)";
1377
		} else {
1378
			$p->code = "table_valeur($src, (string)$_nom, null)";
1379
		}
1380
	}
1381
1382
	#$p->interdire_scripts = true;
1383
1384
	return $p;
1385
}
1386
1387
/**
1388
 * Compile la balise `#CONFIG` qui retourne une valeur de configuration
1389
 *
1390
 * Cette balise appelle la fonction `lire_config()` pour obtenir les
1391
 * configurations du site.
1392
 *
1393
 * Par exemple `#CONFIG{gerer_trad}` donne 'oui ou 'non' selon le réglage.
1394
 *
1395
 * Le 3ème argument permet de contrôler la sérialisation du résultat
1396
 * (mais ne sert que pour le dépot `meta`) qui doit parfois désérialiser,
1397
 * par exemple avec `|in_array{#CONFIG{toto,#ARRAY,1}}`. Ceci n'affecte
1398
 * pas d'autres dépots et `|in_array{#CONFIG{toto/,#ARRAY}}` sera
1399
 * équivalent.
1400
 *
1401
 * Òn peut appeler d'autres tables que `spip_meta` avec un
1402
 * `#CONFIG{/infos/champ,defaut}` qui lit la valeur de `champ`
1403
 * dans une table des meta qui serait `spip_infos`
1404
 *
1405
 * @balise
1406
 * @link https://www.spip.net/4335
1407
 *
1408
 * @param Champ $p
1409
 *     Pile au niveau de la balise.
1410
 * @return Champ
1411
 *     Pile completée du code PHP d'exécution de la balise
1412
 */
1413
function balise_CONFIG_dist($p) {
1414
	if (!$arg = interprete_argument_balise(1, $p)) {
1415
		$arg = "''";
1416
	}
1417
	$_sinon = interprete_argument_balise(2, $p);
1418
	$_unserialize = sinon(interprete_argument_balise(3, $p), "false");
1419
1420
	$p->code = '(include_spip(\'inc/config\')?lire_config(' . $arg . ',' .
1421
		($_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...
1422
1423
	return $p;
1424
}
1425
1426
1427
/**
1428
 * Compile la balise `#CONNECT` qui retourne le nom du connecteur
1429
 * de base de données
1430
 *
1431
 * Retourne le nom du connecteur de base de données utilisé (le nom
1432
 * du fichier `config/xx.php` sans l'extension, utilisé pour calculer
1433
 * les données du squelette).
1434
 *
1435
 * Retourne `NULL` si le connecteur utilisé est celui par défaut de SPIP
1436
 * (connect.php), sinon retourne son nom.
1437
 *
1438
 * @balise
1439
 *
1440
 * @param Champ $p
1441
 *     Pile au niveau de la balise.
1442
 * @return Champ
1443
 *     Pile completée du code PHP d'exécution de la balise
1444
 */
1445
function balise_CONNECT_dist($p) {
1446
	$p->code = '($connect ? $connect : NULL)';
1447
	$p->interdire_scripts = false;
1448
1449
	return $p;
1450
}
1451
1452
1453
/**
1454
 * Compile la balise `#SESSION` qui permet d’accéder aux informations
1455
 * liées au visiteur authentifié et de différencier automatiquement
1456
 * le cache en fonction du visiteur.
1457
 *
1458
 * Cette balise est un tableau des données du visiteur (nom, email etc).
1459
 * Si elle est invoquée, elle lève un drapeau dans le fichier cache, qui
1460
 * permet à public/cacher de créer un cache différent par visiteur
1461
 *
1462
 * @balise
1463
 * @link https://www.spip.net/3979
1464
 * @see balise_AUTORISER_dist()
1465
 * @see balise_SESSION_SET_dist()
1466
 * @example
1467
 *     ```
1468
 *     #SESSION{nom}
1469
 *     ```
1470
 *
1471
 * @param Champ $p
1472
 *     Pile au niveau de la balise.
1473
 * @return Champ
1474
 *     Pile completée du code PHP d'exécution de la balise
1475
 **/
1476
function balise_SESSION_dist($p) {
1477
	$p->descr['session'] = true;
1478
1479
	$f = function_exists('balise_ENV')
1480
		? 'balise_ENV'
1481
		: 'balise_ENV_dist';
1482
1483
	$p = $f($p, '$GLOBALS["visiteur_session"]');
1484
1485
	return $p;
1486
}
1487
1488
1489
/**
1490
 * Compile la balise `#SESSION_SET` qui d’insérer dans la session
1491
 * des données supplémentaires
1492
 *
1493
 * @balise
1494
 * @link https://www.spip.net/3984
1495
 * @see balise_AUTORISER_dist()
1496
 * @see balise_SESSION_SET_dist()
1497
 * @example
1498
 *     ```
1499
 *     #SESSION_SET{x,y} ajoute x=y dans la session du visiteur
1500
 *     ```
1501
 *
1502
 * @param Champ $p
1503
 *     Pile au niveau de la balise.
1504
 * @return Champ
1505
 *     Pile completée du code PHP d'exécution de la balise
1506
 **/
1507
function balise_SESSION_SET_dist($p) {
1508
	$_nom = interprete_argument_balise(1, $p);
1509
	$_val = interprete_argument_balise(2, $p);
1510
	if (!$_nom or !$_val) {
1511
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SESSION_SET'));
1512
		erreur_squelette($err_b_s_a, $p);
1513
	} else {
1514
		$p->code = '(include_spip("inc/session") AND session_set(' . $_nom . ',' . $_val . '))';
1515
	}
1516
1517
	$p->interdire_scripts = false;
1518
1519
	return $p;
1520
}
1521
1522
1523
/**
1524
 * Compile la balise `#EVAL` qui évalue un code PHP
1525
 *
1526
 * À utiliser avec précautions !
1527
 *
1528
 * @balise
1529
 * @link https://www.spip.net/4587
1530
 * @example
1531
 *     ```
1532
 *     #EVAL{6+9}
1533
 *     #EVAL{'date("Y-m-d")'}
1534
 *     #EVAL{$_SERVER['REQUEST_URI']}
1535
 *     #EVAL{'str_replace("r","z", "roger")'}  (attention les "'" sont interdits)
1536
 *     ```
1537
 *
1538
 * @note
1539
 *     `#EVAL{code}` produit `eval('return code;')`
1540
 *      mais si le code est une expression sans balise, on se dispense
1541
 *      de passer par une construction si compliquée, et le code est
1542
 *      passé tel quel (entre parenthèses, et protégé par interdire_scripts)
1543
 *
1544
 * @param Champ $p
1545
 *     Pile au niveau de la balise.
1546
 * @return Champ
1547
 *     Pile completée du code PHP d'exécution de la balise
1548
 **/
1549
function balise_EVAL_dist($p) {
1550
	$php = interprete_argument_balise(1, $p);
1551
	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...
1552
		# optimisation sur les #EVAL{une expression sans #BALISE}
1553
		# attention au commentaire "// x signes" qui precede
1554 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...
1555
			$php, $r)) {
1556
			$p->code = /* $r[1]. */
1557
				'(' . $r[2] . ')';
1558
		} else {
1559
			$p->code = "eval('return '.$php.';')";
1560
		}
1561
	} else {
1562
		$msg = array('zbug_balise_sans_argument', array('balise' => ' EVAL'));
1563
		erreur_squelette($msg, $p);
1564
	}
1565
1566
	#$p->interdire_scripts = true;
1567
1568
	return $p;
1569
}
1570
1571
1572
/**
1573
 * Compile la balise `#CHAMP_SQL` qui renvoie la valeur d'un champ SQL
1574
 *
1575
 * Signature : `#CHAMP_SQL{champ}`
1576
 *
1577
 * Cette balise permet de récupérer par exemple un champ `notes` dans une table
1578
 * SQL externe (impossible avec la balise `#NOTES` qui est une balise calculée).
1579
 *
1580
 * Ne permet pas de passer une expression comme argument, qui ne peut
1581
 * être qu'un texte statique !
1582
 *
1583
 * @balise
1584
 * @link https://www.spip.net/4041
1585
 * @see champ_sql()
1586
 * @example
1587
 *     ```
1588
 *     #CHAMP_SQL{notes}
1589
 *     ```
1590
 *
1591
 * @param Champ $p
1592
 *     Pile au niveau de la balise
1593
 * @return Champ
1594
 *     Pile complétée par le code à générer
1595
 **/
1596
function balise_CHAMP_SQL_dist($p) {
1597
1598
	if ($p->param
1599
		and isset($p->param[0][1][0])
1600
		and $champ = ($p->param[0][1][0]->texte)
1601
	) {
1602
		$p->code = champ_sql($champ, $p);
1603
	} else {
1604
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => ' CHAMP_SQL'));
1605
		erreur_squelette($err_b_s_a, $p);
1606
	}
1607
1608
	#$p->interdire_scripts = true;
1609
	return $p;
1610
}
1611
1612
/**
1613
 * Compile la balise `#VAL` qui retourne simplement le premier argument
1614
 * qui lui est transmis
1615
 *
1616
 * Cela permet d'appliquer un filtre à une chaîne de caractère
1617
 *
1618
 * @balise
1619
 * @link https://www.spip.net/4026
1620
 * @example
1621
 *     ```
1622
 *     #VAL retourne ''
1623
 *     #VAL{x} retourne 'x'
1624
 *     #VAL{1,2} renvoie '1' (2 est considéré comme un autre paramètre)
1625
 *     #VAL{'1,2'} renvoie '1,2'
1626
 *     [(#VAL{a_suivre}|bouton_spip_rss)]
1627
 *     ```
1628
 *
1629
 * @param Champ $p
1630
 *     Pile au niveau de la balise
1631
 * @return Champ
1632
 *     Pile complétée par le code à générer
1633
 **/
1634
function balise_VAL_dist($p) {
1635
	$p->code = interprete_argument_balise(1, $p);
1636
	if (!strlen($p->code)) {
1637
		$p->code = "''";
1638
	}
1639
	$p->interdire_scripts = false;
1640
1641
	return $p;
1642
}
1643
1644
/**
1645
 * Compile la balise `#REM` servant à commenter du texte
1646
 *
1647
 * Retourne toujours une chaîne vide.
1648
 *
1649
 * @balise
1650
 * @link https://www.spip.net/4578
1651
 * @example
1652
 *     ```
1653
 *     [(#REM)
1654
 *       Ceci est une remarque ou un commentaire,
1655
 *       non affiché dans le code généré
1656
 *     ]
1657
 *     ```
1658
 *
1659
 * @note
1660
 *     La balise `#REM` n'empêche pas l'exécution des balises SPIP contenues
1661
 *     dedans (elle ne sert pas à commenter du code pour empêcher son
1662
 *     exécution).
1663
 *
1664
 * @param Champ $p
1665
 *     Pile au niveau de la balise
1666
 * @return Champ
1667
 *     Pile complétée par le code à générer
1668
 **/
1669
function balise_REM_dist($p) {
1670
	$p->code = "''";
1671
	$p->interdire_scripts = false;
1672
1673
	return $p;
1674
}
1675
1676
/**
1677
 * Une balise #NULL quand on a besoin de passer un argument null sur l'appel d'un filtre ou formulaire
1678
 * (evite un #EVAL{null})
1679
 * @param $p
1680
 * @return mixed
1681
 */
1682
function balise_NULL_dist($p) {
1683
	$p->code = "null";
1684
	$p->interdire_scripts = false;
1685
1686
	return $p;
1687
}
1688
1689
1690
/**
1691
 * Compile la balise `#HTTP_HEADER` envoyant des entêtes de retour HTTP
1692
 *
1693
 * Doit être placée en tête de fichier et ne fonctionne pas dans une
1694
 * inclusion.
1695
 *
1696
 * @balise
1697
 * @link https://www.spip.net/4631
1698
 * @example
1699
 *     ```
1700
 *     #HTTP_HEADER{Content-Type: text/csv; charset=#CHARSET}
1701
 *     ```
1702
 *
1703
 * @param Champ $p
1704
 *     Pile au niveau de la balise
1705
 * @return Champ
1706
 *     Pile complétée par le code à générer
1707
 **/
1708 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...
1709
1710
	$header = interprete_argument_balise(1, $p);
1711
	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...
1712
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'HTTP_HEADER'));
1713
		erreur_squelette($err_b_s_a, $p);
1714
	} else {
1715
		$p->code = "'<'.'?php header(' . _q("
1716
			. $header
1717
			. ") . '); ?'.'>'";
1718
	}
1719
	$p->interdire_scripts = false;
1720
1721
	return $p;
1722
}
1723
1724
1725
/**
1726
 * Compile la balise `#FILTRE` qui exécute un filtre à l'ensemble du squelette
1727
 * une fois calculé.
1728
 *
1729
 * Le filtrage se fait au niveau du squelette, sans s'appliquer aux `<INCLURE>`.
1730
 * Plusieurs filtres peuvent être indiqués, séparés par des barres verticales `|`
1731
 *
1732
 * @balise
1733
 * @link https://www.spip.net/4894
1734
 * @example
1735
 *     ```
1736
 *     #FILTRE{compacte_head}
1737
 *     #FILTRE{supprimer_tags|filtrer_entites|trim}
1738
 *     ```
1739
 *
1740
 * @param Champ $p
1741
 *     Pile au niveau de la balise
1742
 * @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...
1743
 *     Pile complétée par le code à générer
1744
 **/
1745
function balise_FILTRE_dist($p) {
1746
	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...
1747
		$args = array();
1748
		foreach ($p->param as $i => $ignore) {
1749
			$args[] = interprete_argument_balise($i + 1, $p);
1750
		}
1751
		$p->code = "'<' . '"
1752
			. '?php header("X-Spip-Filtre: \'.'
1753
			. join('.\'|\'.', $args)
1754
			. " . '\"); ?'.'>'";
1755
1756
		$p->interdire_scripts = false;
1757
1758
		return $p;
1759
	}
1760
}
1761
1762
1763
/**
1764
 * Compile la balise `#CACHE` definissant la durée de validité du cache du squelette
1765
 *
1766
 * Signature : `#CACHE{duree[,type]}`
1767
 *
1768
 * Le premier argument est la durée en seconde du cache. Le second
1769
 * (par défaut `statique`) indique le type de cache :
1770
 *
1771
 * - `cache-client` autorise gestion du IF_MODIFIED_SINCE
1772
 * - `statique` ne respecte pas l'invalidation par modif de la base
1773
 *   (mais s'invalide tout de même à l'expiration du delai)
1774
 *
1775
 * @balise
1776
 * @see ecrire/public/cacher.php
1777
 * @link https://www.spip.net/4330
1778
 * @example
1779
 *     ```
1780
 *     #CACHE{24*3600}
1781
 *     #CACHE{24*3600, cache-client}
1782
 *     #CACHE{0} pas de cache
1783
 *     ```
1784
 * @note
1785
 *   En absence de cette balise la durée est du cache est donné
1786
 *   par la constante `_DUREE_CACHE_DEFAUT`
1787
 *
1788
 * @param Champ $p
1789
 *     Pile au niveau de la balise
1790
 * @return Champ
1791
 *     Pile complétée par le code à générer
1792
 **/
1793
function balise_CACHE_dist($p) {
1794
1795
	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...
1796
		$duree = valeur_numerique($p->param[0][1][0]->texte);
1797
1798
		// noter la duree du cache dans un entete proprietaire
1799
1800
		$code = "'<'.'" . '?php header("X-Spip-Cache: '
1801
			. $duree
1802
			. '"); ?' . "'.'>'";
1803
1804
		// Remplir le header Cache-Control
1805
		// cas #CACHE{0}
1806
		if ($duree == 0) {
1807
			$code .= ".'<'.'"
1808
				. '?php header("Cache-Control: no-cache, must-revalidate"); ?'
1809
				. "'.'><'.'"
1810
				. '?php header("Pragma: no-cache"); ?'
1811
				. "'.'>'";
1812
		}
1813
1814
		// recuperer les parametres suivants
1815
		$i = 1;
1816
		while (isset($p->param[0][++$i])) {
1817
			$pa = ($p->param[0][$i][0]->texte);
1818
1819
			if ($pa == 'cache-client'
1820
				and $duree > 0
1821
			) {
1822
				$code .= ".'<'.'" . '?php header("Cache-Control: max-age='
1823
					. $duree
1824
					. '"); ?' . "'.'>'";
1825
				// il semble logique, si on cache-client, de ne pas invalider
1826
				$pa = 'statique';
1827
			}
1828
1829
			if ($pa == 'statique'
1830
				and $duree > 0
1831
			) {
1832
				$code .= ".'<'.'" . '?php header("X-Spip-Statique: oui"); ?' . "'.'>'";
1833
			}
1834
		}
1835
	} else {
1836
		$code = "''";
1837
	}
1838
	$p->code = $code;
1839
	$p->interdire_scripts = false;
1840
1841
	return $p;
1842
}
1843
1844
1845
/**
1846
 * Compile la balise `#INSERT_HEAD` permettant d'insérer du contenu dans
1847
 * le `<head>` d'une page HTML
1848
 *
1849
 * La balise permet aux plugins d'insérer des styles, js ou autre
1850
 * dans l'entête sans modification du squelette.
1851
 * Les css doivent être inserées de préférence par `#INSERT_HEAD_CSS`
1852
 * pour en faciliter la surcharge.
1853
 *
1854
 * On insère ici aussi un morceau de PHP qui verifiera à l'exécution
1855
 * que le pipeline `insert_head_css` a bien été vu
1856
 * et dans le cas contraire l'appelera. Ceal permet de ne pas oublier
1857
 * les css de `#INSERT_HEAD_CSS` même si cette balise n'est pas presente.
1858
 *
1859
 * Il faut mettre ce php avant le `insert_head` car le compresseur y mets
1860
 * ensuite un php du meme type pour collecter
1861
 * CSS et JS, et on ne veut pas qu'il rate les css insérées en fallback
1862
 * par `insert_head_css_conditionnel`.
1863
 *
1864
 * @link https://www.spip.net/4629
1865
 * @see balise_INSERT_HEAD_CSS_dist()
1866
 *
1867
 * @param Champ $p
1868
 *     Pile au niveau de la balise
1869
 * @return Champ
1870
 *     Pile complétée par le code à générer
1871
 */
1872
function balise_INSERT_HEAD_dist($p) {
1873
	$p->code = "'<'.'"
1874
		. '?php header("X-Spip-Filtre: insert_head_css_conditionnel"); ?'
1875
		. "'.'>'";
1876
	$p->code .= ". pipeline('insert_head','<!-- insert_head -->')";
1877
	$p->interdire_scripts = false;
1878
1879
	return $p;
1880
}
1881
1882
/**
1883
 * Compile la balise `#INSERT_HEAD_CSS` homologue de `#INSERT_HEAD` pour les CSS
1884
 *
1885
 * Et par extension pour le JS inline qui doit préférentiellement
1886
 * être inséré avant les CSS car bloquant sinon.
1887
 *
1888
 * @link https://www.spip.net/4605
1889
 * @see balise_INSERT_HEAD_dist()
1890
 *
1891
 * @param Champ $p
1892
 *     Pile au niveau de la balise
1893
 * @return Champ
1894
 *     Pile complétée par le code à générer
1895
 */
1896
function balise_INSERT_HEAD_CSS_dist($p) {
1897
	$p->code = "pipeline('insert_head_css','<!-- insert_head_css -->')";
1898
	$p->interdire_scripts = false;
1899
1900
	return $p;
1901
}
1902
1903
/**
1904
 * Compile la balise `#INCLUDE` alias de `#INCLURE`
1905
 *
1906
 * @balise
1907
 * @see balise_INCLURE_dist()
1908
 *
1909
 * @param Champ $p
1910
 *     Pile au niveau de la balise
1911
 * @return Champ
1912
 *     Pile complétée par le code à générer
1913
 **/
1914
function balise_INCLUDE_dist($p) {
1915
	if (function_exists('balise_INCLURE')) {
1916
		return balise_INCLURE($p);
1917
	} else {
1918
		return balise_INCLURE_dist($p);
1919
	}
1920
}
1921
1922
/**
1923
 * Compile la balise `#INCLURE` qui inclut un résultat de squelette
1924
 *
1925
 * Signature : `[(#INCLURE{fond=nom_du_squelette, argument, argument=xx})]`
1926
 *
1927
 * L'argument `env` permet de transmettre tout l'environnement du squelette
1928
 * en cours au squelette inclus.
1929
 *
1930
 * On parle d’inclusion « statique » car le résultat de compilation est
1931
 * ajouté au squelette en cours, dans le même fichier de cache.
1932
 * Cette balise est donc différente d’une inclusion « dynamique » avec
1933
 * `<INCLURE.../>` qui, elle, crée un fichier de cache séparé
1934
 * (avec une durée de cache qui lui est propre).
1935
 *
1936
 * L'inclusion est realisée au calcul du squelette, pas au service
1937
 * ainsi le produit du squelette peut être utilisé en entrée de filtres
1938
 * à suivre. On peut faire un `#INCLURE{fichier}` sans squelette
1939
 * (Incompatible avec les balises dynamiques).
1940
 *
1941
 * @balise
1942
 * @example
1943
 *     ```
1944
 *     [(#INCLURE{fond=inclure/documents,id_article, env})]
1945
 *     ```
1946
 *
1947
 * @param Champ $p
1948
 *     Pile au niveau de la balise
1949
 * @return Champ
1950
 *     Pile complétée par le code à générer
1951
 **/
1952
function balise_INCLURE_dist($p) {
1953
	$id_boucle = $p->id_boucle;
1954
	// la lang n'est pas passe de facon automatique par argumenter
1955
	// mais le sera pas recuperer_fond, sauf si etoile=>true est passe
1956
	// en option
1957
1958
	$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $id_boucle, false, false);
1959
1960
	// erreur de syntaxe = fond absent
1961
	// (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
1962
	if (!$_contexte) {
1963
		$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...
1964
	}
1965
1966
	if (isset($_contexte['fond'])) {
1967
1968
		$f = $_contexte['fond'];
1969
		// toujours vrai :
1970
		if (preg_match('/^.fond.\s*=>(.*)$/s', $f, $r)) {
1971
			$f = $r[1];
1972
			unset($_contexte['fond']);
1973
		} else {
1974
			spip_log("compilation de #INCLURE a revoir");
1975
		}
1976
1977
		// #INCLURE{doublons}
1978
		if (isset($_contexte['doublons'])) {
1979
			$_contexte['doublons'] = "'doublons' => \$doublons";
1980
		}
1981
1982
		// Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
1983
		$flag_env = false;
1984 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...
1985
			$flag_env = true;
1986
			unset($_contexte['env']);
1987
		}
1988
1989
		$_options = array();
1990 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...
1991
			$_options[] = preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
1992
			unset($_contexte['ajax']);
1993
		}
1994
		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...
1995
			$_options[] = "'etoile'=>true";
1996
		}
1997
		$_options[] = "'compil'=>array(" . memoriser_contexte_compil($p) . ")";
1998
1999
		$_l = 'array(' . join(",\n\t", $_contexte) . ')';
2000
		if ($flag_env) {
2001
			$_l = "array_merge(\$Pile[0],$_l)";
2002
		}
2003
2004
		$p->code = sprintf(CODE_RECUPERER_FOND, $f, $_l, join(',', $_options), "_request('connect')");
2005
2006
	} elseif (!isset($_contexte[1])) {
2007
		$msg = array('zbug_balise_sans_argument', array('balise' => ' INCLURE'));
2008
		erreur_squelette($msg, $p);
2009
	} else {
2010
		$p->code = 'charge_scripts(' . $_contexte[1] . ',false)';
2011
	}
2012
2013
	$p->interdire_scripts = false; // la securite est assuree par recuperer_fond
2014
	return $p;
2015
}
2016
2017
2018
/**
2019
 * Compile la balise `#MODELE` qui inclut un résultat de squelette de modèle
2020
 *
2021
 * `#MODELE{nom}` insère le résultat d’un squelette contenu dans le
2022
 * répertoire `modeles/`. L’identifiant de la boucle parente est transmis
2023
 * par défaut avec le paramètre `id` à cette inclusion.
2024
 *
2025
 * Des arguments supplémentaires peuvent être transmis :
2026
 * `[(#MODELE{nom, argument=xx, argument})]`
2027
 *
2028
 * @balise
2029
 * @see balise_INCLURE_dist()
2030
 * @example
2031
 *     ```
2032
 *     #MODELE{article_traductions}
2033
 *     ```
2034
 *
2035
 * @param Champ $p
2036
 *     Pile au niveau de la balise
2037
 * @return Champ
2038
 *     Pile complétée par le code à générer
2039
 **/
2040
function balise_MODELE_dist($p) {
2041
2042
	$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false);
2043
2044
	// erreur de syntaxe = fond absent
2045
	// (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP
2046
	if (!$_contexte) {
2047
		$_contexte = array();
2048
	}
2049
2050
	if (!isset($_contexte[1])) {
2051
		$msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE'));
2052
		erreur_squelette($msg, $p);
2053
	} else {
2054
		$nom = $_contexte[1];
2055
		unset($_contexte[1]);
2056
2057
		if (preg_match("/^\s*'[^']*'/s", $nom)) {
2058
			$nom = "'modeles/" . substr($nom, 1);
2059
		} else {
2060
			$nom = "'modeles/' . $nom";
2061
		}
2062
2063
		$flag_env = false;
2064
		if (isset($_contexte['env'])) {
2065
			$flag_env = true;
2066
			unset($_contexte['env']);
2067
		}
2068
2069
		// Incoherence dans la syntaxe du contexte. A revoir.
2070
		// Reserver la cle primaire de la boucle courante si elle existe
2071
		if (isset($p->boucles[$p->id_boucle]->primary)) {
2072
			$primary = $p->boucles[$p->id_boucle]->primary;
2073
			if (!strpos($primary, ',')) {
2074
				$id = champ_sql($primary, $p);
2075
				$_contexte[] = "'$primary'=>" . $id;
2076
				$_contexte[] = "'id'=>" . $id;
2077
			}
2078
		}
2079
		$_contexte[] = "'recurs'=>(++\$recurs)";
2080
		$connect = '';
2081
		if (isset($p->boucles[$p->id_boucle])) {
2082
			$connect = $p->boucles[$p->id_boucle]->sql_serveur;
2083
		}
2084
2085
		$_options = memoriser_contexte_compil($p);
2086
		$_options = "'compil'=>array($_options), 'trim'=>true";
2087 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...
2088
			$_options .= ", " . preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
2089
			unset($_contexte['ajax']);
2090
		}
2091
2092
		$_l = 'array(' . join(",\n\t", $_contexte) . ')';
2093
		if ($flag_env) {
2094
			$_l = "array_merge(\$Pile[0],$_l)";
2095
		}
2096
2097
		$page = sprintf(CODE_RECUPERER_FOND, $nom, $_l, $_options, _q($connect));
2098
2099
		$p->code = "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t$page)\n";
2100
2101
		$p->interdire_scripts = false; // securite assuree par le squelette
2102
	}
2103
2104
	return $p;
2105
}
2106
2107
2108
/**
2109
 * Compile la balise `#SET` qui affecte une variable locale au squelette
2110
 *
2111
 * Signature : `#SET{cle,valeur}`
2112
 *
2113
 * @balise
2114
 * @link https://www.spip.net/3990 Balises #SET et #GET
2115
 * @see balise_GET_dist()
2116
 * @example
2117
 *     ```
2118
 *     #SET{nb,5}
2119
 *     #GET{nb} // affiche 5
2120
 *     ```
2121
 *
2122
 * @param Champ $p
2123
 *     Pile au niveau de la balise
2124
 * @return Champ
2125
 *     Pile complétée par le code à générer
2126
 **/
2127 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...
2128
	$_nom = interprete_argument_balise(1, $p);
2129
	$_val = interprete_argument_balise(2, $p);
2130
2131
	if (!$_nom or !$_val) {
2132
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'SET'));
2133
		erreur_squelette($err_b_s_a, $p);
2134
	}
2135
	// affectation $_zzz inutile, mais permet de contourner un bug OpCode cache sous PHP 5.5.4
2136
	// cf https://bugs.php.net/bug.php?id=65845
2137
	else {
2138
		$p->code = "vide(\$Pile['vars'][\$_zzz=(string)$_nom] = $_val)";
2139
	}
2140
2141
	$p->interdire_scripts = false; // la balise ne renvoie rien
2142
	return $p;
2143
}
2144
2145
2146
/**
2147
 * Compile la balise `#GET` qui récupère une variable locale au squelette
2148
 *
2149
 * Signature : `#GET{cle[,defaut]}`
2150
 *
2151
 * La clé peut obtenir des sous clés séparés par des `/`
2152
 *
2153
 * @balise
2154
 * @link https://www.spip.net/3990 Balises #SET et #GET
2155
 * @see balise_SET_dist()
2156
 * @example
2157
 *     ```
2158
 *     #SET{nb,5}
2159
 *     #GET{nb} affiche 5
2160
 *     #GET{nb,3} affiche la valeur de nb, sinon 3
2161
 *
2162
 *     #SET{nb,#ARRAY{boucles,3}}
2163
 *     #GET{nb/boucles} affiche 3, équivalent à #GET{nb}|table_valeur{boucles}
2164
 *     ```
2165
 *
2166
 * @param Champ $p
2167
 *     Pile au niveau de la balise
2168
 * @return Champ
2169
 *     Pile complétée par le code à générer
2170
 **/
2171
function balise_GET_dist($p) {
2172
	$p->interdire_scripts = false; // le contenu vient de #SET, donc il est de confiance
2173
	if (function_exists('balise_ENV')) {
2174
		return balise_ENV($p, '$Pile["vars"]');
2175
	} else {
2176
		return balise_ENV_dist($p, '$Pile["vars"]');
2177
	}
2178
}
2179
2180
2181
/**
2182
 * Compile la balise `#DOUBLONS` qui redonne les doublons enregistrés
2183
 *
2184
 * - `#DOUBLONS{mots}` ou `#DOUBLONS{mots,famille}`
2185
 *   donne l'état des doublons `(MOTS)` à cet endroit
2186
 *   sous forme de tableau d'id_mot comme `array(1,2,3,...)`
2187
 * - `#DOUBLONS` tout seul donne la liste brute de tous les doublons
2188
 * - `#DOUBLONS*{mots}` donne la chaine brute `,1,2,3,...`
2189
 *   (changera si la gestion des doublons evolue)
2190
 *
2191
 * @balise
2192
 * @link https://www.spip.net/4123
2193
 *
2194
 * @param Champ $p
2195
 *     Pile au niveau de la balise
2196
 * @return Champ
2197
 *     Pile complétée par le code à générer
2198
 **/
2199
function balise_DOUBLONS_dist($p) {
2200
	if ($type = interprete_argument_balise(1, $p)) {
2201
		if ($famille = interprete_argument_balise(2, $p)) {
2202
			$type .= '.' . $famille;
2203
		}
2204
		$p->code = '(isset($doublons[' . $type . ']) ? $doublons[' . $type . '] : "")';
2205
		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...
2206
			$p->code = 'array_filter(array_map("intval",explode(",",'
2207
				. $p->code . ')))';
2208
		}
2209
	} else {
2210
		$p->code = '$doublons';
2211
	}
2212
2213
	$p->interdire_scripts = false;
2214
2215
	return $p;
2216
}
2217
2218
2219
/**
2220
 * Compile la balise `#PIPELINE` pour permettre d'insérer des sorties de
2221
 * pipeline dans un squelette
2222
 *
2223
 * @balise
2224
 * @see pipeline()
2225
 * @example
2226
 *     ```
2227
 *     #PIPELINE{nom}
2228
 *     #PIPELINE{nom,données}
2229
 *     #PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{type,rubrique,id,#ENV{id_rubrique}}}}
2230
 *     ```
2231
 *
2232
 * @param Champ $p
2233
 *     Pile au niveau de la balise
2234
 * @return Champ
2235
 *     Pile complétée par le code à générer
2236
 **/
2237 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...
2238
	$_pipe = interprete_argument_balise(1, $p);
2239
	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...
2240
		$err_b_s_a = array('zbug_balise_sans_argument', array('balise' => 'PIPELINE'));
2241
		erreur_squelette($err_b_s_a, $p);
2242
	} else {
2243
		$_flux = interprete_argument_balise(2, $p);
2244
		$_flux = $_flux ? $_flux : "''";
2245
		$p->code = "pipeline( $_pipe , $_flux )";
2246
		$p->interdire_scripts = false;
2247
	}
2248
2249
	return $p;
2250
}
2251
2252
2253
/**
2254
 * Compile la balise `#EDIT` qui ne fait rien dans SPIP
2255
 *
2256
 * Cette balise ne retourne rien mais permet d'indiquer, pour certains plugins
2257
 * qui redéfinissent cette balise, le nom du champ SQL (ou le nom d'un contrôleur)
2258
 * correspondant à ce qui est édité. Cela sert particulièrement au plugin Crayons.
2259
 * Ainsi en absence du plugin, la balise est toujours reconnue (mais n'a aucune action).
2260
 *
2261
 * @balise
2262
 * @link https://www.spip.net/4584
2263
 * @example
2264
 *     ```
2265
 *     [<div class="#EDIT{texte} texte">(#TEXTE)</div>]
2266
 *     ```
2267
 *
2268
 * @param Champ $p
2269
 *     Pile au niveau de la balise
2270
 * @return Champ
2271
 *     Pile complétée par le code à générer
2272
 **/
2273
function balise_EDIT_dist($p) {
2274
	$p->code = "''";
2275
	$p->interdire_scripts = false;
2276
2277
	return $p;
2278
}
2279
2280
2281
/**
2282
 * Compile la balise `#TOTAL_UNIQUE` qui récupère le nombre d'éléments
2283
 * différents affichés par le filtre `unique`
2284
 *
2285
 * @balise
2286
 * @link https://www.spip.net/4374
2287
 * @see unique()
2288
 * @example
2289
 *     ```
2290
 *     #TOTAL_UNIQUE affiche le nombre de #BALISE|unique
2291
 *     #TOTAL_UNIQUE{famille} afiche le nombre de #BALISE|unique{famille}
2292
 *     ```
2293
 *
2294
 * @param Champ $p
2295
 *     Pile au niveau de la balise
2296
 * @return Champ
2297
 *     Pile complétée par le code à générer
2298
 **/
2299
function balise_TOTAL_UNIQUE_dist($p) {
2300
	$_famille = interprete_argument_balise(1, $p);
2301
	$_famille = $_famille ? $_famille : "''";
2302
	$p->code = "unique('', $_famille, true)";
2303
2304
	return $p;
2305
}
2306
2307
/**
2308
 * Compile la balise `#ARRAY` créant un tableau PHP associatif
2309
 *
2310
 * Crée un `array` PHP à partir d'arguments calculés.
2311
 * Chaque paire d'arguments représente la clé et la valeur du tableau.
2312
 *
2313
 * @balise
2314
 * @link https://www.spip.net/4009
2315
 * @example
2316
 *     ```
2317
 *     #ARRAY{key1,val1,key2,val2 ...} retourne
2318
 *     array( key1 => val1, key2 => val2, ...)
2319
 *     ```
2320
 *
2321
 * @param Champ $p
2322
 *     Pile au niveau de la balise
2323
 * @return Champ
2324
 *     Pile complétée par le code à générer
2325
 **/
2326
function balise_ARRAY_dist($p) {
2327
	$_code = array();
2328
	$n = 1;
2329
	do {
2330
		$_key = interprete_argument_balise($n++, $p);
2331
		$_val = interprete_argument_balise($n++, $p);
2332
		if ($_key and $_val) {
2333
			$_code[] = "$_key => $_val";
2334
		}
2335
	} 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...
2336
	$p->code = 'array(' . join(', ', $_code) . ')';
2337
	$p->interdire_scripts = false;
2338
2339
	return $p;
2340
}
2341
2342
/**
2343
 * Compile la balise `#LISTE` qui crée un tableau PHP avec les valeurs, sans préciser les clés
2344
 *
2345
 * @balise
2346
 * @link https://www.spip.net/5547
2347
 * @example
2348
 *    ```
2349
 *    #LISTE{a,b,c,d,e}
2350
 *    ```
2351
 *
2352
 * @param Champ $p
2353
 *     Pile au niveau de la balise
2354
 * @return Champ
2355
 *     Pile complétée par le code à générer
2356
 */
2357 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...
2358
	$_code = array();
2359
	$n = 1;
2360
	while ($_val = interprete_argument_balise($n++, $p)) {
2361
		$_code[] = $_val;
2362
	}
2363
	$p->code = 'array(' . join(', ', $_code) . ')';
2364
	$p->interdire_scripts = false;
2365
2366
	return $p;
2367
}
2368
2369
2370
/**
2371
 * Compile la balise `#AUTORISER` qui teste une autorisation
2372
 *
2373
 * Appelle la fonction `autoriser()` avec les mêmes arguments,
2374
 * et renvoie un espace ' ' si OK (l'action est autorisée),
2375
 * sinon une chaine vide '' (l'action n'est pas autorisée).
2376
 *
2377
 * Cette balise créée un cache par session.
2378
 *
2379
 * Signature : `#AUTORISER{faire[,type[,id[,auteur[,options]]]}`
2380
 *
2381
 * @note
2382
 *     La priorité des opérateurs exige && plutot que AND
2383
 *
2384
 * @balise
2385
 * @link https://www.spip.net/3896
2386
 * @see autoriser()
2387
 * @see sinon_interdire_acces()
2388
 * @example
2389
 *    ```
2390
 *    [(#AUTORISER{modifier,rubrique,#ID_RUBRIQUE}) ... ]
2391
 *    [(#AUTORISER{voir,rubrique,#ID_RUBRIQUE}|sinon_interdire_acces)]
2392
 *    ```
2393
 *
2394
 * @param Champ $p
2395
 *     Pile au niveau de la balise
2396
 * @return Champ
2397
 *     Pile complétée par le code à générer
2398
 **/
2399 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...
2400
	$_code = array();
2401
	$p->descr['session'] = true; // faire un cache par session
2402
2403
	$n = 1;
2404
	while ($_v = interprete_argument_balise($n++, $p)) {
2405
		$_code[] = $_v;
2406
	}
2407
2408
	$p->code = '((function_exists("autoriser")||include_spip("inc/autoriser"))&&autoriser(' . join(', ',
2409
			$_code) . ')?" ":"")';
2410
	$p->interdire_scripts = false;
2411
2412
	return $p;
2413
}
2414
2415
2416
/**
2417
 * Compile la balise `#PLUGIN` qui permet d’afficher les informations d'un plugin actif
2418
 *
2419
 * @balise
2420
 * @see filtre_info_plugin_dist()
2421
 * @link https://www.spip.net/4591
2422
 * @example
2423
 *     ```
2424
 *     #PLUGIN Retourne la liste sérialisée des préfixes de plugins actifs
2425
 *     #PLUGIN{prefixe} Renvoie true si le plugin avec ce préfixe est actif
2426
 *     #PLUGIN{prefixe, x} Renvoie l'information x du plugin (s'il est actif)
2427
 *     #PLUGIN{prefixe, tout} Renvoie toutes les informations du plugin (s'il est actif)
2428
 *     ```
2429
 *
2430
 * @param Champ $p
2431
 *     Pile au niveau de la balise
2432
 * @return Champ
2433
 *     Pile complétée par le code à générer
2434
 **/
2435
function balise_PLUGIN_dist($p) {
2436
	$plugin = interprete_argument_balise(1, $p);
2437
	$plugin = isset($plugin) ? str_replace('\'', '"', $plugin) : '""';
2438
	$type_info = interprete_argument_balise(2, $p);
2439
	$type_info = isset($type_info) ? str_replace('\'', '"', $type_info) : '"est_actif"';
2440
2441
	$f = chercher_filtre('info_plugin');
2442
	$p->code = $f . '(' . $plugin . ', ' . $type_info . ')';
2443
2444
	return $p;
2445
}
2446
2447
/**
2448
 * Compile la balise `#AIDER` qui permet d’afficher l’icone de l’aide
2449
 * au sein des squelettes.
2450
 *
2451
 * @balise
2452
 * @see inc_aide_dist()
2453
 * @link https://www.spip.net/4733
2454
 * @example
2455
 *     ```
2456
 *     #AIDER{raccourcis}
2457
 *     ```
2458
 *
2459
 * @param Champ $p
2460
 *     Pile au niveau de la balise
2461
 * @return Champ
2462
 *     Pile complétée par le code à générer
2463
 **/
2464
function balise_AIDER_dist($p) {
2465
	$_motif = interprete_argument_balise(1, $p);
2466
	$p->code = "((\$aider=charger_fonction('aide','inc',true))?\$aider($_motif):'')";
2467
	return $p;
2468
}
2469
2470
/**
2471
 * Compile la balise `#ACTION_FORMULAIRE` qui insère le contexte
2472
 * des formulaires charger / vérifier / traiter avec les hidden de
2473
 * l'URL d'action
2474
 *
2475
 * Accèpte 2 arguments optionnels :
2476
 * - L'url de l'action (par défaut `#ENV{action}`
2477
 * - Le nom du formulaire (par défaut `#ENV{form}`
2478
 *
2479
 * @balise
2480
 * @see form_hidden()
2481
 * @example
2482
 *     ```
2483
 *     <form method='post' action='#ENV{action}'><div>
2484
 *     #ACTION_FORMULAIRE
2485
 *     ```
2486
 *
2487
 * @param Champ $p
2488
 *     Pile au niveau de la balise
2489
 * @return Champ
2490
 *     Pile complétée par le code à générer
2491
 **/
2492
function balise_ACTION_FORMULAIRE($p) {
2493
	if (!$_url = interprete_argument_balise(1, $p)) {
2494
		$_url = "@\$Pile[0]['action']";
2495
	}
2496
	if (!$_form = interprete_argument_balise(2, $p)) {
2497
		$_form = "@\$Pile[0]['form']";
2498
	}
2499
2500
	// envoyer le nom du formulaire que l'on traite
2501
	// transmettre les eventuels args de la balise formulaire
2502
	$p->code = "	'<span class=\"form-hidden\">' .
2503
	form_hidden($_url) .
2504
	'<input name=\'formulaire_action\' type=\'hidden\'
2505
		value=\'' . $_form . '\' />' .
2506
	'<input name=\'formulaire_action_args\' type=\'hidden\'
2507
		value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
2508
	(!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') .
2509
	'</span>'";
2510
2511
	$p->interdire_scripts = false;
2512
2513
	return $p;
2514
}
2515
2516
2517
/**
2518
 * Compile la balise `#BOUTON_ACTION` qui génère un bouton d'action en post, ajaxable
2519
 *
2520
 * Cette balise s'utilise à la place des liens `action_auteur`, sous la forme
2521
 * `#BOUTON_ACTION{libelle[,url[,class[,confirm[,title[,callback]]]]]}`
2522
 *
2523
 * - libelle  : Texte du bouton
2524
 * - url      : URL d’action sécurisée
2525
 * - class    : Classes à ajouter au bouton, à l'exception de `ajax` qui est placé sur le formulaire.
2526
 *              Pour d'autres classes sur le formulaire, utiliser le filtre `ajouter_class`
2527
 * - confirm  : message de confirmation oui/non avant l'action
2528
 * - title    : attribut title à ajouter au bouton
2529
 * - callback : callback js a appeler lors de l'évènement action et avant execution de l'action
2530
 *               (ou après confirmation éventuelle si $confirm est non vide).
2531
 *               Si la callback renvoie false, elle annule le déclenchement de l'action.
2532
 *
2533
 * @balise
2534
 * @uses bouton_action()
2535
 * @link https://www.spip.net/4583
2536
 * @example
2537
 *     ```
2538
 *     [(#AUTORISER{reparer,base}|oui)
2539
 *        [(#BOUTON_ACTION{
2540
 *            <:bouton_tenter_recuperation:>,
2541
 *            #URL_ECRIRE{base_repair},
2542
 *            "ajax btn_large",
2543
 *        })]
2544
 *     ]
2545
 *     ```
2546
 *
2547
 * @param Champ $p
2548
 *     Pile au niveau de la balise
2549
 * @return Champ
2550
 *     Pile complétée par le code à générer
2551
 */
2552
function balise_BOUTON_ACTION_dist($p) {
2553
2554
	$args = array();
2555
	for ($k = 1; $k <= 6; $k++) {
2556
		$_a = interprete_argument_balise($k, $p);
2557
		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...
2558
			$_a = "''";
2559
		}
2560
		$args[] = $_a;
2561
	}
2562
	// supprimer les args vides
2563
	while (end($args) == "''" and count($args) > 2) {
2564
		array_pop($args);
2565
	}
2566
	$args = implode(",", $args);
2567
2568
	$bouton_action = chercher_filtre("bouton_action");
2569
	$p->code = "$bouton_action($args)";
2570
	$p->interdire_scripts = false;
2571
2572
	return $p;
2573
}
2574
2575
2576
/**
2577
 * Compile la balise `#SLOGAN_SITE_SPIP` qui retourne le slogan du site
2578
 *
2579
 * @balise
2580
 * @example
2581
 *     ```
2582
 *     [<p id="slogan">(#SLOGAN_SITE_SPIP)</p>]
2583
 *     ```
2584
 *
2585
 * @param Champ $p
2586
 *     Pile au niveau de la balise
2587
 * @return Champ
2588
 *     Pile complétée par le code à générer
2589
 */
2590
function balise_SLOGAN_SITE_SPIP_dist($p) {
2591
	$p->code = "\$GLOBALS['meta']['slogan_site']";
2592
2593
	#$p->interdire_scripts = true;
2594
	return $p;
2595
}
2596
2597
2598
/**
2599
 * Compile la balise `#HTML5` indiquant si l'espace public peut utiliser du HTML5
2600
 *
2601
 * Renvoie `' '` si le webmestre souhaite que SPIP génère du code (X)HTML5 sur
2602
 * le site public, et `''` si le code doit être strictement compatible HTML4
2603
 *
2604
 * @balise
2605
 * @uses html5_permis()
2606
 * @example
2607
 *     ```
2608
 *     [(#HTML5) required="required"]
2609
 *     <input[ (#HTML5|?{type="email",type="text"})] ... />
2610
 *     ```
2611
 *
2612
 * @param Champ $p
2613
 *     Pile au niveau de la balise
2614
 * @return Champ
2615
 *     Pile complétée par le code à générer
2616
 */
2617
function balise_HTML5_dist($p) {
2618
	$p->code = html5_permis() ? "' '" : "''";
2619
	$p->interdire_scripts = false;
2620
2621
	return $p;
2622
}
2623
2624
2625
/**
2626
 * Compile la balise `#TRI` permettant d'afficher un lien de changement d'ordre de tri
2627
 * d'une colonne de la boucle
2628
 *
2629
 * La balise `#TRI{champ[,libelle]}` champ prend `>` ou `<` pour afficher
2630
 * le lien de changement de sens croissant ou decroissant (`>` `<` indiquent
2631
 * un sens par une flèche)
2632
 *
2633
 * @balise
2634
 * @example
2635
 *     ```
2636
 *     <th>[(#TRI{titre,<:info_titre:>,ajax})]</th>
2637
 *     ```
2638
 *
2639
 * @param Champ $p
2640
 *     Pile au niveau de la balise
2641
 * @param string $liste
2642
 *     Inutilisé
2643
 * @return Champ
2644
 *     Pile complétée par le code à générer
2645
 */
2646
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...
2647
	$b = index_boucle_mere($p);
2648
	// s'il n'y a pas de nom de boucle, on ne peut pas trier
2649
	if ($b === '') {
2650
		$msg = array('zbug_champ_hors_boucle', array('champ' => zbug_presenter_champ($p)));
2651
		erreur_squelette($msg, $p);
2652
		$p->code = "''";
2653
2654
		return $p;
2655
	}
2656
	$boucle = $p->boucles[$b];
2657
2658
	// s'il n'y a pas de tri_champ, c'est qu'on se trouve
2659
	// dans un boucle recursive ou qu'on a oublie le critere {tri}
2660
	if (!isset($boucle->modificateur['tri_champ'])) {
2661
		$msg = array('zbug_champ_hors_critere', array(
2662
			'champ' => zbug_presenter_champ($p),
2663
			'critere' => 'tri'
2664
		));
2665
		erreur_squelette($msg, $p);
2666
		$p->code = "''";
2667
2668
		return $p;
2669
	}
2670
2671
	$_champ = interprete_argument_balise(1, $p);
2672
	// si pas de champ, renvoyer le critere de tri utilise
2673
	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...
2674
		$p->code = $boucle->modificateur['tri_champ'];
2675
2676
		return $p;
2677
	}
2678
	// forcer la jointure si besoin, et si le champ est statique
2679
	if (preg_match(",^'([\w.]+)'$,i", $_champ, $m)) {
2680
		index_pile($b, $m[1], $p->boucles, '', null, true, false);
2681
	}
2682
2683
	$_libelle = interprete_argument_balise(2, $p);
2684
	$_libelle = $_libelle ? $_libelle : $_champ;
2685
2686
	$_class = interprete_argument_balise(3, $p);
2687
	// si champ = ">" c'est un lien vers le tri croissant : de gauche a droite ==> 1
2688
	// si champ = "<" c'est un lien vers le tri decroissant : (sens inverse) == -1
2689
	$_issens = "in_array($_champ,array('>','<'))";
2690
	$_sens = "(strpos('< >',$_champ)-1)";
2691
2692
	$_variable = "((\$s=$_issens)?'sens':'tri')." . $boucle->modificateur['tri_nom'];
2693
	$_url = "parametre_url(self(),$_variable,\$s?$_sens:$_champ)";
2694
	$_url = "parametre_url($_url,'var_memotri',strncmp(" . $boucle->modificateur['tri_nom'] . ",'session',7)==0?$_variable:'')";
2695
	$_on = "\$s?(" . $boucle->modificateur['tri_sens'] . "==$_sens" . '):(' . $boucle->modificateur['tri_champ'] . "==$_champ)";
2696
2697
	$p->code = "lien_ou_expose($_url,$_libelle,$_on" . ($_class ? ",$_class" : "") . ")";
2698
	//$p->code = "''";
2699
	$p->interdire_scripts = false;
2700
2701
	return $p;
2702
}
2703
2704
2705
/**
2706
 * Compile la balise `#SAUTER{n}` qui permet de sauter en avant n resultats dans une boucle
2707
 *
2708
 * La balise modifie le compteur courant de la boucle, mais pas les autres
2709
 * champs qui restent les valeurs de la boucle avant le saut. Il est donc
2710
 * preferable d'utiliser la balise juste avant la fermeture `</BOUCLE>`
2711
 *
2712
 * L'argument `n` doit être supérieur à zéro sinon la balise ne fait rien
2713
 *
2714
 * @balise
2715
 *
2716
 * @param Champ $p
2717
 *     Pile au niveau de la balise
2718
 * @return Champ
2719
 *     Pile complétée par le code à générer
2720
 */
2721
function balise_SAUTER_dist($p) {
2722
	$id_boucle = $p->id_boucle;
2723
2724
	if (empty($p->boucles[$id_boucle])) {
2725
		$msg = array('zbug_champ_hors_boucle', array('champ' => '#SAUTER'));
2726
		erreur_squelette($msg, $p);
2727
	} else {
2728
		$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...
2729
		$_saut = interprete_argument_balise(1, $p);
2730
		$_compteur = "\$Numrows['$id_boucle']['compteur_boucle']";
2731
		$_total = "\$Numrows['$id_boucle']['total']";
2732
2733
		$p->code = "vide($_compteur=\$iter->skip($_saut,$_total))";
2734
	}
2735
	$p->interdire_scripts = false;
2736
2737
	return $p;
2738
}
2739
2740
2741
/**
2742
 * Compile la balise `#PUBLIE` qui indique si un objet est publié ou non
2743
 *
2744
 * @balise
2745
 * @link https://www.spip.net/5545
2746
 * @see objet_test_si_publie()
2747
 * @example
2748
 *     ```
2749
 *     #PUBLIE : porte sur la boucle en cours
2750
 *     [(#PUBLIE{article, 3}|oui) ... ] : pour l'objet indiqué
2751
 *     ```
2752
 *
2753
 * @param Champ $p
2754
 *     Pile au niveau de la balise
2755
 * @return Champ
2756
 *     Pile complétée par le code à générer
2757
 */
2758
function balise_PUBLIE_dist($p) {
2759
	if (!$_type = interprete_argument_balise(1, $p)) {
2760
		$_type = _q($p->type_requete);
2761
		$_id = champ_sql($p->boucles[$p->id_boucle]->primary, $p);
2762
	} else {
2763
		$_id = interprete_argument_balise(2, $p);
2764
	}
2765
2766
	$connect = '';
2767
	if (isset($p->boucles[$p->id_boucle])) {
2768
		$connect = $p->boucles[$p->id_boucle]->sql_serveur;
2769
	}
2770
2771
	$p->code = "(objet_test_si_publie(" . $_type . ",intval(" . $_id . ")," . _q($connect) . ")?' ':'')";
2772
	$p->interdire_scripts = false;
2773
2774
	return $p;
2775
}
2776
2777
/**
2778
 * Compile la balise `#PRODUIRE` qui génère un fichier statique à partir
2779
 * d'un squelette SPIP
2780
 *
2781
 * Le format du fichier sera extrait de la pre-extension du squelette
2782
 * (typo.css.html, messcripts.js.html)
2783
 * ou par l'argument `format=css` ou `format=js` passé en argument.
2784
 *
2785
 * S'il n'y a pas de format détectable, on utilise `.html`, comme pour les squelettes.
2786
 *
2787
 * La syntaxe de la balise est la même que celle de `#INCLURE`.
2788
 *
2789
 * @balise
2790
 * @see balise_INCLURE_dist()
2791
 * @link https://www.spip.net/5505
2792
 * @example
2793
 *     ```
2794
 *     <link rel="stylesheet" type="text/css" href="#PRODUIRE{fond=css/macss.css,couleur=ffffff}" />
2795
 *     ```
2796
 *
2797
 * @param Champ $p
2798
 *     Pile au niveau de la balise
2799
 * @return Champ
2800
 *     Pile complétée par le code à générer
2801
 */
2802
function balise_PRODUIRE_dist($p) {
2803
	$balise_inclure = charger_fonction('INCLURE', 'balise');
2804
	$p = $balise_inclure($p);
2805
2806
	$p->code = str_replace('recuperer_fond(', 'produire_fond_statique(', $p->code);
2807
2808
	return $p;
2809
}
2810
2811
/**
2812
 * Compile la balise `#LARGEUR_ECRAN` qui définit la largeur d'écran
2813
 * dans l'espace privé
2814
 *
2815
 * @balise
2816
 * @example
2817
 *     ```
2818
 *     #LARGEUR_ECRAN{pleine_largeur}
2819
 *     ```
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_LARGEUR_ECRAN_dist($p) {
2827
	$_class = interprete_argument_balise(1, $p);
2828
	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...
2829
		$_class = 'null';
2830
	}
2831
	$p->code = "(is_string($_class)?vide(\$GLOBALS['largeur_ecran']=$_class):(isset(\$GLOBALS['largeur_ecran'])?\$GLOBALS['largeur_ecran']:''))";
2832
2833
	return $p;
2834
}
2835
2836
2837
/**
2838
 * Compile la balise `#CONST` qui retourne la valeur de la constante passée en argument
2839
 *
2840
 * @balise
2841
 * @example `#CONST{_DIR_IMG}`
2842
 *
2843
 * @param Champ $p
2844
 *     Pile au niveau de la balise
2845
 * @return Champ
2846
 *     Pile complétée par le code à générer
2847
 **/
2848
function balise_CONST_dist($p) {
2849
	$_const = interprete_argument_balise(1, $p);
2850
	if (!strlen($_const)) {
2851
		$p->code = "''";
2852
	}
2853
	else {
2854
		$p->code = "(defined($_const)?constant($_const):'')";
2855
	}
2856
	$p->interdire_scripts = false;
2857
2858
	return $p;
2859
}
2860