source: spip-zone/_core_/plugins/textwheel/inc/texte.php

Last change on this file was 113294, checked in by spip.franck@…, 2 months ago

Il parait que le futur c'est maintenant :-D

File size: 23.0 KB
Line 
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 * Gestion des textes et raccourcis SPIP
15 *
16 * Surcharge de ecrire/inc/texte
17 *
18 * @package SPIP\Textwheel\Texte
19 **/
20
21if (!defined('_ECRIRE_INC_VERSION')) {
22        return;
23}
24
25include_spip('inc/texte_mini');
26include_spip('inc/lien');
27
28include_spip('inc/textwheel');
29
30
31defined('_AUTOBR') || define('_AUTOBR', "<br class='autobr' />");
32define('_AUTOBR_IGNORER', _AUTOBR ? "<!-- ig br -->" : "");
33
34// Avec cette surcharge, cette globale n'est plus définie, et du coup ça plante dans les plugins qui font un foreach dessus comme ZPIP
35$GLOBALS['spip_raccourcis_typo'] = array();
36if (!isset($GLOBALS['toujours_paragrapher'])) {
37        $GLOBALS['toujours_paragrapher'] = true;
38}
39
40// class_spip : savoir si on veut class="spip" sur p i strong & li
41// class_spip_plus : class="spip" sur les ul ol h3 hr quote table...
42// la difference c'est que des css specifiques existent pour les seconds
43//
44if (!isset($GLOBALS['class_spip'])) {
45        $GLOBALS['class_spip'] = '';
46}
47if (!isset($GLOBALS['class_spip_plus'])) {
48        $GLOBALS['class_spip_plus'] = ' class="spip"';
49}
50
51
52/**
53 * Échapper et affichier joliement les `<script` ...
54 *
55 * @param string $t
56 * @return string
57 */
58function echappe_js($t) {
59        static $wheel = null;
60
61        if (!isset($wheel)) {
62                $wheel = new TextWheel(
63                        SPIPTextWheelRuleset::loader($GLOBALS['spip_wheels']['echappe_js'])
64                );
65        }
66
67        try {
68                $t = $wheel->text($t);
69        } catch (Exception $e) {
70                erreur_squelette($e->getMessage());
71                // sanitizer le contenu methode brute, puisqu'on a pas fait mieux
72                $t = textebrut($t);
73        }
74
75        return $t;
76}
77
78
79/**
80 * Paragrapher seulement
81 *
82 * Fermer les paragraphes ; Essaie de préserver des paragraphes indiqués
83 * à la main dans le texte (par ex: on ne modifie pas un `<p align='center'>`)
84 *
85 * @param string $t
86 *     Le texte
87 * @param null $toujours_paragrapher
88 *     true pour forcer les `<p>` même pour un seul paragraphe
89 * @return string
90 *     Texte paragraphé
91 */
92function paragrapher($t, $toujours_paragrapher = null) {
93        static $wheel = array();
94        if (is_null($toujours_paragrapher)) {
95                $toujours_paragrapher = $GLOBALS['toujours_paragrapher'];
96        }
97
98        if (!isset($wheel[$toujours_paragrapher])) {
99                $ruleset = SPIPTextWheelRuleset::loader($GLOBALS['spip_wheels']['paragrapher']);
100                if (!$toujours_paragrapher
101                        and $rule = $ruleset->getRule('toujours-paragrapher')
102                ) {
103                        $rule->disabled = true;
104                        $ruleset->addRules(array('toujours-paragrapher' => $rule));
105                }
106                $wheel[$toujours_paragrapher] = new TextWheel($ruleset);
107        }
108
109        try {
110                $t = $wheel[$toujours_paragrapher]->text($t);
111        } catch (Exception $e) {
112                erreur_squelette($e->getMessage());
113        }
114
115        return $t;
116}
117
118/**
119 * Empêcher l'exécution de code PHP et JS
120 *
121 * Sécurité : empêcher l'exécution de code PHP, en le transformant en joli code
122 * dans l'espace privé. Cette fonction est aussi appelée par propre et typo.
123 *
124 * De la même manière, la fonction empêche l'exécution de JS mais selon le mode
125 * de protection passe en argument
126 *
127 * Il ne faut pas désactiver globalement la fonction dans l'espace privé car elle protège
128 * aussi les balises des squelettes qui ne passent pas forcement par propre ou typo après
129 * si elles sont appelées en direct
130 *
131 * @param string $arg
132 *     Code à protéger
133 * @param int $mode_filtre
134 *     Mode de protection
135 *       -1 : protection dans l'espace privé et public
136 *       0  : protection dans l'espace public
137 *       1  : aucune protection
138 *     utilise la valeur de la globale filtrer_javascript si non fourni
139 * @return string
140 *     Code protégé
141 **/
142function interdire_scripts($arg, $mode_filtre=null) {
143        // on memorise le resultat sur les arguments non triviaux
144        static $dejavu = array();
145        static $wheel = array();
146
147        if (is_null($mode_filtre) or !in_array($mode_filtre, array(-1, 0, 1))) {
148                $mode_filtre = $GLOBALS['filtrer_javascript'];
149        }
150
151        // Attention, si ce n'est pas une chaine, laisser intact
152        if (!$arg or !is_string($arg) or !strstr($arg, '<')) {
153                return $arg;
154        }
155        if (isset($dejavu[$mode_filtre][$arg])) {
156                return $dejavu[$mode_filtre][$arg];
157        }
158
159        if (!isset($wheel[$mode_filtre])) {
160                $ruleset = SPIPTextWheelRuleset::loader(
161                        $GLOBALS['spip_wheels']['interdire_scripts']
162                );
163                // Pour le js, trois modes : parano (-1), prive (0), ok (1)
164                // desactiver la regle echappe-js si besoin
165                if ($mode_filtre == 1
166                        or ($mode_filtre == 0 and !test_espace_prive())
167                ) {
168                        $ruleset->addRules(array('securite-js' => array('disabled' => true)));
169                }
170                $wheel[$mode_filtre] = new TextWheel($ruleset);
171        }
172
173        try {
174                $t = $wheel[$mode_filtre]->text($arg);
175        } catch (Exception $e) {
176                erreur_squelette($e->getMessage());
177                // sanitizer le contenu methode brute, puisqu'on a pas fait mieux
178                $t = textebrut($arg);
179        }
180
181        // Reinserer les echappements des modeles
182        if (defined('_PROTEGE_JS_MODELES')) {
183                $t = echappe_retour($t, "javascript" . _PROTEGE_JS_MODELES);
184        }
185        if (defined('_PROTEGE_PHP_MODELES')) {
186                $t = echappe_retour($t, "php" . _PROTEGE_PHP_MODELES);
187        }
188
189        return $dejavu[$mode_filtre][$arg] = $t;
190}
191
192
193/**
194 * Applique la typographie générale
195 *
196 * Effectue un traitement pour que les textes affichés suivent les règles
197 * de typographie. Fait une protection préalable des balises HTML et SPIP.
198 * Transforme les balises `<multi>`
199 *
200 * @filtre
201 * @uses traiter_modeles()
202 * @uses corriger_typo()
203 * @uses echapper_faux_tags()
204 * @see  propre()
205 *
206 * @param string $letexte
207 *     Texte d'origine
208 * @param bool $echapper
209 *     Échapper ?
210 * @param string|null $connect
211 *     Nom du connecteur à la bdd
212 * @param array $env
213 *     Environnement (pour les calculs de modèles)
214 * @return string $t
215 *     Texte transformé
216 **/
217function typo($letexte, $echapper = true, $connect = null, $env = array()) {
218        // Plus vite !
219        if (!$letexte) {
220                return $letexte;
221        }
222
223        // les appels directs a cette fonction depuis le php de l'espace
224        // prive etant historiquement ecrit sans argment $connect
225        // on utilise la presence de celui-ci pour distinguer les cas
226        // ou il faut passer interdire_script explicitement
227        // les appels dans les squelettes (de l'espace prive) fournissant un $connect
228        // ne seront pas perturbes
229        $interdire_script = false;
230        if (is_null($connect)) {
231                $connect = '';
232                $interdire_script = true;
233                $env['espace_prive'] = test_espace_prive();
234        }
235
236        $echapper = ($echapper ? 'TYPO' : false);
237        // Echapper les codes <html> etc
238        if ($echapper) {
239                $letexte = echappe_html($letexte, $echapper);
240        }
241
242        //
243        // Installer les modeles, notamment images et documents ;
244        //
245        // NOTE : propre() ne passe pas par ici mais directement par corriger_typo
246        // cf. inc/lien
247
248        $letexte = traiter_modeles($mem = $letexte, false, $echapper ? $echapper : '', $connect, null, $env);
249        if (!$echapper and $letexte != $mem) {
250                $echapper = '';
251        }
252        unset($mem);
253
254        $letexte = corriger_typo($letexte);
255        $letexte = echapper_faux_tags($letexte);
256
257        // reintegrer les echappements
258        if ($echapper !== false) {
259                $letexte = echappe_retour($letexte, $echapper);
260        }
261
262        // Dans les appels directs hors squelette, securiser ici aussi
263        if ($interdire_script) {
264                $letexte = interdire_scripts($letexte);
265        }
266
267        // Dans l'espace prive on se mefie de tout contenu dangereux
268        // https://core.spip.net/issues/3371
269        // et aussi dans l'espace public si la globale filtrer_javascript = -1
270        // https://core.spip.net/issues/4166
271        if ($GLOBALS['filtrer_javascript'] == -1
272          or (isset($env['espace_prive']) and $env['espace_prive'] and $GLOBALS['filtrer_javascript']<=0)) {
273                $letexte = echapper_html_suspect($letexte);
274        }
275
276        return $letexte;
277}
278
279// Correcteur typographique
280
281define('_TYPO_PROTEGER', "!':;?~%-");
282define('_TYPO_PROTECTEUR', "\x1\x2\x3\x4\x5\x6\x7\x8");
283
284define('_TYPO_BALISE', ",</?[a-z!][^<>]*[" . preg_quote(_TYPO_PROTEGER) . "][^<>]*>,imsS");
285
286/**
287 * Corrige la typographie
288 *
289 * Applique les corrections typographiques adaptées à la langue indiquée.
290 *
291 * @pipeline_appel pre_typo
292 * @pipeline_appel post_typo
293 * @uses corriger_caracteres()
294 * @uses corriger_caracteres()
295 *
296 * @param string $t Texte
297 * @param string $lang Langue
298 * @return string Texte
299 */
300function corriger_typo($t, $lang = '') {
301        static $typographie = array();
302        // Plus vite !
303        if (!$t) {
304                return $t;
305        }
306
307        $t = pipeline('pre_typo', $t);
308
309        // Caracteres de controle "illegaux"
310        $t = corriger_caracteres($t);
311
312        // Proteger les caracteres typographiques a l'interieur des tags html
313        if (preg_match_all(_TYPO_BALISE, $t, $regs, PREG_SET_ORDER)) {
314                foreach ($regs as $reg) {
315                        $insert = $reg[0];
316                        // hack: on transforme les caracteres a proteger en les remplacant
317                        // par des caracteres "illegaux". (cf corriger_caracteres())
318                        $insert = strtr($insert, _TYPO_PROTEGER, _TYPO_PROTECTEUR);
319                        $t = str_replace($reg[0], $insert, $t);
320                }
321        }
322
323        // trouver les blocs idiomes et les traiter à part
324        $t = extraire_idiome($ei = $t, $lang, true);
325        $ei = ($ei !== $t);
326
327        // trouver les blocs multi et les traiter à part
328        $t = extraire_multi($em = $t, $lang, true);
329        $em = ($em !== $t);
330
331        // Charger & appliquer les fonctions de typographie
332        $idxl = "$lang:" . (isset($GLOBALS['lang_objet']) ? $GLOBALS['lang_objet'] : $GLOBALS['spip_lang']);
333        if (!isset($typographie[$idxl])) {
334                $typographie[$idxl] = charger_fonction(lang_typo($lang), 'typographie');
335        }
336        $t = $typographie[$idxl]($t);
337
338        // Les citations en une autre langue, s'il y a lieu
339        if ($ei) {
340                $t = echappe_retour($t, 'idiome');
341        }
342        if ($em) {
343                $t = echappe_retour($t, 'multi');
344        }
345
346        // Retablir les caracteres proteges
347        $t = strtr($t, _TYPO_PROTECTEUR, _TYPO_PROTEGER);
348
349        // pipeline
350        $t = pipeline('post_typo', $t);
351
352        # un message pour abs_url - on est passe en mode texte
353        $GLOBALS['mode_abs_url'] = 'texte';
354
355        return $t;
356}
357
358
359//
360// Tableaux
361//
362
363define('_RACCOURCI_TH_SPAN', '\s*(:?{{[^{}]+}}\s*)?|<');
364
365/**
366 * Traitement des raccourcis de tableaux
367 *
368 * @param string $bloc
369 * @return string
370 */
371function traiter_tableau($bloc) {
372        // id "unique" pour les id du tableau
373        $tabid = substr(md5($bloc), 0, 4);
374
375        // Decouper le tableau en lignes
376        preg_match_all(',([|].*)[|]\n,UmsS', $bloc, $regs, PREG_PATTERN_ORDER);
377        $lignes = array();
378        $debut_table = $summary = '';
379        $l = 0;
380
381        // Traiter chaque ligne
382        $reg_line1 = ',^(\|(' . _RACCOURCI_TH_SPAN . '))+$,sS';
383        $reg_line_all = ',^(' . _RACCOURCI_TH_SPAN . ')$,sS';
384        $hc = $hl = array();
385        foreach ($regs[1] as $ligne) {
386                $l++;
387
388                // Gestion de la premiere ligne :
389                if ($l == 1) {
390                        // - <caption> et summary dans la premiere ligne :
391                        //   || caption | summary || (|summary est optionnel)
392                        if (preg_match(',^\|\|([^|]*)(\|(.*))?$,sS', rtrim($ligne, '|'), $cap)) {
393                                $cap = array_pad($cap, 4, null);
394                                $l = 0;
395                                if ($caption = trim($cap[1])) {
396                                        $debut_table .= "<caption>" . $caption . "</caption>\n";
397                                }
398                                $summary = ' summary="' . entites_html(trim($cap[3])) . '"';
399                        }
400                        // - <thead> sous la forme |{{titre}}|{{titre}}|
401                        //   Attention thead oblige a avoir tbody
402                        else {
403                                if (preg_match($reg_line1, $ligne, $thead)) {
404                                        preg_match_all('/\|([^|]*)/S', $ligne, $cols);
405                                        $ligne = '';
406                                        $cols = $cols[1];
407                                        $colspan = 1;
408                                        for ($c = count($cols) - 1; $c >= 0; $c--) {
409                                                $attr = '';
410                                                if ($cols[$c] == '<') {
411                                                        $colspan++;
412                                                } else {
413                                                        if ($colspan > 1) {
414                                                                $attr = " colspan='$colspan'";
415                                                                $colspan = 1;
416                                                        }
417                                                        // inutile de garder le strong qui n'a servi que de marqueur
418                                                        $cols[$c] = str_replace(array('{', '}'), '', $cols[$c]);
419                                                        $ligne = "<th id='id{$tabid}_c$c'$attr>$cols[$c]</th>$ligne";
420                                                        $hc[$c] = "id{$tabid}_c$c"; // pour mettre dans les headers des td
421                                                }
422                                        }
423
424                                        $debut_table .= "<thead><tr class='row_first'>" .
425                                                $ligne . "</tr></thead>\n";
426                                        $l = 0;
427                                }
428                        }
429                }
430
431                // Sinon ligne normale
432                if ($l) {
433                        // Gerer les listes a puce dans les cellules
434                        // on declenche simplement sur \n- car il y a les
435                        // -* -# -? -! (qui produisent des -&nbsp;!)
436                        if (strpos($ligne, "\n-") !== false) {
437                                $ligne = traiter_listes($ligne);
438                        }
439
440                        // tout mettre dans un tableau 2d
441                        preg_match_all('/\|([^|]*)/S', $ligne, $cols);
442
443                        // Pas de paragraphes dans les cellules
444                        foreach ($cols[1] as &$col) {
445                                if (strlen($col = trim($col))) {
446                                        $col = preg_replace("/\n{2,}/S", "<br /> <br />", $col);
447                                        if (_AUTOBR) {
448                                                $col = str_replace("\n", _AUTOBR . "\n", $col);
449                                        }
450                                }
451                        }
452
453                        // assembler le tableau
454                        $lignes[] = $cols[1];
455                }
456        }
457
458        // maintenant qu'on a toutes les cellules
459        // on prepare une liste de rowspan par defaut, a partir
460        // du nombre de colonnes dans la premiere ligne.
461        // Reperer egalement les colonnes numeriques pour les cadrer a droite
462        $rowspans = $numeric = array();
463        $n = $lignes ? count($lignes[0]) : 0;
464        $k = count($lignes);
465        // distinguer les colonnes numeriques a point ou a virgule,
466        // pour les alignements eventuels sur "," ou "."
467        $numeric_class = array(
468                '.' => 'point',
469                ',' => 'virgule',
470                true => ''
471        );
472        for ($i = 0; $i < $n; $i++) {
473                $align = true;
474                for ($j = 0; $j < $k; $j++) {
475                        $rowspans[$j][$i] = 1;
476                        if ($align and preg_match('/^[{+-]*(?:\s|\d)*([.,]?)\d*[}]*$/', trim($lignes[$j][$i]), $r)) {
477                                if ($r[1]) {
478                                        $align = $r[1];
479                                }
480                        } else {
481                                $align = '';
482                        }
483                }
484                $numeric[$i] = $align ? (" class='numeric " . $numeric_class[$align] . "'") : '';
485        }
486        for ($j = 0; $j < $k; $j++) {
487                if (preg_match($reg_line_all, $lignes[$j][0])) {
488                        $hl[$j] = "id{$tabid}_l$j"; // pour mettre dans les headers des td
489                } else {
490                        unset($hl[0]);
491                }
492        }
493        if (!isset($hl[0])) {
494                $hl = array();
495        } // toute la colonne ou rien
496
497        // et on parcourt le tableau a l'envers pour ramasser les
498        // colspan et rowspan en passant
499        $html = '';
500
501        for ($l = count($lignes) - 1; $l >= 0; $l--) {
502                $cols = $lignes[$l];
503                $colspan = 1;
504                $ligne = '';
505
506                for ($c = count($cols) - 1; $c >= 0; $c--) {
507                        $attr = $numeric[$c];
508                        $cell = trim($cols[$c]);
509                        if ($cell == '<') {
510                                $colspan++;
511
512                        } elseif ($cell == '^') {
513                                $rowspans[$l - 1][$c] += $rowspans[$l][$c];
514
515                        } else {
516                                if ($colspan > 1) {
517                                        $attr .= " colspan='$colspan'";
518                                        $colspan = 1;
519                                }
520                                if (($x = $rowspans[$l][$c]) > 1) {
521                                        $attr .= " rowspan='$x'";
522                                }
523                                $b = ($c == 0 and isset($hl[$l])) ? 'th' : 'td';
524                                $h = (isset($hc[$c]) ? $hc[$c] : '') . ' ' . (($b == 'td' and isset($hl[$l])) ? $hl[$l] : '');
525                                if ($h = trim($h)) {
526                                        $attr .= " headers='$h'";
527                                }
528                                // inutile de garder le strong qui n'a servi que de marqueur
529                                if ($b == 'th') {
530                                        $attr .= " id='" . $hl[$l] . "'";
531                                        $cols[$c] = str_replace(array('{', '}'), '', $cols[$c]);
532                                }
533                                $ligne = "\n<$b" . $attr . '>' . $cols[$c] . "</$b>" . $ligne;
534                        }
535                }
536
537                // ligne complete
538                $class = alterner($l + 1, 'odd', 'even');
539                $html = "<tr class='row_$class $class'>$ligne</tr>\n$html";
540        }
541
542        $class = $GLOBALS['class_spip_plus'];
543        if (!$class or strpos($GLOBALS['class_spip_plus'],'class=') === false) {
544                $class = ' ' . trim('class="table" ' . $class);
545        }
546        else {
547                $class = str_replace('class="','class="table ', $class);
548                $class = str_replace("class='","class='table ", $class);
549        }
550        return "\n\n<table" . $class . $summary . ">\n"
551        . $debut_table
552        . "<tbody>\n"
553        . $html
554        . "</tbody>\n"
555        . "</table>\n\n";
556}
557
558
559/**
560 * Traitement des listes
561 *
562 * On utilise la wheel correspondante
563 *
564 * @param string $t
565 * @return string
566 */
567function traiter_listes($t) {
568        static $wheel = null;
569
570        if (!isset($wheel)) {
571                $wheel = new TextWheel(
572                        SPIPTextWheelRuleset::loader($GLOBALS['spip_wheels']['listes'])
573                );
574        }
575
576        try {
577                $t = $wheel->text($t);
578        } catch (Exception $e) {
579                erreur_squelette($e->getMessage());
580        }
581
582        return $t;
583}
584
585
586// Ces deux constantes permettent de proteger certains caracteres
587// en les remplacanat par des caracteres "illegaux". (cf corriger_caracteres)
588
589define('_RACCOURCI_PROTEGER', "{}_-");
590define('_RACCOURCI_PROTECTEUR', "\x1\x2\x3\x4");
591
592define('_RACCOURCI_BALISE', ",</?[a-z!][^<>]*[" . preg_quote(_RACCOURCI_PROTEGER) . "][^<>]*>,imsS");
593
594/**
595 * mais d'abord, une callback de reconfiguration des raccourcis
596 * a partir de globales (est-ce old-style ? on conserve quand meme
597 * par souci de compat ascendante)
598 *
599 * @param $ruleset
600 * @return string
601 */
602function personnaliser_raccourcis(&$ruleset) {
603        if ($ruleset) {
604                if (isset($GLOBALS['debut_intertitre']) and $rule = $ruleset->getRule('intertitres')) {
605                        $rule->replace[0] = preg_replace(',<[^>]*>,Uims', $GLOBALS['debut_intertitre'], $rule->replace[0]);
606                        $rule->replace[1] = preg_replace(',<[^>]*>,Uims', $GLOBALS['fin_intertitre'], $rule->replace[1]);
607                        $ruleset->addRules(array('intertitres' => $rule));
608                }
609                if (isset($GLOBALS['debut_gras']) and $rule = $ruleset->getRule('gras')) {
610                        $rule->replace[0] = preg_replace(',<[^>]*>,Uims', $GLOBALS['debut_gras'], $rule->replace[0]);
611                        $rule->replace[1] = preg_replace(',<[^>]*>,Uims', $GLOBALS['fin_gras'], $rule->replace[1]);
612                        $ruleset->addRules(array('gras' => $rule));
613                }
614                if (isset($GLOBALS['debut_italique']) and $rule = $ruleset->getRule('italiques')) {
615                        $rule->replace[0] = preg_replace(',<[^>]*>,Uims', $GLOBALS['debut_italique'], $rule->replace[0]);
616                        $rule->replace[1] = preg_replace(',<[^>]*>,Uims', $GLOBALS['fin_italique'], $rule->replace[1]);
617                        $ruleset->addRules(array('italiques' => $rule));
618                }
619                if (isset($GLOBALS['ligne_horizontale']) and $rule = $ruleset->getRule('ligne-horizontale')) {
620                        $rule->replace = preg_replace(',<[^>]*>,Uims', $GLOBALS['ligne_horizontale'], $rule->replace);
621                        $ruleset->addRules(array('ligne-horizontale' => $rule));
622                }
623                if (isset($GLOBALS['toujours_paragrapher']) and !$GLOBALS['toujours_paragrapher']
624                        and $rule = $ruleset->getRule('toujours-paragrapher')
625                ) {
626                        $rule->disabled = true;
627                        $ruleset->addRules(array('toujours-paragrapher' => $rule));
628                }
629        }
630
631        // retourner une signature de l'etat de la fonction, pour la mise en cache
632        return implode("/",
633                array(
634                        isset($GLOBALS['debut_intertitre']) ? $GLOBALS['debut_intertitre'] : "",
635                        isset($GLOBALS['debut_gras']) ? $GLOBALS['debut_gras'] : "",
636                        isset($GLOBALS['debut_italique']) ? $GLOBALS['debut_italique'] : "",
637                        isset($GLOBALS['ligne_horizontale']) ? $GLOBALS['ligne_horizontale'] : "",
638                        isset($GLOBALS['toujours_paragrapher']) ? $GLOBALS['toujours_paragrapher'] : 1,
639                )
640        );
641}
642
643/**
644 * Nettoie un texte, traite les raccourcis autre qu'URL, la typo, etc.
645 *
646 * @pipeline_appel pre_propre
647 * @pipeline_appel post_propre
648 *
649 * @param string $t
650 * @param bool $show_autobr
651 * @return string
652 */
653function traiter_raccourcis($t, $show_autobr = false) {
654        static $wheel = array(), $notes;
655        static $img_br_auto, $img_br_manuel, $img_br_no;
656        global $spip_lang, $spip_lang_rtl;
657
658        // hack1: respecter le tag ignore br
659        if (_AUTOBR_IGNORER
660                and strncmp($t, _AUTOBR_IGNORER, strlen(_AUTOBR_IGNORER)) == 0
661        ) {
662                $ignorer_autobr = true;
663                $t = substr($t, strlen(_AUTOBR_IGNORER));
664        } else {
665                $ignorer_autobr = false;
666        }
667
668        // Appeler les fonctions de pre_traitement
669        $t = pipeline('pre_propre', $t);
670
671        $key = "";
672        $key = personnaliser_raccourcis($key);
673        if (!isset($wheel[$key])) {
674                $ruleset = SPIPTextWheelRuleset::loader(
675                        $GLOBALS['spip_wheels']['raccourcis'], 'personnaliser_raccourcis'
676                );
677                $wheel[$key] = new TextWheel($ruleset);
678
679                if (_request('var_mode') == 'wheel'
680                        and autoriser('debug')
681                ) {
682                        $f = $wheel->compile();
683                        echo "<pre>\n" . spip_htmlspecialchars($f) . "</pre>\n";
684                        exit;
685                }
686                $notes = charger_fonction('notes', 'inc');
687        }
688
689        // Gerer les notes (ne passe pas dans le pipeline)
690        list($t, $mes_notes) = $notes($t);
691
692        try {
693                $t = $wheel[$key]->text($t);
694        } catch (Exception $e) {
695                erreur_squelette($e->getMessage());
696        }
697
698        // Appeler les fonctions de post-traitement
699        $t = pipeline('post_propre', $t);
700
701        if ($mes_notes) {
702                $notes($mes_notes, 'traiter', $ignorer_autobr);
703        }
704
705        if (_AUTOBR and !function_exists('aide_lang_dir')) {
706                include_spip('inc/lang');
707        }
708
709        // hack2: wrap des autobr dans l'espace prive, pour affichage css
710        // car en css on ne sait pas styler l'element BR
711        if ($ignorer_autobr and _AUTOBR) {
712                if (is_null($img_br_no)) {
713                        $img_br_no = ($show_autobr ? http_img_pack("br-no" . aide_lang_dir($spip_lang, $spip_lang_rtl) . "-10.png",
714                                _T("tw:retour_ligne_ignore"), "class='br-no'", _T("tw:retour_ligne_ignore")) : "");
715                }
716                $t = str_replace(_AUTOBR, $img_br_no, $t);
717        }
718        if ($show_autobr and _AUTOBR) {
719                if (is_null($img_br_manuel)) {
720                        $img_br_manuel = http_img_pack("br-manuel" . aide_lang_dir($spip_lang, $spip_lang_rtl) . "-10.png",
721                                _T("tw:retour_ligne_manuel"), "class='br-manuel'", _T("tw:retour_ligne_manuel"));
722                }
723                if (is_null($img_br_auto)) {
724                        $img_br_auto = http_img_pack("br-auto" . aide_lang_dir($spip_lang, $spip_lang_rtl) . "-10.png",
725                                _T("tw:retour_ligne_auto"), "class='br-auto'", _T("tw:retour_ligne_auto"));
726                }
727                if (false !== strpos(strtolower($t), '<br')) {
728                        $t = preg_replace("/<br\b.*>/UiS", "$img_br_manuel\\0", $t);
729                        $t = str_replace($img_br_manuel . _AUTOBR, $img_br_auto . _AUTOBR, $t);
730                }
731        }
732
733        return $t;
734}
735
736
737/**
738 * Transforme les raccourcis SPIP, liens et modèles d'un texte en code HTML
739 *
740 * Filtre à appliquer aux champs du type `#TEXTE*`
741 *
742 * @filtre
743 * @uses echappe_html()
744 * @uses expanser_liens()
745 * @uses traiter_raccourcis()
746 * @uses echappe_retour_modeles()
747 * @see  typo()
748 *
749 * @param string $t
750 *     Texte avec des raccourcis SPIP
751 * @param string|null $connect
752 *     Nom du connecteur à la bdd
753 * @param array $env
754 *     Environnement (pour les calculs de modèles)
755 * @return string $t
756 *     Texte transformé
757 **/
758function propre($t, $connect = null, $env = array()) {
759        // les appels directs a cette fonction depuis le php de l'espace
760        // prive etant historiquement ecrits sans argment $connect
761        // on utilise la presence de celui-ci pour distinguer les cas
762        // ou il faut passer interdire_script explicitement
763        // les appels dans les squelettes (de l'espace prive) fournissant un $connect
764        // ne seront pas perturbes
765        $interdire_script = false;
766        if (is_null($connect) and test_espace_prive()) {
767                $connect = '';
768                $interdire_script = true;
769        }
770
771        if (!$t) {
772                return strval($t);
773        }
774
775        $t = pipeline('pre_echappe_html_propre', $t);
776
777        // Dans l'espace prive on se mefie de tout contenu dangereux
778        // avant echappement des balises <html>
779        // https://core.spip.net/issues/3371
780        // et aussi dans l'espace public si la globale filtrer_javascript = -1
781        // https://core.spip.net/issues/4166
782        if ($interdire_script
783                or $GLOBALS['filtrer_javascript'] == -1
784                or (isset($env['espace_prive']) and $env['espace_prive'] and $GLOBALS['filtrer_javascript']<=0)
785                or (isset($env['wysiwyg']) and $env['wysiwyg'] and $GLOBALS['filtrer_javascript']<=0)) {
786                $t = echapper_html_suspect($t, false);
787        }
788        $t = echappe_html($t);
789        $t = expanser_liens($t, $connect, $env);
790
791        $t = traiter_raccourcis($t, (isset($env['wysiwyg']) and $env['wysiwyg']) ? true : false);
792        $t = echappe_retour_modeles($t, $interdire_script);
793
794        $t = pipeline('post_echappe_html_propre', $t);
795
796        return $t;
797}
Note: See TracBrowser for help on using the repository browser.