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 |
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.