vendor\klio\klio-bundle\src\Symfony\RouteController.php line 287
<?phpnamespace Klio\KlioBundle\Symfony;use voku\helper\HtmlMin;use App\Controller\Routes;use Klio\KlioBundle\Form\Form;use Klio\KlioBundle\Files\File;use Klio\KlioBundle\Files\Image;use Klio\KlioBundle\Security\Hash;use Klio\KlioBundle\Security\Crypt;use Klio\KlioBundle\Security\ClientIp;use Klio\KlioBundle\Files\UploadedFile;use Klio\KlioBundle\FileSystem\FsUtils;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;class RouteController extends AbstractController{private Request $request;private HtmlSanitizerInterface $sanitizer;protected Controller $controller;/*** les constantes*//*** On empèche de créer d'autres propriétées que celes d'origine** @param [type] $name* @param [type] $value*/public function __set($name, $value){throw new \Exception("Cannot add or change property \$$name to instance of " . __CLASS__);}/*** Configuration initiale et commune à toutes les routes, création des constantes** @param string $configFile Fichier de config complémentaire optionnel* @return void*/public function init(string $configFile = ""): void{$this->request = $this->container->get('request_stack')->getCurrentRequest();$this->controller = new Controller($this);global $SESSION;$SESSION = $this->request->getSession();// on defini une constante ROOT qui donne le path versdefine('__ROOT__', FsUtils::localPathSanitizer($this->getParameter('kernel.project_dir')));define('__PRIVATE__', __ROOT__ . '/private');// l'hôte du sitedefine('__HOST__', $_SERVER['SERVER_NAME']);// mode DEV ?define('__DEV__', $_ENV["APP_ENV"] === "dev");// mode recette ?define("__RECETTE__", @$_ENV['APP_MODE'] === 'recette');//Import des variables d'environnement du fichier de conf du store$store = $_ENV['STORE_FOLDER'];if (substr($store, 0, 1) == "/" && substr($store, 0, 2) != "//" && substr($store, 0, 6) != "/Users") $store = __ROOT__ . $store;define("__STORE_FOLDER__", $store);define('__STORE__', $store);unset($store);// upload folder, dossier ou on stocke tous les fichiers téléchargésdefine('__UPLOAD__', __STORE__ . '/upload');define('__APP_USER__', $_ENV["APP_USER"]);define('__PHILIPPE__', $_ENV['APP_USER'] === "philippe");define('__SAMI__', $_ENV['APP_USER'] === "sami");// temp folder$temp = $_ENV['TEMP_FOLDER'];if (substr($temp, 0, 1) == "/" && substr($temp, 0, 6) != "/Users") $temp = __ROOT__ . $temp;define('__TEMP__', $temp);unset($temp);include_once(__STORE_FOLDER__ . '/Config.php');// les éléments liés à l'IP /Klio/Scecurity/ClientIP$IP = new ClientIp();// l'IP du clientdefine("__IP__", $IP->getIp());// est-ce une IP KLIO ?define("__ISKLIO__", $IP->isKlio());// est-ce une IP CAF ?define("__ISCAF__", $IP->isCaf());// est-ce une IP audit ?//define("__ISAUDIT__", $IP->isAudit());// est-ce une IP de confiance ?define("__SECUREIP__", $IP->isSecure()); //// desctruction de l'objet une fois les constantes définiesunset($IP);// clé de salage pour les fonctions de cryptographiedefine('__SALT__', 'Phu42J;/Q7kBv+8n9zSMxZ+ekAR+EKQc7ZzRéYezz/8twk0F91jD/mq0J,DjC4!ON6%*5tïfZ7sçlg');// l'URL appelée par le client, si elle se termine par un slash, on enève le slash final$url = $this->request->getPathInfo();define('__USER_URL__', $url); // on garde le slash final pour le mode compatibilité avec le FW7 et le FW4if (substr($url, -1) === "/") $url = substr($url, 0, -1);define('__URL__', $url);// le chemin local, dans /private qui correspond à l'URLdefine('__PATH__', FsUtils::routeSanitizer($this->request->getPathInfo()));define('__PATHDIR__', FsUtils::dirSanitizer($this->request->getPathInfo()));// public folder pathdefine('__PUBLIC__', getcwd());// token de sessionif (!$SESSION->get("TOKEN")) {$SESSION->set("TOKEN", Hash::uuid62());}define('__TOKEN__', $SESSION->get("TOKEN"));//if (!$SESSION->get("CRYPTOKEY")) {$SESSION->set("CRYPTOKEY", Crypt::newKey());}define('__CRYPTOKEY__', $SESSION->get("CRYPTOKEY"));}/*** On traite toutes les variables pour ortenir une reponse soit par du code direct, soit via un twig* Cette fonction sert de setter aux deux éléments essentiels : ->response et ->status** @return void*/protected function routeResponse(){/*** __URL__ = l'URL saisie* les chemins de traitement d'image ou de fichiers* on les traite avant les pages car ils peuvet avoir des caractères spéciaux dans l'URL ( Exemple : /pdf/newsletter/Newsletter%20Janvier.pdf)*/if (stripos(__URL__, '/i/') === 0) {/*fontion image/i/folder/hash/format/nom_de_l_image.jpg ou /i/folder/hash/nom_de_l_image.jpgformat : 0x200 , c200x200, c0x200o0x0b100x200c = cropo = originb = boxdossier non sécure, on met l'image en cachedossier secure, on utilise obligatoirement un php avec test d'accès*/// on peut avoir une fonction personnalisée dans un controller à la racine de private /private/_file/Controller.phpif (!file_exists(__PRIVATE__ . '/_config/_i/Controller.php')) {Image::getImage(__URL__);exit();}}// téléchargement forcé (image ou pdf ne s'ouvre pas dans le navigateur mais en téléchargement)if (stripos(__URL__, '/d/') === 0) {// on peut avoir une fonction personnalisée dans un controller à la racine de private /private/_download/Controller.phpif (!file_exists(__PRIVATE__ . '/_config/routes/_d/Controller.php')) {$file = new File(__URL__);$file->download();} else $this->controller->setController('/_config/routes/_d/Controller.php');}// chargement de fichier (image ou pdf s'ouvre dans le navigateur)if (stripos(__URL__, '/f/') === 0) {// on peut avoir une fonction personnalisée dans un controller à la racine de private /private/_file/Controller.phpif (!file_exists(__PRIVATE__ . '/_config/routes/_f/Controller.php')) {$file = new File(__URL__);$file->stream();} else $this->controller->setController('/_config/routes/_f/Controller.php');}// suppression de fichierif (stripos(__URL__, '/delf/') === 0) {// on peut avoir une fonction personnalisée dans un controller à la racine de private /private/_file/Controller.phpif (file_exists(__PRIVATE__ . '/_config/routes/_delf/Controller.php')) {$this->controller->setController('/_config/routes/_delf/Controller.php');} else die("Error DELFILE");}// fichier PDF, éventuellement créé à la voléeif (stripos(__URL__, '/p/') === 0) {/*function pdf/p/folder/hash/nom_de_fichier.pdf ou /p/folder/fonction_de_generation_de_pdf/id_source/nom_de_fichier.pdf*/}// on teste l'url pour vérifier si elle estif (!$this->checkPath()) {$this->controller->routeCancel = true; // on marque la route comme trouvée pour ne pas chercher$this->send404(); // on renvoie d'office un 404 notfound}/** si la route est propre, on inclut le code du controller* soit celui par défaut (Controller.php dans le dossier /private qui correspond à __PATH__), soit celui qui a été indiqué via $this>setController()* la fonction includePrivateController dira s'occupe de definir $this->controller->routeFound*/ else $this->controller->includePrivateController();}/**** dans FsUtils::routeSanitizer on définie une constante __PATH__ "propre". L'URL sans aucun caractère spéciaux (uniquement A-Za-z0-9_-)* __PATH__ est censé donner le chemin dans /private* URL et PATH doivent être identiques* si l'URL n'est pas propre, on considère que c'est une tentative de hack, on bloque la demande** @return void */protected function checkPath(): bool{$path = __PATH__;$url = __URL__;// upload de fichier V4if (strpos(__URL__, '/upload/files/') === 0) return true;// si l'URL commence par /FW7/ ou /FW4/, on est en mode compatibilité, on a le droit d'appeller directement un fichier php uniquement.if ((strpos(__URL__, '/FW4/') === 0or strpos(__URL__, '/FW7/') === 0or strpos(__URL__, '/k4/') === 0) and strtolower(substr(__URL__, -4)) === '.php') {return true;}// les chemins spéciaux : /d/ /f/ /i/if ((stripos(__URL__, '/d/') === 0or stripos(__URL__, '/i/') === 0or stripos(__URL__, '/f/') === 0or stripos(__URL__, '/p/') === 0)) return true;// cas particulier pour la homeif ($path === '/' and $url == '') return true;// sinon, on doit être égal//dump($path);// dd($url);return ($path === $url);}protected function routeFound(): bool{return $this->controller->getRouteFound();}/*** Défini le fichier php qui va être include dans l'objet Controller pour y ajouter une logique** @param string $controllerFile Le path/name du .php* @return string*/protected function setController(string $controllerFile): string{$this->controller->setController($controllerFile);return $this->controller->getController();}protected function addController(string $controllerFile): array{$this->controller->addController($controllerFile);return $this->controller->getControllers();}protected function getResponse(): string{$this->routeResponse();$this->routeRender();return $this->controller->getResponse();}protected function getStatus(): string{return $this->controller->getStatus();}private function encore(){// on init les deux tableaux pour les JS et les CSS$encore = [];$encore['encore_js'] = [];$encore['encore_css'] = [];$jsArray = $this->controller->getJs();foreach ($jsArray as $idx => $js) {if (!str_starts_with($js, '/')) $js = $this->controller->getControllerPath() . '/' . $js;$js = str_replace('//', '/', $js);$jsArray[$idx] = $js;$encore['encore_js'][] = md5("./private" . $js);}$this->controller->setJs($jsArray);$cssArray = $this->controller->getCss();foreach ($cssArray as $idx => $css) {if (!str_starts_with($css, '/')) $css = $this->controller->getControllerPath() . '/' . $css;$css = str_replace('//', '/', $css);$cssArray[$idx] = $css;$encore['encore_css'][] = md5("./private" . $css);}$this->controller->setCss($cssArray);$this->controller->addTwig($encore);}/**** Faire le rendu du Twig** par défaut le TWIG, c'est le fichier Template.twig dans le même dossier que le Controller.php* mais on peut dans le controller choisir d'appeller un autre TWIG* en renseigant $RESPONSE->template en donnant au choix* un chemin absolu qui commence par* Exemple /test/tmp.twig va chercher dans /private/test/tmp.twig ou /templates/test/tmp.twig* Exemple /tmp.twig va chercher dans /private/tmp.twig ou /templates/tmp.twig* un chemin relatif sans / : Autre.twig pour chercher dans le même dosssier que le Controller.php* Exemple : Template2.twig va chercher dans le même dosssier que le controller le fichier Template2.twig**/public function routeRender(){// si on a déjà une réponse via getResponse, pas besoin d'aller chercher le twig// le twig n'est là que pour remplir controller->responseif ($this->controller->getResponse()) return true;// à ce stade, si la route n'est pas trouvée, on renvoi un 404if (!$this->controller->getRouteFound()) $this->send404();// le template$template = $this->controller->getTemplate();if (!$template) {$path = $this->controller->getControllerPath();if ($this->routeFound()) $template = ($path == '/' ? $path : $path . '/') . "Template.twig";} else if (!str_starts_with($template, '/')) $template = $this->controller->getControllerPath() . "/" . $template;$this->controller->setTemplate($template);// les listes de JS et les CSS associés$this->encore();// le rendu du template pour obtenir la réponse$this->controller->setResponse($this->renderView($this->controller->getTemplate(), $this->controller->getTwig()));$this->outputBuffer();//if (__DEV__) dump($this->controller);}/*** mise à jour du code initial en le faisant passer à travers un buffer de sortie** @param Controller &$CONTROLLER* @param string $template* @return void*/private function outputBuffer(){$response = $this->controller->getResponse();//on charge SimpleDomHtml//require_once __FW__ . '/php/libs/simplehtmldom_1_9_1/simple_html_dom.php';//require_once __ROOT__ . '/vendor/simplehtmldom/simplehtmldom/simple_html_dom.php';require_once $_ENV['PACKAGES_FOLDER'] . "/frameworks/simplehtmldom_1_9_1/simple_html_dom.php";$DOM = str_get_html($response, $lowercase = true, $forceTagsClosed = true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN = false, $defaultBRText = DEFAULT_BR_TEXT, $defaultSpanText = DEFAULT_SPAN_TEXT);// traitement du form// on fait passer le code de sortie à travers cette fonction pour changer le code à l'intérieur des formif ($DOM) {foreach ($DOM->find('form') as $form) {if (!$form->getAttribute('nobuffer')) new Form($form, $DOM);}// si l'objet response à sa propre function de buffer (pour un traitement spécifique du code de sortie)// on appelle cette fonctionif ($this->controller->getBuffer() and is_callable('\App\Controller\OutputBuffers::' . $this->controller->getBuffer())) {//call_user_func('\App\Controller\OutputBuffers::' . $this->controller->getBuffer(), $DOM, $this->controller);}/*** on sauve le résultat modifié dans le code de sortie de l'objet response*/$response = $DOM->save();$DOM->clear();unset($DOM);//$htmlMin = new HtmlMin();//$response = $htmlMin->minify($response);// le minifier de voku supprime les balises </body></html> ce qui est correct au sens du html5 mais enmpèche symfony de positionner la debug bar// on remet donc les balises juste pour ce besoin//if (__DEV__ and stripos($response, '<html>') !== false) $response .= '</body></html>';}$this->controller->setResponse($response);}/*** Annule la route et envoie un 404** @return bool*/public function send404(): void{$this->controller->setStatus(404);$this->controller->setTemplate('/404.twig');$this->controller->setTwig(["status" => "404", "message" => "Page introuvable."]);if (is_callable('App\Controller\Routes::notFound')) Routes::notFound($this->controller);}}