PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/spip/ecrire/urls/arbo.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 468 lines | 279 code | 65 blank | 124 comment | 71 complexity | e585e76980f4c8fd3e376a7aacacfb64 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. define('URLS_ARBO_EXEMPLE', '/article/titre');
  13. // TODO: une interface permettant de verifier qu'on veut effectivment modifier
  14. // une adresse existante
  15. define('CONFIRMER_MODIFIER_URL', false);
  16. /**
  17. * - Comment utiliser ce jeu d'URLs ?
  18. * Recopiez le fichier "htaccess.txt" du repertoire de base du site SPIP sous
  19. * le sous le nom ".htaccess" (attention a ne pas ecraser d'autres reglages
  20. * que vous pourriez avoir mis dans ce fichier) ; si votre site est en
  21. * "sous-repertoire", vous devrez aussi editer la ligne "RewriteBase" ce fichier.
  22. * Les URLs definies seront alors redirigees vers les fichiers de SPIP.
  23. *
  24. * Choisissez "arbo" dans les pages de configuration d'URL
  25. *
  26. * SPIP calculera alors ses liens sous la forme "Mon-titre-d-article".
  27. * Variantes :
  28. *
  29. * Terminaison :
  30. * les terminaisons ne *sont pas* stockees en base, elles servent juste
  31. * a rendre les url jolies ou conformes a un usage
  32. * pour avoir des url terminant par html
  33. * define ('_terminaison_urls_arbo', '.html');
  34. *
  35. * pour preciser des terminaisons particulieres pour certains types
  36. * $GLOBALS['url_arbo_terminaisons']=array(
  37. * 'rubrique' => '/',
  38. * 'mot' => '',
  39. * 'groupe' => '/',
  40. * 'defaut' => '.html');
  41. *
  42. * pour avoir des url numeriques (id) du type 12/5/4/article/23
  43. * define ('_URLS_ARBO_MIN',255);
  44. *
  45. *
  46. * pour conserver la casse des titres dans les url
  47. * define ('_url_arbo_minuscules',0);
  48. *
  49. * pour choisir le caractere de separation titre-id en cas de doublon
  50. * (ne pas utiliser '/')
  51. * define ('_url_arbo_sep_id','-');
  52. *
  53. * pour modifier la hierarchie apparente dans la constitution des urls
  54. * ex pour que les mots soient classes par groupes
  55. * $GLOBALS['url_arbo_parents']=array(
  56. * 'article'=>array('id_rubrique','rubrique'),
  57. * 'rubrique'=>array('id_parent','rubrique'),
  58. * 'breve'=>array('id_rubrique','rubrique'),
  59. * 'site'=>array('id_rubrique','rubrique'),
  60. * 'mot'=>array('id_groupe','groupes_mot'));
  61. *
  62. * pour personaliser les types
  63. * $GLOBALS['url_arbo_types']=array(
  64. * 'rubrique'=>'', // pas de type pour les rubriques
  65. * 'article'=>'a',
  66. * 'mot'=>'tags'
  67. * );
  68. *
  69. */
  70. define ('_debut_urls_arbo', '');
  71. define ('_terminaison_urls_arbo', '');
  72. define ('_url_arbo_sep_id','-');
  73. define ('_url_arbo_minuscules',1);
  74. // Ces chaines servaient de marqueurs a l'epoque ou les URL propres devaient
  75. // indiquer la table ou les chercher (articles, auteurs etc),
  76. // et elles etaient retirees par les preg_match dans la fonction ci-dessous.
  77. // Elles sont a present definies a "" pour avoir des URL plus jolies
  78. // mais les preg_match restent necessaires pour gerer les anciens signets.
  79. #define('_MARQUEUR_URL', serialize(array('rubrique1' => '-', 'rubrique2' => '-', 'breve1' => '+', 'breve2' => '+', 'site1' => '@', 'site2' => '@', 'auteur1' => '_', 'auteur2' => '_', 'mot1' => '+-', 'mot2' => '-+')));
  80. define('_MARQUEUR_URL', false);
  81. function url_arbo_parent($type){
  82. static $parents = null;
  83. if (is_null($parents)){
  84. $parents = array(
  85. 'article'=>array('id_rubrique','rubrique'),
  86. 'rubrique'=>array('id_parent','rubrique'),
  87. 'breve'=>array('id_rubrique','rubrique'),
  88. 'site'=>array('id_rubrique','rubrique'));
  89. if (isset($GLOBALS['url_arbo_parents']) AND !isset($_REQUEST['url_arbo_parents'])){
  90. $parents = array_merge($parents,$GLOBALS['url_arbo_parents']);
  91. }
  92. }
  93. return (isset($parents[$type])?$parents[$type]:'');
  94. }
  95. function url_arbo_terminaison($type){
  96. static $terminaison_types = null;
  97. if ($terminaison_types==null){
  98. $terminaison_types = array('rubrique' => '/','mot' => '','defaut' => defined('_terminaison_urls_arbo')?_terminaison_urls_arbo:'.html');
  99. if (isset($GLOBALS['url_arbo_terminaisons']))
  100. $terminaison_types = array_merge($terminaison_types,$GLOBALS['url_arbo_terminaisons']);
  101. }
  102. // si c'est un appel avec type='' c'est pour avoir la liste des terminaisons
  103. if (!$type)
  104. return array_unique(array_values($terminaison_types));
  105. if (isset($terminaison_types[$type]))
  106. return $terminaison_types[$type];
  107. elseif (isset($terminaison_types['defaut']))
  108. return $terminaison_types['defaut'];
  109. return "";
  110. }
  111. function url_arbo_type($type){
  112. // par defaut les rubriques ne sont pas typees, mais le reste oui
  113. static $synonymes_types = null;
  114. if (!$synonymes_types){
  115. $synonymes_types = array('rubrique'=>'');
  116. if (isset($GLOBALS['url_arbo_types']) AND is_array($GLOBALS['url_arbo_types']))
  117. $synonymes_types = array_merge($synonymes_types,$GLOBALS['url_arbo_types']);
  118. }
  119. // si c'est un appel avec type='' c'est pour avoir la liste inversee des synonymes
  120. if (!$type)
  121. return array_flip($synonymes_types);
  122. return
  123. ($t=(isset($synonymes_types[$type])?$synonymes_types[$type]:$type)) // le type ou son synonyme
  124. . ($t?'/':''); // le / eventuel pour separer, si le synonyme n'est pas vide
  125. }
  126. // Pipeline pour creation d'une adresse : il recoit l'url propose par le
  127. // precedent, un tableau indiquant le titre de l'objet, son type, son id,
  128. // et doit donner en retour une chaine d'url, sans se soucier de la
  129. // duplication eventuelle, qui sera geree apres
  130. // http://doc.spip.org/@creer_chaine_url
  131. function urls_arbo_creer_chaine_url($x) {
  132. // NB: ici url_old ne sert pas, mais un plugin qui ajouterait une date
  133. // pourrait l'utiliser pour juste ajouter la
  134. $url_old = $x['data'];
  135. $objet = $x['objet'];
  136. include_spip('inc/filtres');
  137. if (!defined('_URLS_ARBO_MAX')) define('_URLS_ARBO_MAX', 35);
  138. if (!defined('_URLS_ARBO_MIN')) define('_URLS_ARBO_MIN', 3);
  139. include_spip('action/editer_url');
  140. if (!$url = url_nettoyer($objet['titre'],_URLS_ARBO_MAX,_URLS_ARBO_MIN,'-',_url_arbo_minuscules?'strtolower':''))
  141. $url = $objet['id_objet'];
  142. $x['data'] =
  143. url_arbo_type($objet['type']) // le type ou son synonyme
  144. . $url; // le titre
  145. return $x;
  146. }
  147. // http://doc.spip.org/@declarer_url_arbo_rec
  148. function declarer_url_arbo_rec($url,$type,$parent,$type_parent){
  149. if (is_null($parent)){
  150. return $url;
  151. }
  152. if($parent==0)
  153. return rtrim($url,'/');
  154. else {
  155. $url_parent = declarer_url_arbo($type_parent?$type_parent:'rubrique',$parent);
  156. return rtrim($url_parent,'/') . '/' . rtrim($url,'/');
  157. }
  158. }
  159. // http://doc.spip.org/@declarer_url_arbo
  160. function declarer_url_arbo($type, $id_objet) {
  161. static $urls=array();
  162. // Se contenter de cette URL si elle existe ;
  163. // sauf si on invoque par "voir en ligne" avec droit de modifier l'url
  164. // l'autorisation est verifiee apres avoir calcule la nouvelle url propre
  165. // car si elle ne change pas, cela ne sert a rien de verifier les autorisations
  166. // qui requetent en base
  167. $modifier_url = $GLOBALS['var_urls'];
  168. if (!isset($urls[$type][$id_objet]) OR $modifier_url) {
  169. $trouver_table = charger_fonction('trouver_table', 'base');
  170. $desc = $trouver_table(table_objet($type));
  171. $champ_titre = $desc['titre'];
  172. $col_id = @$desc['key']["PRIMARY KEY"];
  173. // $type doit designer une table, avec champ indiquant un titre
  174. if (!$col_id OR !$champ_titre) return false;
  175. $table = $desc['table'];
  176. $id_objet = intval($id_objet);
  177. // parent
  178. $champ_parent = url_arbo_parent($type);
  179. $sel_parent = ($champ_parent)?", O.".reset($champ_parent).' as parent':'';
  180. // Recuperer une URL propre correspondant a l'objet.
  181. $row = sql_fetsel("U.url, U.date, O.$champ_titre $sel_parent", "$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);
  182. if ($row){
  183. $urls[$type][$id_objet] = $row;
  184. $urls[$type][$id_objet]['type_parent'] = $champ_parent?end($champ_parent):'';
  185. }
  186. }
  187. if (!isset($urls[$type][$id_objet])) return ""; # objet inexistant
  188. $url_propre = $urls[$type][$id_objet]['url'];
  189. if (!is_null($url_propre) AND !$modifier_url)
  190. return declarer_url_arbo_rec($url_propre,$type,
  191. isset($urls[$type][$id_objet]['parent'])?$urls[$type][$id_objet]['parent']:null,
  192. isset($urls[$type][$id_objet]['type_parent'])?$urls[$type][$id_objet]['type_parent']:null);
  193. // Sinon, creer une URL
  194. $url = pipeline('arbo_creer_chaine_url',
  195. array(
  196. 'data' => $url_propre, // le vieux url_propre
  197. 'objet' => array_merge($urls[$type][$id_objet],
  198. array('type' => $type, 'id_objet' => $id_objet)
  199. )
  200. )
  201. );
  202. // Eviter de tamponner les URLs a l'ancienne (cas d'un article
  203. // intitule "auteur2")
  204. include_spip('inc/urls');
  205. $objets = urls_liste_objets();
  206. if (preg_match(',^('.$objets.')[0-9]*$,', $url, $r)
  207. AND $r[1] != $type)
  208. $url = $url._url_arbo_sep_id.$id_objet;
  209. // Pas de changement d'url
  210. if ($url == $url_propre)
  211. return declarer_url_arbo_rec($url_propre,$type,$urls[$type][$id_objet]['parent'],$urls[$type][$id_objet]['type_parent']);
  212. // verifier l'autorisation, maintenant qu'on est sur qu'on va agir
  213. if ($modifier_url) {
  214. include_spip('inc/autoriser');
  215. $modifier_url = autoriser('modifierurl', $type, $id_objet);
  216. }
  217. // Verifier si l'utilisateur veut effectivement changer l'URL
  218. if ($modifier_url
  219. AND CONFIRMER_MODIFIER_URL
  220. AND $url_propre
  221. AND $url != preg_replace('/,.*/', '', $url_propre))
  222. $confirmer = true;
  223. else
  224. $confirmer = false;
  225. if ($confirmer AND !_request('ok')) {
  226. die ("vous changez d'url ? $url_propre -&gt; $url");
  227. }
  228. $set = array('url' => $url, 'type' => $type, 'id_objet' => $id_objet);
  229. include_spip('action/editer_url');
  230. if (url_insert($set,$confirmer,_url_arbo_sep_id)){
  231. $urls[$type][$id_objet]['url'] = $set['url'];
  232. }
  233. else {
  234. // l'insertion a echoue,
  235. //serveur out ? retourner au mieux
  236. $urls[$type][$id_objet]['url']=$url_propre;
  237. }
  238. return declarer_url_arbo_rec($urls[$type][$id_objet]['url'],$type,$urls[$type][$id_objet]['parent'],$urls[$type][$id_objet]['type_parent']);
  239. }
  240. // http://doc.spip.org/@_generer_url_arbo
  241. function _generer_url_arbo($type, $id, $args='', $ancre='') {
  242. if ($generer_url_externe = charger_fonction("generer_url_$type",'urls',true)) {
  243. $url = $generer_url_externe($id, $args, $ancre);
  244. if (NULL != $url) return $url;
  245. }
  246. if ($type == 'document') {
  247. include_spip('inc/documents');
  248. return generer_url_document_dist($id, $args, $ancre);
  249. }
  250. // Mode propre
  251. $propre = declarer_url_arbo($type, $id);
  252. if ($propre === false) return ''; // objet inconnu. raccourci ?
  253. if ($propre) {
  254. $url = _debut_urls_arbo
  255. . rtrim($propre,'/')
  256. . url_arbo_terminaison($type);
  257. } else {
  258. // objet connu mais sans possibilite d'URL lisible, revenir au defaut
  259. include_spip('base/connect_sql');
  260. $id_type = id_table_objet($type);
  261. $url = get_spip_script('./')."?"._SPIP_PAGE."=$type&$id_type=$id";
  262. }
  263. // Ajouter les args
  264. if ($args)
  265. $url .= ((strpos($url, '?')===false) ? '?' : '&') . $args;
  266. // Ajouter l'ancre
  267. if ($ancre)
  268. $url .= "#$ancre";
  269. return _DIR_RACINE . $url;
  270. }
  271. // @return array([contexte],[type],[url_redirect],[fond]) : url decodee
  272. // http://doc.spip.org/@urls_arbo_dist
  273. function urls_arbo_dist($i, $entite, $args='', $ancre='') {
  274. if (is_numeric($i))
  275. return _generer_url_arbo($entite, $i, $args, $ancre);
  276. // traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23
  277. if ($GLOBALS['profondeur_url']>0 AND $entite=='sommaire'){
  278. $entite = 'type_urls';
  279. }
  280. // recuperer les &debut_xx;
  281. if (is_array($args))
  282. $contexte = $args;
  283. else
  284. parse_str($args,$contexte);
  285. $url = $i;
  286. $id_objet = $type = 0;
  287. $url_redirect = null;
  288. // Migration depuis anciennes URLs ?
  289. // traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23
  290. if ($GLOBALS['profondeur_url']<=0
  291. AND $_SERVER['REQUEST_METHOD'] != 'POST') {
  292. include_spip('inc/urls');
  293. $r = nettoyer_url_page($i, $contexte);
  294. if ($r) {
  295. list($contexte, $type,,, $suite) = $r;
  296. $_id = id_table_objet($type);
  297. $id_objet = $contexte[$_id];
  298. $url_propre = generer_url_entite($id_objet, $type);
  299. if (strlen($url_propre)
  300. AND !strstr($url,$url_propre)) {
  301. list(,$hash) = explode('#', $url_propre);
  302. $args = array();
  303. foreach(array_filter(explode('&', $suite)) as $fragment) {
  304. if ($fragment != "$_id=$id_objet")
  305. $args[] = $fragment;
  306. }
  307. $url_redirect = generer_url_entite($id_objet, $type, join('&',array_filter($args)), $hash);
  308. return array($contexte, $type, $url_redirect, $type);
  309. }
  310. }
  311. }
  312. /* Fin compatibilite anciennes urls */
  313. // Chercher les valeurs d'environnement qui indiquent l'url-propre
  314. if (isset($_SERVER['REDIRECT_url_propre']))
  315. $url_propre = $_SERVER['REDIRECT_url_propre'];
  316. elseif (isset($_ENV['url_propre']))
  317. $url_propre = $_ENV['url_propre'];
  318. else {
  319. // ne prendre que le segment d'url qui correspond, en fonction de la profondeur calculee
  320. $url = ltrim($url,'/');
  321. $url = explode('/',$url);
  322. while (count($url)>$GLOBALS['profondeur_url']+1)
  323. array_shift($url);
  324. $url = implode('/',$url);
  325. $url_propre = preg_replace(',[?].*,', '', $url);
  326. }
  327. // Mode Query-String ?
  328. if (!$url_propre
  329. AND preg_match(',[?]([^=/?&]+)(&.*)?$,', $url, $r)) {
  330. $url_propre = $r[1];
  331. }
  332. if (!$url_propre) return; // qu'est-ce qu'il veut ???
  333. include_spip('base/abstract_sql'); // chercher dans la table des URLS
  334. // Revenir en utf-8 si encodage type %D8%A7 (farsi)
  335. $url_propre = rawurldecode($url_propre);
  336. // Compatibilite avec .htm/.html et autres terminaisons
  337. $t = array_diff(array_unique(array_merge(array('.html','.htm','/'),url_arbo_terminaison(''))),array(''));
  338. if (count($t))
  339. $url_propre = preg_replace('{('
  340. .implode('|',array_map('preg_quote',$t)).')$}i', '', $url_propre);
  341. if (strlen($url_propre) AND !preg_match(',^[^/]*[.]php,',$url_propre)){
  342. $types_parents = array();
  343. // recuperer tous les objets de larbo xxx/article/yyy/mot/zzzz
  344. $url_arbo = explode('/',$url_propre);
  345. while (count($url_arbo)>0){
  346. $url_propre = array_pop($url_arbo);
  347. if (count($url_arbo))
  348. $type = array_pop($url_arbo);
  349. else
  350. $type=null;
  351. // Compatibilite avec les anciens marqueurs d'URL propres
  352. // Tester l'entree telle quelle (avec 'url_libre' des sites ont pu avoir des entrees avec marqueurs dans la table spip_urls)
  353. if (is_null($type)
  354. OR !$row=sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote("$type/$url_propre")))) {
  355. if (!is_null($type))
  356. array_push($url_arbo,$type);
  357. $row = sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote($url_propre)));
  358. }
  359. if ($row) {
  360. $type = $row['type'];
  361. $col_id = id_table_objet($type);
  362. // n'affecter que la premiere fois un parent de type id_rubrique
  363. if (!isset($contexte[$col_id]))
  364. $contexte[$col_id] = $row['id_objet'];
  365. if (!$entite
  366. OR !in_array($type,$types_parents))
  367. $entite = $type;
  368. if ($p = url_arbo_parent($type))
  369. $types_parents[]=end($p);
  370. }
  371. else {
  372. // un segment est inconnu
  373. if ($entite=='' OR $entite=='type_urls') {
  374. // on genere une 404 comme il faut si on ne sait pas ou aller
  375. return array(array(),'404');
  376. }
  377. return; // ?
  378. }
  379. }
  380. // gerer le retour depuis des urls propres
  381. if (($entite=='' OR $entite=='type_urls')
  382. AND $GLOBALS['profondeur_url']<=0){
  383. $urls_anciennes = charger_fonction('propres','urls');
  384. return $urls_anciennes($url_propre, $entite, $contexte);
  385. }
  386. }
  387. if ($entite=='' OR $entite=='type_urls' /* compat .htaccess 2.0 */) {
  388. if ($type)
  389. $entite = ($type == 'syndic') ? 'site' : $type;
  390. else {
  391. // Si ca ressemble a une URL d'objet, ce n'est pas la home
  392. // et on provoque un 404
  393. if (preg_match(',^[^\.]+(\.html)?$,', $url)) {
  394. $entite = '404';
  395. $contexte['erreur'] = ''; // qu'afficher ici ? l'url n'existe pas... on ne sait plus dire de quel type d'objet il s'agit
  396. }
  397. }
  398. }
  399. define('_SET_HTML_BASE',1);
  400. return array($contexte, $entite, null, $is_qs?$entite:null);
  401. }
  402. ?>