source: spip-zone/_plugins_/_typo_/barre_typo_enrichie/inc/texte.php @ 4671

Last change on this file since 4671 was 4671, checked in by real3t@…, 13 years ago

Correctifs sur les éléments HTML reconnus comme blocs par SPIP.

File size: 35.8 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2006                                                *
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//
15if (!defined("_ECRIRE_INC_VERSION")) return;
16
17include_spip('inc/filtres');
18include_spip('inc/charsets');
19include_spip('inc/lang');
20
21// Verifier les variables de personnalisation
22tester_variable('debut_intertitre', "\n<h3 class=\"spip\">");
23tester_variable('fin_intertitre', "</h3>\n");
24tester_variable('ligne_horizontale', "\n<hr class=\"spip\" />\n");
25tester_variable('ouvre_ref', '&nbsp;[');
26tester_variable('ferme_ref', ']');
27tester_variable('ouvre_note', '[');
28tester_variable('ferme_note', '] ');
29tester_variable('les_notes', '');
30tester_variable('compt_note', 0);
31tester_variable('nombre_surligne', 4);
32tester_variable('url_glossaire_externe', "http://@lang@.wikipedia.org/wiki/");
33
34// on initialise la puce ici car il serait couteux de faire le find_in_path()
35// a chaque hit, alors qu'on n'a besoin de cette valeur que lors du calcul
36function definir_puce() {
37        static $les_puces = array();
38
39        // Attention au sens, qui n'est pas defini de la meme facon dans
40        // l'espace prive (spip_lang est la langue de l'interface, lang_dir
41        // celle du texte) et public (spip_lang est la langue du texte)
42        #include_spip('inc/lang');
43        $dir = _DIR_RESTREINT ?
44                lang_dir($GLOBALS['spip_lang']) : $GLOBALS['lang_dir'];
45        $p = ($dir == 'rtl') ? 'puce_rtl' : 'puce';
46
47        if (!isset($les_puces[$p])) {
48                tester_variable($p, 'AUTO');
49                if ($GLOBALS[$p] == 'AUTO') {
50                        $img = find_in_path($p.'.gif');
51                        list(,,,$size) = @getimagesize($img);
52                        $img = '<img src="'.$img.'" '
53                                .$size.' alt="-" />';
54                } else
55                        $img = $GLOBALS[$p];
56
57                $les_puces[$p] = $img;
58        }
59
60        return $les_puces[$p];
61}
62
63//
64// Diverses fonctions essentielles
65//
66
67
68// XHTML - Preserver les balises-bloc
69// http://fr.selfhtml.org/html/reference/elements.htm#elements_bloc
70define('_BALISES_BLOCS',
71        'div|pre|ul|ol|blockquote|h[1-6r]|'
72        .'table|menu|noframes|p|'
73        .'form|center|marquee|address|'
74        .'dl|noscript|dir|fieldset|isindex');
75
76
77// Ne pas afficher le chapo si article virtuel
78function nettoyer_chapo($chapo){
79        if (substr($chapo,0,1) == "="){
80                $chapo = "";
81        }
82        return $chapo;
83}
84
85
86//
87// Echapper les les elements perilleux en les passant en base64
88//
89
90// Creer un bloc base64 correspondant a $rempl ; au besoin en marquant
91// une $source differente ; le script detecte automagiquement si ce qu'on
92// echappe est un div ou un span
93function code_echappement($rempl, $source='') {
94        // Convertir en base64
95        $base64 = base64_encode($rempl);
96
97        // Tester si on echappe en span ou en div
98        $mode = preg_match(',</?('._BALISES_BLOCS.')[>[:space:]],iS', $rempl) ?
99                'div' : 'span';
100        $nn = ($mode == 'div') ? "\n\n" : '';
101
102        return
103                inserer_attribut("<$mode class=\"base64$source\">", 'title', $base64)
104                ."</$mode>$nn";
105}
106
107// - pour $source voir commentaire infra (echappe_retour)
108// - pour $no_transform voir le filtre post_autobr dans inc_filtres.php3
109function echappe_html($letexte, $source='', $no_transform=false,
110$preg=',<(html|code|cadre|frame)>(.*)</\1>,UimsS') {
111        if (preg_match_all(
112        $preg,
113        $letexte, $matches, PREG_SET_ORDER))
114        foreach ($matches as $regs) {
115
116                // mode d'echappement :
117                //    <span class='base64'> . base64_encode(contenu) . </span>
118                // ou 'div' selon les cas, pour refermer correctement les paragraphes
119                $mode = 'span';
120
121                // echappements tels quels ?
122                if ($no_transform) {
123                        $echap = $regs[0];
124                }
125
126                // sinon les traiter selon le cas
127                else switch(strtolower($regs[1])) {
128
129                        // Echapper les <html>...</ html>
130                        case 'html':
131                                $echap = $regs[2];
132                                break;
133
134                        // Echapper les <code>...</ code>
135                        case 'code':
136                                $echap = entites_html($regs[2]);
137                                // supprimer les sauts de ligne debut/fin
138                                // (mais pas les espaces => ascii art).
139                                $echap = ereg_replace("^\n+|\n+$", "", $echap);
140
141                                // ne pas mettre le <div...> s'il n'y a qu'une ligne
142                                if (is_int(strpos($echap,"\n"))) {
143                                        $echap = nl2br("<div style='text-align: left;' "
144                                        . "class='spip_code' dir='ltr'><code>"
145                                        .$echap."</code></div>");
146                                        $mode = 'div';
147                                } else
148                                        $echap = "<code class='spip_code' "
149                                        ."dir='ltr'>".$echap."</code>";
150
151                                $echap = str_replace("\t",
152                                        "&nbsp; &nbsp; &nbsp; &nbsp; ", $echap);
153                                $echap = str_replace("  ", " &nbsp;", $echap);
154                                break;
155
156                        // Echapper les <cadre>...</ cadre>
157                        case 'cadre':
158                        case 'frame':
159                                $echap = trim(entites_html($regs[2]));
160                                $total_lignes = substr_count($echap, "\n") + 1;
161                                $echap = "<form action=\"/\" method=\"get\"><div>"
162                                ."<textarea readonly='readonly' cols='40' rows='$total_lignes' "
163                                ."class='spip_cadre' dir='ltr'>"
164                                .$echap
165                                ."</textarea></div></form>";
166                                break;
167
168                }
169
170                $letexte = str_replace($regs[0],
171                        code_echappement($echap, $source),
172                        $letexte);
173        }
174
175        // Gestion du TeX
176        if (strpos($letexte, "<math>") !== false) {
177                include_spip('inc/math');
178                $letexte = traiter_math($letexte, $source);
179        }
180
181        return $letexte;
182}
183
184
185//
186// Traitement final des echappements
187// Rq: $source sert a faire des echappements "a soi" qui ne sont pas nettoyes
188// par propre() : exemple dans ecrire/inc_articles_ortho.php, $source='ORTHO'
189// ou encore dans typo()
190function echappe_retour($letexte, $source='') {
191        if (strpos($letexte,"base64$source")) {
192                # echo htmlspecialchars($letexte);  ## pour les curieux
193                if (preg_match_all(
194                ',<(span|div) class=[\'"]base64'.$source.'[\'"]\s.*></\1>,UmsS',
195                $letexte, $regs, PREG_SET_ORDER)) {
196                        foreach ($regs as $reg) {
197                                $rempl = base64_decode(extraire_attribut($reg[0], 'title'));
198                                $letexte = str_replace($reg[0], $rempl, $letexte);
199                        }
200                }
201        }
202        return $letexte;
203}
204
205function nettoyer_raccourcis_typo($texte){
206        $texte = pipeline('nettoyer_raccourcis_typo',$texte);
207        // remplacer les liens
208        if (preg_match_all(',[[]([^][]*)->(>?)([^][]*)[]],S', $texte, $regs, PREG_SET_ORDER))
209                foreach ($regs as $reg) {
210                        if (strlen($reg[1]))
211                                $titre = $reg[1];
212                        else
213                                $titre= calculer_url($reg[3], $reg[1], 'titre');
214                        $texte = str_replace($reg[0], $titre, $texte);
215                }
216
217        // supprimer les notes
218        $texte = ereg_replace("\[\[([^]]|\][^]])*\]\]", "", $texte);
219
220        // supprimer les codes typos
221        $texte = ereg_replace("[}{]", "", $texte);
222
223        // supprimer les tableaux
224        $texte = ereg_replace("(^|\r)\|.*\|\r", "\r", $texte); 
225        return $texte;
226}
227
228function couper($texte, $taille=50) {
229        $offset = 400 + 2*$taille;
230        if (    $offset<strlen($texte)
231                        && ($p_tag_ouvrant = strpos($texte,'<',$offset))!==NULL){
232                $p_tag_fermant = strpos($texte,'>',$offset);
233                if ($p_tag_fermant<$p_tag_ouvrant)
234                        $offset += $p_tag_fermant; // prolonger la coupe jusqu'au tag fermant suivant eventuel
235        }
236        $texte = substr($texte, 0, $offset); /* eviter de travailler sur 10ko pour extraire 150 caracteres */
237
238        // on utilise les \r pour passer entre les gouttes
239        $texte = str_replace("\r\n", "\n", $texte);
240        $texte = str_replace("\r", "\n", $texte);
241
242        // sauts de ligne et paragraphes
243        $texte = ereg_replace("\n\n+", "\r", $texte);
244        $texte = ereg_replace("<(p|br)( [^>]*)?".">", "\r", $texte);
245
246        // supprimer les traits, lignes etc
247        $texte = ereg_replace("(^|\r|\n)(-[-#\*]*|_ )", "\r", $texte);
248
249        // supprimer les tags
250        $texte = supprimer_tags($texte);
251        $texte = trim(str_replace("\n"," ", $texte));
252        $texte .= "\n"; // marquer la fin
253
254        // travailler en accents charset
255        $texte = unicode2charset(html2unicode($texte, /* secure */ true));
256
257        $texte = nettoyer_raccourcis_typo($texte);
258
259        // corriger la longueur de coupe
260        // en fonction de la presence de caracteres utf
261        if ($GLOBALS['meta']['charset']=='utf-8'){
262                $long = charset2unicode($texte);
263                $long = spip_substr($long, 0, max($taille,1));
264                $nbcharutf = preg_match_all("/(&#[0-9]{3,5};)/S",$long,$matches);
265                $taille += $nbcharutf;
266        }
267
268
269        // couper au mot precedent
270        $long = spip_substr($texte, 0, max($taille-4,1));
271        $court = ereg_replace("([^[:space:]][[:space:]]+)[^[:space:]]*\n?$", "\\1", $long);
272        $points = '&nbsp;(...)';
273
274        // trop court ? ne pas faire de (...)
275        if (spip_strlen($court) < max(0.75 * $taille,2)) {
276                $points = '';
277                $long = spip_substr($texte, 0, $taille);
278                $texte = ereg_replace("([^[:space:]][[:space:]]+)[^[:space:]]*$", "\\1", $long);
279                // encore trop court ? couper au caractere
280                if (spip_strlen($texte) < 0.75 * $taille)
281                        $texte = $long;
282        } else
283                $texte = $court;
284
285        if (strpos($texte, "\n"))       // la fin est encore la : c'est qu'on n'a pas de texte de suite
286                $points = '';
287
288        // remettre les paragraphes
289        $texte = ereg_replace("\r+", "\n\n", $texte);
290
291        // supprimer l'eventuelle entite finale mal coupee
292        $texte = preg_replace('/&#?[a-z0-9]*$/S', '', $texte);
293
294        return quote_amp(trim($texte)).$points;
295}
296
297// prendre <intro>...</intro> sinon couper a la longueur demandee
298function couper_intro($texte, $long) {
299        $texte = extraire_multi(eregi_replace("(</?)intro>", "\\1intro>", $texte)); // minuscules
300        $intro = '';
301        while ($fin = strpos($texte, "</intro>")) {
302                $zone = substr($texte, 0, $fin);
303                $texte = substr($texte, $fin + strlen("</intro>"));
304                if ($deb = strpos($zone, "<intro>") OR substr($zone, 0, 7) == "<intro>")
305                        $zone = substr($zone, $deb + 7);
306                $intro .= $zone;
307        }
308
309        if ($intro)
310                $intro = $intro.'&nbsp;(...)';
311        else {
312                $intro = preg_replace(',([|]\s*)+,S', '; ', couper($texte, $long));
313        }
314
315        // supprimer un eventuel chapo redirecteur =http:/.....
316        return preg_replace(',^=[^[:space:]]+,S','',$intro);
317}
318
319
320//
321// Les elements de propre()
322//
323
324// Securite : empecher l'execution de code PHP ou javascript ou autre malice
325function interdire_scripts($source) {
326        $source = preg_replace(",<(\%|\?|/?[[:space:]]*(script|base)),imsS", "&lt;\\1", $source);
327        return $source;
328}
329
330// Securite : utiliser SafeHTML s'il est present dans ecrire/safehtml/
331function safehtml($t) {
332        static $process, $test;
333
334        # attention safehtml nettoie deux ou trois caracteres de plus. A voir
335        if (strpos($t,'<')===false)
336                return str_replace("\x00", '', $t);
337
338        if (!$test) {
339                if ($f = include_spip('safehtml/classes/safehtml', false)) {
340                        define('XML_HTMLSAX3', dirname($f).'/');
341                        include($f);
342                        $process = new safehtml();
343                } else die('pas de safe');
344                if ($process)
345                        $test = 1; # ok
346                else
347                        $test = -1; # se rabattre sur interdire_scripts
348        }
349
350        if ($test > 0) {
351                # reset ($process->clear() ne vide que _xhtml...),
352                # on doit pouvoir programmer ca plus propremement
353                $process->_counter = array();
354                $process->_stack = array();
355                $process->_dcCounter = array();
356                $process->_dcStack = array();
357                $process->_listScope = 0;
358                $process->_liStack = array();
359#               $process->parse(''); # cas particulier ?
360                $process->clear();
361                $t = $process->parse($t);
362        }
363
364        return interdire_scripts($t); # gere le < ?php > en plus
365}
366
367// Correction typographique francaise
368function typo_fr($letexte) {
369        static $trans;
370
371        // Nettoyer 160 = nbsp ; 187 = raquo ; 171 = laquo ; 176 = deg ; 147 = ldquo; 148 = rdquo
372        if (!$trans) {
373                $trans = array(
374                        "&nbsp;" => "~",
375                        "&raquo;" => "&#187;",
376                        "&laquo;" => "&#171;",
377                        "&rdquo;" => "&#148;",
378                        "&ldquo;" => "&#147;",
379                        "&deg;" => "&#176;"
380                );
381                $chars = array(160 => '~', 187 => '&#187;', 171 => '&#171;', 148 => '&#148;', 147 => '&#147;', 176 => '&#176;');
382                $chars_trans = array_keys($chars);
383                $chars = array_values($chars);
384                $chars_trans = implode(' ',array_map('chr',$chars_trans));
385                $chars_trans = unicode2charset(charset2unicode($chars_trans, 'iso-8859-1', 'forcer'));
386                $chars_trans = explode(" ",$chars_trans);
387                foreach($chars as $k=>$r)
388                        $trans[$chars_trans[$k]] = $r;
389        }
390
391        $letexte = strtr($letexte, $trans);
392
393        $cherche1 = array(
394                /* 1 */         '/((^|[^\#0-9a-zA-Z\&])[\#0-9a-zA-Z]*)\;/S',
395                /* 2 */         '/&#187;| --?,|:([^0-9]|$)/S',
396                /* 3 */         '/([^[<!?])([!?])/S',
397                /* 4 */         '/&#171;|(M(M?\.|mes?|r\.?)|[MnN]&#176;) /S'
398        );
399        $remplace1 = array(
400                /* 1 */         '\1~;',
401                /* 2 */         '~\0',
402                /* 3 */         '\1~\2',
403                /* 4 */         '\0~'
404        );
405        $letexte = preg_replace($cherche1, $remplace1, $letexte);
406        $letexte = preg_replace("/ *~+ */S", "~", $letexte);
407
408        $cherche2 = array(
409                '/([^-\n]|^)--([^-]|$)/S',
410                '/(http|https|ftp|mailto)~:/S',
411                '/~/'
412        );
413        $remplace2 = array(
414                '\1&mdash;\2',
415                '\1:',
416                '&nbsp;'
417        );
418        $letexte = preg_replace($cherche2, $remplace2, $letexte);
419
420        return $letexte;
421}
422
423// rien sauf les "~" et "-,"
424function typo_en($letexte) {
425
426        $cherche1 = array(
427                '/ --?,/S'
428        );
429        $remplace1 = array(
430                '~\0'
431        );
432        $letexte = preg_replace($cherche1, $remplace1, $letexte);
433
434        $letexte = str_replace("&nbsp;", "~", $letexte);
435        $letexte = ereg_replace(" *~+ *", "~", $letexte);
436
437        $cherche2 = array(
438                '/([^-\n]|^)--([^-]|$)/',
439                '/~/'
440        );
441        $remplace2 = array(
442                '\1&mdash;\2',
443                '&nbsp;'
444        );
445
446        $letexte = preg_replace($cherche2, $remplace2, $letexte);
447
448        return $letexte;
449}
450
451//
452// Typographie generale
453// note: $echapper = false lorsqu'on appelle depuis propre() [pour accelerer]
454//
455function typo($letexte, $echapper=true) {
456
457        // Echapper les codes <html> etc
458        if ($echapper)
459                $letexte = echappe_html($letexte, 'TYPO');
460
461        // Appeler les fonctions de pre-traitement
462        $letexte = pipeline('pre_typo', $letexte);
463        // old style
464        if (function_exists('avant_typo'))
465                $letexte = avant_typo($letexte);
466
467        // Caracteres de controle "illegaux"
468        $letexte = corriger_caracteres($letexte);
469
470        // Proteger les caracteres typographiques a l'interieur des tags html
471        $protege = "!':;?~";
472        $illegal = "\x1\x2\x3\x4\x5\x6";
473        if (preg_match_all(",</?[a-z!][^<>]*[!':;\?~][^<>]*>,imsS",
474        $letexte, $regs, PREG_SET_ORDER)) {
475                foreach ($regs as $reg) {
476                        $insert = $reg[0];
477                        // hack: on transforme les caracteres a proteger en les remplacant
478                        // par des caracteres "illegaux". (cf corriger_caracteres())
479                        $insert = strtr($insert, $protege, $illegal);
480                        $letexte = str_replace($reg[0], $insert, $letexte);
481                }
482        }
483
484        // zouli apostrophe
485        $letexte = str_replace("'", "&#8217;", $letexte);
486
487        // typo francaise ou anglaise ?
488        // $lang_typo est fixee dans l'interface privee pour editer
489        // un texte anglais en interface francaise (ou l'inverse) ;
490        // sinon determiner la typo en fonction de la langue
491        if (!$lang = $GLOBALS['lang_typo']) {
492                #include_spip('inc/lang');
493                $lang = lang_typo($GLOBALS['spip_lang']);
494        }
495        if ($lang == 'fr')
496                $letexte = typo_fr($letexte);
497        else
498                $letexte = typo_en($letexte);
499
500        // Retablir les caracteres proteges
501        $letexte = strtr($letexte, $illegal, $protege);
502
503        //
504        // Installer les images et documents ;
505        //
506        // NOTE : dans propre() ceci s'execute avant les tableaux a cause du "|",
507        // et apres les liens a cause du traitement de [<imgXX|right>->URL]
508        if (preg_match(__preg_img, $letexte)) {
509                include_spip('inc/documents');
510                $letexte = inserer_documents($letexte);
511        }
512
513        // Appeler les fonctions de post-traitement
514        $letexte = pipeline('post_typo', $letexte);
515        // old style
516        if (function_exists('apres_typo'))
517                $letexte = apres_typo($letexte);
518
519        // reintegrer les echappements
520        if ($echapper)
521                $letexte = echappe_retour($letexte, 'TYPO');
522
523        # un message pour abs_url - on est passe en mode texte
524        $GLOBALS['mode_abs_url'] = 'texte';
525
526        // Dans l'espace prive, securiser ici
527        if (!_DIR_RESTREINT)
528                $letexte = interdire_scripts($letexte);
529
530        return $letexte;
531}
532
533// obsolete, utiliser calculer_url
534
535function extraire_lien ($regs) {
536        list($lien, $class, $texte) = calculer_url($regs[3], $regs[1],'tout');
537        // Preparer le texte du lien ; attention s'il contient un <div>
538        // (ex: [<docXX|right>->lien]), il faut etre smart
539        $ref = "<a href=\"$lien\" class=\"$class\">$texte</a>";
540        return array($ref, $lien, $texte);
541}
542
543// traitement des raccourcis issus de [TITRE->RACCOURCInnn] et connexes
544//
545// Valeur retournee selon le parametre $pour:
546// 'tout' : <a href="L">T</a>
547// 'titre': seulement T ci-dessus (i.e. le TITRE ci-dessus ou dans table SQL)
548// 'url':   seulement L (i.e. generer_url_RACCOURCI)
549
550function calculer_url ($lien, $texte='', $pour='url') {
551
552        // Cherche un lien du type [->raccourci 123]
553        // associe a une fonction generer_url_raccourci()
554        if (preg_match(',^(\S*?)\s*(\d+)(\?([^#]+))?(#[^\s]*)?$,S', trim($lien), $match)) {
555                $ancre = isset($match[5]) ? $match[5] :'';
556                $params = isset($match[4]) ? $match[4] :'';
557                // valeur par defaut
558                if (!$f = $match[1]) $f = 'article';
559
560                // aliases (historique)
561                if ($f == 'art') $f = 'article';
562                else if ($f == 'art') $f = 'article';
563                else if ($f == 'rub') $f = 'rubrique';
564                else if ($f == 'rub') $f = 'rubrique';
565                else if ($f == 'aut') $f = 'auteur';
566                else if ($f == 'doc' OR $f == 'im' OR $f == 'img' OR $f == 'image')
567                        $f = 'document';
568                else if (preg_match(',^br..?ve$,S', $f)) $f = 'breve'; # accents :(
569
570                // chercher la fonction nommee generer_url_$raccourci
571                // ou calculer_url_raccourci si on n'a besoin que du lien
572                $f=(($pour == 'url') ? 'generer' : 'calculer') . '_url_' . $f;
573                charger_generer_url();
574                if (function_exists($f)) {
575                        if ($pour == 'url') {
576                                $lien = $f($match[2]);
577                                if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
578                                return  $lien . $params . $ancre;
579                        }
580                        $res = $f($match[2], $texte, $ancre, $params);
581                        return ($pour == 'titre') ? $res[2] : $res;
582                }
583        }
584
585        $lien = ltrim($lien);
586        if ($lien[0] == '?') {
587                if ($pour == 'titre') return $texte;
588                $lien = entites_html(substr($lien, 1));
589                return ($pour == 'url') ? $lien :
590                        array($lien, 'spip_glossaire', $texte);
591        }
592        // Liens explicites
593        if (!$texte) {
594                $texte = str_replace('"', '', $lien);
595                if (strlen($texte)>40)
596                                $texte = substr($texte,0,35).'...';
597                $texte = "<html>$texte</html>";
598                $class = "spip_url";
599        } else  $class = "spip_out";
600
601        if ($pour == 'titre') return $texte;
602
603        $lien = entites_html(vider_url($lien));
604
605        // petites corrections d'URL
606        if (preg_match(",^www\.[^@]+$,S",$lien))
607                $lien = "http://".$lien;
608        else if (strpos($lien, "@") && email_valide($lien))
609                $lien = "mailto:".$lien;
610               
611        if (preg_match(",^#,",$lien)) $class = "spip_ancre";
612
613        return ($pour == 'url') ? $lien : array($lien, $class, $texte);
614}
615
616function calculer_url_article($id, $texte, $ancre, $params)
617{
618        $lien = generer_url_article($id);
619        if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
620        $lien = $lien . $params . $ancre;
621        if (!$texte) {
622                $row = @spip_fetch_array(spip_query("SELECT titre FROM spip_articles WHERE id_article=$id"));
623                $texte = $row['titre'];
624        }
625        return array($lien, 'spip_in', $texte);
626}
627
628function calculer_url_rubrique($id, $texte, $ancre, $params)
629{
630        $lien = generer_url_rubrique($id);
631        if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
632        $lien = $lien . $params . $ancre;
633        if (!$texte) {
634                $row = @spip_fetch_array(spip_query("SELECT titre FROM spip_rubriques WHERE id_rubrique=$id"));
635                $texte = $row['titre'];
636        }
637        return array($lien, 'spip_in', $texte);
638}
639
640function calculer_url_mot($id, $texte, $ancre, $params)
641{
642        $lien = generer_url_mot($id);
643        if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
644        $lien = $lien . $params . $ancre;
645        if (!$texte) {
646                $row = @spip_fetch_array(spip_query("SELECT titre FROM spip_mots WHERE id_mot=$id"));
647                $texte = $row['titre'];
648        }
649        return array($lien, 'spip_in', $texte);
650}
651
652function calculer_url_breve($id, $texte, $ancre, $params)
653{
654        $lien = generer_url_breve($id);
655        if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
656        $lien = $lien . $params . $ancre;
657        if (!$texte) {
658                $row = @spip_fetch_array(spip_query("SELECT titre FROM spip_breves WHERE id_breve=$id"));
659                $texte = $row['titre'];
660        }
661        return array($lien, 'spip_in', $texte);
662}
663
664function calculer_url_auteur($id, $texte, $ancre, $params)
665{
666        $lien = generer_url_auteur($id);
667        if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
668        $lien = $lien . $params . $ancre;
669        if (!$texte) {
670                $row = @spip_fetch_array(spip_query("SELECT nom FROM spip_auteurs WHERE id_auteur=$id"));
671                $texte = $row['nom'];
672        }
673        return array($lien, 'spip_in', $texte);
674}
675
676function calculer_url_document($id, $texte, $ancre, $params)
677{
678        $lien = generer_url_document($id);
679        if ($params != '') $params = ((strpos($lien, '?') > 0) ? '&' : '?') . $params;
680        $lien = $lien . $params . $ancre;
681        if (!$texte) {
682                $row = @spip_fetch_array(spip_query("SELECT titre,fichier FROM spip_documents WHERE id_document=$id"));
683                $texte = $row['titre'];
684                if (!$texte)
685                        $texte = ereg_replace("^.*/","",$row['fichier']);
686        }
687        return array($lien, 'spip_in', $texte);
688}
689
690function calculer_url_site($id, $texte, $ancre, $params)
691{
692        # attention dans le cas des sites le lien pointe non pas sur
693        # la page locale du site, mais directement sur le site lui-meme
694        # et on ne tient pas compte de $ancre et $params
695        $row = @spip_fetch_array(spip_query("SELECT nom_site,url_site FROM spip_syndic WHERE id_syndic=$id"));
696        if ($row) {
697                $lien = $row['url_site'];
698                if (!$texte)
699                        $texte = $row['nom_site'];
700        }
701        return array($lien, 'spip_out', $texte);
702}
703
704//
705// Tableaux
706//
707function traiter_tableau($bloc) {
708
709        // Decouper le tableau en lignes
710        preg_match_all(',([|].*)[|]\n,UmsS', $bloc, $regs, PREG_PATTERN_ORDER);
711        $lignes = array();
712
713        // Traiter chaque ligne
714        foreach ($regs[1] as $ligne) {
715                $l ++;
716
717                // Gestion de la premiere ligne :
718                if ($l == 1) {
719                // - <caption> et summary dans la premiere ligne :
720                //   || caption | summary || (|summary est optionnel)
721                        if (preg_match(',^\|\|([^|]*)(\|(.*))?\|$,sS', $ligne, $cap)) {
722                                $l = 0;
723                                if ($caption = trim($cap[1]))
724                                        $debut_table .= "<caption>".$caption."</caption>\n";
725                                $summary = ' summary="'.entites_html(trim($cap[3])).'"';
726                        }
727                // - <thead> sous la forme |{{titre}}|{{titre}}|
728                //   Attention thead oblige a avoir tbody
729                        else if (preg_match(',^(\|([[:space:]]*{{[^}]+}}[[:space:]]*|<))+$,sS',
730                                $ligne, $thead)) {
731                                preg_match_all("/\|([^|]*)/S", $ligne, $cols);
732                                $ligne='';$cols= $cols[1];
733                                $colspan=1;
734                                for($c=count($cols)-1; $c>=0; $c--) {
735                                        $attr='';
736                                        if($cols[$c]=='<') {
737                                          $colspan++;
738                                        } else {
739                                          if($colspan>1) {
740                                                $attr= " colspan='$colspan'";
741                                                $colspan=1;
742                                          }
743                                          $ligne= "<th scope='col'$attr>$cols[$c]</th>$ligne";
744                                        }
745                                }
746
747                                $debut_table .= "<thead><tr class='row_first'>".
748                                        $ligne."</tr></thead>\n";
749                                $l = 0;
750                        }
751                }
752
753                // Sinon ligne normale
754                if ($l) {
755                        // Gerer les listes a puce dans les cellules
756                        if (ereg("\n-[*#]", $ligne))
757                                $ligne = traiter_listes($ligne);
758
759                        // Pas de paragraphes dans les cellules
760                        $ligne = preg_replace("/\n{2,}/", "<br />\n", $ligne);
761
762                        // tout mettre dans un tableau 2d
763                        preg_match_all("/\|([^|]*)/S", $ligne, $cols);
764                        $lignes[]= $cols[1];
765                }
766        }
767
768        // maintenant qu'on a toutes les cellules
769        // on prepare une liste de rowspan par defaut, a partir
770        // du nombre de colonnes dans la premiere ligne
771        $rowspans = array();
772        for ($i=0; $i<count($lignes[0]); $i++)
773                $rowspans[] = 1;
774
775        // et on parcourt le tableau a l'envers pour ramasser les
776        // colspan et rowspan en passant
777        for($l=count($lignes)-1; $l>=0; $l--) {
778                $cols= $lignes[$l];
779                $colspan=1;
780                $ligne='';
781
782                for($c=count($cols)-1; $c>=0; $c--) {
783                        $attr='';
784                        if($cols[$c]=='<') {
785                          $colspan++;
786
787                        } elseif($cols[$c]=='^') {
788                          $rowspans[$c]++;
789
790                        } else {
791                          if($colspan>1) {
792                                $attr.= " colspan='$colspan'";
793                                $colspan=1;
794                          }
795                          if($rowspans[$c]>1) {
796                                $attr.= " rowspan='$rowspans[$c]'";
797                                $rowspans[$c]=1;
798                          }
799                          $ligne= '<td'.$attr.'>'.$cols[$c].'</td>'.$ligne;
800                        }
801                }
802
803                // ligne complete
804                $class = 'row_'.alterner($l+1, 'even', 'odd');
805                $html = "<tr class=\"$class\">" . $ligne . "</tr>\n".$html;
806        }
807
808        return "\n\n<table class=\"spip\"$summary>\n"
809                . $debut_table
810                . "<tbody>\n"
811                . $html
812                . "</tbody>\n"
813                . "</table>\n\n";
814}
815
816
817//
818// Traitement des listes (merci a Michael Parienti)
819//
820function traiter_listes ($texte) {
821        $parags = preg_split(",\n[[:space:]]*\n,S", $texte);
822        $texte ='';
823
824        // chaque paragraphe est traite a part
825        while (list(,$para) = each($parags)) {
826                $niveau = 0;
827                $lignes = explode("\n-", "\n" . $para);
828
829                // ne pas toucher a la premiere ligne
830                list(,$debut) = each($lignes);
831                $texte .= $debut;
832
833                // chaque item a sa profondeur = nb d'etoiles
834                $type ='';
835                while (list(,$item) = each($lignes)) {
836                        preg_match(",^([*]*|[#]*)([^*#].*)$,sS", $item, $regs);
837                        $profond = strlen($regs[1]);
838
839                        if ($profond > 0) {
840                                $ajout='';
841
842                                // changement de type de liste au meme niveau : il faut
843                                // descendre un niveau plus bas, fermer ce niveau, et
844                                // remonter
845                                $nouv_type = (substr($item,0,1) == '*') ? 'ul' : 'ol';
846                                $change_type = ($type AND ($type <> $nouv_type) AND ($profond == $niveau)) ? 1 : 0;
847                                $type = $nouv_type;
848
849                                // d'abord traiter les descentes
850                                while ($niveau > $profond - $change_type) {
851                                        $ajout .= $pile_li[$niveau];
852                                        $ajout .= $pile_type[$niveau];
853                                        if (!$change_type)
854                                                unset ($pile_li[$niveau]);
855                                        $niveau --;
856                                }
857
858                                // puis les identites (y compris en fin de descente)
859                                if ($niveau == $profond && !$change_type) {
860                                        $ajout .= $pile_li[$niveau];
861                                }
862
863                                // puis les montees (y compris apres une descente un cran trop bas)
864                                while ($niveau < $profond) {
865                                        if ($niveau == 0) $ajout .= "\n\n";
866                                        $niveau ++;
867                                        $ajout .= "<$type class=\"spip\">";
868                                        $pile_type[$niveau] = "</$type>";
869                                }
870
871                                $ajout .= "<li class=\"spip\">";
872                                $pile_li[$profond] = "</li>";
873                        }
874                        else {
875                                $ajout = "\n-"; // puce normale ou <hr>
876                        }
877
878                        $texte .= $ajout . $regs[2];
879                }
880
881                // retour sur terre
882                $ajout = '';
883                while ($niveau > 0) {
884                        $ajout .= $pile_li[$niveau];
885                        $ajout .= $pile_type[$niveau];
886                        $niveau --;
887                }
888                $texte .= $ajout;
889
890                // paragraphe
891                $texte .= "\n\n";
892        }
893
894        // sucrer les deux derniers \n
895        return substr($texte, 0, -2);
896}
897
898// Definition de la regexp des images/documents
899define('__preg_img', ',<(img|doc|emb)([0-9]+)(\|([^>]*))?'.'>,iS');
900
901// fonction en cas de texte extrait d'un serveur distant:
902// on ne sait pas (encore) rapatrier les documents joints
903
904function supprime_img($letexte) {
905        $message = _T('img_indisponible');
906        preg_replace(__preg_img, "($message)", $letexte);
907        return $letexte;
908}
909
910
911//
912// Une fonction pour fermer les paragraphes ; on essaie de preserver
913// des paragraphes indiques a la main dans le texte
914// (par ex: on ne modifie pas un <p align='center'>)
915//
916function paragrapher($letexte) {
917
918        if (preg_match(',<p[>[:space:]],iS',$letexte)) {
919
920                // Ajouter un espace aux <p> et un "STOP P"
921                // transformer aussi les </p> existants en <p>, nettoyes ensuite
922                $letexte = preg_replace(',</?p(\s([^>]*))?'.'>,iS', '<STOP P><p \2>',
923                        '<p>'.$letexte.'<STOP P>');
924
925                // Fermer les paragraphes (y compris sur "STOP P")
926                $letexte = preg_replace(
927                        ',(<p\s.*)(</?(STOP P|'._BALISES_BLOCS.')[>[:space:]]),UimsS',
928                        "\n\\1</p>\n\\2", $letexte);
929
930                // Supprimer les marqueurs "STOP P"
931                $letexte = str_replace('<STOP P>', '', $letexte);
932
933                // Reduire les blancs dans les <p>
934                $letexte = preg_replace(
935                ',(<p(>|\s[^>]*)>)\s*|\s*(</p[>[:space:]]),iS', '\1\3',
936                        $letexte);
937
938                // Supprimer les <p xx></p> vides
939                $letexte = preg_replace(',<p\s[^>]*></p>\s*,iS', '',
940                        $letexte);
941
942                // Renommer les paragraphes normaux avec class="spip"
943                $letexte = str_replace('<p >', '<p class="spip">',
944                        $letexte);
945
946        }
947
948        return $letexte;
949}
950
951// Nettoie un texte, traite les raccourcis spip, la typo, etc.
952function traiter_raccourcis($letexte) {
953        global $debut_intertitre, $fin_intertitre, $ligne_horizontale, $url_glossaire_externe;
954        global $compt_note;
955        global $marqueur_notes;
956        global $ouvre_ref;
957        global $ferme_ref;
958        global $ouvre_note;
959        global $ferme_note;
960        global $lang_dir;
961        static $notes_vues;
962
963        // Appeler les fonctions de pre_traitement
964        $letexte = pipeline('pre_propre', $letexte);
965        // old style
966        if (function_exists('avant_propre'))
967                $letexte = avant_propre($letexte);
968
969
970        // Gestion de la <poesie>
971        if (preg_match_all(",<(poesie|poetry)>(.*)<\/(poesie|poetry)>,UimsS",
972        $letexte, $regs, PREG_SET_ORDER)) {
973                foreach ($regs as $reg) {
974                        $lecode = preg_replace(",\r\n?,S", "\n", $reg[2]);
975                        $lecode = ereg_replace("\n[[:space:]]*\n", "\n&nbsp;\n",$lecode);
976                        $lecode = "<div class=\"spip_poesie\">\n<div>".ereg_replace("\n+", "</div>\n<div>", trim($lecode))."</div>\n</div>\n\n";
977                        $letexte = str_replace($reg[0], $lecode, $letexte);
978                }
979        }
980
981        // Harmoniser les retours chariot
982        $letexte = preg_replace(",\r\n?,S", "\n", $letexte);
983
984        // Recuperer les para HTML
985        $letexte = preg_replace(",<p[>[:space:]],iS", "\n\n\\0", $letexte);
986        $letexte = preg_replace(",</p[>[:space:]],iS", "\\0\n\n", $letexte);
987
988        //
989        // Notes de bas de page
990        //
991        $mes_notes = '';
992        $regexp = ', *\[\[(.*?)\]\],msS';
993        if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER))
994        foreach ($matches as $regs) {
995                $note_source = $regs[0];
996                $note_texte = $regs[1];
997                $num_note = false;
998
999                // note auto ou pas ?
1000                if (preg_match(",^ *<([^>]*)>,", $note_texte, $regs)){
1001                        $num_note = $regs[1];
1002                        $note_texte = str_replace($regs[0], "", $note_texte);
1003                } else {
1004                        $compt_note++;
1005                        $num_note = $compt_note;
1006                }
1007
1008                // preparer la note
1009                if ($num_note) {
1010                        if ($marqueur_notes) // quand il y a plusieurs series
1011                                                                 // de notes sur une meme page
1012                                $mn = $marqueur_notes.'-';
1013                        $ancre = $mn.rawurlencode($num_note);
1014
1015                        // ne mettre qu'une ancre par appel de note (XHTML)
1016                        if (!$notes_vues[$ancre]++)
1017                                $name_id = " name=\"nh$ancre\" id=\"nh$ancre\"";
1018                        else
1019                                $name_id = "";
1020
1021                        $lien = "<a href=\"#nb$ancre\"$name_id class=\"spip_note\">";
1022
1023                        // creer le popup 'title' sur l'appel de note
1024                        if ($title = supprimer_tags(propre($note_texte))) {
1025                                $title = $ouvre_note.$num_note.$ferme_note.$title;
1026                                $title = couper($title,80);
1027                                $lien = inserer_attribut($lien, 'title', $title);
1028                        }
1029
1030                        $insert = "$ouvre_ref$lien$num_note</a>$ferme_ref";
1031
1032                        // on l'echappe
1033                        $insert = code_echappement($insert);
1034
1035                        $appel = "$ouvre_note<a href=\"#nh$ancre\" name=\"nb$ancre\" class=\"spip_note\" title=\"" . _T('info_notes') . " $ancre\">$num_note</a>$ferme_note";
1036                } else {
1037                        $insert = '';
1038                        $appel = '';
1039                }
1040
1041                // l'ajouter "tel quel" (echappe) dans les notes
1042                if ($note_texte) {
1043                        if ($mes_notes)
1044                                $mes_notes .= "\n\n";
1045                        $mes_notes .= code_echappement($appel) . $note_texte;
1046                }
1047
1048                // dans le texte, mettre l'appel de note a la place de la note
1049                $pos = strpos($letexte, $note_source);
1050                $letexte = substr($letexte, 0, $pos) . $insert
1051                        . substr($letexte, $pos + strlen($note_source));
1052        }
1053
1054        //
1055        // Raccourcis automatiques [?SPIP] vers un glossaire
1056        // (on traite ce raccourci en deux temps afin de ne pas appliquer
1057        //  la typo sur les URLs, voir raccourcis liens ci-dessous)
1058        //
1059        if ($url_glossaire_externe) {
1060                $regexp = "|\[\?+([^][<>]+)\]|";
1061                if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER))
1062                foreach ($matches as $regs) {
1063                        $terme = trim($regs[1]);
1064                        $terme_underscore = rawurlencode(preg_replace(',\s+,', '_', preg_replace("/([^|]+)(\|.*)?/", "$1", $terme)));
1065                        if (strstr($url_glossaire_externe,"%s"))
1066                                $url = str_replace("%s", $terme_underscore, $url_glossaire_externe);
1067                        else
1068                                $url = $url_glossaire_externe.$terme_underscore;
1069                        $url = str_replace("@lang@", $GLOBALS['spip_lang'], $url);
1070                        $code = '['.$terme.'->?'.$url.']';
1071
1072                        // Eviter les cas particulier genre "[?!?]"
1073                        if (preg_match(',[a-z],i', $terme))
1074                                $letexte = str_replace($regs[0], $code, $letexte);
1075                }
1076        }
1077
1078
1079        //
1080        // Raccourcis ancre [#ancre<-]
1081        //
1082        $regexp = "|\[#?([^][]*)<-\]|S";
1083        if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER))
1084        foreach ($matches as $regs)
1085                $letexte = str_replace($regs[0],
1086                '<a name="'.entites_html($regs[1]).'"></a>', $letexte);
1087
1088
1089        //
1090        // Raccourcis liens [xxx->url]
1091        // Note : complique car c'est ici qu'on applique typo() !
1092        //
1093        #$regexp = "|\[([^][]*)->(>?)([^]]*)\]|ms";
1094        $regexp =  "|\[([^][]*)(\|([^]>{]*)(\{([a-z-]+)})?)?->(>)?([^]]*)\]|msU";
1095        $inserts = array();
1096        if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER)) {
1097                $i = 0;
1098                foreach ($matches as $regs) {
1099                        $str_title = attribut_html($regs[3]);
1100                        if ($str_title) $str_title = " title=\"$str_title\"";
1101                        $str_hreflang = attribut_html($regs[5]);
1102                        if ($str_hreflang) $str_hreflang = " hreflang=\"$str_hreflang\"";
1103                        //$str_targetblank = $regs[6]; // Pourrait servir pour la compatibilité AGORA
1104                        list($lien, $class, $texte) = calculer_url($regs[7], $regs[1], 'tout');
1105                        # ici bien passer le lien pour traiter [<doc3>->url]
1106                        $inserts[++$i] = typo("<a href=\"$lien\" class=\"$class\"$str_title$str_hreflang>"
1107                                . supprimer_numero($texte)
1108                                . "</a>");
1109
1110                        $letexte = str_replace($regs[0], "@@SPIP_ECHAPPE_LIEN_$i@@",
1111                                $letexte);
1112                }
1113        }
1114
1115        $letexte = typo($letexte, /* echap deja fait, accelerer */ false);
1116
1117        foreach ($inserts as $i => $insert) {
1118                $letexte = str_replace("@@SPIP_ECHAPPE_LIEN_$i@@", $insert, $letexte);
1119        }
1120
1121
1122        //
1123        // Tableaux
1124        //
1125
1126        // ne pas oublier les tableaux au debut ou a la fin du texte
1127        $letexte = preg_replace(",^\n?[|],S", "\n\n|", $letexte);
1128        $letexte = preg_replace(",\n\n+[|],S", "\n\n\n\n|", $letexte);
1129        $letexte = preg_replace(",[|](\n\n+|\n?$),S", "|\n\n\n\n", $letexte);
1130
1131        // traiter chaque tableau
1132        if (preg_match_all(',[^|](\n[|].*[|]\n)[^|],UmsS', $letexte,
1133        $regs, PREG_SET_ORDER))
1134        foreach ($regs as $tab) {
1135                $letexte = str_replace($tab[1], traiter_tableau($tab[1]), $letexte);
1136        }
1137
1138        //
1139        // Ensemble de remplacements implementant le systeme de mise
1140        // en forme (paragraphes, raccourcis...)
1141        //
1142
1143        $letexte = "\n".trim($letexte);
1144
1145        // les listes
1146        if (ereg("\n-[*#]", $letexte))
1147                $letexte = traiter_listes($letexte);
1148
1149        // Puce
1150        if (strpos($letexte, "\n- ") !== false)
1151                $puce = definir_puce();
1152        else $puce = '';
1153
1154
1155        // Proteger les caracteres actifs a l'interieur des tags html
1156        $protege = "{}-";
1157        $illegal = "\x1\x2\x3";
1158        if (preg_match_all(",</?[a-z!][^<>]*[!':;\?~][^<>]*>,imsS",
1159        $letexte, $regs, PREG_SET_ORDER)) {
1160                foreach ($regs as $reg) {
1161                        $insert = $reg[0];
1162                        // hack: on transforme les caracteres a proteger en les remplacant
1163                        // par des caracteres "illegaux". (cf corriger_caracteres())
1164                        $insert = strtr($insert, $protege, $illegal);
1165                        $letexte = str_replace($reg[0], $insert, $letexte);
1166                }
1167        }
1168
1169        // autres raccourcis
1170        $cherche1 = array(
1171                /* 0 */         "/\n(----+|____+)/S",
1172                /* 1 */         "/\n-- */S",
1173                /* 2 */         "/\n- */S",
1174                /* 3 */         "/\n_ +/S",
1175                /* 4 */   "/(^|[^{])[{][{][{]/S",
1176                /* 5 */   "/[}][}][}]($|[^}])/S",
1177                /* 6 */         "/(( *)\n){2,}(<br[[:space:]]*\/?".">)?/S",
1178                /* 7 */         "/[{][{]/S",
1179                /* 8 */         "/[}][}]/S",
1180                /* 9 */         "/[{]/S",
1181                /* 10 */        "/[}]/S",
1182                /* 11 */        "/(<br[[:space:]]*\/?".">){2,}/S",
1183                /* 12 */        "/<p>([\n]*(<br[[:space:]]*\/?".">)*)*/S",
1184                /* 13 */        "/<quote>/S",
1185                /* 14 */        "/<\/quote>/S"
1186        );
1187        $remplace1 = array(
1188                /* 0 */         "\n\n$ligne_horizontale\n\n",
1189                /* 1 */         "\n<br />&mdash;&nbsp;",
1190                /* 2 */         "\n<br />$puce&nbsp;",
1191                /* 3 */         "\n<br />",
1192                /* 4 */         "\$1\n\n$debut_intertitre",
1193                /* 5 */         "$fin_intertitre\n\n\$1",
1194                /* 6 */         "<p>",
1195                /* 7 */         "<strong class=\"spip\">",
1196                /* 8 */         "</strong>",
1197                /* 9 */         "<i class=\"spip\">",
1198                /* 10 */        "</i>",
1199                /* 11 */        "<p>",
1200                /* 12 */        "<p>",
1201                /* 13 */        "<blockquote class=\"spip\"><p>",
1202                /* 14 */        "</blockquote><p>"
1203        );
1204        $letexte = preg_replace($cherche1, $remplace1, $letexte);
1205        $letexte = preg_replace("@^ <br />@S", "", $letexte);
1206
1207        // Retablir les caracteres proteges
1208        $letexte = strtr($letexte, $illegal, $protege);
1209
1210        // Fermer les paragraphes
1211        $letexte = paragrapher($letexte);
1212
1213        // Appeler les fonctions de post-traitement
1214        $letexte = pipeline('post_propre', $letexte);
1215        // old style
1216        if (function_exists('apres_propre'))
1217                $letexte = apres_propre($letexte);
1218
1219        if ($mes_notes) traiter_les_notes($mes_notes);
1220
1221        return $letexte;
1222}
1223
1224function traiter_les_notes($mes_notes) {
1225        $mes_notes = propre('<p>'.$mes_notes);
1226        $mes_notes = str_replace(
1227                '<p class="spip">', '<p class="spip_note">', $mes_notes);
1228        $GLOBALS['les_notes'] .= $mes_notes;
1229}
1230
1231
1232// Filtre a appliquer aux champs du type #TEXTE*
1233function propre($letexte) {
1234
1235        // Echapper les <a href>, <html>...< /html>, <code>...< /code>
1236        $letexte = echappe_html($letexte);
1237
1238        // Traiter le texte
1239        $letexte = traiter_raccourcis($letexte);
1240
1241        // Reinserer les echappements
1242        $letexte = echappe_retour($letexte);
1243
1244        // Vider les espaces superflus
1245        $letexte = trim($letexte);
1246
1247        // Dans l'espace prive, securiser ici
1248        if (!_DIR_RESTREINT)
1249                $letexte = interdire_scripts($letexte);
1250
1251        return $letexte;
1252}
1253
1254?>
Note: See TracBrowser for help on using the repository browser.