/** * API : retourner l'url d'un objet si i est numerique * ou decoder cette url si c'est une chaine * array([contexte],[type],[url_redirect],[fond]) : url decodee * * http://doc.spip.org/@urls_arbo_dist * * @param string|int $i * @param string $entite * @param string|array $args * @param string $ancre * @return array|string */ function urls_arbo_dist($i, $entite, $args = '', $ancre = '') { if (is_numeric($i)) { return _generer_url_arbo($entite, $i, $args, $ancre); } // traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23 if ($GLOBALS['profondeur_url'] > 0 and $entite == 'sommaire') { $entite = 'type_urls'; } // recuperer les &debut_xx; if (is_array($args)) { $contexte = $args; } else { parse_str($args, $contexte); } $url = $i; $id_objet = $type = 0; $url_redirect = null; // Migration depuis anciennes URLs ? // traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23 if ($GLOBALS['profondeur_url'] <= 0 and $_SERVER['REQUEST_METHOD'] != 'POST') { include_spip('inc/urls'); $r = nettoyer_url_page($i, $contexte); if ($r) { list($contexte, $type, , , $suite) = $r; $_id = id_table_objet($type); $id_objet = $contexte[$_id]; $url_propre = generer_url_entite($id_objet, $type); if (strlen($url_propre) and !strstr($url, $url_propre)) { list(, $hash) = explode('#', $url_propre); $args = array(); foreach (array_filter(explode('&', $suite)) as $fragment) { if ($fragment != "{$_id}={$id_objet}") { $args[] = $fragment; } } $url_redirect = generer_url_entite($id_objet, $type, join('&', array_filter($args)), $hash); return array($contexte, $type, $url_redirect, $type); } } } /* Fin compatibilite anciennes urls */ // Chercher les valeurs d'environnement qui indiquent l'url-propre if (isset($_SERVER['REDIRECT_url_propre'])) { $url_propre = $_SERVER['REDIRECT_url_propre']; } elseif (isset($_ENV['url_propre'])) { $url_propre = $_ENV['url_propre']; } else { // ne prendre que le segment d'url qui correspond, en fonction de la profondeur calculee $url = ltrim($url, '/'); $url = explode('/', $url); while (count($url) > $GLOBALS['profondeur_url'] + 1) { array_shift($url); } $url = implode('/', $url); $url_propre = preg_replace(',[?].*,', '', $url); } // Mode Query-String ? if (!$url_propre and preg_match(',[?]([^=/?&]+)(&.*)?$,', $url, $r)) { $url_propre = $r[1]; } if (!$url_propre or $url_propre == _DIR_RESTREINT_ABS or $url_propre == _SPIP_SCRIPT) { return; } // qu'est-ce qu'il veut ??? include_spip('base/abstract_sql'); // chercher dans la table des URLS // Revenir en utf-8 si encodage type %D8%A7 (farsi) $url_propre = rawurldecode($url_propre); // Compatibilite avec .htm/.html et autres terminaisons $t = array_diff(array_unique(array_merge(array('.html', '.htm', '/'), url_arbo_terminaison(''))), array('')); if (count($t)) { $url_propre = preg_replace('{(' . implode('|', array_map('preg_quote', $t)) . ')$}i', '', $url_propre); } if (strlen($url_propre) and !preg_match(',^[^/]*[.]php,', $url_propre)) { $parents_vus = array(); // recuperer tous les objets de larbo xxx/article/yyy/mot/zzzz // on parcourt les segments de gauche a droite // pour pouvoir contextualiser un segment par son parent $url_arbo = explode('/', $url_propre); $url_arbo_new = array(); $dernier_parent_vu = false; $objet_segments = 0; while (count($url_arbo) > 0) { $type = null; if (count($url_arbo) > 1) { $type = array_shift($url_arbo); } $url_segment = array_shift($url_arbo); // Rechercher le segment de candidat // si on est dans un contexte de parent, donne par le segment precedent, // prefixer le segment recherche avec ce contexte $cp = "0"; // par defaut : parent racine, id=0 if ($dernier_parent_vu) { $cp = $parents_vus[$dernier_parent_vu]; } // d'abord recherche avec prefixe parent, en une requete car aucun risque de colision $row = sql_fetsel('id_objet, type, url', 'spip_urls', is_null($type) ? "url=" . sql_quote($url_segment) : sql_in('url', array("{$type}/{$url_segment}", $type)), '', (intval($cp) ? "id_parent=" . intval($cp) . " DESC, " : "") . "segments DESC, id_parent"); if ($row) { if (!is_null($type) and $row['url'] == $type) { array_unshift($url_arbo, $url_segment); $url_segment = $type; $type = null; } $type = $row['type']; $col_id = id_table_objet($type); // le plus a droite l'emporte pour des objets presents plusieurs fois dans l'url (ie rubrique) $contexte[$col_id] = $row['id_objet']; $type_parent = ''; if ($p = url_arbo_parent($type)) { $type_parent = end($p); } // l'entite la plus a droite l'emporte, si le type de son parent a ete vu // sinon c'est un segment contextuel supplementaire a ignorer // ex : rub1/article/art1/mot1 : il faut ignorer le mot1, la vrai url est celle de l'article if (!$entite or $dernier_parent_vu == $type_parent) { if ($objet_segments == 0) { $entite = $type; } } else { $objet_segments++; } $url_arbo_new[$objet_segments]['id_objet'] = $row['id_objet']; $url_arbo_new[$objet_segments]['objet'] = $type; $url_arbo_new[$objet_segments]['segment'][] = $row['url']; // on note le dernier parent vu de chaque type $parents_vus[$dernier_parent_vu = $type] = $row['id_objet']; } else { // un segment est inconnu if ($entite == '' or $entite == 'type_urls') { // on genere une 404 comme il faut si on ne sait pas ou aller return array(array(), '404'); } // ici on a bien reconnu un segment en amont, mais le segment en cours est inconnu // on pourrait renvoyer sur le dernier segment identifie // mais de fait l'url entiere est inconnu : 404 aussi // mais conserver le contexte qui peut contenir un fond d'ou venait peut etre $entite (reecriture urls) return array($contexte, '404'); } } if (count($url_arbo_new)) { $caller = debug_backtrace(); $caller = $caller[1]['function']; // si on est appele par un autre module d'url c'est du decodage d'une ancienne URL // ne pas regenerer des segments arbo, mais rediriger vers la nouvelle URL // dans la nouvelle forme if (strncmp($caller, "urls_", 5) == 0 and $caller !== "urls_decoder_url") { // en absolue, car assembler ne gere pas ce cas particulier include_spip('inc/filtres_mini'); $col_id = id_table_objet($entite); $url_new = generer_url_entite($contexte[$col_id], $entite); // securite contre redirection infinie if ($url_new !== $url_propre and rtrim($url_new, "/") !== rtrim($url_propre, "/")) { $url_redirect = url_absolue($url_new); } } else { foreach ($url_arbo_new as $k => $o) { if ($s = declarer_url_arbo($o['objet'], $o['id_objet'])) { $url_arbo_new[$k] = $s; } else { $url_arbo_new[$k] = implode('/', $o['segment']); } } $url_arbo_new = ltrim(implode('/', $url_arbo_new), '/'); if ($url_arbo_new !== $url_propre) { $url_redirect = $url_arbo_new; // en absolue, car assembler ne gere pas ce cas particulier include_spip('inc/filtres_mini'); $url_redirect = url_absolue($url_redirect); } } } // gerer le retour depuis des urls propres if (($entite == '' or $entite == 'type_urls') and $GLOBALS['profondeur_url'] <= 0) { $urls_anciennes = charger_fonction('propres', 'urls'); return $urls_anciennes($url_propre, $entite, $contexte); } } if ($entite == '' or $entite == 'type_urls') { if ($type) { $entite = objet_type($type); } else { // Si ca ressemble a une URL d'objet, ce n'est pas la home // et on provoque un 404 if (preg_match(',^[^\\.]+(\\.html)?$,', $url)) { $entite = '404'; $contexte['erreur'] = ''; // qu'afficher ici ? l'url n'existe pas... on ne sait plus dire de quel type d'objet il s'agit } } } define('_SET_HTML_BASE', 1); return array($contexte, $entite, $url_redirect, null); }
function urls_arbo_dist($i, $entite, $args='', $ancre='') { if (is_numeric($i)) return _generer_url_arbo($entite, $i, $args, $ancre); // traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23 if ($GLOBALS['profondeur_url']>0 AND $entite=='sommaire'){ $entite = 'type_urls'; } // recuperer les &debut_xx; if (is_array($args)) $contexte = $args; else parse_str($args,$contexte); $url = $i; $id_objet = $type = 0; $url_redirect = null; // Migration depuis anciennes URLs ? // traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23 if ($GLOBALS['profondeur_url']<=0 AND $_SERVER['REQUEST_METHOD'] != 'POST') { include_spip('inc/urls'); $r = nettoyer_url_page($i, $contexte); if ($r) { list($contexte, $type,,, $suite) = $r; $_id = id_table_objet($type); $id_objet = $contexte[$_id]; $url_propre = generer_url_entite($id_objet, $type); if (strlen($url_propre) AND !strstr($url,$url_propre)) { list(,$hash) = explode('#', $url_propre); $args = array(); foreach(array_filter(explode('&', $suite)) as $fragment) { if ($fragment != "$_id=$id_objet") $args[] = $fragment; } $url_redirect = generer_url_entite($id_objet, $type, join('&',array_filter($args)), $hash); return array($contexte, $type, $url_redirect, $type); } } } /* Fin compatibilite anciennes urls */ // Chercher les valeurs d'environnement qui indiquent l'url-propre if (isset($_SERVER['REDIRECT_url_propre'])) $url_propre = $_SERVER['REDIRECT_url_propre']; elseif (isset($_ENV['url_propre'])) $url_propre = $_ENV['url_propre']; else { // ne prendre que le segment d'url qui correspond, en fonction de la profondeur calculee $url = ltrim($url,'/'); $url = explode('/',$url); while (count($url)>$GLOBALS['profondeur_url']+1) array_shift($url); $url = implode('/',$url); $url_propre = preg_replace(',[?].*,', '', $url); } // Mode Query-String ? if (!$url_propre AND preg_match(',[?]([^=/?&]+)(&.*)?$,', $url, $r)) { $url_propre = $r[1]; } if (!$url_propre) return; // qu'est-ce qu'il veut ??? include_spip('base/abstract_sql'); // chercher dans la table des URLS // Revenir en utf-8 si encodage type %D8%A7 (farsi) $url_propre = rawurldecode($url_propre); // Compatibilite avec .htm/.html et autres terminaisons $t = array_diff(array_unique(array_merge(array('.html','.htm','/'),url_arbo_terminaison(''))),array('')); if (count($t)) $url_propre = preg_replace('{(' .implode('|',array_map('preg_quote',$t)).')$}i', '', $url_propre); if (strlen($url_propre) AND !preg_match(',^[^/]*[.]php,',$url_propre)){ $types_parents = array(); // recuperer tous les objets de larbo xxx/article/yyy/mot/zzzz $url_arbo = explode('/',$url_propre); while (count($url_arbo)>0){ $url_propre = array_pop($url_arbo); if (count($url_arbo)) $type = array_pop($url_arbo); else $type=null; // Compatibilite avec les anciens marqueurs d'URL propres // Tester l'entree telle quelle (avec 'url_libre' des sites ont pu avoir des entrees avec marqueurs dans la table spip_urls) if (is_null($type) OR !$row=sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote("$type/$url_propre")))) { if (!is_null($type)) array_push($url_arbo,$type); $row = sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote($url_propre))); } if ($row) { $type = $row['type']; $col_id = id_table_objet($type); // n'affecter que la premiere fois un parent de type id_rubrique if (!isset($contexte[$col_id])) $contexte[$col_id] = $row['id_objet']; if (!$entite OR !in_array($type,$types_parents)) $entite = $type; if ($p = url_arbo_parent($type)) $types_parents[]=end($p); } else { // un segment est inconnu if ($entite=='' OR $entite=='type_urls') { // on genere une 404 comme il faut si on ne sait pas ou aller return array(array(),'404'); } return; // ? } } // gerer le retour depuis des urls propres if (($entite=='' OR $entite=='type_urls') AND $GLOBALS['profondeur_url']<=0){ $urls_anciennes = charger_fonction('propres','urls'); return $urls_anciennes($url_propre, $entite, $contexte); } } if ($entite=='' OR $entite=='type_urls' /* compat .htaccess 2.0 */) { if ($type) $entite = ($type == 'syndic') ? 'site' : $type; else { // Si ca ressemble a une URL d'objet, ce n'est pas la home // et on provoque un 404 if (preg_match(',^[^\.]+(\.html)?$,', $url)) { $entite = '404'; $contexte['erreur'] = ''; // qu'afficher ici ? l'url n'existe pas... on ne sait plus dire de quel type d'objet il s'agit } } } define('_SET_HTML_BASE',1); return array($contexte, $entite, null, $is_qs?$entite:null); }