lien.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2014 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. include_spip('base/abstract_sql');
  13. //
  14. // Production de la balise A+href a partir des raccourcis [xxx->url] etc.
  15. // Note : complique car c'est ici qu'on applique typo(),
  16. // et en plus on veut pouvoir les passer en pipeline
  17. //
  18. function inc_lien_dist($lien, $texte='', $class='', $title='', $hlang='', $rel='', $connect='', $env=array()) {
  19. static $u=null;
  20. if (!$u) $u=url_de_base();
  21. $typo = false;
  22. // Si une langue est demandee sur un raccourci d'article, chercher
  23. // la traduction ;
  24. // - [{en}->art2] => traduction anglaise de l'article 2, sinon art 2
  25. // - [{}->art2] => traduction en langue courante de l'art 2, sinon art 2
  26. // s'applique a tout objet traduit
  27. if ($hlang
  28. AND $match = typer_raccourci($lien)) {
  29. @list($type,,$id,,$args,,$ancre) = $match;
  30. $trouver_table = charger_fonction('trouver_table', 'base');
  31. $desc = $trouver_table(table_objet($type, $connect),$connect);
  32. if ($desc
  33. AND $id_table_objet = $desc['key']['PRIMARY KEY']) {
  34. $table_objet_sql = $desc['table'];
  35. if ($row=sql_fetsel('*', $table_objet_sql, "$id_table_objet=".intval($id))
  36. AND isset($row['id_trad'])
  37. AND isset($row['lang'])
  38. AND $id_dest = sql_getfetsel($id_table_objet, $table_objet_sql,"id_trad=".intval($row['id_trad'])." AND lang=" . sql_quote($hlang))
  39. AND objet_test_si_publie($type,$id_dest)
  40. )
  41. $lien = "$type$id_dest";
  42. else
  43. $hlang = '';
  44. }
  45. else
  46. $hlang = '';
  47. }
  48. $mode = ($texte AND $class) ? 'url' : 'tout';
  49. $lien = calculer_url($lien, $texte, $mode, $connect);
  50. if ($mode === 'tout') {
  51. $texte = $lien['titre'];
  52. if (!$class AND isset($lien['class'])) $class = $lien['class'];
  53. $lang = isset($lien['lang']) ?$lien['lang'] : '';
  54. $mime = isset($lien['mime']) ? " type='".$lien['mime']."'" : "";
  55. $lien = $lien['url'];
  56. }
  57. $lien = trim($lien);
  58. if (strncmp($lien,"#",1) == 0) # ancres pures (internes a la page)
  59. $class = 'spip_ancre';
  60. elseif (strncasecmp($lien,'mailto:',7)==0) # pseudo URL de mail
  61. $class = "spip_mail";
  62. elseif (strncmp($texte,'<html>',6)==0) # cf traiter_lien_explicite
  63. $class = "spip_url spip_out";
  64. elseif (!$class) $class = "spip_out"; # si pas spip_in|spip_glossaire
  65. // Si l'objet n'est pas de la langue courante, on ajoute hreflang
  66. if (!$hlang AND $lang!==$GLOBALS['spip_lang'])
  67. $hlang = $lang;
  68. $lang = ($hlang ? " hreflang='$hlang'" : '');
  69. if ($title)
  70. $title = ' title="'.attribut_html($title).'"';
  71. else
  72. $title = ''; // $title peut etre 'false'
  73. // rel=external pour les liens externes
  74. if ((strncmp($lien,'http://',7)==0 OR strncmp($lien,'https://',8)==0)
  75. AND strncmp("$lien/", $u ,strlen($u))!=0)
  76. $rel = trim("$rel external");
  77. if ($rel) $rel = " rel='$rel'";
  78. // si pas de modele dans le texte du lien, on peut juste passer typo sur le texte, c'est plus rapide
  79. // les rares cas de lien qui encapsule un modele passe en dessous, c'est plus lent
  80. if (traiter_modeles($texte, false, '', $connect, null, $env)==$texte){
  81. $texte = typo($texte, true, $connect, $env);
  82. $lien = "<a href=\"".str_replace('"', '&quot;', $lien)."\" class='$class'$lang$title$rel".(isset($mime)?$mime:'').">$texte</a>";
  83. return $lien;
  84. }
  85. # ceci s'execute heureusement avant les tableaux et leur "|".
  86. # Attention, le texte initial est deja echappe mais pas forcement
  87. # celui retourne par calculer_url.
  88. # Penser au cas [<imgXX|right>->URL], qui exige typo('<a>...</a>')
  89. $lien = "<a href=\"".str_replace('"', '&quot;', $lien)."\" class='$class'$lang$title$rel$mime>$texte</a>";
  90. $res = typo($lien, true, $connect, $env);
  91. // dans ce cas, echapons le resultat du modele pour que propre etc ne viennent pas pouicher le html
  92. $res = echappe_html("<html>$res</html>");
  93. return $res;
  94. }
  95. // Regexp des raccourcis, aussi utilisee pour la fusion de sauvegarde Spip
  96. // Laisser passer des paires de crochets pour la balise multi
  97. // mais refuser plus d'imbrications ou de mauvaises imbrications
  98. // sinon les crochets ne peuvent plus servir qu'a ce type de raccourci
  99. define('_RACCOURCI_LIEN', "/\[([^][]*?([[][^]>-]*[]][^][]*)*)->(>?)([^]]*)\]/msS");
  100. // http://code.spip.net/@expanser_liens
  101. function expanser_liens($t, $connect='', $env=array())
  102. {
  103. $t = pipeline('pre_liens', $t);
  104. expanser_un_lien($connect,'init', $env);
  105. if (strpos($t, '->') !== false)
  106. $t = preg_replace_callback (_RACCOURCI_LIEN, 'expanser_un_lien',$t);
  107. // on passe a traiter_modeles la liste des liens reperes pour lui permettre
  108. // de remettre le texte d'origine dans les parametres du modele
  109. $t = traiter_modeles($t, false, false, $connect, expanser_un_lien('','sources'), $env);
  110. $t = corriger_typo($t);
  111. $t = expanser_un_lien($t,'reinsert');
  112. return $t;
  113. }
  114. function expanser_un_lien($reg, $quoi='echappe', $env=null){
  115. static $pile = array();
  116. static $inserts;
  117. static $sources;
  118. static $regs;
  119. static $k = 0;
  120. static $lien;
  121. static $connect='';
  122. static $contexte = array();
  123. switch ($quoi){
  124. case 'init':
  125. if (!$lien) $lien = charger_fonction('lien', 'inc');
  126. if (!is_null($env))
  127. $contexte = $env;
  128. array_push($pile,array($inserts,$sources,$regs,$connect,$k));
  129. $inserts = $sources = $regs = array();
  130. $connect = $reg; // stocker le $connect pour les appels a inc_lien_dist
  131. $k=0;
  132. return;
  133. break;
  134. case 'echappe':
  135. $inserts[$k] = '@@SPIP_ECHAPPE_LIEN_' . $k . '@@';
  136. $sources[$k] = $reg[0];
  137. #$titre=$reg[1];
  138. list($titre, $bulle, $hlang) = traiter_raccourci_lien_atts($reg[1]);
  139. $r = end($reg);
  140. // la mise en lien automatique est passee par la a tort !
  141. // corrigeons pour eviter d'avoir un <a...> dans un href...
  142. if (strncmp($r,'<a',2)==0){
  143. $href = extraire_attribut($r, 'href');
  144. // remplacons dans la source qui peut etre reinjectee dans les arguments
  145. // d'un modele
  146. $sources[$k] = str_replace($r,$href,$sources[$k]);
  147. // et prenons le href comme la vraie url a linker
  148. $r = $href;
  149. }
  150. $regs[$k] = $lien($r, $titre, '', $bulle, $hlang, '', $connect, $contexte);
  151. return $inserts[$k++];
  152. break;
  153. case 'reinsert':
  154. if (count($inserts))
  155. $reg = str_replace($inserts, $regs, $reg);
  156. list($inserts,$sources,$regs,$connect,$k) = array_pop($pile);
  157. return $reg;
  158. break;
  159. case 'sources':
  160. return array($inserts, $sources);
  161. break;
  162. }
  163. }
  164. // Meme analyse mais pour eliminer les liens
  165. // et ne laisser que leur titre, a expliciter si ce n'est fait
  166. // http://code.spip.net/@nettoyer_raccourcis_typo
  167. function nettoyer_raccourcis_typo($texte, $connect='')
  168. {
  169. $texte = pipeline('nettoyer_raccourcis_typo',$texte);
  170. if (preg_match_all(_RACCOURCI_LIEN, $texte, $regs, PREG_SET_ORDER))
  171. include_spip('inc/texte');
  172. foreach ($regs as $reg) {
  173. list ($titre,,)= traiter_raccourci_lien_atts($reg[1]);
  174. if (!$titre) {
  175. $match = typer_raccourci($reg[count($reg)-1]);
  176. @list($type,,$id,,,,) = $match;
  177. if ($type) {
  178. $url = generer_url_entite($id,$type,'','',true);
  179. if (is_array($url)) list($type, $id) = $url;
  180. $titre = traiter_raccourci_titre($id, $type, $connect);
  181. }
  182. $titre = $titre ? $titre['titre'] : $match[0];
  183. }
  184. $titre = corriger_typo(supprimer_tags($titre));
  185. $texte = str_replace($reg[0], $titre, $texte);
  186. }
  187. // supprimer les ancres
  188. $texte = preg_replace(_RACCOURCI_ANCRE,"",$texte);
  189. // supprimer les notes
  190. $texte = preg_replace(",[[][[]([^]]|[]][^]])*[]][]],UimsS","",$texte);
  191. // supprimer les codes typos
  192. $texte = str_replace(array('}','{'), '', $texte);
  193. // supprimer les tableaux
  194. $texte = preg_replace(",(^|\r)\|.*\|\r,s", "\r", $texte);
  195. return $texte;
  196. }
  197. // Repere dans la partie texte d'un raccourci [texte->...]
  198. // la langue et la bulle eventuelles : [texte|title{lang}->...]
  199. // accepte un niveau de paire de crochets dans le texte :
  200. // [texte[]|title{lang}->...]
  201. // mais refuse
  202. // [texte[|title{lang}->...]
  203. // pour ne pas confondre avec un autre raccourci
  204. define('_RACCOURCI_ATTRIBUTS', '/^((?:[^[]*?(?:\[[^]]*\])?)*?)([|]([^<>]*?))?([{]([a-z_]*)[}])?$/');
  205. // http://code.spip.net/@traiter_raccourci_lien_atts
  206. function traiter_raccourci_lien_atts($texte) {
  207. $bulle = $hlang = false;
  208. // title et hreflang donnes par le raccourci ?
  209. if (strpbrk($texte, "|{") !== false AND
  210. preg_match(_RACCOURCI_ATTRIBUTS, $texte, $m)) {
  211. $n =count($m);
  212. // |infobulle ?
  213. if ($n > 2) {
  214. $bulle = $m[3];
  215. // {hreflang} ?
  216. if ($n > 4) {
  217. // si c'est un code de langue connu, on met un hreflang
  218. if (traduire_nom_langue($m[5]) <> $m[5]) {
  219. $hlang = $m[5];
  220. } elseif (!$m[5]) {
  221. $hlang = test_espace_prive() ?
  222. $GLOBALS['lang_objet'] : $GLOBALS['spip_lang'];
  223. // sinon c'est un italique
  224. } else {
  225. $m[1] .= $m[4];
  226. }
  227. // S'il n'y a pas de hreflang sous la forme {}, ce qui suit le |
  228. // est peut-etre une langue
  229. } else if (preg_match('/^[a-z_]+$/', $m[3])) {
  230. // si c'est un code de langue connu, on met un hreflang
  231. // mais on laisse le title (c'est arbitraire tout ca...)
  232. if (traduire_nom_langue($m[3]) <> $m[3]) {
  233. $hlang = $m[3];
  234. }
  235. }
  236. }
  237. $texte = $m[1];
  238. }
  239. return array(trim($texte), $bulle, $hlang);
  240. }
  241. define('_EXTRAIRE_DOMAINE', '/^(?:(?:[^\W_]((?:[^\W_]|-){0,61}[^\W_,])?\.)+[a-z0-9]{2,6}|localhost)\b/Si');
  242. define('_RACCOURCI_CHAPO', '/^(\W*)(\W*)(\w*\d+([?#].*)?)$/');
  243. /**
  244. * Fonction pour les champs virtuels de redirection qui peut etre:
  245. * 1. un raccourci Spip habituel (premier If) [texte->TYPEnnn]
  246. * 2. un ultra raccourci TYPEnnn voire nnn (article) (deuxieme If)
  247. * 3. une URL std
  248. *
  249. * renvoie l'url reelle de redirection si le $url=true,
  250. * l'url brute contenue dans le chapo sinon
  251. *
  252. * http://code.spip.net/@chapo_redirige
  253. *
  254. * @param string $virtuel
  255. * @param bool $url
  256. * @return string
  257. */
  258. function virtuel_redirige($virtuel, $url=false){
  259. if (!strlen($virtuel)) return '';
  260. if (!preg_match(_RACCOURCI_LIEN, $virtuel, $m))
  261. if (!preg_match(_RACCOURCI_CHAPO, $virtuel, $m))
  262. return $virtuel;
  263. return !$url ? $m[3] : traiter_lien_implicite($m[3]);
  264. }
  265. // Cherche un lien du type [->raccourci 123]
  266. // associe a une fonction generer_url_raccourci() definie explicitement
  267. // ou implicitement par le jeu de type_urls courant.
  268. //
  269. // Valeur retournee selon le parametre $pour:
  270. // 'tout' : tableau d'index url,class,titre,lang (vise <a href="U" class='C' hreflang='L'>T</a>)
  271. // 'titre': seulement T ci-dessus (i.e. le TITRE ci-dessus ou dans table SQL)
  272. // 'url': seulement U (i.e. generer_url_RACCOURCI)
  273. // http://code.spip.net/@calculer_url
  274. function calculer_url ($ref, $texte='', $pour='url', $connect='', $echappe_typo = true) {
  275. $r = traiter_lien_implicite($ref, $texte, $pour, $connect, $echappe_typo);
  276. $r = ($r ? $r : traiter_lien_explicite($ref, $texte, $pour, $connect, $echappe_typo));
  277. return $r;
  278. }
  279. define('_EXTRAIRE_LIEN', ",^\s*(http:?/?/?|mailto:?)\s*$,iS");
  280. // http://code.spip.net/@traiter_lien_explicite
  281. function traiter_lien_explicite ($ref, $texte='', $pour='url', $connect='', $echappe_typo = true)
  282. {
  283. if (preg_match(_EXTRAIRE_LIEN, $ref))
  284. return ($pour != 'tout') ? '' : array('','','','');
  285. $lien = entites_html(trim($ref));
  286. // Liens explicites
  287. if (!$texte) {
  288. $texte = str_replace('"', '', $lien);
  289. static $lien_court;
  290. // evite l'affichage de trop longues urls.
  291. if (!$lien_court)
  292. $lien_court = charger_fonction('lien_court', 'inc');
  293. $texte = $lien_court($texte);
  294. if ($echappe_typo){
  295. $texte = "<html>".quote_amp($texte)."</html>";
  296. }
  297. }
  298. // petites corrections d'URL
  299. if (preg_match('/^www\.[^@]+$/S',$lien))
  300. $lien = "http://".$lien;
  301. else if (strpos($lien, "@") && email_valide($lien)) {
  302. if (!$texte) $texte = $lien;
  303. $lien = "mailto:".$lien;
  304. }
  305. if ($pour == 'url') return $lien;
  306. if ($pour == 'titre') return $texte;
  307. return array('url' => $lien, 'titre' => $texte);
  308. }
  309. function liens_implicite_glose_dist($texte,$id,$type,$args,$ancre,$connect=''){
  310. if ( ($ancre AND function_exists($f = 'glossaire_' . $ancre))
  311. OR function_exists($f = 'glossaire_'))
  312. $url = $f($texte, $id, $ancre);
  313. else
  314. $url = glossaire_std($texte);
  315. return $url;
  316. }
  317. /**
  318. * Transformer un lien raccourci art23 en son URL
  319. * Par defaut la fonction produit une url prive si on est dans le prive
  320. * ou publique si on est dans le public.
  321. * La globale lien_implicite_cible_public permet de forcer un cas ou l'autre :
  322. * $GLOBALS['lien_implicite_cible_public'] = true;
  323. * => tous les liens raccourcis pointent vers le public
  324. * $GLOBALS['lien_implicite_cible_public'] = false;
  325. * => tous les liens raccourcis pointent vers le prive
  326. * unset($GLOBALS['lien_implicite_cible_public']);
  327. * => retablit le comportement automatique
  328. *
  329. * http://code.spip.net/@traiter_lien_implicite
  330. *
  331. * @param string $ref
  332. * @param string $texte
  333. * @param string $pour
  334. * @param string $connect
  335. * @return array|bool|string
  336. */
  337. function traiter_lien_implicite ($ref, $texte='', $pour='url', $connect='')
  338. {
  339. $cible = ($connect ? $connect : (isset($GLOBALS['lien_implicite_cible_public'])?$GLOBALS['lien_implicite_cible_public']:null));
  340. if (!($match = typer_raccourci($ref))) return false;
  341. @list($type,,$id,,$args,,$ancre) = $match;
  342. # attention dans le cas des sites le lien doit pointer non pas sur
  343. # la page locale du site, mais directement sur le site lui-meme
  344. $url = '';
  345. if ($f = charger_fonction("implicite_$type","liens",true))
  346. $url = $f($texte,$id,$type,$args,$ancre,$connect);
  347. if (!$url)
  348. $url = generer_url_entite($id,$type,$args,$ancre,$cible);
  349. if (!$url) return false;
  350. if (is_array($url)) {
  351. @list($type,$id) = $url;
  352. $url = generer_url_entite($id,$type,$args,$ancre,$cible);
  353. }
  354. if ($pour === 'url') return $url;
  355. $r = traiter_raccourci_titre($id, $type, $connect);
  356. if ($r) $r['class'] = ($type == 'site')?'spip_out':'spip_in';
  357. if ($texte = trim($texte)) $r['titre'] = $texte;
  358. if (!@$r['titre']) $r['titre'] = _T($type) . " $id";
  359. if ($pour=='titre') return $r['titre'];
  360. $r['url'] = $url;
  361. // dans le cas d'un lien vers un doc, ajouter le type='mime/type'
  362. if ($type == 'document'
  363. AND $mime = sql_getfetsel('mime_type', 'spip_types_documents',
  364. "extension IN (".sql_get_select("extension","spip_documents","id_document=".sql_quote($id)).")",
  365. '','','','',$connect)
  366. )
  367. $r['mime'] = $mime;
  368. return $r;
  369. }
  370. // analyse des raccourcis issus de [TITRE->RACCOURCInnn] et connexes
  371. define('_RACCOURCI_URL', '/^\s*(\w*?)\s*(\d+)(\?(.*?))?(#([^\s]*))?\s*$/S');
  372. // http://code.spip.net/@typer_raccourci
  373. function typer_raccourci ($lien) {
  374. if (!preg_match(_RACCOURCI_URL, $lien, $match)) return array();
  375. $f = $match[1];
  376. // valeur par defaut et alias historiques
  377. if (!$f) $f = 'article';
  378. else if ($f == 'art') $f = 'article';
  379. else if ($f == 'br') $f = 'breve';
  380. else if ($f == 'rub') $f = 'rubrique';
  381. else if ($f == 'aut') $f = 'auteur';
  382. else if ($f == 'doc' OR $f == 'im' OR $f == 'img' OR $f == 'image' OR $f == 'emb')
  383. $f = 'document';
  384. else if (preg_match('/^br..?ve$/S', $f)) $f = 'breve'; # accents :(
  385. $match[0] = $f;
  386. return $match;
  387. }
  388. // Retourne le champ textuel associe a une cle primaire, et sa langue
  389. function traiter_raccourci_titre($id, $type, $connect=NULL)
  390. {
  391. $trouver_table = charger_fonction('trouver_table', 'base');
  392. $desc = $trouver_table(table_objet($type));
  393. if (!($desc AND $s = $desc['titre'])) return array();
  394. $_id = $desc['key']['PRIMARY KEY'];
  395. $r = sql_fetsel($s, $desc['table'], "$_id=$id", '','','','',$connect);
  396. if (!$r) return array();
  397. $r['titre'] = supprimer_numero($r['titre']);
  398. if (!$r['titre']) $r['titre'] = $r['surnom'];
  399. if (!isset($r['lang'])) $r['lang'] = '';
  400. return $r;
  401. }
  402. // traite les modeles (dans la fonction typo), en remplacant
  403. // le raccourci <modeleN|parametres> par la page calculee a
  404. // partir du squelette modeles/modele.html
  405. // Le nom du modele doit faire au moins trois caracteres (evite <h2>)
  406. // Si $doublons==true, on repere les documents sans calculer les modeles
  407. // mais on renvoie les params (pour l'indexation par le moteur de recherche)
  408. // http://code.spip.net/@traiter_modeles
  409. define('_PREG_MODELE',
  410. '(<([a-z_-]{3,})' # <modele
  411. .'\s*([0-9]*)\s*' # id
  412. .'([|](?:<[^<>]*>|[^>])*?)?' # |arguments (y compris des tags <...>)
  413. .'\s*/?'.'>)' # fin du modele >
  414. );
  415. define('_RACCOURCI_MODELE',
  416. _PREG_MODELE
  417. .'\s*(<\/a>)?' # eventuel </a>
  418. );
  419. define('_RACCOURCI_MODELE_DEBUT', '@^' . _RACCOURCI_MODELE .'@isS');
  420. // http://code.spip.net/@traiter_modeles
  421. function traiter_modeles($texte, $doublons=false, $echap='', $connect='', $liens = null, $env = array()) {
  422. // preserver la compatibilite : true = recherche des documents
  423. if ($doublons===true)
  424. $doublons = array('documents'=>array('doc','emb','img'));
  425. // detecter les modeles (rapide)
  426. if (strpos($texte,"<")!==false AND
  427. preg_match_all('/<[a-z_-]{3,}\s*[0-9|]+/iS', $texte, $matches, PREG_SET_ORDER)) {
  428. include_spip('public/assembler');
  429. $wrap_embed_html = charger_fonction("wrap_embed_html","inc",true);
  430. foreach ($matches as $match) {
  431. // Recuperer l'appel complet (y compris un eventuel lien)
  432. $a = strpos($texte,$match[0]);
  433. preg_match(_RACCOURCI_MODELE_DEBUT,
  434. substr($texte, $a), $regs);
  435. while(count($regs) < 6) $regs[] = ""; // s'assurer qu'il y a toujours un 5e arg, eventuellement vide
  436. list(,$mod, $type, $id, $params, $fin) = $regs;
  437. if ($fin AND
  438. preg_match('/<a\s[^<>]*>\s*$/i',
  439. substr($texte, 0, $a), $r)) {
  440. $lien = array(
  441. 'href' => extraire_attribut($r[0],'href'),
  442. 'class' => extraire_attribut($r[0],'class'),
  443. 'mime' => extraire_attribut($r[0],'type')
  444. );
  445. $n = strlen($r[0]);
  446. $a -= $n;
  447. $cherche = $n + strlen($regs[0]);
  448. } else {
  449. $lien = false;
  450. $cherche = strlen($mod);
  451. }
  452. // calculer le modele
  453. # hack indexation
  454. if ($doublons)
  455. $texte .= preg_replace(',[|][^|=]*,s',' ',$params);
  456. # version normale
  457. else {
  458. // si un tableau de liens a ete passe, reinjecter le contenu d'origine
  459. // dans les parametres, plutot que les liens echappes
  460. if (!is_null($liens))
  461. $params = str_replace($liens[0], $liens[1], $params);
  462. $modele = inclure_modele($type, $id, $params, $lien, $connect, $env);
  463. // en cas d'echec,
  464. // si l'objet demande a une url,
  465. // creer un petit encadre vers elle
  466. if ($modele === false) {
  467. $modele = substr($texte,$a,$cherche);
  468. if (!is_null($liens))
  469. $modele = str_replace($liens[0], $liens[1], $modele);
  470. $contexte = array_merge($env,array('id'=>$id,'type'=>$type,'modele'=>$modele));
  471. if ($lien) {
  472. # un eventuel guillemet (") sera reechappe par #ENV
  473. $contexte['lien'] = str_replace("&quot;",'"', $lien['href']);
  474. $contexte['lien_class'] = $lien['class'];
  475. $contexte['lien_mime'] = $lien['mime'];
  476. }
  477. $modele = recuperer_fond("modeles/dist", $contexte, array(), $connect);
  478. }
  479. // le remplacer dans le texte
  480. if ($modele !== false) {
  481. $modele = protege_js_modeles($modele);
  482. if ($wrap_embed_html){
  483. $modele = $wrap_embed_html($mod,$modele);
  484. }
  485. $rempl = code_echappement($modele, $echap);
  486. $texte = substr($texte, 0, $a)
  487. . $rempl
  488. . substr($texte, $a+$cherche);
  489. }
  490. }
  491. // hack pour tout l'espace prive
  492. if (((!_DIR_RESTREINT) OR ($doublons)) AND ($id)){
  493. foreach($doublons?$doublons:array('documents'=>array('doc','emb','img')) as $quoi=>$modeles)
  494. if (in_array($type,$modeles))
  495. $GLOBALS["doublons_{$quoi}_inclus"][] = $id;
  496. }
  497. }
  498. }
  499. return $texte;
  500. }
  501. //
  502. // Raccourcis ancre [#ancre<-]
  503. //
  504. define('_RACCOURCI_ANCRE', "/\[#?([^][]*)<-\]/S");
  505. // http://code.spip.net/@traiter_raccourci_ancre
  506. function traiter_raccourci_ancre($letexte)
  507. {
  508. if (preg_match_all(_RACCOURCI_ANCRE, $letexte, $m, PREG_SET_ORDER))
  509. foreach ($m as $regs)
  510. $letexte = str_replace($regs[0],
  511. '<a name="'.entites_html($regs[1]).'"></a>', $letexte);
  512. return $letexte;
  513. }
  514. //
  515. // Raccourcis automatiques [?SPIP] vers un glossaire
  516. // Wikipedia par defaut, avec ses contraintes techniques
  517. // cf. http://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Conventions_sur_les_titres
  518. define('_RACCOURCI_GLOSSAIRE', "/\[\?+\s*([^][<>]+)\]/S");
  519. define('_RACCOURCI_GLOSES', '/^([^|#{]*\w[^|#{]*)([^#]*)(#([^|{}]*))?(.*)$/S');
  520. // http://code.spip.net/@traiter_raccourci_glossaire
  521. function traiter_raccourci_glossaire($texte)
  522. {
  523. if (!preg_match_all(_RACCOURCI_GLOSSAIRE,
  524. $texte, $matches, PREG_SET_ORDER))
  525. return $texte;
  526. include_spip('inc/charsets');
  527. $lien = charger_fonction('lien', 'inc');
  528. foreach ($matches as $regs) {
  529. // Eviter les cas particulier genre "[?!?]"
  530. // et isoler le lexeme a gloser de ses accessoires
  531. // (#:url du glossaire, | bulle d'aide, {} hreflang)
  532. // Transformation en pseudo-raccourci pour passer dans inc_lien
  533. if (preg_match(_RACCOURCI_GLOSES, $regs[1], $r)) {
  534. preg_match('/^(.*?)(\d*)$/', $r[4], $m);
  535. $_n = intval($m[2]);
  536. $gloss = $m[1] ? ('#' . $m[1]) : '';
  537. $t = $r[1] . $r[2] . $r[5];
  538. list($t, $bulle, $hlang) = traiter_raccourci_lien_atts($t);
  539. if ($bulle===false) $bulle = $m[1];
  540. $t = unicode2charset(charset2unicode($t), 'utf-8');
  541. $ref = $lien("glose$_n$gloss", $t, 'spip_glossaire', $bulle, $hlang);
  542. $texte = str_replace($regs[0], $ref, $texte);
  543. }
  544. }
  545. return $texte;
  546. }
  547. // http://code.spip.net/@glossaire_std
  548. function glossaire_std($terme)
  549. {
  550. global $url_glossaire_externe;
  551. static $pcre = NULL;
  552. if ($pcre === NULL) {
  553. $pcre = isset($GLOBALS['meta']['pcre_u'])
  554. ? $GLOBALS['meta']['pcre_u']
  555. : '';
  556. if (strpos($url_glossaire_externe, "%s") === false)
  557. $url_glossaire_externe .= '%s';
  558. }
  559. $glosateur = str_replace("@lang@",
  560. $GLOBALS['spip_lang'],
  561. $GLOBALS['url_glossaire_externe']);
  562. $terme = rawurlencode(preg_replace(',\s+,'.$pcre, '_', $terme));
  563. return str_replace("%s", $terme, $glosateur);
  564. }
  565. ?>