I'm trying to use an .htaccess
file to redirect requests for http://example.org/folder/folder/index.php?with=parameters
,
to http://example.org/index.php?with=parameters
- removing the folder/folder/
part from the request url.
To test my .htaccess
file, I've created an example
folder in my C:\xampp\htdocs
folder, with an index.php
file that just echos the request url and an .htaccess
file that looks like this:
RewriteEngine on
RewriteRule ^folder/folder/index\.php(.*) index.php$1 [R=301,L]
If I now go to http://localhost/example/folder/folder/index.php?with=parameters
it redirects to the url http://localhost/C:/xampp/htdocs/example/index.php?with=parameters
which doesn't exist (forbidden).
So it is removing the folder/folder/
part, but it is adding C:/xampp/htdocs/
to the url.
How can I get rid of the extra C:/xampp/htdocs/
in the new url?
RewriteRule ^folder/folder/index\.php(.*) index.php$1 [R=301,L]
If I now go to
http://localhost/example/folder/folder/index.php?with=parameters
it redirects to the urlhttp://localhost/C:/xampp/htdocs/example/index.php?with=parameters
which doesn't exist (forbidden).
This is because of the relative substitution string (index.php$1
) - second argument to the RewriteRule
directive. It is relative because it does not start with a slash (root-relative, eg. /index.php
) or does not start with a scheme+hostname (absolute, eg.. https://example.com/...
). In .htaccess
, a relative substitution string is treated as a file-path (not a URL-path) and so the directory-prefix (ie. C:/xampp/htdocs/
in this case) is added back at the end of the rewriting process (necessary for internal rewrites) - which is exposed when triggering the external redirect.
You basically just need a slash prefix on the substitution string to make it root-relative. But because you are also in the /example
subdirectory, this also needs to be included. eg. /example/index.php
. (There are various ways to "capture" the example
subdirectory if reqd, to prevent it being hardcoded.)
In addition, you don't need to do anything with regards to the query string (URL parameters). These are passed through to the substitution by default. But, importantly, the RewriteRule
pattern only matches against the URL-path anyway, not the query string, so your capturing subpattern (ie. (.*)
) at the end of the pattern is not actually doing anything anyway.
So, all you need is the following:
RewriteRule ^folder/folder/index\.php$ /example/index.php [R=301,L]
Note the addition of the slash prefix (and /example
subdirectory) on the substitution string. The RewriteRule
pattern matches against a relative URL-path (relative to the directory that contains the .htaccess
file - so the example
directory should not be specified here.)
The query string on the original request is passed through to the substitution string by default. Only if you are wanting to change the query string (URL params) in some way would you need to do anything.
Note that you will need to clear your browser (and possibly any intermediary) cache(s) since the erroneous 301 (permanent) redirect will have been cached persistently by the browser. You should test with a 302 (temporary) redirect to avoid these caching issues.
RewriteBase
Alternatively, you could use the RewriteBase
directive. The RewriteBase
directive specifies the URL-path that should be prefixed to relative substitution strings (this overrides the directory-prefix). For example, the following is equivalent*1 to the above (in this limited example):
RewriteBase /example
RewriteRule ^folder/folder/index\.php$ index.php [R=301,L]
Note that the RewriteBase
directive affects the entire file and can only occur once in the file. (The value to the RewriteBase
directive does not need to include a trailing slash - it is optional, but is always implied. The docs are not consistent in this respect.)
However, generally, when issuing external redirects I would not rely on the RewriteBase
. Using an explicit root-relative (or absolute) substitution string in the rule itself is recommended.
*1 It's not directly equivalent, since the RewriteBase
is only applied at the end of the rewriting process, not as the RewriteRule
directive is processed. But the result is the same in most cases.