[SPIP] v3.2.1-->v3.2.2
[lhc/web/www.git] / www / ecrire / inc / lien.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2019 *
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')) {
14 return;
15 }
16
17 include_spip('base/abstract_sql');
18
19 //
20 // Production de la balise A+href a partir des raccourcis [xxx->url] etc.
21 // Note : complique car c'est ici qu'on applique typo(),
22 // et en plus on veut pouvoir les passer en pipeline
23 //
24
25 function inc_lien_dist(
26 $lien,
27 $texte = '',
28 $class = '',
29 $title = '',
30 $hlang = '',
31 $rel = '',
32 $connect = '',
33 $env = array()
34 ) {
35 return $lien;
36 }
37
38 // Regexp des raccourcis, aussi utilisee pour la fusion de sauvegarde Spip
39 // Laisser passer des paires de crochets pour la balise multi
40 // mais refuser plus d'imbrications ou de mauvaises imbrications
41 // sinon les crochets ne peuvent plus servir qu'a ce type de raccourci
42 define('_RACCOURCI_LIEN', "/\[([^][]*?([[]\w*[]][^][]*)*)->(>?)([^]]*)\]/msS");
43
44 // http://code.spip.net/@expanser_liens
45 function expanser_liens($t, $connect = '', $env = array()) {
46
47 $t = pipeline('pre_liens', $t);
48
49 // on passe a traiter_modeles la liste des liens reperes pour lui permettre
50 // de remettre le texte d'origine dans les parametres du modele
51 $t = traiter_modeles($t, false, false, $connect);
52
53 return $t;
54 }
55
56 // Meme analyse mais pour eliminer les liens
57 // et ne laisser que leur titre, a expliciter si ce n'est fait
58 // http://code.spip.net/@nettoyer_raccourcis_typo
59 function nettoyer_raccourcis_typo($texte, $connect = '') {
60 return $texte;
61 }
62
63 // Repere dans la partie texte d'un raccourci [texte->...]
64 // la langue et la bulle eventuelles
65 // http://code.spip.net/@traiter_raccourci_lien_atts
66 function traiter_raccourci_lien_atts($texte) {
67 $bulle = '';
68 $hlang = '';
69
70 return array(trim($texte), $bulle, $hlang);
71 }
72
73 define('_RACCOURCI_CHAPO', '/^(\W*)(\W*)(\w*\d+([?#].*)?)$/');
74 /**
75 * Retourne la valeur d'un champ de redirection (articles virtuels)
76 *
77 * @note
78 * Pas d'action dans le noyau SPIP directement.
79 * Se réferer inc/lien du plugin Textwheel.
80 *
81 * @param string $virtuel
82 * @param bool $url
83 * @return string
84 */
85 function virtuel_redirige($virtuel, $url = false) {
86 return $virtuel;
87 }
88
89 // Cherche un lien du type [->raccourci 123]
90 // associe a une fonction generer_url_raccourci() definie explicitement
91 // ou implicitement par le jeu de type_urls courant.
92 //
93 // Valeur retournee selon le parametre $pour:
94 // 'tout' : tableau d'index url,class,titre,lang (vise <a href="U" class='C' hreflang='L'>T</a>)
95 // 'titre': seulement T ci-dessus (i.e. le TITRE ci-dessus ou dans table SQL)
96 // 'url': seulement U (i.e. generer_url_RACCOURCI)
97
98 // http://code.spip.net/@calculer_url
99 function calculer_url($ref, $texte = '', $pour = 'url', $connect = '', $echappe_typo = true) {
100 $r = traiter_lien_implicite($ref, $texte, $pour, $connect, $echappe_typo);
101
102 return $r ? $r : traiter_lien_explicite($ref, $texte, $pour, $connect, $echappe_typo);
103 }
104
105 define('_EXTRAIRE_LIEN', ',^\s*(?:' . _PROTOCOLES_STD . '):?/?/?\s*$,iS');
106
107 // http://code.spip.net/@traiter_lien_explicite
108 function traiter_lien_explicite($ref, $texte = '', $pour = 'url', $connect = '', $echappe_typo = true) {
109 if (preg_match(_EXTRAIRE_LIEN, $ref)) {
110 return ($pour != 'tout') ? '' : array('', '', '', '');
111 }
112
113 $lien = entites_html(trim($ref));
114
115 // Liens explicites
116 if (!$texte) {
117 $texte = str_replace('"', '', $lien);
118 // evite l'affichage de trops longues urls.
119 $lien_court = charger_fonction('lien_court', 'inc');
120 $texte = $lien_court($texte);
121 if ($echappe_typo) {
122 $texte = "<html>" . quote_amp($texte) . "</html>";
123 }
124 }
125
126 // petites corrections d'URL
127 if (preg_match('/^www\.[^@]+$/S', $lien)) {
128 $lien = "http://" . $lien;
129 } else {
130 if (strpos($lien, "@") && email_valide($lien)) {
131 if (!$texte) {
132 $texte = $lien;
133 }
134 $lien = "mailto:" . $lien;
135 }
136 }
137
138 if ($pour == 'url') {
139 return $lien;
140 }
141
142 if ($pour == 'titre') {
143 return $texte;
144 }
145
146 return array('url' => $lien, 'titre' => $texte);
147 }
148
149 function liens_implicite_glose_dist($texte, $id, $type, $args, $ancre, $connect = '') {
150 if (function_exists($f = 'glossaire_' . $ancre)) {
151 $url = $f($texte, $id);
152 } else {
153 $url = glossaire_std($texte);
154 }
155
156 return $url;
157 }
158
159 // http://code.spip.net/@traiter_lien_implicite
160 function traiter_lien_implicite($ref, $texte = '', $pour = 'url', $connect = '') {
161 if (!($match = typer_raccourci($ref))) {
162 return false;
163 }
164 @list($type, , $id, , $args, , $ancre) = $match;
165 // attention dans le cas des sites le lien doit pointer non pas sur
166 // la page locale du site, mais directement sur le site lui-meme
167 if ($f = charger_fonction("implicite_$type", "liens", true)) {
168 $url = $f($texte, $id, $type, $args, $ancre, $connect);
169 }
170 if (!$url) {
171 $url = generer_url_entite($id, $type, $args, $ancre, $connect ? $connect : null);
172 }
173 if (!$url) {
174 return false;
175 }
176 if (is_array($url)) {
177 @list($type, $id) = $url;
178 $url = generer_url_entite($id, $type, $args, $ancre, $connect ? $connect : null);
179 }
180 if ($pour === 'url') {
181 return $url;
182 }
183 $r = traiter_raccourci_titre($id, $type, $connect);
184 if ($r) {
185 $r['class'] = ($type == 'site') ? 'spip_out' : 'spip_in';
186 }
187 if ($texte = trim($texte)) {
188 $r['titre'] = $texte;
189 }
190 if (!@$r['titre']) {
191 $r['titre'] = _T($type) . " $id";
192 }
193 if ($pour == 'titre') {
194 return $r['titre'];
195 }
196 $r['url'] = $url;
197
198 // dans le cas d'un lien vers un doc, ajouter le type='mime/type'
199 if ($type == 'document'
200 and $mime = sql_getfetsel('mime_type', 'spip_types_documents',
201 "extension IN (" . sql_get_select("extension", "spip_documents", "id_document=" . sql_quote($id)) . ")",
202 '', '', '', '', $connect)
203 ) {
204 $r['mime'] = $mime;
205 }
206
207 return $r;
208 }
209
210 // analyse des raccourcis issus de [TITRE->RACCOURCInnn] et connexes
211
212 define('_RACCOURCI_URL', '/^\s*(\w*?)\s*(\d+)(\?(.*?))?(#([^\s]*))?\s*$/S');
213
214 // http://code.spip.net/@typer_raccourci
215 function typer_raccourci($lien) {
216 if (!preg_match(_RACCOURCI_URL, $lien, $match)) {
217 return array();
218 }
219 $f = $match[1];
220 // valeur par defaut et alias historiques
221 if (!$f) {
222 $f = 'article';
223 } else {
224 if ($f == 'art') {
225 $f = 'article';
226 } else {
227 if ($f == 'br') {
228 $f = 'breve';
229 } else {
230 if ($f == 'rub') {
231 $f = 'rubrique';
232 } else {
233 if ($f == 'aut') {
234 $f = 'auteur';
235 } else {
236 if ($f == 'doc' or $f == 'im' or $f == 'img' or $f == 'image' or $f == 'emb') {
237 $f = 'document';
238 } else {
239 if (preg_match('/^br..?ve$/S', $f)) {
240 $f = 'breve';
241 }
242 }
243 }
244 }
245 }
246 }
247 } # accents :(
248 $match[0] = $f;
249
250 return $match;
251 }
252
253 /**
254 * Retourne le titre et la langue d'un objet éditorial
255 *
256 * @param int $id Identifiant de l'objet
257 * @param string $type Type d'objet
258 * @param string|null $connect Connecteur SQL utilisé
259 * @return array {
260 * @var string $titre Titre si présent, sinon ''
261 * @var string $lang Langue si présente, sinon ''
262 * }
263 **/
264 function traiter_raccourci_titre($id, $type, $connect = null) {
265 $trouver_table = charger_fonction('trouver_table', 'base');
266 $desc = $trouver_table(table_objet($type));
267 if (!($desc and $s = $desc['titre'])) {
268 return array();
269 }
270 $_id = $desc['key']['PRIMARY KEY'];
271 $r = sql_fetsel($s, $desc['table'], "$_id=$id", '', '', '', '', $connect);
272 if (!$r) {
273 return array();
274 }
275 $r['titre'] = supprimer_numero($r['titre']);
276 if (!$r['titre'] and !empty($r['surnom'])) {
277 $r['titre'] = $r['surnom'];
278 }
279 if (!isset($r['lang'])) {
280 $r['lang'] = '';
281 }
282
283 return $r;
284 }
285
286 // traite les modeles (dans la fonction typo), en remplacant
287 // le raccourci <modeleN|parametres> par la page calculee a
288 // partir du squelette modeles/modele.html
289 // Le nom du modele doit faire au moins trois caracteres (evite <h2>)
290 // Si $doublons==true, on repere les documents sans calculer les modeles
291 // mais on renvoie les params (pour l'indexation par le moteur de recherche)
292 // http://code.spip.net/@traiter_modeles
293
294 define('_RACCOURCI_MODELE',
295 '(<([a-z_-]{3,})' # <modele
296 . '\s*([0-9]*)\s*' # id
297 . '([|](?:<[^<>]*>|[^>])*?)?' # |arguments (y compris des tags <...>)
298 . '\s*/?' . '>)' # fin du modele >
299 . '\s*(<\/a>)?' # eventuel </a>
300 );
301
302 define('_RACCOURCI_MODELE_DEBUT', '@^' . _RACCOURCI_MODELE . '@isS');
303
304 // http://code.spip.net/@traiter_modeles
305 function traiter_modeles($texte, $doublons = false, $echap = '', $connect = '', $liens = null, $env = array()) {
306 // preserver la compatibilite : true = recherche des documents
307 if ($doublons === true) {
308 $doublons = array('documents' => array('doc', 'emb', 'img'));
309 }
310 // detecter les modeles (rapide)
311 if (strpos($texte, "<") !== false and
312 preg_match_all('/<[a-z_-]{3,}\s*[0-9|]+/iS', $texte, $matches, PREG_SET_ORDER)
313 ) {
314 include_spip('public/assembler');
315 $wrap_embed_html = charger_fonction("wrap_embed_html", "inc", true);
316 foreach ($matches as $match) {
317 // Recuperer l'appel complet (y compris un eventuel lien)
318
319 $a = strpos($texte, $match[0]);
320 preg_match(_RACCOURCI_MODELE_DEBUT,
321 substr($texte, $a), $regs);
322 $regs[] = ""; // s'assurer qu'il y a toujours un 5e arg, eventuellement vide
323 list(, $mod, $type, $id, $params, $fin) = $regs;
324 if ($fin and
325 preg_match('/<a\s[^<>]*>\s*$/i',
326 substr($texte, 0, $a), $r)
327 ) {
328 $lien = array(
329 'href' => extraire_attribut($r[0], 'href'),
330 'class' => extraire_attribut($r[0], 'class'),
331 'mime' => extraire_attribut($r[0], 'type'),
332 'title' => extraire_attribut($r[0], 'title'),
333 'hreflang' => extraire_attribut($r[0], 'hreflang')
334 );
335 $n = strlen($r[0]);
336 $a -= $n;
337 $cherche = $n + strlen($regs[0]);
338 } else {
339 $lien = false;
340 $cherche = strlen($mod);
341 }
342
343 // calculer le modele
344 # hack indexation
345 if ($doublons) {
346 $texte .= preg_replace(',[|][^|=]*,s', ' ', $params);
347 } # version normale
348 else {
349 // si un tableau de liens a ete passe, reinjecter le contenu d'origine
350 // dans les parametres, plutot que les liens echappes
351 if (!is_null($liens)) {
352 $params = str_replace($liens[0], $liens[1], $params);
353 }
354 $modele = inclure_modele($type, $id, $params, $lien, $connect, $env);
355 // en cas d'echec,
356 // si l'objet demande a une url,
357 // creer un petit encadre vers elle
358 if ($modele === false) {
359 if (!$lien) {
360 $lien = traiter_lien_implicite("$type$id", '', 'tout', $connect);
361 }
362 if ($lien) {
363 $modele = '<a href="'
364 . $lien['url']
365 . '" class="spip_modele'
366 . '">'
367 . sinon($lien['titre'], _T('ecrire:info_sans_titre'))
368 . "</a>";
369 } else {
370 $modele = "";
371 if (test_espace_prive()) {
372 $modele = entites_html(substr($texte, $a, $cherche));
373 if (!is_null($liens)) {
374 $modele = "<pre>" . str_replace($liens[0], $liens[1], $modele) . "</pre>";
375 }
376 }
377 }
378 }
379 // le remplacer dans le texte
380 if ($modele !== false) {
381 $modele = protege_js_modeles($modele);
382 if ($wrap_embed_html) {
383 $modele = $wrap_embed_html($mod, $modele);
384 }
385 $rempl = code_echappement($modele, $echap);
386 $texte = substr($texte, 0, $a)
387 . $rempl
388 . substr($texte, $a + $cherche);
389 }
390 }
391
392 // hack pour tout l'espace prive
393 if (((!_DIR_RESTREINT) or ($doublons)) and ($id)) {
394 foreach ($doublons ? $doublons : array('documents' => array('doc', 'emb', 'img')) as $quoi => $modeles) {
395 if (in_array($type, $modeles)) {
396 $GLOBALS["doublons_{$quoi}_inclus"][] = $id;
397 }
398 }
399 }
400 }
401 }
402
403 return $texte;
404 }
405
406 //
407 // Raccourcis ancre [#ancre<-]
408 //
409 // http://code.spip.net/@traiter_raccourci_ancre
410 function traiter_raccourci_ancre($letexte) {
411 return $letexte;
412 }
413
414 // http://code.spip.net/@traiter_raccourci_glossaire
415 function traiter_raccourci_glossaire($texte) {
416 return $texte;
417 }
418
419 // http://code.spip.net/@glossaire_std
420 function glossaire_std($terme) {
421 return $terme;
422 }