source: spip-zone/_plugins_/htmlpurifier/trunk/inc/texte.php @ 112299

Last change on this file since 112299 was 112299, checked in by gouz@…, 2 years ago

surcharge effective de inc/texte.php via <necessite et modification paquet.xml puis suppression de plugin.xml

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