Redirigez tout vers index.php en utilisant htaccess

131

J'écris un simple framework MVC-ish basé sur PHP. Je veux que ce framework puisse être installé dans n'importe quel répertoire.

Mon script PHP saisit l'URI de la requête et le divise en segments. Il fait du segment 1 le contrôleur et du segment 2 l'action. Tout va bien quand je fais ceci:

http://www.example.com/mvc/module/test/

Il ira au contrôleur de module et à la méthode spécifiques. Maintenant, j'ai un contrôleur par défaut, le contrôleur home, qui se trouve dans le dossier home.

Maintenant, quand j'accède directement à ce dossier http://www.example.com/mvc/home/ Il affichera un 403 interdit, car ce dossier existe, à la place il devrait également retourner sur http://www.example.com /mvc/index.php

Si j'aurais installé le framework dans un dossier différent, disons le framework de dossier qu'il doit rediriger vers http://www.example.com/framework/index.php

Je voudrais rediriger chaque dossier et fichier php vers le index.php, en laissant tout le reste tel quel.

Mon premier problème que j'ai rencontré était qu'il ne redirige jamais vers le bon dossier, toujours vers le dossier racine du domaine.

Voici ce que j'ai essayé:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
David Ericsson
la source
Juste pour être sûr de bien comprendre votre question: vous voulez rediriger chaque demande vers la racine index.php ou vous voulez rediriger chaque demande faite vers ce dossier spécifique index.php ?
Technoh
Dans le dossier dans lequel se trouve le fichier htaccess, le répertoire racine du framework. Dans mon exemple, retour au répertoire mvc
David Ericsson

Réponses:

259

Votre règle de réécriture semble presque correcte.

Assurez-vous d'abord que votre .htaccessfichier est à la racine de votre document (au même endroit que index.php), sinon il n'affectera que le sous-dossier dans lequel il se trouve (et tous les sous-dossiers qu'il contient - de manière récursive).

Ensuite, modifiez légèrement votre règle pour qu'elle ressemble à quelque chose comme:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?path=$1 [NC,L,QSA]

En ce moment , vous qu'aligner sur ce .qui est un exemple de caractère, vous avez besoin au moins .*pour correspondre à un certain nombre de cas de tout caractère.

La $_GET['path']variable contiendra la fausse structure de répertoire, /mvc/module/testpar exemple, que vous pourrez ensuite utiliser dans index.php pour déterminer le contrôleur et les actions que vous souhaitez effectuer.


Si vous voulez que tout le shebang soit installé dans un sous-répertoire, tel que /mvc/ ou /framework/la manière la moins compliquée de le faire, c'est de changer légèrement la règle de réécriture pour en tenir compte.

RewriteRule ^(.*)$ /mvc/index.php?path=$1 [NC,L,QSA]

Et assurez-vous que votre index.php êtes dans ce dossier tandis que le .htaccessfichier est à la racine du document.


Alternative à$_GET['path'] (mise à jour de février 18 et janvier 19)

Il n'est pas réellement nécessaire (ni même courant maintenant) de définir le chemin en tant que $_GETvariable, de nombreux frameworks s'appuieront sur$_SERVER['REQUEST_URI'] pour récupérer les mêmes informations - normalement pour déterminer quel contrôleur utiliser - mais le principe est exactement le même.

Cela simplifie RewriteRulelégèrement le problème car vous n'avez pas besoin de créer le paramètre de chemin (ce qui signifie que l'original de l'OP RewriteRule sera maintenant travailler):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]

Cependant , la règle d'installation dans un sous-répertoire s'applique toujours, par exemple

RewriteRule ^.*$ /mvc/index.php [L,QSA]



Les drapeaux:

NC = Pas de casse (pas sensible à la casse, pas vraiment nécessaire car il n'y a pas de caractères dans le motif)

L = Last (la réécriture s'arrêtera après cette réécriture, alors assurez-vous que c'est la dernière chose de votre liste de réécritures)

QSA= Chaîne de requête Ajouter, juste au cas où vous auriez quelque chose comme ?like=penguinsà la fin que vous voulez conserver et passer à index.php.

CD001
la source
1
il devrait être index.php? path = $ 1
Jacek Pietal
1
@Prozi pas si vous êtes dans un sous-répertoire et que index.php est dans la docroot, alors vous avez besoin du / - avec Options +Indexeset index.php inclus dans DirectoryIndexvous pouvez laisser index.php complètement et simplement utiliser /?path=$1Ceci est vrai quand faire des réécritures via .htaccess plutôt que dans une <Directory>directive de type httpd-vhosts.conf .
CD001
Si vous utilisez cela et que vous comptez sur $ _GET ['path'], vous aurez des problèmes en cas de passage au serveur nginx ...
barell
3
Belle publication! Il est à noter que l'utilisateur peut écraser $_GET['path']s'il ajoute path=whateverà l'URL.
rybo111 du
1
@Liviuge - c'est vrai, mais au départ, je passais tout le chemin, $_GETdonc cela aurait nécessité (.*)... c'est drôle mais la RewriteRule que l'OP utilisait il y a 6 ans ne fonctionnait pas pour eux alors - mais avec la façon dont l'architecture MVC a évolué avec PHP (comme je l'ai mis dans le bit Mise à jour du 18 février ), il le ferait maintenant ... je suppose qu'ils étaient en avance sur leur temps :) Il faut toujours le chemin correct vers le /mvc/répertoire bien sûr.
CD001
28

Pour rediriger tout ce qui n'existe pas index.php, vous pouvez également utiliser la FallBackResourcedirective

FallbackResource /index.php

Cela fonctionne de la même manière que ErrorDocument, lorsque vous demandez un chemin ou un fichier inexistant sur le serveur, la directive transmet silencieusement la requête à index.php.

Si vous souhaitez rediriger tout ( including existant files or folders) vers index.php, vous pouvez utiliser quelque chose comme ce qui suit:

RewriteEngine on

RewriteRule ^((?!index\.php).+)$ /index.php [L]

Notez que le modèle ^((?!index\.php).+)$ correspond à n'importe quel uri sauf que index.phpnous avons exclu le chemin de destination pour éviter une erreur de boucle infinie.

Amit Verma
la source
Mais vous pouvez aussi utiliser:DirectoryIndex index.php
Shao
1
Utilisez à la *place de +dans le modèle si vous souhaitez également rediriger le chemin racine lui-même.
Mir-Ismaili
15

Vous pouvez utiliser quelque chose comme ceci:

RewriteEngine on
RewriteRule ^.+$ /index.php [L]

Cela redirigera chaque requête vers l'index.php du répertoire racine. Notez qu'il redirigera également les requêtes pour les fichiers existants, tels que les images, les fichiers javascript ou les feuilles de style.

Technoh
la source
1
Cette solution a presque fonctionné pour moi. J'ai continué à recevoir "AH00124: La demande a dépassé la limite de 10 redirections internes". J'ai ajouté "RewriteRule ^ index \ .php - [L]" avant et cela fonctionne parfaitement!
Fredster
11

Il y a un "truc" pour ce problème qui convient à tous les scénarios, une solution si évidente que vous devrez l'essayer pour croire que cela fonctionne réellement ... :)

C'est ici...

<IfModule mod_rewrite.c>

   RewriteEngine On

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

</IfModule>

Fondamentalement, vous demandez à MOD_REWRITE de transmettre à index.phpla requête URI toujours lorsqu'un fichier existe ET toujours lorsque le fichier demandé n'existe pas !

En enquêtant sur le code source de MOD-REWRITE pour comprendre son fonctionnement, je me suis rendu compte que toutes ses vérifications se produisent toujours après la vérification si le fichier référencé existe ou non. Ce n'est qu'alors que les RegExfichiers sont traités. Même lorsque votre URI pointe vers un dossier, Apache appliquera la vérification des fichiers d'index répertoriés dans son fichier de configuration.

Sur la base de cette simple découverte, devenue évidente, une simple validation de fichier serait suffisante pour tous les appels possibles , dans la mesure où nous tapons deux fois sur la vérification de la présence de fichier et acheminons les deux résultats vers le même point final, couvrant 100% des possibilités.

IMPORTANT: notez qu'il n'y a pas de " / " dans index.php. Par défaut, MOD_REWRITE utilisera le dossier qu'il est défini comme "dossier de base" pour le transfert. La beauté de celui-ci est qu'il n'a pas nécessairement besoin d'être le "dossier racine" du site, ce qui permet à cette solution de fonctionner pourlocalhost/ et / ou tout sous-dossier que vous appliquez.

En fin de compte, certaines autres solutions que j'ai testées auparavant (celles qui semblaient fonctionner correctement) ont cassé la capacité de PHP à "exiger" un fichier via son chemin relatif, ce qui est une déception. Faites attention.

Certaines personnes peuvent dire que c'est une solution inélégante. C'est peut-être, en fait, mais en ce qui concerne les tests, dans plusieurs scénarios, plusieurs serveurs, plusieurs versions différentes d'Apache, etc., cette solution a fonctionné à 100% sur tous les cas!

Julio Marchi
la source
Merci, cela a résolu mon problème où une FallbackResource index.phpligne fonctionnait sur un Mac (OS X 10.11) mais pas sous Centos 7.5. Cependant: cela RewriteRuleréécrit également l'emplacement des fichiers CSS par exemple. Comme je devais rediriger uniquement les fichiers PHP, j'ai modifié la règle en RewriteRule ^(.*)php$ index.php [L,QSA]. YMMV.
Laryx Decidua
1
Je suis heureux que cela ait aidé. Vous avez raison, il cible TOUS les fichiers car la question était: " Tout rediriger vers index.php en utilisant htaccess ". Il existe d'autres moyens plus élégants de rediriger uniquement les fichiers PHP, tels que RewriteRule ^(.*)\.php$ index.php [L,NE,QSA](qui ne nécessite aucune condition pour fonctionner). De nos jours, cependant, j'utilise une règle moins coûteuse:, RewriteRule ^.+$ index.php [L,NE,QSA]qui peut être combinée avec les conditions RewriteCond %{REQUEST_FILENAME} !-fet RewriteCond %{REQUEST_FILENAME} !-d, ou même avec RewriteCond $1 !^(index\.php|assets|robots\.txt|favicon\.ico)pour être vraiment spécifique.
Julio Marchi
5

Réponse idiote mais si vous ne pouvez pas comprendre pourquoi il ne redirige pas, vérifiez que ce qui suit est activé pour le dossier Web.

AllowOverride All

Cela vous permettra d'exécuter htaccess qui doit être en cours d'exécution! (il existe des alternatives mais pas sur cela causera des problèmes https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride )

Antony
la source
0

Après avoir fait le n'oubliez pas de changer votre balise d'ancrage, accueil

Exemple:

.htacces file
RewriteEngine On

RewriteRule ^about/$ /about.php

PHP file:
<a href="about/"> about</a>
Collins Benson
la source
N'oubliez jamais de changer la balise <a>.
Collins Benson
2
Que signifie après avoir fait le ne pas changer votre étiquette, maison ?
Enrico Maria De Angelis
0

juste au cas où vous vous demanderiez encore comment rediriger toutes les demandes, soit si le répertoire existe (pour les dossiers et fichiers du framework principal) vers le gestionnaire d'index du framework, après quelques tentatives d'erreur / succès, j'ai juste remarqué que j'avais juste besoin de changer le RewriteCond dans le .htaccess fichier

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

la condition ci-dessus indique "fichiers non trouvés" et "répertoires non trouvés", ok, que se passe-t-il si simplement supprimer la ligne "introuvable" (! -d), et se terminer par quelque chose comme ci-dessous:

RewriteEngine on
RewriteBase /framework/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /framework/index.php [L,QSA]

Cela a fonctionné pour moi comme un charme

AugustoM
la source