I have a specific mod_rewrite case which I don't know how to solve or if it is solveable at all.
To start I have the folder foo
with many files and subfolders in it, e.g.
foo/subfoo/example.html
I now rename foo
to bar
. Then I re-create a new empty folder foo
for a new project.
But I have many clients that have bookmarked the old URLs. If I want to continue to keep them working, I want to do the following:
foo/subfoo/example.html
comes inbar/subfoo/example.html
exists. If yes go there.foo/subfoo/example.html
in the new foo
folder which might or might not existAnyway to check in RewriteCond
if bar/subfoo/example.html
exists before rewrite happens (e.g. using regex)?
I have seen examples that check the existence of a file based on the REQUEST_FILENAME
first but I want to check the existence of a file in a modified REQUEST_FILENAME
.
Assuming you have changed all the old URLs from /foo/...
to /bar/...
(including all links/URLs to static assets) and this is simply for "clients that have bookmarked the old URLs" (and possibly search engines that have indexed the old URLs) then you can implement a 301 "permanent" external redirect as follows in .htaccess
:
RewriteEngine On
# Redirect requests from "foo" to "bar" if the file exists in "bar"
RewriteCond %{DOCUMENT_ROOT}/bar/$1 -f
RewriteRule ^foo/(.+\.(html|css|js|webp|jpg|gif))$ /bar/$1 [R=301,L]
This rule would need to go near the top of the root .htaccess
file before existing mod_rewrite directives.
The $1
backreference contains the requested URL-path, less the /foo/
prefix. This is then used to construct the file-path to test for in the preceding RewriteCond
directive and to redirect to in the RewriteRule
substitution (if the condition is successful).
The (html|css|js|webp|jpg|gif)
part of the regex checks just for the file extensions we are concerned with. Although, strictly speaking, if this is only for bookmarked/indexed URLs then you may just need the .html
extension here.
You do not need to repeat the RewriteEngine
directive if this already exists later in the file.
You should test first with a 302 (temporary) redirect to avoid potential caching issues if there happens to be an error.
Note that this does not redirect requests for directories themselves, just files within those directories. So a request for /foo/subfoo/
would not be redirected, but /foo/subfoo/example.html
would. An additional rule would be required to handle such requests if that is a requirement.
Background...
I have seen examples that check the existence of a file based on the
REQUEST_FILENAME
first but I want to check the existence of a file in a modifiedREQUEST_FILENAME
REQUEST_FILENAME
is a server variable that contains the computed absolute filesystem path that the requested URL-path would map to. Most of the time this is the same as DOCUMENT_ROOT
+ REQUEST_URI
(the requested root-relative URL-path).
RewriteRule TestString CondPattern [flags]
The first argument to the RewriteCond
directive is a TestString that is evaluated against the second argument (CondPattern). So, instead of using %{REQUEST_FILENAME}
you could use %{DOCUMENT_ROOT}%{REQUEST_URI}
to construct the absolute file-path for the requested resource. You can construct any string to test against the second argument (eg. to test whether it is a physical file).