I'm using Apache and mod_rewrite to rewrite URLs for my web app. You can see it here:
RewriteEngine On
RewriteBase /
# www. to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
# Redirect non-existant files so there's a trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [R=301,L]
# Send the URL to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L,QSA]
All working fine, but the problem is the trailing slash rewrite. It works when I'm at the root of the domain, but in my staging environment I'm running this app within a subdirectory. I'm having to modify the RewriteBase directive to include the subdirectory or the rewrite fails.
I'm looking for a solution that will add a trailing slash to the URL - regardless of whether the app is running on the root of the server, without having to change the RewriteBase. Thanks in advance.
After poking around and some help by #MortBM, looks like the below works well:
RewriteEngine On
# www. to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
# Add a trailing slash to any non-existent files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ %{REQUEST_URI}/ [R=301,L]
# Send the URI to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [QSA,L]
Summary: removing the RewriteBase, and using %{REQUEST_URI} within the redirect did it :)
Related
.htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
With this setup the page /foo/bar is accessible under the pretty URL example.com/foo/bar while the ugly URL example.com/index.php/foo/bar is still valid. What I need to achieve is a permanent redirection from example.com/index.php/foo/bar to example.com/foo/bar.
RewriteRule .* index.php [R=301,L] doesn't work.
RewriteRule (.*) index.php/$1 [R=301,L] does the exact opposite, it redirects from example.com/foo/bar to example.com/index.php/foo/bar. Please help me out!
I recommend writing this:
RewriteEngine On
RewriteBase /
# remove index.php from / OR any /dir
RewriteCond %{THE_REQUEST} /index\.php [NC]
RewriteCond %{REQUEST_URI} ^(.*/)index\.php$ [NC]
RewriteRule ^ %1 [L,R=301,NE]
# redirect rule to remove /index.php/ from start
RewriteRule ^index\.php(/.*) $1 [L,R=301,NC]
RewriteCond %{REQUEST_URI} !^/index\.php [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
In the new rule, we match a pattern using regex ^index\.php(/.*) which matches a URI that starts with /index.php/ followed by zero or more of any characters. (/.*) is our match and the capture group after /index.php which is used as back-reference i.e. $1 (string that we've captured in group #1) in target to get a URI after /index.php as desired.
References:
Apache mod_rewrite Introduction
.htaccess tips and tricks
I have this in .htaccess to redirect /abc/def/ to /abc/def, removing trailing slash:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
Which works well. Now I want to exclude URLs starting with /xxx/yyy/ to NOT be redirected by the above rule, e.g. /xxx/yyy/12345/ which need to stay as it is without being redirected to /xxx/yyy/12345, retaining trailing slash.
So I have:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/xxx/yyy/
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
But it doesn't work as /xxx/yyy/12345/ is still being redirected to /xxx/yyy/12345. What am I doing wrong here?
Use THE_REQUEST variable instead of REQUEST_URI as REQUEST_URI may change due to execution of other rules:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} !\s/+xxx/yyy/ [NC]
RewriteCond %{REQUEST_URI} ^(.+)/$
RewriteRule ^ %1 [L,R=301,NE]
Make sure to use a new browser for testing.
It seems it's because I have this in a .htaccess:
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^ index.php [L]
RewriteRule ^(.*)$ public/$1 [L]
In one of the upper directory. So what I have to use is this:
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/public/xxx/yyy/
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
Adding /public/ before /xxx/yyy/ though the public URL is actually /xxx/yyy/.
I've searched over previously asked questions but none have the same problem as me. I'm wanting to remove the trailing slash, whilst still sending all pages to index.php (or if the file actually exists, use that.)
I'd like a solution that I don't have to fiddle with between server and localhost.
So localhost/pages/to/file/ and http://example.com/pages/to/file/, go to ... /pages/to/file
My current htaccess file:
RewriteEngine on
# removes www.
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [R=301,QSA,NC,L]
# if file exists, ignore the index.php re-write
RewriteCond %{REQUEST_FILENAME} !-f
# send everything to index.php
RewriteRule . index.php
Give the following a try:
RewriteEngine on
# Remove the trailing slash, if not in a directory
# DirectorySlash off can be used instead.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Remove www. (generic method with HTTPS support)
RewriteCond %{HTTP_HOST} ^www\.
RewriteCond %{HTTPS}s ^on(s)|off
RewriteCond http%1://%{HTTP_HOST} ^(https?://)(www\.)?(.+)$
RewriteRule ^ %1%3%{REQUEST_URI} [R,L]
# Send everything (except existing files) to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
If this works for you, change the R flag to R=301 to make the redirect permanent.
You can add an extra condition to your existing rule to remove www and remove any trailing slash in that rule too.
RewriteEngine on
# removes www. and trailing slash
RewriteCond %{REQUEST_URI} /$ [OR]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*?)/?$ http://%1/$1 [R=301,QSA,NC,L]
# if file exists, ignore the index.php re-write
RewriteCond %{REQUEST_FILENAME} !-f
# send everything to index.php
RewriteRule . index.php
See the documentation for clarification.
Have a separate rule for removal of trailing slash:
RewriteEngine on
# removes www.
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,NE,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{THE_REQUEST} \s/+(.*?)[^/][?\s]
RewriteRule [^/]$ %{REQUEST_URI}/ [L,NE,R=301]
# if file/directory exists, ignore the index.php re-write
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# send everything to index.php
RewriteRule . index.php [L]
I successfully managed to redirect all requests to a subfolder of my web server.
This is the code I'm using:
/.htaccess
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !^/public/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /public/$1 [L]
/public/.htaccess
# redirect all urls that doesn’t have a
# trailing slash to urls with a trailing slash
# (this is my try)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1 [NC]
It works perfectly, so the following redirects work:
example.com -> example.com/public/
example.com/foo/ -> example.com/public/foo/
example.com/foo/about.html -> example.com/public/foo/about.html
By the way, the following redirect has a problem:
example.com/foo -> example.com/public/foo
Although it redirects correctly, the actual URL in the address bar is:
example.com/public/foo/
So my question is:
How can I have a clean URL when redirecting from a URL without a forward slash?
Hope it makes sense.
Place this code in root .htaccess:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R=301,L]
RewriteCond %{REQUEST_URI} !^/public/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /public/$1/ [L]
Then just remove /public/.htaccess since that is not needed.
I have been working this issue for several nights with no luck. I'm trying to Rewrite web requests using (.htaccess)
from: cobweb.seas.gwu.edu/~mpnl
to: cobweb.seas.gwu.edu/~mpnl/joomla
My latest (.htaccess) file is below:
# turn on Rewrite
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?cobweb.seas.gwu.edu/~mpnl$
RewriteCond %{REQUEST_URI} !^/joomla/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /joomla/$1 [L]
RewriteRule ^(/)?$ joomla/index.php [L]
You can't match against the URI path with the %{HTTP_HOST} var, only the host. You'll need to either include the ~mpnl part as a rewrite base or as part of the request URI:
RewriteEngine on
# remove the "/~mpnl" from the end of this line, add a [NC]
RewriteCond %{HTTP_HOST} ^(www.)?cobweb.seas.gwu.edu$ [NC]
# add a "/~mpnl" to here
RewriteCond %{REQUEST_URI} !^/~mpnl/joomla/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# remove the leading slash before "joomla"
RewriteRule ^(.*)$ joomla/$1 [L]
# add a condition to this:
RewriteCond %{REQUEST_URI} !^/~mpnl/joomla/
RewriteRule ^(/)?$ joomla/index.php [L]
To rewrite requests with a UserDir in the URI, you have to set a RewriteBase:
RewriteBase /~mpnl/