web-dev-qa-db-fra.com

Comment supprimer des extensions de et forcer la barre de fin à la fin des URL?

Exemple de structure de fichier actuelle:

example.com/foo.php  
example.com/bar.html  
example.com/directory/  
example.com/directory/foo.php  
example.com/directory/bar.html  
example.com/cgi-bin/directory/foo.cgi*  

Je souhaite supprimer les extensions HTML, PHP et CGI, puis forcer la barre oblique finale à la fin des URL. Donc, ça pourrait ressembler à ça:

example.com/foo/  
example.com/bar/  
example.com/directory/  
example.com/directory/foo/  
example.com/directory/bar/  
example.com/cgi-bin/directory/foo/

Je suis très frustré parce que j'ai cherché pendant 17 heures directement dans la solution et visité plus de quelques centaines de pages sur divers blogs et forums. Je ne plaisante pas. Donc, je pense avoir fait mes recherches.

Voici le code qui se trouve dans mon fichier .htaccess en ce moment:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(([^/]+/)*[^./]+)/$ $1.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]|/)$
RewriteRule (.*)$ /$1/ [R=301,L]

Comme vous pouvez le constater, ce code ne supprime que le fichier .html (et je n’en suis pas très heureux, car j’estime que cela pourrait être beaucoup plus simple). Je peux supprimer l'extension des fichiers PHP lorsque je les renomme en .html via .htaccess, mais ce n'est pas ce que je veux. Je veux l'enlever tout droit. C'est la première chose que je ne sais pas faire.

La deuxième chose est en réalité très énervante. Mon fichier .htaccess avec le code ci-dessus ajoute .html/ à chaque chaîne entrée après example.com/directory/foo/. Donc, si j'entre example.com/directory/foo/bar (évidemment /bar n'existe pas puisque foo est un fichier), au lieu d'afficher un message indiquant que la page n'a pas été trouvée, il le convertit en example.com/directory/foo/bar.html/, puis recherche un fichier pendant quelques secondes, puis affiche le message non trouvé. Ceci, bien sûr, est un mauvais comportement.

Donc, encore une fois, j'ai besoin du code dans .htaccess pour faire les choses suivantes:

  • Supprimer l'extension .html
  • Supprimer l'extension .php
  • Supprimer l'extension .cgi
  • Forcer la barre oblique à la fin des URL
  • Les requêtes doivent se comporter correctement (pas d’ajout de barres obliques ou d’extensions aux chaînes si le fichier ou le répertoire n’existe pas sur le serveur)
  • Le code doit être aussi simple que possible

@Kronbernkzion excellent. Le seul problème que j'ai maintenant, c'est que 404 ne semble pas fonctionner correctement et me conduit dans un endroit vraiment génial, je ne peux même pas utiliser une redirection absolue 404.

ErrorDocument 404 http://www.google.com

Avez-vous rencontré cela? Comment l'avez-vous passé?

Mis à part la réécriture 404, le code complet que j'ai utilisé était le suivant:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule (.*)/$ $1.html [L]

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)/$ $1.php [L]

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond %{REQUEST_FILENAME}\.cgi -f
RewriteRule (.*)/$ $1.cgi [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f [OR]
RewriteCond %{REQUEST_FILENAME}\.php -f [OR]
RewriteCond %{REQUEST_FILENAME}\.cgi -f
RewriteRule .* %{REQUEST_FILENAME}/ [R=301,L]
</IfModule>
7
Kronbernkzion

Alors j'ai écrit un ensemble de règles de réécriture qui a fait ce que tu voulais, mais ça a complètement cassé mon site web. J'ai réalisé que ce que vous voulez n'est probablement pas ce dont vous avez besoin. L'ajout de barres obliques à la fin de toutes les URL dérange vraiment la sémantique de l'URL en ce sens que vous n'accédez plus au fichier /foo mais à la liste de contenu du répertoire /foo/.

Par exemple:

changer /mypage en /mypage/ aura probablement coupure tous les liens relatifs. Si vous référencez un fichier Javascript <script src="myscript.js">, au lieu de rechercher /myscript.js, le navigateur cherchera /mypage/myscript.js. Vous devez modifier votre source pour lire <script src="../myscript.js"> lequel 1) n’a pas de sens pour l’auteur, et 2) a l'air plus laid que de ne pas avoir de barres obliques.

Pour référence:

RewriteCond %{REQUEST_FILE}\.html -f
RewriteRule (.*)$ $1.html [L]

RewriteCond %{REQUEST_FILE}\.php -f
RewriteRule (.*)$ $1.php [L]

RewriteCond %{REQUEST_FILE}\.cgi -f
RewriteRule (.*)$ $1.cgi [L]

changerait seulement les extensions php, cgi et html, mais une meilleure idée serait d'utiliser la négociation de contenu Apache2 (avec MultiViews).

Modifier:

Le code original Ou au moins une partie de celui-ci. Je l'ai cassé, puis réduit à ce qui précède, et maintenant je ne me souviens plus très bien de ce que j'ai fait. Mais il fait tout sauf enlever les extensions de fin.

# This block adds the trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond /your/web/directory%{REQUEST_URI}\.html -f [OR]
RewriteCond /your/web/directory%{REQUEST_URI}\.php -f [OR]
RewriteCond /your/web/directory%{REQUEST_URI}\.cgi -f
RewriteRule .* %{REQUEST_URI}/ [R=301,L]

# These blocks redirect /foo/ to /foo.html and so on
RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond /your/web/directory%1\.html -f
RewriteRule (.*)/$ $1.html [L]

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond /your/web/directory%1\.php -f
RewriteRule (.*)/$ $1.php [L]

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond /your/web/directory%1\.cgi -f
RewriteRule (.*)/$ $1.cgi [L]

Vous pouvez m'envoyer un email à mazin (at) aztekera.com si vous le souhaitez.

6
erjiang

Mazin, merci beaucoup pour votre aide et pour m'avoir montré la bonne direction! Le code ci-dessous fonctionne pour supprimer les extensions .html, .php et .cgi, ainsi que pour forcer les barres obliques finales à la fin des URL. Le code de travail final ressemble à ceci:

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule (.*)/$ $1.html [L]

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)/$ $1.php [L]

RewriteCond %{REQUEST_URI} (.*)/$
RewriteCond %{REQUEST_FILENAME}\.cgi -f
RewriteRule (.*)/$ $1.cgi [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f [OR]
RewriteCond %{REQUEST_FILENAME}\.php -f [OR]
RewriteCond %{REQUEST_FILENAME}\.cgi -f
RewriteRule .* %{REQUEST_FILENAME}/ [R=301,L]

Je suis extrêmement heureux de la façon dont cela s'est avéré.

J'ai envoyé une carte-cadeau iTunes de 50 $ à Mazin sous la forme d'un gros merci pour m'avoir aidé.

3
Kronbernkzion

On dirait que vous essayez de faire quelque chose de similaire à une implémentation d'URL compatible REST.

J'ai déjà vu cela sur SO, ici: https://stackoverflow.com/questions/395650/url-mapping-in-php

Vous pourrez peut-être adapter les 2 meilleures solutions à vos besoins.

1
Chris Thorpe

Si vous connaissez le format exact de chaque URL dont vous avez besoin, le processus est plutôt simple. Si vous ne savez pas quelle extension vous devez faire correspondre, eh bien, alors je suis à peu près sûr que c'est impossible.

Par exemple, si vous savez que vous avez foo.html et bar.php - et que /foo/ doit correspondre à foo.html et que vous SAVEZ que /bar/doit correspondre à /bar.php, alors cela peut être fait. Mais si quelqu'un télécharge /cat.php et que quelqu'un entre /cat/ - le système ne saura pas s'il doit correspondre à /cat.html ou /cat.php - vous devez le dire. Si vous ne vous occupiez que d'une extension, ce ne serait pas si grave, vous pourriez l'ajouter à chaque demande.

Pour réécrire /foo/ sur /foo.html, vous devez alors:

RewriteRule (/foo/) /foo.html

Facile

Si vous souhaitez faire correspondre chaque demande à une extension SINGLE, vous pouvez effectuer les opérations suivantes:

RewriteRule (/foo/)(.*)(/) /foo/$2.html

Ceci mappera /foo/mypage/ à /foo/mypage.html (et vous pourrez l'étendre à un répertoire à plusieurs niveaux en utilisant un RegEx-fu supérieur à ma note salariale).

Maintenant, je ne sais pas vraiment que c'est ce que vous demandez, alors veuillez commenter ma réponse ou mettre à jour votre question si ces règles ne vont pas fonctionner pour vous.

-- Modifier --

Je viens de remarquer votre réponse à mon commentaire ci-dessus. Vous ne pouvez absolument pas faire ce que vous voulez avec .htaccess, car .htaccess n'a pas la capacité de vérifier si un fichier demande existe. Comment saura-t-il que /foo/ est censé être /foo.html ou /foo.php ou /foo.cgi? Votre seul moyen de contourner le problème sera de:

1) Transférer CHAQUE demande via un fichier single.php qui a ensuite la possibilité de savoir/de vérifier si la version .php, .html ou .cgi du fichier existe, puis de transmettre votre demande de cette façon.

2) Créez un fichier .htaccess contenant une entrée pour chaque fichier unique

0
Mark Henderson