[SPIP] +2.1.12
[velocampus/web/www.git] / www / ecrire / urls / propres.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2011 *
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 define('URLS_PROPRES_EXEMPLE', 'Titre-de-l-article -Rubrique-');
16
17 // TODO: une interface permettant de verifier qu'on veut effectivment modifier
18 // une adresse existante
19 define('CONFIRMER_MODIFIER_URL', false);
20
21 /*
22
23 - Comment utiliser ce jeu d'URLs ?
24
25 Recopiez le fichier "htaccess.txt" du repertoire de base du site SPIP sous
26 le sous le nom ".htaccess" (attention a ne pas ecraser d'autres reglages
27 que vous pourriez avoir mis dans ce fichier) ; si votre site est en
28 "sous-repertoire", vous devrez aussi editer la ligne "RewriteBase" ce fichier.
29 Les URLs definies seront alors redirigees vers les fichiers de SPIP.
30
31 Dans les pages de configuration, choisissez 'propres' comme type d'url
32
33 SPIP calculera alors ses liens sous la forme
34 "Mon-titre-d-article".
35
36 La variante 'propres2' ajoutera '.html' aux adresses generees :
37 "Mon-titre-d-article.html"
38
39 Variante 'qs' (experimentale) : ce systeme fonctionne en "Query-String",
40 c'est-a-dire sans utilisation de .htaccess ; les adresses sont de la forme
41 "/?Mon-titre-d-article"
42 */
43
44 define ('_terminaison_urls_propres', '');
45 define ('_debut_urls_propres', '');
46
47 // option pour tout passer en minuscules
48 define ('_url_minuscules',0);
49
50 // pour choisir le caractere de separation titre-id en cas de doublon
51 // (ne pas utiliser '/')
52 define ('_url_propres_sep_id',',');
53
54 // Ces chaines servaient de marqueurs a l'epoque ou les URL propres devaient
55 // indiquer la table ou les chercher (articles, auteurs etc),
56 // et elles etaient retirees par les preg_match dans la fonction ci-dessous.
57 // Elles peuvent a present etre definies a "" pour avoir des URL plus jolies.
58 // Les preg_match restent necessaires pour gerer les anciens signets.
59
60 define('_MARQUEUR_URL', serialize(array('rubrique1' => '-', 'rubrique2' => '-', 'breve1' => '+', 'breve2' => '+', 'site1' => '@', 'site2' => '@', 'auteur1' => '_', 'auteur2' => '_', 'mot1' => '+-', 'mot2' => '-+')));
61
62 // Retire les marqueurs de type dans une URL propre ancienne maniere
63
64 // http://doc.spip.org/@retirer_marqueurs_url_propre
65 function retirer_marqueurs_url_propre($url_propre) {
66 if (preg_match(',^[+][-](.*?)[-][+]$,', $url_propre, $regs)) {
67 return $regs[1];
68 }
69 else if (preg_match(',^([-+_@])(.*?)\1?$,', $url_propre, $regs)) {
70 return $regs[2];
71 }
72 // les articles n'ont pas de marqueur
73 return $url_propre;
74 }
75
76
77 // Pipeline pour creation d'une adresse : il recoit l'url propose par le
78 // precedent, un tableau indiquant le titre de l'objet, son type, son id,
79 // et doit donner en retour une chaine d'url, sans se soucier de la
80 // duplication eventuelle, qui sera geree apres
81 // http://doc.spip.org/@creer_chaine_url
82 function urls_propres_creer_chaine_url($x) {
83 // NB: ici url_old ne sert pas, mais un plugin qui ajouterait une date
84 // pourrait l'utiliser pour juste ajouter la
85 $url_old = $x['data'];
86 $objet = $x['objet'];
87 include_spip('inc/filtres');
88 if (!defined('_URLS_PROPRES_MAX')) define('_URLS_PROPRES_MAX', 35);
89 if (!defined('_URLS_PROPRES_MIN')) define('_URLS_PROPRES_MIN', 3);
90
91 include_spip('action/editer_url');
92 if (!$url = url_nettoyer($objet['titre'],_URLS_PROPRES_MAX,_URLS_PROPRES_MIN,'-',_url_minuscules?'strtolower':''))
93 $url = $objet['type'].$objet['id_objet'];
94
95 $x['data'] = $url;
96
97 return $x;
98 }
99
100 // Trouver l'URL associee a la n-ieme cle primaire d'une table SQL
101
102 // http://doc.spip.org/@declarer_url_propre
103 function declarer_url_propre($type, $id_objet) {
104 $trouver_table = charger_fonction('trouver_table', 'base');
105 $desc = $trouver_table(table_objet($type));
106 $champ_titre = $desc['titre'];
107 $col_id = @$desc['key']["PRIMARY KEY"];
108 // $type doit designer une table, avec champ indiquant un titre
109 if (!$col_id OR !$champ_titre) return false;
110
111 $table = $desc['table'];
112 $id_objet = intval($id_objet);
113
114 // Recuperer une URL propre correspondant a l'objet.
115 $row = sql_fetsel("U.url, U.date, O.$champ_titre", "$table AS O LEFT JOIN spip_urls AS U ON (U.type='$type' AND U.id_objet=O.$col_id)", "O.$col_id=$id_objet", '', 'U.date DESC', 1);
116
117 if (!$row) return ""; # Quand $id_objet n'est pas un numero connu
118
119 $url_propre = $row['url'];
120
121 // Se contenter de cette URL si elle existe ;
122 // sauf si on invoque par "voir en ligne" avec droit de modifier l'url
123
124 // l'autorisation est verifiee apres avoir calcule la nouvelle url propre
125 // car si elle ne change pas, cela ne sert a rien de verifier les autorisations
126 // qui requetent en base
127 $modifier_url = $GLOBALS['var_urls'];
128 if ($url_propre AND !$modifier_url)
129 return $url_propre;
130
131 // Sinon, creer une URL
132 $url = pipeline('propres_creer_chaine_url',
133 array(
134 'data' => $url_propre, // le vieux url_propre
135 'objet' => array_merge($row,
136 array('type' => $type, 'id_objet' => $id_objet)
137 )
138 )
139 );
140
141 // Eviter de tamponner les URLs a l'ancienne (cas d'un article
142 // intitule "auteur2")
143 include_spip('inc/urls');
144 $objets = urls_liste_objets();
145 if (preg_match(',^('.$objets.')[0-9]+$,', $url, $r)
146 AND $r[1] != $type)
147 $url = $url._url_propres_sep_id.$id_objet;
148
149 // Pas de changement d'url
150 if ($url == $url_propre)
151 return $url_propre;
152
153 // verifier l'autorisation, maintenant qu'on est sur qu'on va agir
154 if ($modifier_url) {
155 include_spip('inc/autoriser');
156 $modifier_url = autoriser('modifierurl', $type, $id_objet);
157 }
158
159 // Verifier si l'utilisateur veut effectivement changer l'URL
160 if ($modifier_url
161 AND CONFIRMER_MODIFIER_URL
162 AND $url_propre
163 AND $url != preg_replace('/,.*/', '', $url_propre))
164 $confirmer = true;
165 else
166 $confirmer = false;
167
168 if ($confirmer AND !_request('ok')) {
169 die ("vous changez d'url ? $url_propre -&gt; $url");
170 }
171
172 $set = array('url' => $url, 'type' => $type, 'id_objet' => $id_objet);
173 include_spip('action/editer_url');
174 if (!url_insert($set,$confirmer,_url_propres_sep_id))
175 return $url_propre; //serveur out ? retourner au mieux
176
177 return $set['url'];
178 }
179
180 // http://doc.spip.org/@_generer_url_propre
181 function _generer_url_propre($type, $id, $args='', $ancre='') {
182 if ($generer_url_externe = charger_fonction("generer_url_$type",'urls',true)) {
183 $url = $generer_url_externe($id, $args, $ancre);
184 if (NULL != $url) return $url;
185 }
186
187 if ($type == 'document') {
188 include_spip('inc/documents');
189 return generer_url_document_dist($id, $args, $ancre);
190 }
191
192 // Mode compatibilite pour conserver la distinction -Rubrique-
193 if (_MARQUEUR_URL) {
194 $marqueur = unserialize(_MARQUEUR_URL);
195 $marqueur1 = $marqueur[$type.'1']; // debut '+-'
196 $marqueur2 = $marqueur[$type.'2']; // fin '-+'
197 } else
198 $marqueur1 = $marqueur2 = '';
199 // fin
200
201 // Mode propre
202 $propre = declarer_url_propre($type, $id);
203
204 if ($propre === false) return ''; // objet inconnu. raccourci ?
205
206 if ($propre) {
207 $url = _debut_urls_propres
208 . $marqueur1
209 . $propre
210 . $marqueur2
211 . _terminaison_urls_propres;
212
213 // Repositionne l'URL par rapport a la racine du site (#GLOBALS)
214 $url = str_repeat('../', $GLOBALS['profondeur_url']).$url;
215 } else {
216
217 // objet connu mais sans possibilite d'URL lisible, revenir au defaut
218 include_spip('base/connect_sql');
219 $id_type = id_table_objet($type);
220 $url = _DIR_RACINE . get_spip_script('./')."?"._SPIP_PAGE."=$type&$id_type=$id";
221 }
222
223 // Ajouter les args
224 if ($args)
225 $url .= ((strpos($url, '?')===false) ? '?' : '&') . $args;
226
227 // Ajouter l'ancre
228 if ($ancre)
229 $url .= "#$ancre";
230
231 return $url;
232 }
233
234 // retrouve le fond et les parametres d'une URL propre
235 // ou produit une URL propre si on donne un parametre
236 // @return array([contexte],[type],[url_redirect],[fond]) : url decodee
237 // http://doc.spip.org/@urls_propres_dist
238 function urls_propres_dist($i, $entite, $args='', $ancre='') {
239
240 if (is_numeric($i))
241 return _generer_url_propre($entite, $i, $args, $ancre);
242
243 $url = $i;
244 $id_objet = $type = 0;
245 $url_redirect = null;
246 // recuperer les &debut_xx;
247 if (is_array($args))
248 $contexte = $args;
249 else
250 parse_str($args,$contexte);
251
252
253 // Migration depuis anciennes URLs ?
254 // traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23
255 if ($GLOBALS['profondeur_url']<=0
256 AND $_SERVER['REQUEST_METHOD'] != 'POST') {
257 include_spip('inc/urls');
258 $r = nettoyer_url_page($i, $contexte);
259 if ($r) {
260 list($contexte, $type,,, $suite) = $r;
261 $_id = id_table_objet($type);
262 $id_objet = $contexte[$_id];
263 $url_propre = generer_url_entite($id_objet, $type);
264 if (strlen($url_propre)
265 AND !strstr($url,$url_propre)) {
266 list(,$hash) = explode('#', $url_propre);
267 $args = array();
268 foreach(array_filter(explode('&', $suite)) as $fragment) {
269 if ($fragment != "$_id=$id_objet")
270 $args[] = $fragment;
271 }
272 $url_redirect = generer_url_entite($id_objet, $type, join('&',array_filter($args)), $hash);
273
274 return array($contexte, $type, $url_redirect, $type);
275 }
276 }
277 }
278 /* Fin compatibilite anciennes urls */
279 // Chercher les valeurs d'environnement qui indiquent l'url-propre
280 if (isset($_SERVER['REDIRECT_url_propre']))
281 $url_propre = $_SERVER['REDIRECT_url_propre'];
282 elseif (isset($_ENV['url_propre']))
283 $url_propre = $_ENV['url_propre'];
284 else {
285 // ne prendre que le segment d'url qui correspond, en fonction de la profondeur calculee
286 $url = ltrim($url,'/');
287 $url = explode('/',$url);
288 while (count($url)>$GLOBALS['profondeur_url']+1)
289 array_shift($url);
290 $url = implode('/',$url);
291 $url_propre = preg_replace(',[?].*,', '', $url);
292 }
293
294 // Mode Query-String ?
295 $is_qs = false;
296 if (!$url_propre
297 AND preg_match(',[?]([^=/?&]+)(&.*)?$,', $url, $r)) {
298 $url_propre = $r[1];
299 $is_qs = true;
300 }
301
302 if (!$url_propre) return; // qu'est-ce qu'il veut ???
303
304 // gerer le cas de retour depuis des urls arbos
305 // mais si url arbo ne trouve pas, on veut une 404 par securite
306 if ($GLOBALS['profondeur_url']>0){
307 $urls_anciennes = charger_fonction('arbo','urls');
308 return $urls_anciennes($url_propre, $entite, $contexte);
309 }
310
311 include_spip('base/abstract_sql'); // chercher dans la table des URLS
312
313 // Compatibilite avec propres2
314 $url_propre = preg_replace(',\.html$,i', '', $url_propre);
315
316 // Revenir en utf-8 si encodage type %D8%A7 (farsi)
317 $url_propre = rawurldecode($url_propre);
318
319 // Compatibilite avec les anciens marqueurs d'URL propres
320 // Tester l'entree telle quelle (avec 'url_libre' des sites ont pu avoir des entrees avec marqueurs dans la table spip_urls)
321 if (!$row = sql_fetsel('id_objet, type, date', 'spip_urls', 'url='.sql_quote($url_propre))) {
322 // Sinon enlever les marqueurs eventuels
323 $url_propre2 = retirer_marqueurs_url_propre($url_propre);
324
325 $row = sql_fetsel('id_objet, type, date', 'spip_urls', 'url='.sql_quote($url_propre2));
326 }
327
328 if ($row) {
329 $type = $row['type'];
330 $col_id = id_table_objet($type);
331 $contexte[$col_id] = $row['id_objet'];
332 $entite = $row['type'];
333
334 // Si l'url est vieux, donner le nouveau
335 if ($recent = sql_fetsel('url, date', 'spip_urls',
336 'type='.sql_quote($row['type']).' AND id_objet='.sql_quote($row['id_objet'])
337 .' AND date>'.sql_quote($row['date']), '', 'date DESC', 1)) {
338 // Mode compatibilite pour conserver la distinction -Rubrique-
339 if (_MARQUEUR_URL) {
340 $marqueur = unserialize(_MARQUEUR_URL);
341 $marqueur1 = $marqueur[$type.'1']; // debut '+-'
342 $marqueur2 = $marqueur[$type.'2']; // fin '-+'
343 } else
344 $marqueur1 = $marqueur2 = '';
345 $url_redirect = $marqueur1 . $recent['url'] . $marqueur2;
346 }
347 }
348
349 if ($entite=='' OR $entite=='type_urls' /* compat .htaccess 2.0 */) {
350 if ($type) {
351 $entite = ($type == 'syndic') ? 'site' : $type;
352 } else {
353 // Si ca ressemble a une URL d'objet, ce n'est pas la home
354 // et on provoque un 404
355 if (preg_match(',^.*/[^\.]+(\.html)?$,', $url)) {
356 $entite = '404';
357 $contexte['erreur'] = '';
358
359 // l'url n'existe pas...
360 // on ne sait plus dire de quel type d'objet il s'agit
361 // sauf si on a le marqueur. et la c'est un peu sale...
362 if (_MARQUEUR_URL) {
363 $fmarqueur = @array_flip(unserialize(_MARQUEUR_URL));
364 preg_match(',^([+][-]|[-+@_]),', $url_propre, $regs);
365 $objet = $regs ? substr($fmarqueur[$regs[1]],0,n-1) : 'article';
366 $contexte['erreur'] = _T(
367 ($objet=='rubrique' OR $objet=='breve')
368 ? 'public:aucune_'.$objet
369 : 'public:aucun_'.$objet
370 );
371 }
372 }
373 }
374 }
375
376 return array($contexte, $entite, $url_redirect, $is_qs?$entite:null);
377 }
378
379 ?>