Mise en route du suivi.
[aidenligne_francais_universite.git] / ecrire / public / composer.php
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/meta');
16 include_spip("inc/indexation");
17 include_spip('inc/texte');
18 include_spip('inc/documents');
19 include_spip('inc/forum');
20 include_spip('inc/distant');
21 include_spip('inc/rubriques'); # pour calcul_branche (cf critere branche)
22 include_spip('public/debug'); # toujours prevoir le pire
23
24 # Charge et retourne un composeur, i.e. la fonction principale d'un squelette
25 # ou '' s'il est inconnu. Le compile au besoin
26 # Charge egalement un fichier homonyme de celui du squelette
27 # mais de suffixe '_fonctions.php' pouvant contenir:
28 # 1. des filtres
29 # 2. des fonctions de traduction de balise, de critere et de boucle
30 # 3. des declaration de tables SQL supplementaires
31 # Toutefois pour 2. et 3. preferer la technique de la surcharge
32
33 // http://doc.spip.org/@public_composer_dist
34 function public_composer_dist($squelette, $mime_type, $gram, $sourcefile) {
35
36 $nom = $mime_type . '_' . md5($squelette);
37
38 // si squelette est deja en memoire (INCLURE a repetition)
39 if (function_exists($nom))
40 return $nom;
41
42 $phpfile = sous_repertoire(_DIR_SKELS) . $nom . '.php';
43
44 // si squelette est deja compile et perenne, le charger
45 if (!squelette_obsolete($phpfile, $sourcefile)
46 AND lire_fichier ($phpfile, $contenu,
47 array('critique' => 'oui', 'phpcheck' => 'oui')))
48 eval('?'.'>'.$contenu);
49
50 if (@file_exists($fonc = $squelette . '_fonctions'.'.php')
51 OR @file_exists($fonc = $squelette . '_fonctions'.'.php3')) {
52 include_once $fonc;
53 }
54
55 // tester si le eval ci-dessus a mis le squelette en memoire
56
57 if (function_exists($nom)) return $nom;
58
59 // charger le source, si possible, et compiler
60 if (lire_fichier ($sourcefile, $skel)) {
61 $compiler = charger_fonction('compiler', 'public');
62 $skel_code = $compiler($skel, $nom, $gram, $sourcefile);
63 }
64
65 // Tester si le compilateur renvoie une erreur
66 if (is_array($skel_code))
67 erreur_squelette($skel_code[0], $skel_code[1]);
68 else {
69 if ($GLOBALS['var_mode'] == 'debug') {
70 debug_dumpfile ($skel_code, $nom, 'code');
71 }
72 eval('?'.'>'.$skel_code);
73 if (function_exists($nom)) {
74 ecrire_fichier ($phpfile, $skel_code);
75 return $nom;
76 } else {
77 erreur_squelette(_T('zbug_erreur_compilation'), $sourcefile);
78 }
79 }
80 }
81
82 // Le squelette compile est-il trop vieux ?
83 // http://doc.spip.org/@squelette_obsolete
84 function squelette_obsolete($skel, $squelette) {
85 return (
86 ($GLOBALS['var_mode'] AND $GLOBALS['var_mode']<>'calcul')
87 OR !@file_exists($skel)
88 OR ((@file_exists($squelette)?@filemtime($squelette):0)
89 > ($date = @filemtime($skel)))
90 OR (
91 (@file_exists($fonc = 'mes_fonctions.php')
92 OR @file_exists($fonc = 'mes_fonctions.php3'))
93 AND @filemtime($fonc) > $date) # compatibilite
94 OR (defined('_FILE_OPTIONS') AND @filemtime(_FILE_OPTIONS) > $date)
95 );
96 }
97
98 //
99 // Des fonctions diverses utilisees lors du calcul d'une page ; ces fonctions
100 // bien pratiques n'ont guere de logique organisationnelle ; elles sont
101 // appelees par certaines balises au moment du calcul des pages. (Peut-on
102 // trouver un modele de donnees qui les associe physiquement au fichier
103 // definissant leur balise ???
104 //
105
106 // Pour les documents comme pour les logos, le filtre |fichier donne
107 // le chemin du fichier apres 'IMG/' ; peut-etre pas d'une purete
108 // remarquable, mais a conserver pour compatibilite ascendante.
109 // -> http://www.spip.net/fr_article901.html
110
111
112 // Renvoie le code html pour afficher un logo, avec ou sans survol, lien, etc.
113
114 // http://doc.spip.org/@affiche_logos
115 function affiche_logos($logos, $lien, $align) {
116
117 list ($arton, $artoff) = $logos;
118
119 if (!$arton) return $artoff;
120
121 if ($taille = @getimagesize($arton)) {
122 $taille = " ".$taille[3];
123 }
124
125 if ($artoff)
126 $artoff = " onmouseover=\"this.src='$artoff'\" "
127 ."onmouseout=\"this.src='$arton'\"";
128
129 $milieu = "<img src=\"$arton\" alt=\"\""
130 . ($align ? " align=\"$align\"" : '')
131 . $taille
132 . $artoff
133 . ' class="spip_logos" />';
134
135 return (!$lien ? $milieu :
136 ('<a href="' .
137 quote_amp($lien) .
138 '">' .
139 $milieu .
140 '</a>'));
141 }
142
143 //
144 // Retrouver le logo d'un objet (et son survol)
145 //
146
147 // http://doc.spip.org/@calcule_logo
148 function calcule_logo($type, $onoff, $id, $id_rubrique, $flag_fichier) {
149 $chercher_logo = charger_fonction('chercher_logo', 'inc');
150 $nom = strtolower($onoff);
151
152 while (1) {
153 $on = $chercher_logo($id, $type, $nom);
154 if ($on) {
155 if ($flag_fichier)
156 return (array('', "$on[2].$on[3]"));
157 else {
158 $off = ($onoff != 'ON') ? '' :
159 $chercher_logo($id, $type, 'off');
160 return array ($on[0], ($off ? $off[0] : ''));
161 }
162 }
163 else if ($id_rubrique) {
164 $type = 'id_rubrique';
165 $id = $id_rubrique;
166 $id_rubrique = 0;
167 } else if ($id AND $type == 'id_rubrique')
168 $id = sql_parent($id);
169 else return array('','');
170 }
171 }
172
173 //
174 // fonction standard de calcul de la balise #INTRODUCTION
175 // on peut la surcharger en definissant dans mes_fonctions :
176 // function introduction($type,$texte,$chapo,$descriptif) {...}
177 //
178 // http://doc.spip.org/@calcul_introduction
179 function calcul_introduction ($type, $texte, $chapo='', $descriptif='') {
180 if (function_exists("introduction"))
181 return introduction ($type, $texte, $chapo, $descriptif);
182
183 switch ($type) {
184 case 'articles':
185 # si descriptif contient juste des espaces ca produit une intro vide,
186 # c'est une fonctionnalite, pas un bug
187 if ($descriptif)
188 return propre($descriptif);
189 else if (substr($chapo, 0, 1) == '=') // article virtuel
190 return '';
191 else
192 return PtoBR(propre(supprimer_tags(couper_intro($chapo."\n\n\n".$texte, 500))));
193 break;
194 case 'breves':
195 return PtoBR(propre(supprimer_tags(couper_intro($texte, 300))));
196 break;
197 case 'forums':
198 return PtoBR(propre(supprimer_tags(couper_intro($texte, 600))));
199 break;
200 case 'rubriques':
201 if ($descriptif)
202 return propre($descriptif);
203 else
204 return PtoBR(propre(supprimer_tags(couper_intro($texte, 600))));
205 break;
206 }
207 }
208
209
210 //
211 // Balises dynamiques
212 //
213
214 // elles sont traitees comme des inclusions
215 // http://doc.spip.org/@synthetiser_balise_dynamique
216 function synthetiser_balise_dynamique($nom, $args, $file, $lang, $ligne) {
217 return
218 ('<'.'?php
219 include_spip(\'inc/lang\');
220 lang_select("'.$lang.'");
221 include_once(_DIR_RACINE . "'
222 . $file
223 . '");
224 inclure_balise_dynamique(balise_'
225 . $nom
226 . '_dyn('
227 . join(", ", array_map('argumenter_squelette', $args))
228 . "),1, $ligne);
229 lang_dselect();
230 ?"
231 .">");
232 }
233 // http://doc.spip.org/@argumenter_squelette
234 function argumenter_squelette($v) {
235
236 if (!is_array($v))
237 return "'" . texte_script($v) . "'";
238 else return 'array(' . join(", ", array_map('argumenter_squelette', $v)) . ')';
239 }
240
241 // verifier leurs arguments et filtres, et calculer le code a inclure
242 // http://doc.spip.org/@executer_balise_dynamique
243 function executer_balise_dynamique($nom, $args, $filtres, $lang, $ligne) {
244 if (!$file = include_spip('balise/' . strtolower($nom)))
245 die ("pas de balise dynamique pour #". strtolower($nom)." !");
246
247 // Y a-t-il une fonction de traitement filtres-arguments ?
248 $f = 'balise_' . $nom . '_stat';
249 if (function_exists($f))
250 $r = $f($args, $filtres);
251 else
252 $r = $args;
253 if (!is_array($r))
254 return $r;
255 else {
256 if (!_DIR_RESTREINT)
257 $file = _DIR_RESTREINT_ABS . $file;
258 return synthetiser_balise_dynamique($nom, $r, $file, $lang, $ligne);
259 }
260 }
261
262
263 //
264 // FONCTIONS FAISANT DES APPELS SQL
265 //
266
267 # NB : a l'exception des fonctions pour les balises dynamiques
268
269 // http://doc.spip.org/@calculer_hierarchie
270 function calculer_hierarchie($id_rubrique, $exclure_feuille = false) {
271
272 if (!$id_rubrique = intval($id_rubrique))
273 return '0';
274
275 $hierarchie = array();
276
277 if (!$exclure_feuille)
278 $hierarchie[] = $id_rubrique;
279
280 while ($id_rubrique = sql_parent($id_rubrique))
281 array_unshift($hierarchie, $id_rubrique);
282
283 if (count($hierarchie))
284 return join(',', $hierarchie);
285 else
286 return '0';
287 }
288
289
290 // http://doc.spip.org/@calcul_exposer
291 function calcul_exposer ($id, $type, $reference) {
292 static $exposer;
293 static $ref_precedente;
294
295 // Que faut-il exposer ? Tous les elements de $reference
296 // ainsi que leur hierarchie ; on ne fait donc ce calcul
297 // qu'une fois (par squelette) et on conserve le resultat
298 // en static.
299 if ($reference<>$ref_precedente) {
300 $ref_precedente = $reference;
301
302 $exposer = array();
303 foreach ($reference as $element=>$id_element) {
304 if ($element == 'id_secteur') $element = 'id_rubrique';
305 if ($x = table_from_primary($element)) {
306 list($table,$hierarchie) = $x;
307 $exposer[$element][$id_element] = true;
308 if ($hierarchie) {
309 $row = spip_abstract_fetsel(array('id_rubrique'), array($table), array("$element="._q($id_element)));
310 $hierarchie = calculer_hierarchie($row['id_rubrique']);
311 foreach (split(',',$hierarchie) as $id_rubrique)
312 $exposer['id_rubrique'][$id_rubrique] = true;
313 }
314 }
315 }
316 }
317
318 // And the winner is...
319 return isset($exposer[$type]) ? isset($exposer[$type][$id]) : '';
320 }
321
322 // http://doc.spip.org/@lister_objets_avec_logos
323 function lister_objets_avec_logos ($type) {
324 $type_logos = array(
325 'hierarchie' => 'rub',
326 'rubriques' => 'rub',
327 'articles' => 'art',
328 'breves' => 'breve',
329 'mots' => 'mot',
330 'sites' => 'site',
331 'auteurs' => 'aut'
332 );
333
334 $logos = array();
335 if ($type = $type_logos[$type]) {
336 $a = preg_files(_DIR_IMG.$type.'on[0-9]+\.(gif|png|jpg)$');
337 foreach ($a as $f)
338 $logos[] = intval(substr($f, strlen(_DIR_IMG.$type.'on')));
339 }
340
341 return join(',',$logos);
342 }
343
344 // http://doc.spip.org/@table_from_primary
345 function table_from_primary($id) {
346 global $tables_principales;
347 include_spip('base/serial');
348 foreach ($tables_principales as $k => $v) {
349 if ($v['key']['PRIMARY KEY'] == $id)
350 return array($k, array_key_exists('id_rubrique', $v['field']));
351 }
352 return '';
353 }
354
355 // fonction appelee par la balise #LOGO_DOCUMENT
356 // http://doc.spip.org/@calcule_logo_document
357 function calcule_logo_document($id_document, $doubdoc, &$doublons, $flag_fichier, $lien, $align, $params) {
358
359 if (!$id_document) return '';
360 if ($doubdoc) $doublons["documents"] .= ','.$id_document;
361
362 if (!($row = spip_abstract_select(array('id_type', 'id_vignette', 'fichier', 'mode'), array('spip_documents'), array("id_document = $id_document"))))
363 // pas de document. Ne devrait pas arriver
364 return '';
365
366 $row = spip_abstract_fetch($row);
367 $id_type = $row['id_type'];
368 $id_vignette = $row['id_vignette'];
369 $fichier = $row['fichier'];
370 $mode = $row['mode'];
371
372 // Y a t il une vignette personnalisee ?
373 if ($id_vignette) {
374 if ($res = spip_abstract_select(array('fichier'),
375 array('spip_documents'),
376 array("id_document = $id_vignette"))) {
377 $vignette = spip_abstract_fetch($res);
378 if (@file_exists(_DIR_RACINE.$vignette['fichier']))
379 $logo = generer_url_document($id_vignette);
380 }
381 } else if ($mode == 'vignette') {
382 $logo = generer_url_document($id_document);
383 if (!@file_exists($logo))
384 $logo = '';
385 }
386
387 // taille maximum [(#LOGO_DOCUMENT{300,52})]
388 if ($params
389 AND preg_match('/{\s*(\d+),\s*(\d+)\s*}/', $params, $r)) {
390 $x = intval($r[1]);
391 $y = intval($r[2]);
392 }
393
394 // Retrouver l'extension et le type mime
395 $ex = spip_abstract_fetch(spip_abstract_select(
396 array('extension', 'mime_type'),
397 array('spip_types_documents'),
398 array("id_type = " . intval($id_type))));
399 $extension = $ex['extension'];
400 $mime = $ex['mime_type'];
401 if (!$extension) $extension = 'txt';
402 if (($logo) AND (@file_exists($logo) OR (strpos($logo,'?')!==FALSE))) {
403 if ($x OR $y)
404 $logo = reduire_image($logo, $x, $y);
405 else {
406 $size = @getimagesize($logo);
407 $logo = "<img src='$logo' ".$size[3]." />";
408 }
409 }
410 else {
411 // Pas de vignette, mais un fichier image -- creer la vignette
412 if (strpos($GLOBALS['meta']['formats_graphiques'], $extension)!==false) {
413 if ($img = _DIR_RACINE.copie_locale($fichier)
414 AND @file_exists($img)) {
415 if (!$x AND !$y) {
416 $logo = reduire_image($img);
417 } else {
418 # eviter une double reduction
419 $size = @getimagesize($img);
420 $logo = "<img src='$img' ".$size[3]." />";
421 }
422 }
423 }
424
425 // Document sans vignette ni image : vignette par defaut
426 if (!$logo) {
427 $img = vignette_par_defaut($extension, false);
428 $size = @getimagesize($img);
429 $logo = "<img src='$img' ".$size[3]." />";
430 }
431 }
432
433 // Reduire si une taille precise est demandee
434 if ($x OR $y)
435 $logo = reduire_image($logo, $x, $y);
436
437 // flag_fichier : seul le fichier est demande
438 if ($flag_fichier)
439 return preg_replace(',^' . preg_quote(_DIR_IMG).',', '',
440 extraire_attribut($logo, 'src'));
441
442
443 // Calculer le code html complet (cf. calcule_logo)
444 $logo = inserer_attribut($logo, 'alt', '');
445 $logo = inserer_attribut($logo, 'class', 'spip_logos');
446 if ($align)
447 $logo = inserer_attribut($logo, 'align', $align);
448
449 if ($lien)
450 $logo = "<a href='$lien' type='$mime'>$logo</a>";
451
452 return $logo;
453 }
454
455
456 // les balises dynamiques et EMBED ont des filtres sans arguments
457 // car en fait ce sont des arguments pas des filtres.
458 // Si le besoin s'en fait sentir, il faudra recuperer la 2e moitie du tableau
459
460 // http://doc.spip.org/@argumenter_balise
461 function argumenter_balise($fonctions, $sep) {
462 $res = array();
463 if ($fonctions)
464 foreach ($fonctions as $f)
465 $res[] = str_replace('\'', '\\\'', str_replace('\\', '\\\\',$f[0]));
466 return ("'" . join($sep, $res) . "'");
467 }
468
469 // fonction appelee par la balise #NOTES
470 // http://doc.spip.org/@calculer_notes
471 function calculer_notes() {
472 $r = $GLOBALS["les_notes"];
473 $GLOBALS["les_notes"] = "";
474 $GLOBALS["compt_note"] = 0;
475 $GLOBALS["marqueur_notes"] ++;
476 return $r;
477 }
478
479 // Renvoie le titre du "lien hypertexte"
480 // http://doc.spip.org/@construire_titre_lien
481 function construire_titre_lien($nom,$url) {
482 return typo(supprimer_numero(calculer_url($url, $nom, 'titre')));
483 }
484
485 // Ajouter "&lang=..." si la langue de base n'est pas celle du site
486 // http://doc.spip.org/@lang_parametres_forum
487 function lang_parametres_forum($s) {
488 // ne pas se fatiguer si le site est unilingue (plus rapide)
489 if (strstr($GLOBALS['meta']['langues_utilisees'], ',')
490 // chercher l'identifiant qui nous donnera la langue
491 AND preg_match(',(id_(article|breve|rubrique|syndic)=([0-9]+)),', $s, $r)){
492 $lang = spip_abstract_fetsel(array('lang'),
493 array("spip_" . $r[2] .'s'),
494 array($r[1]));
495
496 // Si ce n'est pas la meme que celle du site, l'ajouter aux parametres
497 if ($lang['lang'] AND $lang['lang'] <> $GLOBALS['meta']['langue_site'])
498 return "$s&lang=" . $lang['lang'];
499 }
500
501 return $s;
502 }
503
504 // La fonction presente dans les squelettes compiles
505
506 // http://doc.spip.org/@spip_optim_select
507 function spip_optim_select ($select = array(), $from = array(),
508 $where = array(), $join=array(),
509 $groupby = '', $orderby = array(), $limit = '',
510 $sousrequete = '', $having = array(),
511 $table = '', $id = '', $serveur='') {
512
513 // retirer les criteres vides:
514 // {X ?} avec X absent de l'URL
515 // {par #ENV{X}} avec X absent de l'URL
516 // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
517
518 $menage = false;
519 foreach($where as $k => $v) {
520 if ((!$v) OR ($v==1) OR ($v=='0=0')) {
521 unset($where[$k]);
522 $menage = true;
523 }
524 }
525
526 foreach($having as $k => $v) {
527 if ((!$v) OR ($v==1) OR ($v=='0=0')) {
528 unset($having[$k]);
529 }
530 }
531
532 // Installer les jointures.
533 // Retirer celles seulement utiles aux criteres finalement absents mais
534 // parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
535 // si elle est seulement utile a Ln+1 elle meme inutile
536
537 for($k = count($join); $k > 0; $k--) {
538 list($t,$c) = $join[$k];
539 $cle = "L$k";
540 if (!$menage
541 OR spip_optim_joint($cle, $select)
542 OR spip_optim_joint($cle, $join)
543 OR spip_optim_joint($cle, $where))
544 $where[]= "$t.$c=$cle.$c";
545 else { unset($from[$cle]); unset($join[$k]);}
546 }
547
548 return spip_abstract_select($select, $from, $where,
549 $groupby, array_filter($orderby), $limit,
550 $sousrequete, $having,
551 $table, $id, $serveur);
552
553 }
554
555 //condition suffisante (mais non necessaire) pour qu'une jointure soit inutile
556
557 // http://doc.spip.org/@spip_optim_joint
558 function spip_optim_joint($cle, $exp)
559 {
560 if (!is_array($exp))
561 return (strpos($exp, "$cle.") === false) ? false : true;
562 else {
563 foreach($exp as $v) {
564 if (spip_optim_joint($cle, $v)) return true;
565 }
566 return false;
567 }
568 }
569 ?>