RewriteCond qui ne s'applique pas

Le problème exposé dans ce sujet a été résolu.

Coucou les agrumes,

J’essaie de configurer mon serveur Apache pour que les requêtes de CSS/JS ou d’images ne soient pas redirigées vers mon contrôleur central, mais qu’elles accèdent directement au fichier voulu (ces fichiers ont une URI qui commence par /resources, et sont tous placés dans le dossier View/resources).

J’ai une solution qui marche, à savoir

1
2
3
4
RewriteRule ^resources/(.*)$ View/resources/$1

RewriteRule View/resources/ - [L]
RewriteRule . app.php [QSA,L]

Mais je voulais savoir pourquoi ma config à base de RewriteCond ne marchait pas. J’ai tenté

1
2
3
4
5
RewriteRule ^resources/(.*)$ View/resources/$1

# Exclude resources from redirection to app.php
RewriteCond %{REQUEST_URI} !^View/resources/
RewriteRule . app.php [QSA,L]

Mais ça ne marche pas, ni quand je place la RewriteCond sur !^resources. En revanche, en changeant la dernière ligne pour RewriteRule !^View/resources/ app.php (et en enlevant, ou pas, la RewriteCond), ça marche nickel…

Du coup, ben je comprends pas.

Avec la seconde config donnée, d’après moi Apache devrait fontionner de la manière suivante : il reçoit un GET /resources/css/design.css, qu’il réécrit en GET /View/resources/css/design.css, puis après avoir parsé RewriteRule . app.php [QSA,L] s’aperçoit que la RewriteCond ne correspond pas, puisque l’URI a été changée en View/resources/css/design.css. Apache fait ensuite potentiellement une seconde passe du fichier (pas sûr de moi sur ce coup-là), pour vérifier qu’il n’y a pas de nouvelle règle qui s’applique à l’URI précédemment changée. Puis il trouve le fichier View/resources/css/design.css, qu’il délivre au client.

Sauf que ça atterrit sur le contrôleur quand même.

Des idées ?

+0 -0

Une solution simple serait de profiter de l’option L qui indique que si la règle a été appliquée, plus aucune autre règle ne doit modifier l’URI.

1
2
RewriteRule ^resources/(.*)$ View/resources/$1 [L]
RewriteRule . app.php [QSA,L]

Je vois pas de raison pour laquelle Apache ferait passer le fichier une seconde fois, mais si c’est bien le cas, ça va poser problème pour la réécriture de l’URI.

Bonus, un petit site web sympa pour tester un htaccess et voir quelles règles ou conditions passent ou ne passent pas : http://htaccess.mwl.be/

Ta condition est toujours vraie (= ta seconde règle est toujours appliquée) : %{REQUEST_URI} est le chemin HTTP complet de la ressource, il commence forcément par / or tu as écrit ^V au lieu de ^/V.

Il faut bien comprendre que RewriteRule, dans un contexte dit de répertoire, c’est-à-dire dans un fichier .htaccess ou dans un bloc <Directory>, lui ne teste qu’une partie du chemin HTTP, Apache tronquant ce chemin au fur et à mesure pour le faire correspondre avec le répertoire où est situé le fichier .htaccess (ou la valeur de la directive <Directory>). Voilà pourquoi avec ta règle de non-réécriture (RewriteRule View/resources/ - [L]) ou celle niée (RewriteRule !^View/resources/ app.php), ça fonctionne.

Dit plus simplement, pour illustrer, dans un .htaccess, le chemin HTTP testé par RewriteRule est relatif alors qu’ailleurs il est absolu.

C’est pour cette raison que personnellement, dans un .htaccess, j’évite à tout prix d’utiliser des chemins HTTP absolus (la variable %{REQUEST_URI} notamment) : ça fait un mélange de chemins absolus vs relatifs. Le .htaccess gagne en portabilité si tout est en relatif, c’est pourquoi je réécris systématiquement les RewriteCond %{REQUEST_URI} ... en règle de non-réécriture (RewriteRule ... - [L]). Il vaut mieux aussi éviter les règles niées (avec ! devant le motif) : on ne peut pas faire de capture et ça rend potentiellement les règles plus difficiles à reprendre.

Ensuite, effectivement, faute de [L] sur la première règle, peu importe que cette première règle intervienne ou non, on finit quoi qu’il arrive sur cette seconde règle (toujours appliquée du fait de sa condition vraie).

+0 -0

Si tu finis sur app.php, ce doit être le cas. Oui, je pense que si tu n’as pas de .htaccess dans les niveaux inférieurs entre / et View/resources/$1 (compris), quand tu réécris une de tes "vues", Apache reconsidère ce .htaccess dans un deuxième temps. Du coup, on en retrouve les mêmes règles et surtout la seconde qui renvoie tout sur app.php.

Tiens d’ailleurs, si le but est de tout [le reste] intercepter, j’aurais plutôt employé ^ à . (la différence étant que la chaîne vide, qui correspondrait à la "racine", serait acceptée par le premier mais pas le second - mais si le DirectoryIndex entre en jeu, on ne verra pas la différence).

Et éventuellement, plutôt carrément exclure à cette seconde règle tout ce qui existe physiquement (si toutefois ça correspond à tes besoins) :

1
2
3
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . app.php [L]

De cette façon, les "vues" devraient automatiquement être exclues de la réécriture sur app.php mais aussi tes assets et tout fichier statique en général.

PS : le flag QSA est inutile sur cette règle, c’est le comportement par défaut d’Apache vu que tu ne définis pas de nouvelle query string.

+0 -0

Au début j’avais un RewriteCond %{REQUEST_FILENAME} !-f, mais je l’ai enlevé dès que je me suis rendu compte que ça autorisait l’accès à tous mes fichiers php. Certes ce ne sont que des classes et ça n’exécute rien (et si on s’en sert pour appeler mes vues, à priori ça plante), mais bon.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte