skip to Main Content

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


  1. There probably exist other solutions, but it works if you change two things:

    1. Add a condition to the first RewriteRule that checks if the query string is empty, i.e. product/product.php without query string redirects to /product/.
    2. Change (.*) in the second RewriteRule to (.+) or ([0-9]+) to only rewrite requests containing a product id (requests to /product/ are not rewritten).
    RewriteEngine On
    
    RewriteCond %{QUERY_STRING}        ="" [NC]
    RewriteRule ^product/product.php$ /product/ [NC,R=307,END]
    
    RewriteCond %{REQUEST_URI}  !^/product/product.php [NC]
    RewriteRule ^product/(.+)   /product/product.php?product=$1 [NC]
    
    Login or Signup to reply.
  2. access /product/product.php in the URL bar, it is redirected to /product/ for tidiness

    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:

    # Canonical redirect
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteCond %{QUERY_STRING} ^(?:product=(d*))?$ [NC]
    RewriteRule ^product/product.php$ /product/%1 [NC,R=307,L]
    
    # Rewrite requests from "pretty" URL to underlying filesystem path
    RewriteRule ^product/(d*) /product/product.php?product=$1 [L]
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search