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

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

Indentation et regles de codage selon http://www.spip.net/fr_article3497.html#regles_codage

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