route = $route; $this->controllerName = $this->parseController($route); $this->methodName = $this->parseMethod($route); $this->params = $this->parseParams($route); } else { $this->route = ''; $this->controllerName = ''; $this->methodName = ''; $this->params = ''; } } //Getters et setters public function getRoute() { return $this->route; } public function setRoute($value) { $this->route = $route; } public function getControllerName() { return $this->controllerName; } public function setControllerName($value) { $this->controllerName = $value; } public function getMethodName() { return $this->methodName; } public function setMethodName($value) { $this->methodName = $value; } public function getParams() { return $this->params; } public function setParams($value) { $this->params = $value; } /** * Cette méthode retourne la page 404 par défaut */ public function return404 () { http_response_code(404); include(PWD . 'mvc/404.php'); die(); } /** * Retourne une route avec seulement l'url parsée comme il faut * @param string $route : La route à analyser * @return array : Le tableau de la route parsée */ public function parseRoute($route) { $directory_to_remove = strstr(preg_replace('#http(s)?://#', '', HTTP_PWD), '/'); //On retire la partie protocole, et l'adresse du serveur de la partie de la route à ignorer $route = mb_strcut($route, mb_strlen($directory_to_remove)); //On retire la partie à ignorer de la route $route = explode('?', $route)[0]; //on ne garde que ce qui précède les arguments $route = preg_split('#[/]#', $route); //On explose la route foreach($route as $key => $val) //On garde seulement les repertoires non vides { if(empty($val) && $val !== 0 && $val !== '0') { unset($route[$key]); } } $route = array_values($route); //On remet à 0 les index pour obtenir un tableau propre return $route; } /** * Retrouve le controlleur dans un URL * @param string $route : la route à analyser * @return string : Le nom du controleur */ public function parseController($route) { $route = $this->parseRoute($route); //On récupère la route parsé //Si pas de controlleur, on prend celui par défaut if (empty($route[0])) { return DEFAULT_CONTROLLER; } //Sinon, si le controlleur n'existe pas ou est internal, on retourne une 404 if (!file_exists(PWD_CONTROLLER . $route[0] . '.php') || mb_strpos($route[0], 'internal') !== false) { return $this->return404(); } //On retourne le controlleur adapté return $route[0]; } /** * Retrouve la méthode dans un URL * @param string $route : la route à analyser * @return string : Le nom de la methode */ public function parseMethod($route) { //On instancie le controlleur $controllerName = $this->parseController($route); $controller = new $controllerName(); $prefixMethod = ''; //On recupère les paramètres dans l'url pour les utiliser un peu plus tard $params = $this->parseParams($route); //On vérifie si le controlleur est un controlleur API, si c'est le cas on le refais avec cette fois la bonne methode if ($controller instanceof ApiController) { //On va choisir le type à employer $method = $_SERVER['REQUEST_METHOD']; switch (mb_convert_case($method, MB_CASE_LOWER)) { case 'delete' : $prefixMethod = 'delete'; break; case 'patch' : $prefixMethod = 'patch'; break; case 'post' : $prefixMethod = 'post'; break; case 'put' : $prefixMethod = 'put'; break; default : $prefixMethod = 'get'; } } $route = $this->parseRoute($route); //On récupère la route parsé //On regarde quelle route il nous faut et on evite les routes qui commencent par '_', qui sont maintenant considérées comme privées if (empty($route[1])) { $method = DEFAULT_METHOD; } else { $method = $route[1]; } if ($prefixMethod) { $method = $prefixMethod . mb_convert_case($method, MB_CASE_TITLE); } //Si la méthode à appeler n'existe pas ou si la route commencent par '_', signe qu'elle est un outils non accessibles if (!method_exists($controller, $method) || mb_substr($method, 0, 1) == '_') { return $this->return404(); } //On instancie la classe reflection de PHP sur la méthode que l'on veux analyser pour l'objet controller $methodAnalyser = new ReflectionMethod($controller, $method); //Si la méthode à appeler demande plus de paramètres que fournis on retourne une 404 if ($methodAnalyser->getNumberOfRequiredParameters() > count($params)) { return $this->return404(); } return $method; } /** * Retrouve les paramètres dans un URL * @param string $route : la route à analyser * @return array : La liste des paramètres au format $clef => $valeur */ public function parseParams($route) { $route = $this->parseRoute($route); //On récupère la route parsé $params = array(); //On transforme les paramètres $_GET passés par l'url au format clef-value. Ex : prenom-pierre-lin = $_GET['prenom'] => 'pierre-lin' if (count($route) > 2) //Si on a plus de deux paramètres qui ont été passé { unset($route[0], $route[1]); //On supprime le controlleur, et la route, des paramètres, il ne reste que les parametres a passer en GET foreach ($route as $param) { $params[] = rawurldecode($param); } } return $params; } /** * Cette fonction permet de vérifier si le cache est activé pour une route, et si oui quel fichier utiliser * @param string $route : Route à analyser * @return mixed : Si pas de cache, faux. Sinon un tableau avec deux clefs, "state" => statut du nom de fichier retourné (true, le fichier doit être utilisé, false, le fichier doit être créé), "file" => Le nom du fcihier de cache */ public function verifyCache($route) { //On récupère le nom du controller et de la méthode $controllerName = $this->parseController($route); $methodName = $this->parseMethod($route); $params = $this->parseParams($route); $controller = new $controllerName(); //Si on ne doit pas activer le cache ou si on na pas de cache pour ce fichier if (!ACTIVATING_CACHE || !property_exists($controller, 'cache_' . $methodName)) { return false; } //Si on a du cache, on va déterminer le nom approprié //Format de nom = $hashName = md5($controllerName . $methodName); $hashDatas = md5(json_encode($_GET) . json_encode($_POST) . json_encode($params)); $fileName = $hashName . $hashDatas; //Si il n'existe pas de fichier de cache pour ce fichier if (!file_exists(PWD_CACHE . $fileName)) { return array('state' => false, 'file' => $fileName); } //Sinon, si le fichier de cache existe $fileLastChange = filemtime(PWD_CACHE . $fileName); //On calcul la date de mise à jour valide la plus ancienne possible $now = new DateTime(); $propertyName = 'cache_' . $methodName; $propertyValue = $controller->$propertyName; $now->sub(new DateInterval('PT' . $propertyValue . 'M')); $maxDate = $now->format('U'); //Si le fichier de cache est trop vieux if ($fileLastChange < $maxDate) { return array('state' => false, 'file' => $fileName); } //Sinon, on retourne le fichier de cache en disant de l'utiliser return array('state' => true, 'file' => $fileName); } /** * Cette fonction permet de charger la page adaptée a partir d'une url * Elle gère également le cache * @param string $route : Route à analyser pour charger une page * @return void */ public function loadRoute($route) { $params = $this->parseParams($route); //On récupère les paramètres à passer à la fonction $controllerName = $this->parseController($route); //On récupère le nom du controleur à appeler $controller = new $controllerName(); //On créer le controleur $beforeMethodName = DEFAULT_BEFORE; //On défini le nom de la fonction before if (method_exists($controller, $beforeMethodName)) //Si une fonction before existe pour ce controller, on l'appel { $controller->$beforeMethodName(); //On appel la fonction before } $methodName = $this->parseMethod($route); //On récupère le nom de la méthode $verifyCache = $this->verifyCache($route); //Si on ne doit pas utiliser de cache if ($verifyCache === false) { call_user_func_array(array($controller, $methodName), $params); //On appel la methode, en lui passant les arguments necessaires return null; } //Si on doit utiliser un cache avec un nouveau fichier if ($verifyCache['state'] == false) { //On créer le fichier avec le contenu adapté ob_start(); call_user_func_array(array($controller, $methodName), $params); //On appel la methode, en lui passant les arguments necessaires $content = ob_get_contents(); file_put_contents(PWD_CACHE . $verifyCache['file'], $content); ob_end_clean(); } //On utilise le fichier de cache readfile(PWD_CACHE . $verifyCache['file']); } }