Subversion Repositories Sites.tela-botanica.org

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 david 1
<?php
2
 
3
/***************************************************************************\
4
 *  SPIP, Systeme de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright (c) 2001-2005                                                *
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
//
15
// Ce fichier ne sera execute qu'une fois
16
if (defined("_ECRIRE_INC_TEXTE")) return;
17
define("_ECRIRE_INC_TEXTE", "1");
18
 
19
include_ecrire("inc_filtres.php3");
20
 
21
//
22
// Initialisation de quelques variables globales
23
// (on peut les modifier globalement dans mes_fonctions.php3,
24
//  OU individuellement pour chaque type de page dans article.php3,
25
//  rubrique.php3, etc. cf doc...)
26
//
27
function tester_variable($nom_var, $val){
28
	if (!isset($GLOBALS[$nom_var])) {
29
		$GLOBALS[$nom_var] = $val;
30
		return false;
31
	}
32
	return true;
33
}
34
 
35
tester_variable('debut_intertitre', "\n<h3 class=\"spip\">");
36
tester_variable('fin_intertitre', "</h3>\n");
37
tester_variable('ligne_horizontale', "\n<hr class=\"spip\" />\n");
38
tester_variable('ouvre_ref', '&nbsp;[');
39
tester_variable('ferme_ref', ']');
40
tester_variable('ouvre_note', '[');
41
tester_variable('ferme_note', '] ');
42
tester_variable('les_notes', '');
43
tester_variable('compt_note', 0);
44
tester_variable('nombre_surligne', 4);
45
tester_variable('url_glossaire_externe', "http://@lang@.wikipedia.org/wiki/");
46
 
47
 
48
// On ne prend la $puce_rtl par defaut que si $puce n'a pas ete redefinie
49
 
50
//if (!tester_variable('puce', "<li class='spip_puce' style='list-style-image: url(puce.gif)'>")) {
51
if (!tester_variable('puce', "<img class='spip_puce' src='puce.gif' alt='-' />&nbsp;")) {
52
	tester_variable('puce_rtl', "<img class='spip_puce' src='puce_rtl.gif' alt='-' />&nbsp;");
53
}
54
 
55
 
56
//
57
// Diverses fonctions essentielles
58
//
59
 
60
// Ne pas afficher le chapo si article virtuel
61
function nettoyer_chapo($chapo){
62
	if (substr($chapo,0,1) == "="){
63
		$chapo = "";
64
	}
65
	return $chapo;
66
}
67
 
68
// points d'entree de pre- et post-traitement pour propre() et typo()
69
function spip_avant_propre ($letexte) {
70
	$letexte = avant_propre_ancres($letexte);
71
	$letexte = extraire_multi($letexte);
72
 
73
	if (function_exists('avant_propre'))
74
		$letexte = avant_propre($letexte);
75
 
76
	return $letexte;
77
}
78
 
79
function spip_apres_propre ($letexte) {
80
	if (function_exists('apres_propre'))
81
		$letexte = apres_propre($letexte);
82
 
83
	return $letexte;
84
}
85
 
86
function spip_avant_typo ($letexte) {
87
	$letexte = extraire_multi($letexte);
88
	$letexte = avant_typo_smallcaps($letexte);
89
 
90
	if (function_exists('avant_typo'))
91
		$letexte = avant_typo($letexte);
92
 
93
	return $letexte;
94
}
95
 
96
function spip_apres_typo ($letexte) {
97
 
98
	// relecture des &nbsp;
99
	if (!_DIR_RESTREINT AND $GLOBALS['revision_nbsp'])
100
		$letexte = str_replace('&nbsp;',
101
			'<span class="spip-nbsp">&nbsp;</span>', $letexte);
102
 
103
	if (function_exists('apres_typo'))
104
		$letexte = apres_typo($letexte);
105
 
106
	return $letexte;
107
}
108
 
109
 
110
//
111
// Mise de cote des echappements
112
//
113
 
114
// Definition de la regexp de echappe_html
115
define ('__regexp_echappe',
116
		"/(" . "<html>((.*?))<\/html>" . ")|("	#html
117
		. "<code>((.*?))<\/code>" . ")|("	#code
118
		. "<(cadre|frame)>((.*?))<\/(cadre|frame)>" #cadre
119
		. ")|("
120
		. "<(poesie|poetry)>((.*?))<\/(poesie|poetry)>" #poesie
121
		. ")/si");
122
define('__preg_img', ',<(img|doc|emb)([0-9]+)(\|([^>]*))?'.'>,i');
123
 
124
function echappe_html($letexte, $source='SOURCEPROPRE', $no_transform=false) {
125
	if (preg_match_all(__regexp_echappe, $letexte, $matches, PREG_SET_ORDER))
126
	foreach ($matches as $regs) {
127
		$num_echap++;
128
		$marqueur_echap = "@@SPIP_$source$num_echap@@";
129
 
130
		if ($no_transform) {	// echappements bruts
131
			$les_echap[$num_echap] = $regs[0];
132
		}
133
		else
134
		if ($regs[1]) {
135
			// Echapper les <html>...</ html>
136
			$les_echap[$num_echap] = $regs[2];
137
		}
138
		else
139
		if ($regs[4]) {
140
			// Echapper les <code>...</ code>
141
			$lecode = entites_html($regs[5]);
142
 
143
			// supprimer les sauts de ligne debut/fin (mais pas les espaces => ascii art).
144
			$lecode = ereg_replace("^\n+|\n+$", "", $lecode);
145
 
146
			// ne pas mettre le <div...> s'il n'y a qu'une ligne
147
			if (is_int(strpos($lecode,"\n"))) {
148
				$lecode = nl2br("<div style='text-align: left;' class='spip_code' dir='ltr'><tt>".$lecode."</tt></div>");
149
				$marqueur_echap = "</no p>$marqueur_echap<no p>";
150
			} else
151
				$lecode = "<span class='spip_code' dir='ltr'><tt>".$lecode."</tt></span>";
152
 
153
			$lecode = str_replace("\t", "&nbsp; &nbsp; &nbsp; &nbsp; ", $lecode);
154
			$lecode = str_replace("  ", " &nbsp;", $lecode);
155
			$les_echap[$num_echap] = $lecode;
156
		}
157
		else
158
		if ($regs[7]) {
159
			// Echapper les <cadre>...</cadre>
160
			$lecode = trim(entites_html($regs[9]));
161
			$total_lignes = substr_count($lecode, "\n");
162
 
163
			$les_echap[$num_echap] = "<form action=\"/\" method=\"get\"><div><textarea readonly='readonly' cols='40' rows='$total_lignes' class='spip_cadre' dir='ltr'>".$lecode."</textarea></div></form>";
164
			// Les marques ci-dessous indiquent qu'on ne veut pas paragrapher
165
			$marqueur_echap = "\n\n</no p>$marqueur_echap<no p>\n\n";
166
		}
167
		else
168
		if ($regs[12]) {
169
			$lecode = $regs[14];
170
			$lecode = ereg_replace("\n[[:space:]]*\n", "\n&nbsp;\n",$lecode);
171
			$lecode = str_replace("\r", "\n", $lecode); # gestion des \r a revoir !
172
			$lecode = "<div class=\"spip_poesie\"><div>".ereg_replace("\n+", "</div>\n<div>", $lecode)."</div></div>";
173
			$marqueur_echap = "\n\n</no p>$marqueur_echap<no p>\n\n";
174
			$les_echap[$num_echap] = propre($lecode);
175
		}
176
 
177
		$letexte = str_replace($regs[0], $marqueur_echap, $letexte);
178
	}
179
 
180
	// Gestion du TeX
181
	if (!(strpos($letexte, "<math>") === false)) {
182
		include_ecrire("inc_math.php3");
183
		$letexte = traiter_math($letexte, $les_echap, $num_echap, $source);
184
	}
185
 
186
	// Traitement des images et documents <IMGxx|right>
187
	// (insertion dans echappe_retour pour faciliter les doublons)
188
	if (preg_match_all(__preg_img, $letexte, $matches, PREG_SET_ORDER)) {
189
		foreach ($matches as $match) {
190
			$num_echap++;
191
 
192
			// Si le resultat contient des <div>, forcer la sortie de paragraphes
193
			if ( $match[1] == "doc" OR $match[1] == "emb" OR eregi("^\|center", $match[3]) )  {
194
				$letexte = str_replace($match[0],
195
					"\n\n</no p>@@SPIP_$source$num_echap@@<no p>\n\n", $letexte);
196
			} else {
197
			$letexte = str_replace($match[0],
198
				"@@SPIP_$source$num_echap@@", $letexte);
199
			}
200
			$les_echap[$num_echap] = $match;
201
		}
202
	}
203
 
204
	return array($letexte, $les_echap);
205
}
206
 
207
// Traitement final des echappements
208
function echappe_retour($letexte, $les_echap, $source='') {
209
	$expr = ",@@SPIP_$source([0-9]+)@@,";
210
	if (preg_match_all($expr, $letexte, $regs, PREG_SET_ORDER)) {
211
		foreach ($regs as $reg) {
212
			$rempl = $les_echap[$reg[1]];
213
# si $rempl est un tableau, c'est le resultat (cf echappe_html) de eregi sur :
214
# <(IMG|DOC|EMB)([0-9]+)(\|([^\>]*))?
215
			if (is_array($rempl)) {
216
				include_ecrire("inc_documents.php3");
217
				$type = strtoupper($rempl[1]);
218
				if ($type == 'EMB')
219
					$rempl = embed_document($rempl[2], $rempl[4]);
220
				else
221
					$rempl = integre_image($rempl[2], $rempl[4], $type);
222
 
223
			}
224
			$letexte = str_replace($reg[0], $rempl, $letexte);
225
		}
226
	}
227
	return $letexte;
228
}
229
 
230
 
231
// fonction en cas de texte extrait d'un serveur distant:
232
// on ne sait pas (encore) rapatrier les documents joints
233
 
234
function supprime_img($letexte) {
235
	$message = _T('img_indisponible');
236
	preg_replace(__preg_img, "($message)", $letexte);
237
	return $letexte;
238
}
239
 
240
# il y a 3 couples de fonctions homonymes au prefixe _doublons pres
241
# pour eviter a tous les appels de se trimbaler ce qui concerne les squelettes
242
 
243
function echappe_retour_doublon($letexte, $les_echap, $source, &$doublons)
244
{
245
  if (!$les_echap)
246
    return $letexte;
247
  foreach($les_echap as $rempl) {
248
    if (is_array($rempl)) # cf commentaires dans la fonction echappe_retour
249
      $doublons['documents'] .= "," . $rempl[2];
250
  }
251
  return echappe_retour($letexte, $les_echap, $source);
252
}
253
 
254
//
255
// Gerer les outils mb_string
256
//
257
function spip_substr($c, $start=0, $end='') {
258
	include_ecrire('inc_charsets.php3');
259
	if (init_mb_string()) {
260
		if ($end)
261
			return mb_substr($c, $start, $end);
262
		else
263
			return mb_substr($c, $start);
264
	}
265
 
266
	// methode substr normale
267
	else {
268
		if ($end)
269
			return substr($c, $start, $end);
270
		else
271
			return substr($c, $start);
272
	}
273
}
274
 
275
function spip_strlen($c) {
276
	include_ecrire('inc_charsets.php3');
277
	if (init_mb_string())
278
		return mb_strlen($c);
279
	else
280
		return strlen($c);
281
}
282
// fin mb_string
283
 
284
 
285
function couper($texte, $taille=50) {
286
	$texte = substr($texte, 0, 400 + 2*$taille); /* eviter de travailler sur 10ko pour extraire 150 caracteres */
287
 
288
	// on utilise les \r pour passer entre les gouttes
289
	$texte = str_replace("\r\n", "\n", $texte);
290
	$texte = str_replace("\r", "\n", $texte);
291
 
292
	// sauts de ligne et paragraphes
293
	$texte = ereg_replace("\n\n+", "\r", $texte);
294
	$texte = ereg_replace("<(p|br)( [^>]*)?".">", "\r", $texte);
295
 
296
	// supprimer les traits, lignes etc
297
	$texte = ereg_replace("(^|\r|\n)(-[-#\*]*|_ )", "\r", $texte);
298
 
299
	// supprimer les tags
300
	$texte = supprimer_tags($texte);
301
	$texte = trim(str_replace("\n"," ", $texte));
302
	$texte .= "\n";	// marquer la fin
303
 
304
	// travailler en accents charset
305
	$texte = filtrer_entites($texte);
306
 
307
	// supprimer les liens
308
	$texte = ereg_replace("\[->([^]]*)\]","\\1", $texte); // liens sans texte
309
	$texte = ereg_replace("\[([^\[]*)->([^]]*)\]","\\1", $texte);
310
 
311
	// supprimer les notes
312
	$texte = ereg_replace("\[\[([^]]|\][^]])*\]\]", "", $texte);
313
 
314
	// supprimer les codes typos
315
	$texte = ereg_replace("[}{]", "", $texte);
316
 
317
	// supprimer les tableaux
318
	$texte = ereg_replace("(^|\r)\|.*\|\r", "\r", $texte);
319
 
320
	// couper au mot precedent
321
	$long = spip_substr($texte, 0, max($taille-4,1));
322
	$court = ereg_replace("([^[:space:]][[:space:]]+)[^[:space:]]*\n?$", "\\1", $long);
323
	$points = '&nbsp;(...)';
324
 
325
	// trop court ? ne pas faire de (...)
326
	if (spip_strlen($court) < max(0.75 * $taille,2)) {
327
		$points = '';
328
		$long = spip_substr($texte, 0, $taille);
329
		$texte = ereg_replace("([^[:space:]][[:space:]]+)[^[:space:]]*$", "\\1", $long);
330
		// encore trop court ? couper au caractere
331
		if (spip_strlen($texte) < 0.75 * $taille)
332
			$texte = $long;
333
	} else
334
		$texte = $court;
335
 
336
	if (strpos($texte, "\n"))	// la fin est encore la : c'est qu'on n'a pas de texte de suite
337
		$points = '';
338
 
339
	// remettre les paragraphes
340
	$texte = ereg_replace("\r+", "\n\n", $texte);
341
 
342
	// supprimer l'eventuelle entite finale mal coupee
343
	$texte = preg_replace('/&#?[a-z0-9]*$/', '', $texte);
344
 
345
	return trim($texte).$points;
346
}
347
 
348
// prendre <intro>...</intro> sinon couper a la longueur demandee
349
function couper_intro($texte, $long) {
350
	$texte = extraire_multi(eregi_replace("(</?)intro>", "\\1intro>", $texte)); // minuscules
351
	while ($fin = strpos($texte, "</intro>")) {
352
		$zone = substr($texte, 0, $fin);
353
		$texte = substr($texte, $fin + strlen("</intro>"));
354
		if ($deb = strpos($zone, "<intro>") OR substr($zone, 0, 7) == "<intro>")
355
			$zone = substr($zone, $deb + 7);
356
		$intro .= $zone;
357
	}
358
 
359
	if ($intro)
360
		$intro = $intro.'&nbsp;(...)';
361
	else
362
		$intro = couper($texte, $long);
363
 
364
	// supprimer un eventuel chapo redirecteur =http:/.....
365
	$intro = ereg_replace("^=[^[:space:]]+","",$intro);
366
 
367
	return $intro;
368
}
369
 
370
 
371
//
372
// Les elements de propre()
373
//
374
 
375
// Securite : empecher l'execution de code PHP
376
function interdire_scripts($source) {
377
	$source = preg_replace(",<(\%|\?|([[:space:]]*)script),", "&lt;\\1", $source);
378
	return $source;
379
}
380
 
381
 
382
// Correction typographique francaise
383
function typo_fr($letexte) {
384
	static $trans;
385
 
386
	// Nettoyer 160 = nbsp ; 187 = raquo ; 171 = laquo ; 176 = deg ; 147 = ldquo; 148 = rdquo
387
	if (!$trans) {
388
		$trans = array(
389
			"&nbsp;" => "~",
390
			"&raquo;" => "&#187;",
391
			"&laquo;" => "&#171;",
392
			"&rdquo;" => "&#148;",
393
			"&ldquo;" => "&#147;",
394
			"&deg;" => "&#176;"
395
		);
396
		$chars = array(160 => '~', 187 => '&#187;', 171 => '&#171;', 148 => '&#148;', 147 => '&#147;', 176 => '&#176;');
397
 
398
		include_ecrire('inc_charsets.php3');
399
		while (list($c, $r) = each($chars)) {
400
			$c = unicode2charset(charset2unicode(chr($c), 'iso-8859-1', 'forcer'));
401
			$trans[$c] = $r;
402
		}
403
	}
404
 
405
	$letexte = strtr($letexte, $trans);
406
 
407
	$cherche1 = array(
408
		/* 1		'/{([^}]+)}/',  */
409
		/* 2 */ 	'/((^|[^\#0-9a-zA-Z\&])[\#0-9a-zA-Z]*)\;/',
410
		/* 3 */		'/&#187;| --?,|:([^0-9]|$)/',
411
		/* 4 */		'/([^<!?])([!?])/',
412
		/* 5 */		'/&#171;|(M(M?\.|mes?|r\.?)|[MnN]&#176;) /'
413
	);
414
	$remplace1 = array(
415
		/* 1		'<i class="spip">\1</i>', */
416
		/* 2 */		'\1~;',
417
		/* 3 */		'~\0',
418
		/* 4 */		'\1~\2',
419
		/* 5 */		'\0~'
420
	);
421
	$letexte = preg_replace($cherche1, $remplace1, $letexte);
422
	$letexte = ereg_replace(" *~+ *", "~", $letexte);
423
 
424
	$cherche2 = array(
425
		'/([^-\n]|^)--([^-]|$)/',
426
		'/(http|https|ftp|mailto)~:/',
427
		'/~/'
428
	);
429
	$remplace2 = array(
430
		'\1&mdash;\2',
431
		'\1:',
432
		'&nbsp;'
433
	);
434
	$letexte = preg_replace($cherche2, $remplace2, $letexte);
435
 
436
	return $letexte;
437
}
438
 
439
// rien sauf les "~" et "-,"
440
function typo_en($letexte) {
441
 
442
	$cherche1 = array(
443
		'/ --?,/'
444
	);
445
	$remplace1 = array(
446
		'~\0'
447
	);
448
	$letexte = preg_replace($cherche1, $remplace1, $letexte);
449
 
450
	$letexte = str_replace("&nbsp;", "~", $letexte);
451
	$letexte = ereg_replace(" *~+ *", "~", $letexte);
452
 
453
	$cherche2 = array(
454
		'/([^-\n]|^)--([^-]|$)/',
455
		'/~/'
456
	);
457
	$remplace2 = array(
458
		'\1&mdash;\2',
459
		'&nbsp;'
460
	);
461
 
462
	$letexte = preg_replace($cherche2, $remplace2, $letexte);
463
 
464
	return $letexte;
465
}
466
 
467
//
468
// Typographie generale
469
//
470
function typo_generale($letexte) {
471
	global $spip_lang;
472
 
473
	// Appeler la fonction de pre-traitement
474
	$letexte = spip_avant_typo ($letexte);
475
 
476
	// Caracteres de controle "illegaux"
477
	$letexte = corriger_caracteres($letexte);
478
 
479
	// Proteger les caracteres typographiques a l'interieur des tags html
480
	$protege = "!':;?";
481
	$illegal = "\x1\x2\x3\x4\x5";
482
	if (preg_match_all("/<[a-z!][^<>!':;\?]*[!':;\?][^<>]*>/ims",
483
	$letexte, $regs, PREG_SET_ORDER)) {
484
		foreach ($regs as $reg) {
485
			$insert = $reg[0];
486
			// hack: on transforme les caracteres a proteger en les remplacant
487
			// par des caracteres "illegaux". (cf corriger_caracteres())
488
			$insert = strtr($insert, $protege, $illegal);
489
			$letexte = str_replace($reg[0], $insert, $letexte);
490
		}
491
	}
492
 
493
	// zouli apostrophe
494
	$letexte = str_replace("'", "&#8217;", $letexte);
495
 
496
	// typo francaise ou anglaise ?
497
	// $lang_typo est fixee dans l'interface privee pour editer
498
	// un texte anglais en interface francaise (ou l'inverse) ;
499
	// sinon determiner la typo en fonction de la langue
500
	if (!$lang = $GLOBALS['lang_typo']) {
501
		include_ecrire('inc_lang.php3');
502
		$lang = lang_typo($spip_lang);
503
	}
504
	if ($lang == 'fr')
505
		$letexte = typo_fr($letexte);
506
	else
507
		$letexte = typo_en($letexte);
508
 
509
	// Retablir les caracteres proteges
510
	$letexte = strtr($letexte, $illegal, $protege);
511
 
512
	// Appeler la fonction de post-traitement
513
	$letexte = spip_apres_typo ($letexte);
514
 
515
	# un message pour abs_url - on est passe en mode texte
516
	$GLOBALS['mode_abs_url'] = 'texte';
517
 
518
	// et retour
519
	return $letexte;
520
}
521
 
522
function typo($letexte) {
523
	// echapper les codes <html>...</html> etc.
524
	list($letexte, $les_echap) = echappe_html($letexte, "SOURCETYPO");
525
 
526
	$letexte = typo_generale($letexte);
527
	// reintegrer les echappements
528
	return echappe_retour($letexte, $les_echap, "SOURCETYPO");
529
}
530
 
531
function typo_doublon(&$doublons, $letexte)
532
{
533
	// echapper les codes <html>...</html> etc.
534
	list($letexte, $les_echap) = echappe_html($letexte, "SOURCETYPO");
535
 
536
	$letexte = typo_generale($letexte);
537
	// reintegrer les echappements
538
	return echappe_retour_doublon($letexte, $les_echap, "SOURCETYPO", $doublons);
539
}
540
 
541
// cette fonction est tordue : on lui passe un tableau correspondant au match
542
// de la regexp ci-dessous, et elle retourne le texte a inserer a la place
543
// et le lien "brut" a usage eventuel de redirection...
544
function extraire_lien ($regs) {
545
	$lien_texte = $regs[1];
546
 
547
	$lien_url = entites_html(trim($regs[3]));
548
	$compt_liens++;
549
	$lien_interne = false;
550
	if (ereg('^[[:space:]]*(art(icle)?|rub(rique)?|br(.ve)?|aut(eur)?|mot|site|doc(ument)?|im(age|g))?[[:space:]]*([[:digit:]]+)(#.*)?[[:space:]]*$', $lien_url, $match)) {
551
		// Traitement des liens internes
552
		if (!_DIR_RESTREINT)
553
			include_ecrire('inc_urls.php3');
554
		else
555
		if (@file_exists("inc-urls.php3"))
556
			include_local("inc-urls.php3");
557
		else
558
			include_local("inc-urls-".$GLOBALS['type_urls'].".php3");
559
 
560
		$id_lien = $match[8];
561
		$ancre = $match[9];
562
		$type_lien = substr($match[1], 0, 2);
563
		$lien_interne=true;
564
		$class_lien = "in";
565
		switch ($type_lien) {
566
			case 'ru':
567
				$lien_url = generer_url_rubrique($id_lien);
568
				if (!$lien_texte) {
569
					$req = "select titre from spip_rubriques where id_rubrique=$id_lien";
570
					$row = @spip_fetch_array(@spip_query($req));
571
					$lien_texte = $row['titre'];
572
				}
573
				break;
574
			case 'br':
575
				$lien_url = generer_url_breve($id_lien);
576
				if (!$lien_texte) {
577
					$req = "select titre from spip_breves where id_breve=$id_lien";
578
					$row = @spip_fetch_array(@spip_query($req));
579
					$lien_texte = $row['titre'];
580
				}
581
				break;
582
			case 'au':
583
				$lien_url = generer_url_auteur($id_lien);
584
				if (!$lien_texte) {
585
					$req = "select nom from spip_auteurs where id_auteur = $id_lien";
586
					$row = @spip_fetch_array(@spip_query($req));
587
					$lien_texte = $row['nom'];
588
				}
589
				break;
590
			case 'mo':
591
				$lien_url = generer_url_mot($id_lien);
592
				if (!$lien_texte) {
593
					$req = "select titre from spip_mots where id_mot=$id_lien";
594
					$row = @spip_fetch_array(@spip_query($req));
595
					$lien_texte = $row['titre'];
596
				}
597
				break;
598
			case 'im':
599
			case 'do':
600
				$lien_url = generer_url_document($id_lien);
601
				if (!$lien_texte) {
602
					$req = "select titre,fichier from spip_documents
603
					WHERE id_document=$id_lien";
604
					$row = @spip_fetch_array(@spip_query($req));
605
					$lien_texte = $row['titre'];
606
					if (!$lien_texte)
607
						$lien_texte = ereg_replace("^.*/","",$row['fichier']);
608
				}
609
				break;
610
			case 'si':
611
				# attention dans le cas des sites le lien pointe non pas sur
612
				# la page locale du site, mais directement sur le site lui-meme
613
				$row = @spip_fetch_array(@spip_query("SELECT nom_site,url_site
614
				FROM spip_syndic WHERE id_syndic=$id_lien"));
615
				if ($row) {
616
					$lien_url = $row['url_site'];
617
					if (!$lien_texte)
618
						$lien_texte = typo($row['nom_site']);
619
				}
620
				break;
621
			default:
622
				$lien_url = generer_url_article($id_lien);
623
				if (!$lien_texte) {
624
					$req = "select titre from spip_articles where id_article=$id_lien";
625
					$row = @spip_fetch_array(@spip_query($req));
626
					$lien_texte = $row['titre'];
627
 
628
				}
629
				break;
630
		}
631
 
632
		$lien_url .= $ancre;
633
 
634
		// supprimer les numeros des titres
635
		include_ecrire("inc_filtres.php3");
636
		$lien_texte = supprimer_numero($lien_texte);
637
	}
638
	else if (preg_match(',^\?(.*)$,s', $lien_url, $regs)) {
639
		// Liens glossaire
640
		$lien_url = substr($lien_url, 1);
641
		$class_lien = "glossaire";
642
	}
643
	else {
644
		// Liens non automatiques
645
		$class_lien = "out";
646
		// texte vide ?
647
		if ((!$lien_texte) and (!$lien_interne)) {
648
			$lien_texte = str_replace('"', '', $lien_url);
649
			if (strlen($lien_texte)>40)
650
				$lien_texte = substr($lien_texte,0,35).'...';
651
			$class_lien = "url";
652
			$lien_texte = "<html>$lien_texte</html>";
653
		}
654
		// petites corrections d'URL
655
		if (preg_match(",^www\.[^@]+$,",$lien_url))
656
			$lien_url = "http://".$lien_url;
657
		else if (strpos($lien_url, "@") && email_valide($lien_url))
658
			$lien_url = "mailto:".$lien_url;
659
	}
660
 
661
	$insert = "<a href=\"$lien_url\" class=\"spip_$class_lien\""
662
		.">".typo($lien_texte)."</a>";
663
 
664
	return array($insert, $lien_url);
665
}
666
 
667
//
668
// Tableaux
669
//
670
function traiter_tableau($bloc) {
671
 
672
	// Decouper le tableau en lignes
673
	preg_match_all(',([|].*)[|]\n,Ums', $bloc, $regs, PREG_PATTERN_ORDER);
674
 
675
	// Traiter chaque ligne
676
	foreach ($regs[1] as $ligne) {
677
		$l ++;
678
 
679
		// Gestion de la premiere ligne :
680
		if ($l == 1) {
681
		// - <caption> et summary dans la premiere ligne :
682
		//   || caption | summary || (|summary est optionnel)
683
			if (preg_match(',^\|\|([^|]*)(\|(.*))?\|$,ms', $ligne, $cap)) {
684
				$l = 0;
685
				if ($caption = trim($cap[1]))
686
					$debut_table .= "<caption>".$caption."</caption>\n";
687
				$summary = ' summary="'.entites_html(trim($cap[3])).'"';
688
			}
689
		// - <thead> sous la forme |{{titre}}|{{titre}}|
690
		//   Attention thead oblige a avoir tbody
691
			else if (preg_match(',^(\|[[:space:]]*{{[^}]+}}[[:space:]]*)+$,ms',
692
				$ligne, $thead)) {
693
				$debut_table .= "<thead>
694
					<tr class='row_first'>".
695
					preg_replace(",[|]([^|]*),",
696
						"<th scope='col'>\\1</th>", $ligne)
697
					."</tr></thead>\n";
698
				$l = 0;
699
			}
700
		}
701
 
702
		// Sinon ligne normale
703
		if ($l) {
704
			// definition du tr
705
			if ($l == 1
706
			AND ereg("^(\|[[:space:]]*[{][{][^}]+[}][}][[:space:]]*)+$", $ligne)) {
707
				$class = 'row_first';
708
			} else {
709
				$class = 'row_'.alterner($l, 'even', 'odd');
710
			}
711
 
712
			// Gerer les listes a puce dans les cellules
713
			if (ereg("\n-[*#]", $ligne))
714
				$ligne = traiter_listes($ligne);
715
 
716
			// Pas de paragraphes dans les cellules
717
			$ligne = preg_replace(",\n\n+,", "<br />\n", $ligne);
718
 
719
			// definition du <td>
720
			$ligne = preg_replace(",[|]([^|]*),",
721
				"<td>\\1</td>", $ligne);
722
 
723
			// ligne complete
724
			$html[$l] = "<tr class=\"$class\">" . $ligne . "</tr>\n";
725
		}
726
	}
727
 
728
	return "\n\n</no p><table class=\"spip\"$summary>\n"
729
		. $debut_table
730
		. "<tbody>\n"
731
		. join ('', $html)
732
		. "</tbody>\n"
733
		. "</table><no p>\n\n";
734
}
735
 
736
 
737
//
738
// Traitement des listes (merci a Michael Parienti)
739
//
740
function traiter_listes ($texte) {
741
	$parags = preg_split(",\n[[:space:]]*\n,", $texte);
742
	unset($texte);
743
 
744
	// chaque paragraphe est traite a part
745
	while (list(,$para) = each($parags)) {
746
		$niveau = 0;
747
		$lignes = explode("\n-", "\n" . $para);
748
 
749
		// ne pas toucher a la premiere ligne
750
		list(,$debut) = each($lignes);
751
		$texte .= $debut;
752
 
753
		// chaque item a sa profondeur = nb d'etoiles
754
		unset ($type);
755
		while (list(,$item) = each($lignes)) {
756
			preg_match(",^([*]*|[#]*)([^*#].*)$,s", $item, $regs);
757
			$profond = strlen($regs[1]);
758
 
759
			if ($profond > 0) {
760
				unset ($ajout);
761
 
762
				// changement de type de liste au meme niveau : il faut
763
				// descendre un niveau plus bas, fermer ce niveau, et
764
				// remonter
765
				$nouv_type = (substr($item,0,1) == '*') ? 'ul' : 'ol';
766
				$change_type = ($type AND ($type <> $nouv_type) AND ($profond == $niveau)) ? 1 : 0;
767
				$type = $nouv_type;
768
 
769
				// d'abord traiter les descentes
770
				while ($niveau > $profond - $change_type) {
771
					$ajout .= $pile_li[$niveau];
772
					$ajout .= $pile_type[$niveau];
773
					if (!$change_type)
774
						unset ($pile_li[$niveau]);
775
					$niveau --;
776
				}
777
 
778
				// puis les identites (y compris en fin de descente)
779
				if ($niveau == $profond && !$change_type) {
780
					$ajout .= $pile_li[$niveau];
781
				}
782
 
783
				// puis les montees (y compris apres une descente un cran trop bas)
784
				while ($niveau < $profond) {
785
					if ($niveau == 0) $ajout .= "\n\n";
786
					$niveau ++;
787
					$ajout .= "</no p>"."<$type class=\"spip\">";
788
					$pile_type[$niveau] = "</$type>"."<no p>";
789
				}
790
 
791
				$ajout .= "<li class=\"spip\">";
792
				$pile_li[$profond] = "</li>";
793
			}
794
			else {
795
				$ajout = "\n-";	// puce normale ou <hr>
796
			}
797
 
798
			$texte .= $ajout . $regs[2];
799
		}
800
 
801
		// retour sur terre
802
		unset ($ajout);
803
		while ($niveau > 0) {
804
			$ajout .= $pile_li[$niveau];
805
			$ajout .= $pile_type[$niveau];
806
			$niveau --;
807
		}
808
		$texte .= $ajout;
809
 
810
		// paragraphe
811
		$texte .= "\n\n";
812
	}
813
 
814
	// sucrer les deux derniers \n
815
	return substr($texte, 0, -2);
816
}
817
 
818
// Nettoie un texte, traite les raccourcis spip, la typo, etc.
819
function traiter_raccourcis_generale($letexte) {
820
	global $debut_intertitre, $fin_intertitre, $ligne_horizontale, $url_glossaire_externe;
821
	global $compt_note;
822
	global $marqueur_notes;
823
	global $ouvre_ref;
824
	global $ferme_ref;
825
	global $ouvre_note;
826
	global $ferme_note;
827
	global $lang_dir;
828
 
829
	// Appeler la fonction de pre_traitement
830
	$letexte = spip_avant_propre ($letexte);
831
 
832
	// Puce
833
	if (!$lang_dir) {
834
		include_ecrire('inc_lang.php3');
835
		$lang_dir = lang_dir($GLOBALS['spip_lang']);
836
	}
837
	if ($lang_dir == 'rtl' AND $GLOBALS['puce_rtl'])
838
		$puce = $GLOBALS['puce_rtl'];
839
	else
840
		$puce = $GLOBALS['puce'];
841
 
842
	// Harmoniser les retours chariot
843
	$letexte = preg_replace(",\r\n?,", "\n", $letexte);
844
 
845
	// Corriger HTML
846
	$letexte = preg_replace(",</?p>,i", "\n\n\n", $letexte);
847
 
848
	//
849
	// Notes de bas de page
850
	//
851
	$regexp = ',\[\[(.*?)\]\],ms';
852
	if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER))
853
	foreach ($matches as $regs) {
854
		$note_source = $regs[0];
855
		$note_texte = $regs[1];
856
		$num_note = false;
857
 
858
		// note auto ou pas ?
859
		if (preg_match(",^ *<([^>]*)>,", $note_texte, $regs)){
860
			$num_note = $regs[1];
861
			$note_texte = str_replace($regs[0], "", $note_texte);
862
		} else {
863
			$compt_note++;
864
			$num_note = $compt_note;
865
		}
866
 
867
		// preparer la note
868
		if ($num_note) {
869
			if ($marqueur_notes) // quand il y a plusieurs series
870
								 // de notes sur une meme page
871
				$mn = $marqueur_notes.'-';
872
			$ancre = $mn.urlencode($num_note);
873
 
874
			// creer le popup 'title' sur l'appel de note
875
			if ($title = supprimer_tags(propre($note_texte))) {
876
				$title = $ouvre_note.$ancre.$ferme_note.$title;
877
				$title = ' title="<html>'
878
				. texte_backend(couper($title,80)).'</html>"';
879
			}
880
 
881
			$insert = "$ouvre_ref<a href=\"#nb$ancre\" name=\"nh$ancre\" class=\"spip_note\"$title>$num_note</a>$ferme_ref";
882
			$appel = "<html>$ouvre_note<a href=\"#nh$ancre\" name=\"nb$ancre\" class=\"spip_note\">$num_note</a>$ferme_note</html>";
883
		} else {
884
			$insert = '';
885
			$appel = '';
886
		}
887
 
888
		// l'ajouter "brut" dans les notes
889
		if ($note_texte) {
890
			if ($mes_notes)
891
				$mes_notes .= "\n\n";
892
			$mes_notes .= $appel . $note_texte;
893
		}
894
 
895
		// dans le texte, mettre l'appel de note a la place de la note
896
		$pos = strpos($letexte, $note_source);
897
		$letexte = substr($letexte, 0, $pos) . $insert
898
			. substr($letexte, $pos + strlen($note_source));
899
	}
900
 
901
	//
902
	// Raccourcis automatiques [?SPIP] vers un glossaire
903
	// (on traite ce raccourci en deux temps afin de ne pas appliquer
904
	//  la typo sur les URLs, voir raccourcis liens ci-dessous)
905
	//
906
	if ($url_glossaire_externe) {
907
		$regexp = "|\[\?+([^][<>]+)\]|";
908
		if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER))
909
		foreach ($matches as $regs) {
910
			$terme = trim($regs[1]);
911
			$terme_underscore = urlencode(preg_replace(',\s+,', '_', $terme));
912
			if (strstr($url_glossaire_externe,"%s"))
913
				$url = str_replace("%s", $terme_underscore, $url_glossaire_externe);
914
			else
915
				$url = $url_glossaire_externe.$terme_underscore;
916
			$url = str_replace("@lang@", $GLOBALS['spip_lang'], $url);
917
			$code = '['.$terme.'->?'.$url.']';
918
			$letexte = str_replace($regs[0], $code, $letexte);
919
		}
920
	}
921
 
922
 
923
	//
924
	// Raccourcis liens [xxx->url] (cf. fonction extraire_lien ci-dessus)
925
	// Note : complique car c'est ici qu'on applique la typo() !
926
	//
927
	$regexp = "|\[([^][]*)->(>?)([^]]*)\]|ms";
928
	$inserts = array();
929
	if (preg_match_all($regexp, $letexte, $matches, PREG_SET_ORDER)) {
930
		$i = 0;
931
		foreach ($matches as $regs) {
932
			list($insert) = extraire_lien($regs);
933
			$inserts[++$i] = $insert;
934
			$letexte = str_replace($regs[0], "@@SPIP_ECHAPPE$i@@", $letexte);
935
		}
936
	}
937
	$letexte = typo($letexte);
938
	foreach ($inserts as $i => $insert) {
939
		$letexte = str_replace("@@SPIP_ECHAPPE$i@@", $insert, $letexte);
940
	}
941
 
942
	//
943
	// Tableaux
944
	//
945
	$letexte = preg_replace(",^\n?[|],", "\n\n|", $letexte);
946
	$letexte = preg_replace(",\n\n+[|],", "\n\n\n\n|", $letexte);
947
	$letexte = preg_replace(",[|](\n\n+|\n?$),", "|\n\n\n\n", $letexte);
948
	if (preg_match_all(',\n\n[|].*[|]\n\n,Ums', $letexte,
949
	$regs, PREG_SET_ORDER))
950
	foreach ($regs as $tab) {
951
		$letexte = str_replace($tab[0], traiter_tableau($tab[0]), $letexte);
952
	}
953
 
954
	//
955
	// Ensemble de remplacements implementant le systeme de mise
956
	// en forme (paragraphes, raccourcis...)
957
	//
958
 
959
	$letexte = "\n".trim($letexte);
960
 
961
	// les listes
962
	if (ereg("\n-[*#]", $letexte))
963
		$letexte = traiter_listes($letexte);
964
 
965
	// autres raccourcis
966
	$cherche1 = array(
967
		/* 0 */ 	"/\n(----+|____+)/",
968
		/* 1 */ 	"/\n-- */",
969
		/* 2 */ 	"/\n- */",
970
		/* 3 */ 	"/\n_ +/",
971
		/* 4 */ 	"/[{][{][{]/",
972
		/* 5 */ 	"/[}][}][}]/",
973
		/* 6 */ 	"/(( *)\n){2,}(<br[[:space:]]*\/?".">)?/",
974
		/* 7 */ 	"/[{][{]/",
975
		/* 8 */ 	"/[}][}]/",
976
		/* 9 */ 	"/[{]/",
977
		/* 10 */	"/[}]/",
978
		/* 11 */	"/(<br[[:space:]]*\/?".">){2,}/",
979
		/* 12 */	"/<p>([\n]*)(<br[[:space:]]*\/?".">)+/",
980
		/* 13 */	"/<p>/",
981
		/* 14 		"/\n/", */
982
		/* 15 */	"/<quote>/",
983
		/* 16 */	"/<\/quote>/"
984
	);
985
	$remplace1 = array(
986
		/* 0 */ 	"\n\n@@SPIP_ligne_horizontale@@\n\n",
987
		/* 1 */ 	"\n<br />&mdash;&nbsp;",
988
		/* 2 */ 	"\n<br />$puce&nbsp;",
989
		/* 3 */ 	"\n<br />",
990
		/* 4 */ 	"\n\n@@SPIP_debut_intertitre@@",
991
		/* 5 */ 	"@@SPIP_fin_intertitre@@\n\n",
992
		/* 6 */ 	"<p>",
993
		/* 7 */ 	"<strong class=\"spip\">",
994
		/* 8 */ 	"</strong>",
995
		/* 9 */ 	"<i class=\"spip\">",
996
		/* 10 */	"</i>",
997
		/* 11 */	"<p class=\"spip\">",
998
		/* 12 */	"<p class=\"spip\">",
999
		/* 13 */	"<p class=\"spip\">",
1000
		/* 14 		" ", */
1001
		/* 15 */	"\n\n<blockquote class=\"spip\"><p class=\"spip\">",
1002
		/* 16 */	"</p></blockquote>\n\n"
1003
	);
1004
	$letexte = preg_replace($cherche1, $remplace1, $letexte);
1005
	$letexte = preg_replace("@^ <br />@", "", $letexte);
1006
 
1007
	// paragrapher
1008
	if (strpos(' '.$letexte, '<p class="spip">')) # ce test est destine a disparaitre, avec un impact sur les textes a un seul paragraphe
1009
	{
1010
		$letexte = '<p class="spip">'.str_replace('<p class="spip">', "</p>\n".'<p class="spip">', $letexte).'</p>';
1011
	}
1012
	$letexte = preg_replace(',(<p class="spip">)?\s*(<center>)?\s*</no p>,ims', '\2', $letexte);
1013
	$letexte = preg_replace(',<no p>\s*(</center>)?\s*(</p>)?,ims', '\1', $letexte);
1014
 
1015
	// intertitres / hr / blockquote / table / ul compliants
1016
	$letexte = preg_replace(',(<p class="spip">)?[[:space:]]*@@SPIP_debut_intertitre@@,ms', $debut_intertitre, $letexte);
1017
	$letexte = preg_replace(',@@SPIP_fin_intertitre@@[[:space:]]*(</p>)?,ms', $fin_intertitre, $letexte);
1018
	$letexte = preg_replace(',(<p class="spip">)?[[:space:]]*@@SPIP_ligne_horizontale@@[[:space:]]*(</p>)?,ms', $ligne_horizontale, $letexte);
1019
	$letexte = preg_replace(',(<p class="spip">)?[[:space:]]*<blockquote class=\"spip\"></p>,ms', "\n<blockquote class=\"spip\">", $letexte);
1020
	$letexte = preg_replace(',</blockquote>[[:space:]]*(</p>)?,ms', "</blockquote>\n", $letexte);
1021
	$letexte = preg_replace(',(<p class="spip">)?[[:space:]]*<table([>[:space:]]),ms', "\n<table\\2", $letexte);
1022
	$letexte = preg_replace(',</table>[[:space:]]*(</p>)?,ms', "</table>\n", $letexte);
1023
	$letexte = preg_replace(',(<p class="spip">)?[[:space:]]*<ul([>[:space:]]),ms', "<ul\\2", $letexte);
1024
	$letexte = preg_replace(',</ul>[[:space:]]*(</p>)?,ms', '</ul>', $letexte);
1025
	$letexte = preg_replace(',<p class="spip">[[:space:]]*</p>,ms', "\n", $letexte);
1026
 
1027
	// Appeler la fonction de post-traitement
1028
	$letexte = spip_apres_propre ($letexte);
1029
 
1030
	return array($letexte,$mes_notes);
1031
}
1032
 
1033
function traiter_les_notes($mes_notes, $les_echap) {
1034
	list($mes_notes,) = traiter_raccourcis_generale($mes_notes);
1035
	if (ereg('<p class="spip">',$mes_notes))
1036
		$mes_notes = str_replace('<p class="spip">', '<p class="spip_note">', $mes_notes);
1037
	else
1038
		$mes_notes = '<p class="spip_note">'.$mes_notes."</p>\n";
1039
	$mes_notes = echappe_retour($mes_notes, $les_echap, "SOURCEPROPRE");
1040
	$GLOBALS['les_notes'] .= interdire_scripts($mes_notes);
1041
}
1042
 
1043
function traiter_raccourcis($letexte, $les_echap=false) {
1044
	// echapper les <a href>, <html>...< /html>, <code>...< /code>
1045
 
1046
	if (!$les_echap)
1047
		list($letexte, $les_echap) = echappe_html($letexte, "SOURCEPROPRE");
1048
	list($letexte, $mes_notes) = traiter_raccourcis_generale($letexte);
1049
	if ($mes_notes) traiter_les_notes($mes_notes, $les_echap);
1050
	// Reinserer les echappements
1051
	return trim(echappe_retour($letexte, $les_echap, "SOURCEPROPRE"));
1052
}
1053
 
1054
function traiter_raccourcis_doublon(&$doublons, $letexte) {
1055
	// echapper les <a href>, <html>...< /html>, <code>...< /code>
1056
	list($letexte, $les_echap) = echappe_html($letexte, "SOURCEPROPRE");
1057
	list($letexte, $mes_notes) = traiter_raccourcis_generale($letexte);
1058
	if ($mes_notes) traiter_les_notes($mes_notes, $les_echap);
1059
	// Reinserer les echappements
1060
	return trim(echappe_retour_doublon($letexte, $les_echap, "SOURCEPROPRE", $doublons));
1061
}
1062
 
1063
 
1064
// Filtre a appliquer aux champs du type #TEXTE*
1065
function propre($letexte, $echap=false) {
1066
	return interdire_scripts(traiter_raccourcis(trim($letexte), $echap));
1067
}
1068
 
1069
?>