[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / inc / urls.php
index 108b805..06b4de7 100644 (file)
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2016                                                *
+ *  Copyright (c) 2001-2017                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
 \***************************************************************************/
 
-if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Gestion des URLS
+ *
+ * @package SPIP\Core\URLs
+ **/
+
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
 include_spip('base/objets');
 
 /**
- * Decoder une url en utilisant les fonctions inverse
- * gestion des URLs transformee par le htaccess
- * $renommer = 'urls_propres_dist';
- * renvoie array($contexte, $type, $url_redirect, $nfond)
- * $nfond n'est retourne que si l'url est definie apres le ?
- * et risque d'etre effacee par un form en get
- * elle est utilisee par form_hidden exclusivement
- * Compat ascendante si le retour est null en gerant une sauvegarde/restauration
- * des globales modifiees par les anciennes fonctions
+ * Décoder une URL en utilisant les fonctions inverses
+ *
+ * Gère les URLs transformées par le htaccess.
+ *
+ * @note
+ *   `$renommer = 'urls_propres_dist';`
+ *   renvoie `array($contexte, $type, $url_redirect, $nfond)`
+ *
+ *   `$nfond` n'est retourné que si l'URL est définie apres le `?`
+ *   et risque d'être effacée par un form en get.
+ *   Elle est utilisée par form_hidden exclusivement.
+ *
+ *   Compat ascendante si le retour est NULL en gérant une sauvegarde/restauration
+ *   des globales modifiées par les anciennes fonctions
  *
  * @param string $url
- *  url a decoder
+ *   URL à décoder
  * @param string $fond
- *  fond initial par defaut
+ *   Fond initial par défaut
  * @param array $contexte
- *  contexte initial a prendre en compte
+ *   Contexte initial à prendre en compte
  * @param bool $assembler
- *     true si l'url correspond a l'url principale de la page qu'on est en train d'assembler
- *  dans ce cas la fonction redirigera automatiquement si besoin
- *  et utilisera les eventuelles globales $_SERVER['REDIRECT_url_propre'] et $_ENV['url_propre']
- *  provenant du htaccess
+ *   `true` si l'URL correspond à l'URL principale de la page qu'on est en train d'assembler
+ *   dans ce cas la fonction redirigera automatiquement si besoin
+ *   et utilisera les eventuelles globales `$_SERVER['REDIRECT_url_propre']` et `$_ENV['url_propre']`
+ *   provenant du htaccess
  * @return array
- *  ($fond,$contexte,$url_redirect)
- *  si l'url n'est pas valide, $fond restera a la valeur initiale passee
- *  il suffit d'appeler la fonction sans $fond et de verifier qu'a son retour celui-ci
- *  est non vide pour verifier une url
+ *   Liste `$fond, $contexte, $url_redirect`.
+ *
+ *   Si l'url n'est pas valide, $fond restera à la valeur initiale passée.
+ *   Il suffit d'appeler la fonction sans $fond et de vérifier qu'à son retour celui-ci
+ *   est non vide pour vérifier une URL
  *
  */
-function urls_decoder_url($url, $fond='', $contexte=array(), $assembler=false){
+function urls_decoder_url($url, $fond = '', $contexte = array(), $assembler = false) {
        static $current_base = null;
+
        // les anciennes fonctions modifient directement les globales
        // on les sauve avant l'appel, et on les retablit apres !
-       $save = array(@$GLOBALS['fond'],@$GLOBALS['contexte'],@$_SERVER['REDIRECT_url_propre'],@$_ENV['url_propre'],$GLOBALS['profondeur_url']);
-       if (is_null($current_base)){
+       $save = array(
+               isset($GLOBALS['fond']) ? $GLOBALS['fond'] : null,
+               isset($GLOBALS['contexte']) ? $GLOBALS['contexte'] : null,
+               isset($_SERVER['REDIRECT_url_propre']) ? $_SERVER['REDIRECT_url_propre'] : null,
+               isset($_ENV['url_propre']) ? $_ENV['url_propre'] : null,
+               $GLOBALS['profondeur_url']
+       );
+
+       if (is_null($current_base)) {
                include_spip('inc/filtres_mini');
                // le decodage des urls se fait toujours par rapport au site public
-               $current_base = url_absolue(_DIR_RACINE?_DIR_RACINE:'./');
+               $current_base = url_absolue(_DIR_RACINE ? _DIR_RACINE : './');
+       }
+       if (strncmp($url, $current_base, strlen($current_base)) == 0) {
+               $url = substr($url, strlen($current_base));
        }
-       if (strncmp($url,$current_base,strlen($current_base))==0)
-               $url = substr($url,strlen($current_base));
 
-       // si on est pas en train d'assembler la page principale,
-       // vider les globales url propres qui ne doivent pas etre utilisees en cas
-       // d'inversion url => objet
-       if (!$assembler) {
-               unset($_SERVER['REDIRECT_url_propre']);
-               unset($_ENV['url_propre']);
-               include_spip('inc/filtres_mini');
-               if (strpos($url,"://")===false){
-            $GLOBALS['profondeur_url'] = substr_count(ltrim(resolve_path("/$url"),'/'),'/');
-    }
-    else {
-            $GLOBALS['profondeur_url'] = max(0,substr_count($url,"/")-substr_count($current_base,"/"));
-    }
+       // si on est en train d'assembler la page principale,
+       // recuperer l'url depuis les globales url propres si fournies
+       // sinon extraire la bonne portion d'url
+       if ($assembler) {
+               if (isset($_SERVER['REDIRECT_url_propre'])) {
+                       $url = $_SERVER['REDIRECT_url_propre'];
+               } elseif (isset($_ENV['url_propre'])) {
+                       $url = $_ENV['url_propre'];
+               } else {
+                       $qs = explode("?", $url);
+                       // ne prendre que le segment d'url qui correspond, en fonction de la profondeur calculee
+                       $url = ltrim($qs[0], '/');
+                       $url = explode('/', $url);
+                       while (count($url) > $GLOBALS['profondeur_url'] + 1) {
+                               array_shift($url);
+                       }
+                       $qs[0] = implode('/', $url);
+                       $url = implode("?", $qs);
+               }
+       }
+
+       unset($_SERVER['REDIRECT_url_propre']);
+       unset($_ENV['url_propre']);
+       include_spip('inc/filtres_mini');
+       if (strpos($url, "://") === false) {
+               $GLOBALS['profondeur_url'] = substr_count(ltrim(resolve_path("/$url"), '/'), '/');
+       } else {
+               $GLOBALS['profondeur_url'] = max(0, substr_count($url, "/") - substr_count($current_base, "/"));
        }
 
-       
        $url_redirect = "";
-       $renommer = generer_url_entite('','','','',true);
-       if (!$renommer AND !function_exists('recuperer_parametres_url'))
-               $renommer = charger_fonction('page','urls'); // fallback pour decoder l'url
+       $renommer = generer_url_entite('', '', '', '', true);
+       if (!$renommer and !function_exists('recuperer_parametres_url')) {
+               $renommer = charger_fonction('page', 'urls');
+       } // fallback pour decoder l'url
        if ($renommer) {
                $a = $renommer($url, $fond, $contexte);
                if (is_array($a)) {
                        list($ncontexte, $type, $url_redirect, $nfond) = array_pad($a, 4, null);
-                       if ($url_redirect == $url)
-                               $url_redirect = ""; // securite pour eviter une redirection infinie
-                       if ($assembler AND strlen($url_redirect)) {
+                       if ($url_redirect == $url) {
+                               $url_redirect = "";
+                       } // securite pour eviter une redirection infinie
+                       if ($assembler and strlen($url_redirect)) {
                                spip_log("Redirige $url vers $url_redirect");
                                include_spip('inc/headers');
                                redirige_par_entete($url_redirect, '', 301);
                        }
-                       if (isset($nfond))
+                       if (isset($nfond)) {
                                $fond = $nfond;
-                       else if ($fond == ''
-                       OR $fond == 'type_urls' /* compat avec htaccess 2.0.0 */
-                       )
-                               $fond = $type;
-                       if (isset($ncontexte))
+                       } else {
+                               if ($fond == ''
+                                       or $fond == 'type_urls' /* compat avec htaccess 2.0.0 */
+                               ) {
+                                       $fond = $type;
+                               }
+                       }
+                       if (isset($ncontexte)) {
                                $contexte = $ncontexte;
-                       if (defined('_DEFINIR_CONTEXTE_TYPE') AND _DEFINIR_CONTEXTE_TYPE)
+                       }
+                       if (defined('_DEFINIR_CONTEXTE_TYPE') and _DEFINIR_CONTEXTE_TYPE) {
                                $contexte['type'] = $type;
-                       if (defined('_DEFINIR_CONTEXTE_TYPE_PAGE') AND _DEFINIR_CONTEXTE_TYPE_PAGE)
+                       }
+                       if (defined('_DEFINIR_CONTEXTE_TYPE_PAGE') and _DEFINIR_CONTEXTE_TYPE_PAGE) {
                                $contexte['type-page'] = $type;
+                       }
                }
-       }
-       // compatibilite <= 1.9.2
+       } // compatibilite <= 1.9.2
        elseif (function_exists('recuperer_parametres_url')) {
                $GLOBALS['fond'] = $fond;
                $GLOBALS['contexte'] = $contexte;
@@ -110,8 +155,8 @@ function urls_decoder_url($url, $fond='', $contexte=array(), $assembler=false){
        }
 
        // retablir les globales
-       list($GLOBALS['fond'],$GLOBALS['contexte'],$_SERVER['REDIRECT_url_propre'],$_ENV['url_propre'],$GLOBALS['profondeur_url']) = $save;
-       
+       list($GLOBALS['fond'], $GLOBALS['contexte'], $_SERVER['REDIRECT_url_propre'], $_ENV['url_propre'], $GLOBALS['profondeur_url']) = $save;
+
        // vider les globales url propres qui ne doivent plus etre utilisees en cas
        // d'inversion url => objet
        // maintenir pour compat ?
@@ -120,101 +165,114 @@ function urls_decoder_url($url, $fond='', $contexte=array(), $assembler=false){
        #       unset($_ENV['url_propre']);
        #}
 
-       return array($fond,$contexte,$url_redirect);
+       return array($fond, $contexte, $url_redirect);
 }
 
 
 /**
- * Lister les objets pris en compte dans les urls
- * c'est a dire suceptibles d'avoir une url propre
+ * Lister les objets pris en compte dans les URLs
+ * c'est à dire suceptibles d'avoir une URL propre
  *
  * @param bool $preg
- *  permet de definir si la fonction retourne une chaine avec | comme separateur
+ *  Permet de définir si la fonction retourne une chaine avec `|` comme séparateur
  *  pour utiliser en preg, ou un array()
- * @return string/array
+ * @return string|array
  */
-function urls_liste_objets($preg = true){
+function urls_liste_objets($preg = true) {
        static $url_objets = null;
-       if (is_null($url_objets)){
+       if (is_null($url_objets)) {
                $url_objets = array();
                // recuperer les tables_objets_sql declarees
                $tables_objets = lister_tables_objets_sql();
-               foreach($tables_objets as $t=>$infos){
+               foreach ($tables_objets as $t => $infos) {
                        if ($infos['page']) {
                                $url_objets[] = $infos['type'];
-                               $url_objets = array_merge($url_objets,$infos['type_surnoms']);
+                               $url_objets = array_merge($url_objets, $infos['type_surnoms']);
                        }
                }
-               $url_objets = pipeline('declarer_url_objets',$url_objets);
+               $url_objets = pipeline('declarer_url_objets', $url_objets);
+       }
+       if (!$preg) {
+               return $url_objets;
        }
-       if (!$preg) return $url_objets;
-       return implode('|',array_map('preg_quote',$url_objets));
+
+       return implode('|', array_map('preg_quote', $url_objets));
 }
 
 /**
- * Nettoyer une url, en reperant notamment les raccourcis d'entites
- * comme ?article13, ?rubrique21 ...
- * et en les traduisant pour completer le contexte fourni en entree
+ * Nettoyer une URL, en repérant notamment les raccourcis d'objets
+ *
+ * Repère les entités comme `?article13`, `?rubrique21` ...
+ * les traduisant pour compléter le contexte fourni en entrée
  *
  * @param string $url
  * @param array $contexte
  * @return array
  */
-function nettoyer_url_page($url, $contexte=array())
-{
+function nettoyer_url_page($url, $contexte = array()) {
        $url_objets = urls_liste_objets();
-       $raccourci_url_page_html = ',^(?:[^?]*/)?('. $url_objets . ')([0-9]+)(?:\.html)?([?&].*)?$,';
-       $raccourci_url_page_id = ',^(?:[^?]*/)?('. $url_objets .')\.php3?[?]id_\1=([0-9]+)([?&].*)?$,';
-       $raccourci_url_page_spip = ',^(?:[^?]*/)?(?:spip[.]php)?[?]('. $url_objets .')([0-9]+)=?(&.*)?$,';
+       $raccourci_url_page_html = ',^(?:[^?]*/)?(' . $url_objets . ')([0-9]+)(?:\.html)?([?&].*)?$,';
+       $raccourci_url_page_id = ',^(?:[^?]*/)?(' . $url_objets . ')\.php3?[?]id_\1=([0-9]+)([?&].*)?$,';
+       $raccourci_url_page_spip = ',^(?:[^?]*/)?(?:spip[.]php)?[?](' . $url_objets . ')([0-9]+)=?(&.*)?$,';
 
        if (preg_match($raccourci_url_page_html, $url, $regs)
-       OR preg_match($raccourci_url_page_id, $url, $regs)
-       OR preg_match($raccourci_url_page_spip, $url, $regs)) {
+               or preg_match($raccourci_url_page_id, $url, $regs)
+               or preg_match($raccourci_url_page_spip, $url, $regs)
+       ) {
+               $regs = array_pad($regs, 4, null);
                $type = objet_type($regs[1]);
                $_id = id_table_objet($type);
                $contexte[$_id] = $regs[2];
                $suite = $regs[3];
+
                return array($contexte, $type, null, $type, $suite);
        }
+
        return array();
 }
 
 /**
- * Generer l'url d'un objet dans l'espace prive,
- * fonction de son etat publie ou non
- * calcule a partir de la declaration de statut
+ * Générer l'URL d'un objet dans l'espace privé
+ *
+ * L'URL est calculée en fonction de son état publié ou non,
+ * calculé à partir de la déclaration de statut.
  *
- * @param int $id
+ * @param string $objet Type d'objet
+ * @param int $id Identifiant de l'objet
  * @param string $args
  * @param string $ancre
- * @param string $statut
+ * @param bool|null $public
  * @param string $connect
  * @return string
  *
  */
-function generer_url_ecrire_objet($objet,$id, $args='', $ancre='', $public=null, $connect=''){
+function generer_url_ecrire_objet($objet, $id, $args = '', $ancre = '', $public = null, $connect = '') {
        static $furls = array();
-       if (!isset($furls[$objet])){
+       if (!isset($furls[$objet])) {
                if (function_exists($f = 'generer_url_ecrire_' . $objet)
                        // ou definie par un plugin
-                       OR $f = charger_fonction($f,'urls',true))
+                       or $f = charger_fonction($f, 'urls', true)
+               ) {
                        $furls[$objet] = $f;
-               else
+               } else {
                        $furls[$objet] = '';
+               }
        }
-       if ($furls[$objet])
+       if ($furls[$objet]) {
                return $furls[$objet]($id, $args, $ancre, $public, $connect);
+       }
        // si pas de flag public fourni
        // le calculer en fonction de la declaration de statut
-       if (is_null($public) AND !$connect)
+       if (is_null($public) and !$connect) {
                $public = objet_test_si_publie($objet, $id, $connect);
-       if ($public OR $connect){
+       }
+       if ($public or $connect) {
                return generer_url_entite_absolue($id, $objet, $args, $ancre, $connect);
        }
        $a = id_table_objet($objet) . "=" . intval($id);
-       if (!function_exists('objet_info'))
+       if (!function_exists('objet_info')) {
                include_spip('inc/filtres');
-       return generer_url_ecrire(objet_info($objet,'url_voir'), $a . ($args ? "&$args" : '')). ($ancre ? "#$ancre" : '');
-}
+       }
 
-?>
+       return generer_url_ecrire(objet_info($objet, 'url_voir'), $a . ($args ? "&$args" : '')) . ($ancre ? "#$ancre" : '');
+}