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

Last change on this file since 93092 was 93092, checked in by gilles.vincent@…, 5 years ago

Mise en forme plus homegene et plus lisible, pour les declarations des fonctions
Regles :

  • un espace après chaque virgule
  • un espace avant et apres chaque '='
File size: 14.7 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2015                                                *
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']:80);
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://code.spip.net/@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://code.spip.net/@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://code.spip.net/@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        // de preference avec id_parent=0, puis perma, puis par date desc
122        $row = sql_fetsel("U.url, U.date, U.id_parent, U.perma, $champ_titre",
123                          "$table AS O LEFT JOIN spip_urls AS U ON (U.type='$type' AND U.id_objet=O.$col_id)",
124                          "O.$col_id=$id_objet AND (U.segments IS NULL OR U.segments=1)", '', 'U.id_parent=0 DESC, U.perma DESC, U.date DESC', 1);
125
126        // 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
127        // on verifie donc que l'objet existe bien avant de sortir ou de creer une url pour cet objet
128        if (!$row)
129                $row = sql_fetsel("'' as url, '' as date, 0 as id_parent, 0 as perma, $champ_titre",
130                                  "$table AS O",
131                                  "O.$col_id=$id_objet");
132
133        if (!$row) return ""; # Quand $id_objet n'est pas un numero connu
134
135        $url_propre = $row['url'];
136
137        // si url_propre connue mais avec id_parent non nul, essayer de reinserer tel quel avec id_parent=0
138        if ($url_propre AND $row['id_parent']){
139                include_spip('action/editer_url');
140                $set = array('url' => $url_propre, 'type' => $type, 'id_objet' => $id_objet, 'perma' => $row['perma']);
141                // si on arrive pas a reinserer tel quel, on annule url_propre pour forcer un recalcul d'url
142                if (!url_insert($set,false,_url_propres_sep_id))
143                        $url_propre = "";
144                else
145                        $url_propre = $row['url'] = $set['url'];
146        }
147
148        // Se contenter de cette URL si elle existe ;
149        // sauf si on invoque par "voir en ligne" avec droit de modifier l'url
150
151        // l'autorisation est verifiee apres avoir calcule la nouvelle url propre
152        // car si elle ne change pas, cela ne sert a rien de verifier les autorisations
153        // qui requetent en base
154        $modifier_url = (defined('_VAR_URLS') AND _VAR_URLS AND !$row['perma']);
155        if ($url_propre AND !$modifier_url)
156                return $url_propre;
157
158        // Sinon, creer une URL
159        $url = pipeline('propres_creer_chaine_url',
160                array(
161                        'data' => $url_propre,  // le vieux url_propre
162                        'objet' => array_merge($row,
163                                array('type' => $type, 'id_objet' => $id_objet)
164                        )
165                )
166        );
167
168        // Eviter de tamponner les URLs a l'ancienne (cas d'un article
169        // intitule "auteur2")
170        include_spip('inc/urls');
171        $objets = urls_liste_objets();
172        if (preg_match(',^('.$objets.')[0-9]+$,', $url, $r)
173        AND $r[1] != $type)
174                $url = $url._url_propres_sep_id.$id_objet;
175
176        // Pas de changement d'url
177        if ($url == $url_propre)
178                return $url_propre;
179
180        // verifier l'autorisation, maintenant qu'on est sur qu'on va agir
181        if ($modifier_url) {
182                include_spip('inc/autoriser');
183                $modifier_url = autoriser('modifierurl', $type, $id_objet);
184        }
185
186        // Verifier si l'utilisateur veut effectivement changer l'URL
187        if ($modifier_url
188                AND CONFIRMER_MODIFIER_URL
189                AND $url_propre
190                AND $url != preg_replace('/'.preg_quote(_url_propres_sep_id,'/').'.*/', '', $url_propre))
191                $confirmer = true;
192        else
193                $confirmer = false;
194
195        if ($confirmer AND !_request('ok')) {
196                die ("vous changez d'url ? $url_propre -&gt; $url");
197        }
198
199        $set = array('url' => $url, 'type' => $type, 'id_objet' => $id_objet);
200        include_spip('action/editer_url');
201        if (!url_insert($set,$confirmer,_url_propres_sep_id))
202                return $url_propre; //serveur out ? retourner au mieux
203
204        return $set['url'];
205}
206
207// http://code.spip.net/@_generer_url_propre
208function _generer_url_propre($type, $id, $args = '', $ancre = '') {
209
210        if ($generer_url_externe = charger_fonction("generer_url_$type",'urls',true)) {
211                $url = $generer_url_externe($id, $args, $ancre);
212                if (NULL != $url) return $url;
213        }
214
215        // Mode compatibilite pour conserver la distinction -Rubrique-
216        if (_MARQUEUR_URL) {
217                $marqueur = unserialize(_MARQUEUR_URL);
218                $marqueur1 = isset($marqueur[$type.'1']) ? $marqueur[$type.'1'] : '' ; // debut '+-'
219                $marqueur2 = isset($marqueur[$type.'2']) ? $marqueur[$type.'2'] : '' ; // fin '-+'
220        } else
221                $marqueur1 = $marqueur2 = '';
222        // fin
223
224        // Mode propre
225        $propre = declarer_url_propre($type, $id);
226
227        if ($propre === false) return ''; // objet inconnu. raccourci ?
228
229        if ($propre) {
230                $url = _debut_urls_propres
231                        . $marqueur1
232                        . $propre
233                        . $marqueur2
234                        . _terminaison_urls_propres;
235
236                // les urls de type /1234 sont interpretees comme urls courte vers article 1234
237                // on les encadre d'un - : /-1234-
238                if (is_numeric($url)){
239                        $url = "-".$url."-";
240                }
241
242                if (!defined('_SET_HTML_BASE') OR !_SET_HTML_BASE)
243                        // Repositionne l'URL par rapport a la racine du site (#GLOBALS)
244                        $url = str_repeat('../', $GLOBALS['profondeur_url']).$url;
245                else
246                        $url = _DIR_RACINE . $url;
247        } else {
248
249                // objet connu mais sans possibilite d'URL lisible, revenir au defaut
250                include_spip('base/connect_sql');
251                $id_type = id_table_objet($type);
252                $url = _DIR_RACINE . get_spip_script('./')."?"._SPIP_PAGE."=$type&$id_type=$id";
253        }
254
255        // Ajouter les args
256        if ($args)
257                $url .= ((strpos($url, '?')===false) ? '?' : '&') . $args;
258
259        // Ajouter l'ancre
260        if ($ancre)
261                $url .= "#$ancre";
262
263        return $url;
264}
265
266// retrouve le fond et les parametres d'une URL propre
267// ou produit une URL propre si on donne un parametre
268// @return array([contexte],[type],[url_redirect],[fond]) : url decodee
269// http://code.spip.net/@urls_propres_dist
270function urls_propres_dist($i, $entite, $args = '', $ancre = '') {
271
272        if (is_numeric($i))
273                return _generer_url_propre($entite, $i, $args, $ancre);
274
275        $url = $i;
276        $id_objet = $type = 0;
277        $url_redirect = null;
278        // recuperer les &debut_xx;
279        if (is_array($args))
280                $contexte = $args;
281        else
282                parse_str($args,$contexte);
283
284
285        // Migration depuis anciennes URLs ?
286        // traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23
287        if ($GLOBALS['profondeur_url']<=0
288        AND $_SERVER['REQUEST_METHOD'] != 'POST') {
289                include_spip('inc/urls');
290                $r = nettoyer_url_page($i, $contexte);
291                if ($r) {
292                        list($contexte, $type,,, $suite) = $r;
293                        $_id = id_table_objet($type);
294                        $id_objet = $contexte[$_id];
295                        $url_propre = generer_url_entite($id_objet, $type);
296                        if (strlen($url_propre)
297                        AND !strstr($url,$url_propre)) {
298                                list(,$hash) = array_pad(explode('#', $url_propre), 2, null);
299                                $args = array();
300                                foreach(array_filter(explode('&', $suite)) as $fragment) {
301                                        if ($fragment != "$_id=$id_objet")
302                                                $args[] = $fragment;
303                                }
304                                $url_redirect = generer_url_entite($id_objet, $type, join('&',array_filter($args)), $hash);
305
306                                return array($contexte, $type, $url_redirect, $type);
307                        }
308                }
309        }
310        /* Fin compatibilite anciennes urls */
311
312        // Chercher les valeurs d'environnement qui indiquent l'url-propre
313        $url_propre = preg_replace(',[?].*,', '', $url);
314
315        // Mode Query-String ?
316        $is_qs = false;
317        if (!$url_propre
318        AND preg_match(',[?]([^=/?&]+)(&.*)?$,', $url, $r)) {
319                $url_propre = $r[1];
320                $is_qs = true;
321        }
322
323        if (!$url_propre
324          OR $url_propre==_DIR_RESTREINT_ABS
325          OR $url_propre==_SPIP_SCRIPT) return; // qu'est-ce qu'il veut ???
326
327       
328        // gerer le cas de retour depuis des urls arbos
329        // mais si url arbo ne trouve pas, on veut une 404 par securite
330        if ($GLOBALS['profondeur_url']>0 AND !defined('_FORCE_URLS_PROPRES')){
331                $urls_anciennes = charger_fonction('arbo','urls');
332                return $urls_anciennes($url_propre, $entite, $contexte);
333        }
334       
335        include_spip('base/abstract_sql'); // chercher dans la table des URLS
336
337        // Compatibilite avec propres2
338        $url_propre = preg_replace(',\.html$,i', '', $url_propre);
339
340        // Revenir en utf-8 si encodage type %D8%A7 (farsi)
341        $url_propre = rawurldecode($url_propre);
342
343        // Compatibilite avec les anciens marqueurs d'URL propres
344        // Tester l'entree telle quelle (avec 'url_libre' des sites ont pu avoir des entrees avec marqueurs dans la table spip_urls)
345        if (!$row = sql_fetsel('id_objet, type, date, url', 'spip_urls', 'url='.sql_quote($url_propre, '', 'TEXT'))) {
346                // Sinon enlever les marqueurs eventuels
347                $url_propre2 = retirer_marqueurs_url_propre($url_propre);
348
349                $row = sql_fetsel('id_objet, type, date, url', 'spip_urls', 'url='.sql_quote($url_propre2, '', 'TEXT'));
350        }
351
352        if ($row) {
353                $type = $row['type'];
354                $col_id = id_table_objet($type);
355                $contexte[$col_id] = $row['id_objet'];
356                $entite = $row['type'];
357
358                // Si l'url est vieux, donner le nouveau
359                if ($recent = sql_fetsel('url, date', 'spip_urls',
360                'type='.sql_quote($row['type'], '', 'TEXT').' AND id_objet='.sql_quote($row['id_objet'])
361                .' AND date>'.sql_quote($row['date'], '', 'TEXT')
362                .' AND url<>'.sql_quote($row['url'], '', 'TEXT'), '', 'date DESC', 1)) {
363                        // Mode compatibilite pour conserver la distinction -Rubrique-
364                        if (_MARQUEUR_URL) {
365                                $marqueur = unserialize(_MARQUEUR_URL);
366                                $marqueur1 = $marqueur[$type.'1']; // debut '+-'
367                                $marqueur2 = $marqueur[$type.'2']; // fin '-+'
368                        } else
369                                $marqueur1 = $marqueur2 = '';
370                        $url_redirect = $marqueur1 . $recent['url'] . $marqueur2;
371                }
372        }
373
374        if ($entite=='' OR $entite=='type_urls' /* compat .htaccess 2.0 */) {
375                if ($type) {
376                        $entite =  objet_type($type);
377                } else {
378                        // Si ca ressemble a une URL d'objet, ce n'est pas la home
379                        // et on provoque un 404
380                        if (preg_match(',^[^\.]+(\.html)?$,', $url)) {
381                                $entite = '404';
382                                $contexte['erreur'] = '';
383
384                                // l'url n'existe pas...
385                                // on ne sait plus dire de quel type d'objet il s'agit
386                                // sauf si on a le marqueur. et la c'est un peu sale...
387                                if (_MARQUEUR_URL) {
388                                        $fmarqueur = @array_flip(unserialize(_MARQUEUR_URL));
389                                        preg_match(',^([+][-]|[-+@_]),', $url_propre, $regs);
390                                        $objet = $regs ? substr($fmarqueur[$regs[1]],0,n-1) : 'article';
391                                        $contexte['erreur'] = _T(
392                                                ($objet=='rubrique' OR $objet=='breve')
393                                                        ? 'public:aucune_'.$objet
394                                                        : 'public:aucun_'.$objet
395                                        );
396                                }
397                        }
398                }
399        }
400
401        return array($contexte, $entite, $url_redirect, $is_qs?$entite:null);
402}
403
404?>
Note: See TracBrowser for help on using the repository browser.