source: spip-zone/_core_/branches/spip-3.0/plugins/urls_etendues/urls/propres.php @ 79785

Last change on this file since 79785 was 79785, checked in by denisb@…, 7 years ago

feliĉan novan jaron 2014 !

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