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.
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.