source: spip-zone/_core_/plugins/urls_etendues/urls/propres.php @ 49318

Last change on this file since 49318 was 49318, checked in by cedric@…, 10 years ago

complement a r49317 : ne pas chercher a decoder l'url "spip.php" (form_hidden sur les urls action)

File size: 12.7 KB
Line 
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
13if (!defined("_ECRIRE_INC_VERSION")) return; // securiser
14
15define('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
19define('CONFIRMER_MODIFIER_URL', false);
20
21/*
22
23- Comment utiliser ce jeu d'URLs ?
24
25Recopiez le fichier "htaccess.txt" du repertoire de base du site SPIP sous
26le sous le nom ".htaccess" (attention a ne pas ecraser d'autres reglages
27que vous pourriez avoir mis dans ce fichier) ; si votre site est en
28"sous-repertoire", vous devrez aussi editer la ligne "RewriteBase" ce fichier.
29Les URLs definies seront alors redirigees vers les fichiers de SPIP.
30
31Dans les pages de configuration, choisissez 'propres' comme type d'url
32
33SPIP calculera alors ses liens sous la forme
34        "Mon-titre-d-article".
35
36La variante 'propres2' ajoutera '.html' aux adresses generees :
37        "Mon-titre-d-article.html"
38
39Variante 'qs' (experimentale) : ce systeme fonctionne en "Query-String",
40c'est-a-dire sans utilisation de .htaccess ; les adresses sont de la forme
41        "/?Mon-titre-d-article"
42*/
43
44define ('_terminaison_urls_propres', '');
45define ('_debut_urls_propres', '');
46
47// option pour tout passer en minuscules
48define ('_url_minuscules',0);
49
50// pour choisir le caractere de separation titre-id en cas de doublon
51// (ne pas utiliser '/')
52define ('_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
60define('_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
65function 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
82function 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        @define('_URLS_PROPRES_MAX', 35);
89        @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
103function declarer_url_propre($type, $id_objet) {
104        $trouver_table = charger_fonction('trouver_table', 'base');
105        $desc = $trouver_table(table_objet($type));
106        $table = $desc['table'];
107        $champ_titre = $desc['titre'] ? $desc['titre'] : 'titre';
108        $col_id =  @$desc['key']["PRIMARY KEY"];
109        if (!$col_id) return false; // Quand $type ne reference pas une table
110
111        $id_objet = intval($id_objet);
112
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        // si l'url propre contient un / alors c'est une arbo qu'il faut ignorer !
121        if (strpos($url_propre,"/")!==false)
122                $url_propre = null;
123
124        // Se contenter de cette URL si elle existe ;
125        // sauf si on invoque par "voir en ligne" avec droit de modifier l'url
126
127        // l'autorisation est verifiee apres avoir calcule la nouvelle url propre
128        // car si elle ne change pas, cela ne sert a rien de verifier les autorisations
129        // qui requetent en base
130        $modifier_url = (defined('_VAR_URLS') AND _VAR_URLS);
131        if ($url_propre AND !$modifier_url)
132                return $url_propre;
133
134        // Sinon, creer une URL
135        $url = pipeline('propres_creer_chaine_url',
136                array(
137                        'data' => $url_propre,  // le vieux url_propre
138                        'objet' => array_merge($row,
139                                array('type' => $type, 'id_objet' => $id_objet)
140                        )
141                )
142        );
143
144        // Eviter de tamponner les URLs a l'ancienne (cas d'un article
145        // intitule "auteur2")
146        include_spip('inc/urls');
147        $objets = urls_liste_objets();
148        if (preg_match(',^('.$objets.')[0-9]+$,', $url, $r)
149        AND $r[1] != $type)
150                $url = $url._url_propres_sep_id.$id_objet;
151
152        // Pas de changement d'url
153        if ($url == $url_propre)
154                return $url_propre;
155
156        // verifier l'autorisation, maintenant qu'on est sur qu'on va agir
157        if ($modifier_url) {
158                include_spip('inc/autoriser');
159                $modifier_url = autoriser('modifierurl', $type, $id_objet);
160        }
161
162        // Verifier si l'utilisateur veut effectivement changer l'URL
163        if ($modifier_url
164                AND CONFIRMER_MODIFIER_URL
165                AND $url_propre
166                AND $url != preg_replace('/,.*/', '', $url_propre))
167                $confirmer = true;
168        else
169                $confirmer = false;
170
171        if ($confirmer AND !_request('ok')) {
172                die ("vous changez d'url ? $url_propre -&gt; $url");
173        }
174
175        $set = array('url' => $url, 'type' => $type, 'id_objet' => $id_objet);
176        include_spip('action/editer_url');
177        if (!url_insert($set,$confirmer,_url_propres_sep_id))
178                return $url_propre; //serveur out ? retourner au mieux
179
180        return $set['url'];
181}
182
183// http://doc.spip.org/@_generer_url_propre
184function _generer_url_propre($type, $id, $args='', $ancre='') {
185
186        if ($generer_url_externe = charger_fonction("generer_url_$type",'urls',true)) {
187                $url = $generer_url_externe($id, $args, $ancre);
188                if (NULL != $url) return $url;
189        }
190
191        if ($type == 'document') {
192                include_spip('inc/documents');
193                return generer_url_document_dist($id, $args, $ancre);
194        }
195
196        // Mode compatibilite pour conserver la distinction -Rubrique-
197        if (_MARQUEUR_URL) {
198                $marqueur = unserialize(_MARQUEUR_URL);
199                $marqueur1 = $marqueur[$type.'1']; // debut '+-'
200                $marqueur2 = $marqueur[$type.'2']; // fin '-+'
201        } else
202                $marqueur1 = $marqueur2 = '';
203        // fin
204
205        // Mode propre
206        $propre = declarer_url_propre($type, $id);
207
208        if ($propre === false) return ''; // objet inconnu. raccourci ?
209
210        if ($propre) {
211                $url = _debut_urls_propres
212                        . $marqueur1
213                        . $propre
214                        . $marqueur2
215                        . _terminaison_urls_propres;
216
217                // Repositionne l'URL par rapport a la racine du site (#GLOBALS)
218                $url = str_repeat('../', $GLOBALS['profondeur_url']).$url;
219        } else {
220
221                // objet connu mais sans possibilite d'URL lisible, revenir au defaut
222                include_spip('base/connect_sql');
223                $id_type = id_table_objet($type);
224                $url = _DIR_RACINE . get_spip_script('./')."?"._SPIP_PAGE."=$type&$id_type=$id";
225        }
226
227        // Ajouter les args
228        if ($args)
229                $url .= ((strpos($url, '?')===false) ? '?' : '&') . $args;
230
231        // Ajouter l'ancre
232        if ($ancre)
233                $url .= "#$ancre";
234
235        return $url;
236}
237
238// retrouve le fond et les parametres d'une URL propre
239// ou produit une URL propre si on donne un parametre
240// @return array([contexte],[type],[url_redirect],[fond]) : url decodee
241// http://doc.spip.org/@urls_propres_dist
242function urls_propres_dist($i, $entite, $args='', $ancre='') {
243
244        if (is_numeric($i))
245                return _generer_url_propre($entite, $i, $args, $ancre);
246
247        $url = $i;
248        $id_objet = $type = 0;
249        $url_redirect = null;
250        // recuperer les &debut_xx;
251        if (is_array($args))
252                $contexte = $args;
253        else
254                parse_str($args,$contexte);
255
256
257        // Migration depuis anciennes URLs ?
258        // traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23
259        if ($GLOBALS['profondeur_url']<=0
260        AND $_SERVER['REQUEST_METHOD'] != 'POST') {
261                include_spip('inc/urls');
262                $r = nettoyer_url_page($i, $contexte);
263                if ($r) {
264                        list($contexte, $type,,, $suite) = $r;
265                        $_id = id_table_objet($type);
266                        $id_objet = $contexte[$_id];
267                        $url_propre = generer_url_entite($id_objet, $type);
268                        if (strlen($url_propre)
269                        AND !strstr($url,$url_propre)) {
270                                list(,$hash) = explode('#', $url_propre);
271                                $args = array();
272                                foreach(array_filter(explode('&', $suite)) as $fragment) {
273                                        if ($fragment != "$_id=$id_objet")
274                                                $args[] = $fragment;
275                                }
276                                $url_redirect = generer_url_entite($id_objet, $type, join('&',array_filter($args)), $hash);
277
278                                return array($contexte, $type, $url_redirect, $type);
279                        }
280                }
281        }
282        /* Fin compatibilite anciennes urls */
283        // Chercher les valeurs d'environnement qui indiquent l'url-propre
284        if (isset($_SERVER['REDIRECT_url_propre']))
285                $url_propre = $_SERVER['REDIRECT_url_propre'];
286        elseif (isset($_ENV['url_propre']))
287                $url_propre = $_ENV['url_propre'];
288        else {
289                // ne prendre que le segment d'url qui correspond, en fonction de la profondeur calculee
290                $url = ltrim($url,'/');
291                $url = explode('/',$url);
292                while (count($url)>$GLOBALS['profondeur_url']+1)
293                        array_shift($url);
294                $url = implode('/',$url);
295                $url_propre = preg_replace(',[?].*,', '', $url);
296        }
297
298        // Mode Query-String ?
299        $is_qs = false;
300        if (!$url_propre
301        AND preg_match(',[?]([^=/?&]+)(&.*)?$,', $url, $r)) {
302                $url_propre = $r[1];
303                $is_qs = true;
304        }
305
306        if (!$url_propre
307          OR $url_propre==_DIR_RESTREINT_ABS
308          OR $url_propre==_SPIP_SCRIPT) return; // qu'est-ce qu'il veut ???
309
310       
311        // gerer le cas de retour depuis des urls arbos
312        // mais si url arbo ne trouve pas, on veut une 404 par securite
313        if ($GLOBALS['profondeur_url']>0){
314                $urls_anciennes = charger_fonction('arbo','urls');
315                return $urls_anciennes($url_propre, $entite, $contexte);
316        }
317       
318        include_spip('base/abstract_sql'); // chercher dans la table des URLS
319
320        // Compatibilite avec propres2
321        $url_propre = preg_replace(',\.html$,i', '', $url_propre);
322
323        // Revenir en utf-8 si encodage type %D8%A7 (farsi)
324        $url_propre = rawurldecode($url_propre);
325
326        // Compatibilite avec les anciens marqueurs d'URL propres
327        // Tester l'entree telle quelle (avec 'url_libre' des sites ont pu avoir des entrees avec marqueurs dans la table spip_urls)
328        if (!$row = sql_fetsel('id_objet, type, date', 'spip_urls', 'url='.sql_quote($url_propre))) {
329                // Sinon enlever les marqueurs eventuels
330                $url_propre2 = retirer_marqueurs_url_propre($url_propre);
331
332                $row = sql_fetsel('id_objet, type, date', 'spip_urls', 'url='.sql_quote($url_propre2));
333        }
334
335        if ($row) {
336                $type = $row['type'];
337                $col_id = id_table_objet($type);
338                $contexte[$col_id] = $row['id_objet'];
339                $entite = $row['type'];
340
341                // Si l'url est vieux, donner le nouveau
342                if ($recent = sql_fetsel('url, date', 'spip_urls',
343                'type='.sql_quote($row['type']).' AND id_objet='.sql_quote($row['id_objet'])
344                .' AND date>'.sql_quote($row['date']), '', 'date DESC', 1)) {
345                        // Mode compatibilite pour conserver la distinction -Rubrique-
346                        if (_MARQUEUR_URL) {
347                                $marqueur = unserialize(_MARQUEUR_URL);
348                                $marqueur1 = $marqueur[$type.'1']; // debut '+-'
349                                $marqueur2 = $marqueur[$type.'2']; // fin '-+'
350                        } else
351                                $marqueur1 = $marqueur2 = '';
352                        $url_redirect = $marqueur1 . $recent['url'] . $marqueur2;
353                }
354        }
355
356        if ($entite=='' OR $entite=='type_urls' /* compat .htaccess 2.0 */) {
357                if ($type) {
358                        $entite =  objet_type($type);
359                } else {
360                        // Si ca ressemble a une URL d'objet, ce n'est pas la home
361                        // et on provoque un 404
362                        if (preg_match(',^.*/[^\.]+(\.html)?$,', $url)) {
363                                $entite = '404';
364                                $contexte['erreur'] = '';
365
366                                // l'url n'existe pas...
367                                // on ne sait plus dire de quel type d'objet il s'agit
368                                // sauf si on a le marqueur. et la c'est un peu sale...
369                                if (_MARQUEUR_URL) {
370                                        $fmarqueur = @array_flip(unserialize(_MARQUEUR_URL));
371                                        preg_match(',^([+][-]|[-+@_]),', $url_propre, $regs);
372                                        $objet = $regs ? substr($fmarqueur[$regs[1]],0,n-1) : 'article';
373                                        $contexte['erreur'] = _T(
374                                                ($objet=='rubrique' OR $objet=='breve')
375                                                        ? 'public:aucune_'.$objet
376                                                        : 'public:aucun_'.$objet
377                                        );
378                                }
379                        }
380                }
381        }
382
383        return array($contexte, $entite, $url_redirect, $is_qs?$entite:null);
384}
385
386?>
Note: See TracBrowser for help on using the repository browser.