<?php namespace nur\v; use nur\A; use nur\str; use nur\v\model\IPage; /** * Class prefix: gestion des préfixes pour les URLs */ class prefix { static function get_base_url(): string { $base_url = getenv("BASE_URL"); if ($base_url !== false) { return str::without_suffix("/", parse_url($base_url, PHP_URL_PATH)); } else { return ""; } } /** * obtenir le chemin par défaut du script courant. * - si la variable d'environnement BASE_URL est définie, alors la valeur est * exacte. * - sinon, on part du principe que l'application ne sert des pages qu'à sa * racine, ce qui n'est pas forcément vrai * * la valeur retournée est * - soit le chemin avec le préfixe '/' e.g '/index.php' * - soir la chaine vide '' */ static function get_default_self(): string { $script_name = $_SERVER["SCRIPT_NAME"]; $base_url = getenv("BASE_URL"); if ($base_url !== false) { # d'abord, isoler le chemin de $base_url $base_url = str::without_suffix("/", parse_url($base_url, PHP_URL_PATH)); # puis enlever le préfixe return str::without_prefix($base_url, $script_name); } $pos = strrpos($script_name, "/"); if ($pos === false) return ""; return substr($script_name, $pos); } static function compute(?string $self): string { if ($self !== null) { if (substr($self, 0, 1) != "/") $self = "/$self"; } else { $self = self::get_default_self(); } $php_self = $_SERVER["PHP_SELF"]; $pos = strpos($php_self, $self); if ($pos === false) return ""; $prefix = ""; $offset = $pos + 1; while (($pos = strpos($php_self, "/", $offset)) !== false) { $prefix .= "../"; $offset = $pos + 1; } return $prefix; } static function add(string $url, ?string $prefix): string { if ($prefix === null) return $url; if (preg_match('/^(\/)|(https?:\/\/)/', $url)) { # l'url est de la forme /ANY ou http[s]://ANY # url absolue, laisser en l'état } elseif (str::starts_with("./", $url)) { # l'url est de la forme ./ANY # url relative $url = $prefix.substr($url, 2); } elseif (str::starts_with("__PREFIX__/", $url)) { # l'url est de la forme __PREFIX__/ANY # compatibilité: url exprimée par rapport au préfixe $url = $prefix.substr($url, 11); } else { # par défaut, l'url est exprimée par rapport au préfixe $url = $prefix.$url; } return $url; } ############################################################################# # exemple d'implémentation pour utiliser la valeur calculée de prefix /** * @var string chemin du script correspondant à la page courante, depuis la * racine de l'application e.g. index.php, ou null s'il faut utiliser la * valeur par défaut */ protected static $self; /** @var string */ protected static $prefix; static final function set_self(?string $self) { if ($self === null) $self = self::get_default_self(); self::$self = $self; self::$prefix = self::compute($self); } /** * construire un url avec les paramètres spécifiés. le cas échéant, corriger * l'url en fonction de $self * * cette méthode sera utilisée notamment pour des liens vers des resources * statiques */ static final function resu(string $url, ...$params): string { return html::bu(self::add($url, self::$prefix), ...$params); } /** * construire un url vers le composant destination avec les paramètres * spécifiés. le cas échéant, corriger l'url en fonction de $self * * @param string|IPage $dest composant destination */ static final function dynu($dest, ...$params): string { $url = $dest; #XXX $url = route::get_path($dest); return html::bu(self::add($url, self::$prefix), ...$params); } const BU_STATIC_PARTS = ["scheme", "host", "port", "query", "fragment"]; /** * méthode générique pour construire une url. utiliser des heuristiques pour * déterminer si la destination est une url statique ou si c'est un composant */ static final function bu($dest, ...$params): string { $dyn = true; if (is_string($dest)) { # heuristiques pour déterminer si c'est une url statique $parts = parse_url($dest); foreach (self::BU_STATIC_PARTS as $part) { if (A::has($parts, $part)) { # y a-t-il au moins une partie d'une url statique? $dyn = false; break; } } if ($dyn) { # s'il n'y a qu'un chemin, tester si ça ressemble à une url $path = A::get($parts, "path", ""); if ($path === "" || $path === ".") $dyn = false; elseif (strpos($path, "/")) $dyn = false; elseif (preg_match('/\.(php|html)\b/', $path)) $dyn = false; } } if ($dyn) { # tenir compte du préfixe, puisque les chemins des composants sont # toujours exprimés depuis la racine $url = $dest; #XXX $url = route::get_path($dest); return html::bu(self::add($url, self::$prefix), ...$params); } else { # ne pas corriger une url statique: on fait confiance à l'utilisateur pour # utiliser des chemins relatifs return html::bu($dest, ...$params); } } }