I have two requirements;
- That, for example,
/product/12345
is internally redirected to/product/product.php?product=12345
. - That if the user tries to access
/product/product.php
in the URL bar, it is redirected to/product/
for tidiness.
Separate, they both work correctly, but together it results in an infinite loop – I know that I’m redirecting from /product/
to /product.php
and back again, but the difference is internal vs external and I’m not sure how to distinguish between them.
RewriteEngine On
RewriteRule ^product/product.php /product/ [NC,R=307,END]
RewriteCond %{REQUEST_URI} !^/product/product.php [NC]
RewriteRule ^product/(.*) /product/product.php?product=$1 [NC]
2
Answers
There probably exist other solutions, but it works if you change two things:
RewriteRule
that checks if the query string is empty, i.e.product/product.php
without query string redirects to/product/
.(.*)
in the secondRewriteRule
to(.+)
or([0-9]+)
to only rewrite requests containing a product id (requests to/product/
are not rewritten).You might as well also redirect
/product/product.php?product=12345
to the corresponding canonical URL (ie./product/12345
) – which you can do all in the same rule. If the product ID is numeric only then you should restrict your regex accordingly – this will also avoid the need for an additional condition.For example:
The condition that checks against the
REDIRECT_STATUS
environment variable is necessary to prevent a redirect loop in this instance since the query string is entirely optional.By restricting the match to digits-only, we avoid the need for an additional condition on the internal rewrite,
product.php
won’t match. If the product id can contain letters then restrict the pattern to avoid dots (.
), eg.([^./]*)
.Only include a
NC
flag on the internal rewrite if this is strictly necessary, otherwise this potentially creates a duplicate content issue.