Completed
Push — master ( afa7a5...dd48fb )
by cam
08:20
created

balises.php ➔ balise_RANG_dist()   C

Complexity

Conditions 13
Paths 82

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 82
nop 1
dl 0
loc 76
rs 5.8169
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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