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