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

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

Suivi de la modif proposée par Cédric sur la branche 1.9
Report d'une dernière pétouille SVN

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