apachemod-rewriteurl-rewritingurl-rewrite-moduleerrordocument

Redirect not redirecting on Apache


Below is the content of .htaccess file

Options All -Indexes
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(([a-z0-9_]+\.)? DOMAIN NAME \.in)$ [NC]
RewriteRule .? https://%1%{REQUEST_URI} [R=301,L]
RewriteRule ^itinerary/([A-Za-z0-9-]+)/([A-Za-z0-9]+) details.php?id=$2 [NC,L]
ErrorDocument 404 /404.php

The problem is when I type a non-existing url as DOMAIN/non-existing the error redirect works perfectly but the problem comes when I use some of the redirect to a non-existing url. The error page does not redirect properly.

Sample non-existing link 404.php shown ?
domain/i-donot-exist YES
domain/i-donot-exist-too.php YES
domain/itinerary/something/abc NO
domain/itinerary/something/abc/123 NO
domain/itinerary/something/login.php NO
domain/itinerary/something/abc/123/1.php NO

Solution

  • The ErrorDocument directive defines an Apache error document. A document that will be served when Apache determines there is an error. (This is not served by a "redirect" as your title suggests, but via an "internal subrequest".)

    RewriteRule ^itinerary/([A-Za-z0-9-]+)/([A-Za-z0-9]+) details.php?id=$2 [NC,L]
    

    The 4 URLs that do not show the /404.php response are all written "successfully" to details.php by the 2nd RewriteRule directive (above). From Apache's perspective there is no 404. Control has been handed to details.php and it is now up to PHP to process the request and serve an appropriate 404 response as required. (PHP cannot see what the Apache ErrorDocument is.)

    So, in summary:

    Sample non-existing link 404.php shown? Reason
    #1 /i-donot-exist YES Does not map to file and URL not rewritten
    #2 /i-donot-exist-too.php YES Does not map to file and URL not rewritten
    #3 /itinerary/something/abc NO URL rewritten to details.php?id=abc
    #4 /itinerary/something/abc/123 NO URL rewritten to details.php?id=abc
    #5 /itinerary/something/login.php NO URL rewritten to details.php?id=login
    #6 /itinerary/something/abc/123/1.php NO URL rewritten to details.php?id=abc

    Your first two examples don't match the above rule at all so no rewriting occurs and the Apache 404 ErrorDocument is served (providing they don't map to a physical resource).

    Note that URLs #3, #4 and #6 are all rewritten to the very "same" target!

    The 2nd RewriteRule is clearly not correct (even without knowing the URLs that should be rewritten by it). Without an end-of-string anchor (ie. $) on the regex, it basically rewrites too much (as shown above). Any URL of the form /itinerary/<foo>/<bar><anything> is rewritten to details.php?id=<bar>, seemingly discarding <foo> (the 2nd path segment) and ignoring <anything>. Without knowing more information about what is going on here, the fact you are seemingly discarding the 2nd path segment is strange and potentially opens the site up to duplicate content issues.

    So, by simply appending an end-of-string anchor:

    RewriteRule ^itinerary/[A-Za-z0-9-]+/([A-Za-z0-9]+)$ details.php?id=$1 [NC,L]
    

    Aside: I removed the parentheses around the second path-segment (since you are not making use of this capturing group) and consequently changed the backreference from $2 to $1 in the substitution string.

    This will now fail to rewrite the last 3 URLs in your example (/itinerary/something/abc/123, /itinerary/something/login.php and /itinerary/something/abc/123/1.php) since the regex no longer matches, so the Apache 404 error document will be served.

    However, /itinerary/something/abc (your 3rd example) will still be written to details.php (since it matches the above regex) so the Apache 404 error document will not be served for this URL. If this URL should not be rewritten to details.php then you need to provide additional information as to why it should not be.

    So, after the above tweak to the regex, we now have the following results:

    Sample non-existing link 404.php shown? Reason
    #1 /i-donot-exist YES Does not map to file and URL not rewritten
    #2 /i-donot-exist-too.php YES Does not map to file and URL not rewritten
    #3 /itinerary/something/abc NO URL rewritten to details.php?id=abc
    #4 /itinerary/something/abc/123 YES Does not map to file and URL not rewritten
    #5 /itinerary/something/login.php YES Does not map to file and URL not rewritten
    #6 /itinerary/something/abc/123/1.php YES Does not map to file and URL not rewritten

    Nothing more can be done regarding #3 without knowing more about the format of "valid" URLs. But I suspect this should be handled in your PHP script, not Apache.