Bonjour,

J'ai crée un mini-framework à l'aide de la base que nous a fournis Grafikart, avec le Router.

J'ai cependant un problème sur le serveur, l'url me met 2 slash : www.url.com//{route}

Voici mon htaccess :

# Rediriger toutes les urls sur "index.php?url=URL"

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://www.domain.com/$1 [R=301,L]

Router.php :

<?php 

namespace App\Router;

/**
 * Gère les routes de notre application
 */
class Router {

    /**
     * Url passé en paramètre
     * @var string
     */
    private static $url;

    /**
     * Tableau contenant toutes les routes de notre application (GET, POST, ...)
     * @var array
     */
    private static $routes = [];

    /**
     * Routes portant un nom
     * @var array
     */
    private static $namedRoutes = [];

    /**
     * Initialisation de la classe router
     * @return void
     */
    public static function init() {
        self::$url = $_GET['url'];
    }

    /**
     * Renvoie une page en GET
     * @param  string
     * @param  function
     * @return route
     */
    public static function get($path, $callable, $name = null) {
        return self::add($path, $callable, $name, 'GET');
    }

    /**
     * Renvoie une page en POST
     * @param  string
     * @param  function
     * @return route
     */
    public static function post($path, $callable, $name = null) {
        return self::add($path, $callable, $name, 'POST');
    }

    /**
     * Ajouter une route à notre router
     * @param string
     * @param function
     * @param string 'GET, POST, ...'
     */
    private static function add($path, $callable, $name, $method) {
        $route = new Route($path, $callable);
        self::$routes[$method][] = $route;

        if ($name) {
            self::$namedRoutes[$name] = $route;
        }

        return $route;
    }

    /**
     * Lance le routing
     * @return function
     */
    public static function run() {
        if (!isset(self::$routes[$_SERVER['REQUEST_METHOD']])) {
            throw new RouterException('REQUEST_METHOD doesn\'t exist');
        }

        foreach(self::$routes[$_SERVER['REQUEST_METHOD']] as $route) {
            if ($route->match(self::$url)) {
                return $route->call();
            }
        }
        throw new RouterException('No matching routes');
    }

    /**
     * Retourne l'URL d'une route nommée
     * @param  string
     * @param  array
     * @return string
     */
    public static function url($name, $params = []) {
        if (!isset(self::$namedRoutes[$name])) {
            throw new RouterException("No routes matches this name '$name'.");
        }

        return self::$namedRoutes[$name]->getUrl($params);
    }

}

Route.php :

<?php 

namespace App\Router;

/**
 * Une route
 */
class Route {

    /**
     * Chemin de la route
     * @var string
     */
    private $path;

    /**
     * Fonction anonyme
     * @var function
     */
    private $callable;

    /**
     * Correspondances avec une route du router
     * @var array
     */
    private $matches = [];

    /**
     * Paramètres de la route
     * @var array
     */
    private $params = [];

    /**
     * @param string
     * @param function
     */
    public function __construct($path, $callable) {
        $this->path = trim($path, '/');
        $this->callable = $callable;
    }

    /**
     * Permet d'ajouter des conditions à la route
     * @param  param paramètre où faire la condition
     * @param  regex expression régulière
     * @return route
     */
    public function with($param, $regex) {
        $this->params[$param] = str_replace('(', '(?:', $regex);
        return $this;
    }

    /**
     * On check si la route match l'url
     * @param  url
     * @return boolean
     */
    public function match($url) {
        $url = trim($url, '/');
        $path = preg_replace_callback('#{([\w]+)}#', [$this, 'paramMatch'], $this->path);
        $regex = "#^$path$#i";

        if (!preg_match($regex, $url, $matches)) {
            return false;
        }

        array_shift($matches);
        $this->matches = $matches;

        return true;
    }

    /**
     * On teste si le paramètre "match" avec ce qu'on a dans $this->params
     * @param  match
     * @return regex
     */
    private function paramMatch($match) {
        if (isset($this->params[$match[1]])) {
            return '(' . $this->params[$match[1]] . ')';
        }

        return '([^/]+)';
    }

    /**
     * On appelle la fonction passé en paramètre pour la route (controller ou anonyme)
     * @return function
     */
    public function call() {
        if (is_string($this->callable)) {
            $params = explode('@', $this->callable);
            $controller = "App\\Controller\\" . $params[0];

            $controller = new $controller();

            return call_user_func_array([$controller, $params[1]], $this->matches);
        } else {
            return call_user_func_array($this->callable, $this->matches);
        }
    }

    /**
     * Retourne l'URL de la route avec les paramètres donnés
     * @param  array
     * @return string
     */
    public function getUrl($params) {
        $path = $this->path;
        foreach($params as $k => $v) {
            $path = str_replace("{" . $k . "}", $v, $path);
        }

        if (isset($_SERVER['HTTPS'])) {
            return 'https://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/' . $path;
        }

        return 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/' . $path;
    } 

}

Je viens vers vous car j'ai tout essayé pendant quelques heures, mais je n'arrive pas à règler le problème. Le site fonctionne correctement à part ces 2 slahs !!

Merci beaucoup,
Théo.

2 réponses


Huggy
Réponse acceptée

Dans la méthode getUrl, la fonction dirname($_SERVER['PHP_SELF']) renvoie un slash au début mais pas à la fin, tu en rajoutes un OK
mais dans la cas où tu es à la racine du site, dirname renvoie quand même le slash de début (anti-slash sous windows)
donc tu en a deux

il faut soit traiter le cas particulier de la racine, soit utiliser une constante BASE_URL qui remplacera le dirname
define('BASE_URL', '/'); // http://monsite.com/
ou
define('BASE_URL', '/monsite/'); //wamp http://localhost/monsite/

return 'https://' . $_SERVER['HTTP_HOST'] . BASE_URL . $path;

Merci beaucoup !!

Je ne savais pas du tout cela, et étant donné qu'en local ça ne me faisait pas pareil ^^
En tout cas merci, c'est très gentil !

Bonne soirée,
Cordialement.