ErrorDocument 404 .htaccess not working with RewriteRule - php

.htaccess ErrorDocument 404 page not redirecting when I was using the rewrite rule. Getting 500 Internal Server Error.
Without RewriteRule the ErrorDocument is Working fine.
My Code
RewriteEngine On
<IfModule mod_rewrite.c>
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /stores/$1 [NC,L]
ErrorDocument 404 /404.html
</IfModule>

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /stores/$1 [NC,L]
The "problem" with this rule is that if you make a request for a non-existent file and that file not exist in the /stores/ subdirectory either then it will result in an endless rewrite-loop (hence the 500 Internal Server Error you are seeing) since it will attempt to rewrite as follows:
/not-exists (initial request)
/stores/not-exists (1st rewrite)
/stores/stores/not-exists (2nd pass)
/stores/stores/stores/not-exists (3rd pass)
etc.
You've not actually stated what you are trying to achieve here, but I assume /stores is a "hidden" subdirectory and you are intending to rewrite to actual files within the /stores subdirectory. This is the only way a rule like this would work with an ErrorDocument 404 directive defined in Apache.
So, when rewriting to the /stores subdirectory, you need to first check that the request would map to an actual file before issuing the rewrite. That way, any request that does not exist and does not map to a file in the /stores subdirectory will drop through to the Apache defined 404 ErrorDocument.
For example, try the following instead:
ErrorDocument 404 /404.html
RewriteEngine On
# Rewrite request to "/stores" directory if file exists in that directory
RewriteCond %{DOCUMENT_ROOT}/stores/$1 -f
RewriteRule (.+) stores/$1 [L]
# (OPTIONAL) Rewrite requests for root to "/stores/"
RewriteRule ^$ stores/ [L]
The <IfModule> container is not required (but you had the RewriteEngine directive outside of this container - which defeats the point anyway).
The RewriteBase directive is not required here if the .htaccess file is located in the document root.
It is structurally better to define your ErrorDocuments first.

Related

htaccess - redirect to error pages issue (with slash or without slash)

There is an issue with redirection to error pages:
example.com/test - will redirect to 404 error page
but
example.com/test/ - will go to the white "File not found." page
to mention:
it was working properly until some time ago (maybe update of PHP version ??)
same behavior with www/http/https version of the links
standard structure of the links is www.example.com/test/
.htaccess file code
<Files .htaccess>
order allow,deny
deny from all
</Files>
RewriteEngine On
RewriteRule ^([^/]+)/$ $1.php
RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2.php
RewriteRule sample/(.*)/(.*)/$ /sample.php?$1=$2
ErrorDocument 400 /400.php
ErrorDocument 401 /401.php
ErrorDocument 403 /403.php
ErrorDocument 404 /404.php
ErrorDocument 410 /410.php
The difference with your URLs that end in a trailing slash is that they are unconditionally rewritten to the corresponding .php file. The URLs that do not end in a trailing slash are not rewritten - nothing happens.
You are seeing the same basic "File not found" response when you directly request a non-existent .php file, regardless of whether the request is rewritten (by your rules) or not.
The "problem" might be due to the way PHP is implemented on your server. For instance, if all *.php requests are proxied to an alternative backend process then this is going to bypass your .htaccess file on the application server and the "basic" 404 response you are seeing is possibly coming from the proxy, not your application server.
You may be able to resolve this by first checking that the .php exists before rewriting to it (so it doesn't trigger a 404). And if none of your URLs contain a .php extension, you could also force any direct request for .php files to 404 (on your server, before the request is proxied - if that is what's happening).
RewriteEngine On
RewriteRule ^([^/]+)/$ $1.php
RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2.php
RewriteRule sample/(.*)/(.*)/$ /sample.php?$1=$2
The first two rules can also be combined into one. You are missing L flags on all your rules. You need to ensure that MultiViews is disabled, otherwise the last rule will not work.
Also, the regex in the last rule needs to be anchored and made more specific since it is matching too much, eg. /sample/foo/bar/baz/qux will be rewritten to /sample.php?foo/bar/baz=qux, which I assume is not the intention.
Try the following instead:
Options -MultiViews
RewriteEngine On
# Force any direct request for ".php" files to 404
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \.php$ - [R=404]
# Rewrite to ".php" file - 1 or 2 path segments
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^/]+(/[^/]+)?)/$ $1.php [L]
# Rewrite "/sample/one/two/"
RewriteRule ^sample/([^/]+)/([^/]+)/$ sample.php?$1=$2 [L]
Reference:
Another recent question that has a very similar issue and was resolved in the same way:
Custom 404 error handler in htaccess not working for non-existent ".php" files
The problem is with ending slash of RewriteRule ^([^/]+)/$ $1.php
If you write RewriteRule ^([^/]+)/?$ $1.php the tailing slash would be optional.
edit
You should also add
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
before RewriteRule statements, because of server loop - when the file exists the statements will break loop by skipping rewriting.

500 Server error instead of 404 on nested urls due to mod rewrite htaccess rule(s)

I have a site with custom .htaccess file that handles few things:
1) It treats urls without ".php" extensions as if it has ".php" in the end.
2) It redirects http:// and http://www. urls to https://www.
Here is the .htaccess file:
ErrorDocument 404 /404.php
Options -MultiViews
RewriteEngine On
## add www and turn on https in same rule
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]
# if not a directory and .php file is present then add .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
Everything works as expected, but I have observed some strange behavior that resulted in 500 errors instead of 404:
1) When you visit non-existed root level url such as https://www.example.com/skjdfhkj it redirects to 404 as expected.
2) When you visit non-existed nested url such as https://www.example.com/some-text/skjdfhkj where some-text does not match any existing php files, then it returns 404 as expected.
3) However, when you visit some non-existed nested url such as https://www.example.com/some-existing-page-name/skjdfhkj , where some-existing-page-name matches the name of existing php file (https://www.example.com/some-existing-page-name.php), then it gives out a 500 Server Error.
My question is: how do I update my htaccess to properly return a 404 instead of 500 when someone visits non-existing nested url such as https://www.example.com/some-existing-page-name/skjdfhkj (where some-existing-page-name matches the name of existing php file (https://www.example.com/some-existing-page-name.php)) ?
I guess it has something to do with mod rewrite that treats urls without .php extensions as if it had .php, but don't know how to modify htaccess to make it work properly :(
Try changing last rule as this:
# if not a directory and .php file is present then add .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
%{REQUEST_FILENAME} sometimes can give unexpected matches from filesystem using partial matches.

Access only mydomain_name/filename.html

I need to deny access for all excluded URLs:
mydomainname/filename.html
and redirect this request to:
mydomainname/index.php?page=filename.html
And the user should see in the address bar:
mydomainname/filename.html
And I want all styles and js scripts to work correctly.
How can I do this?
I am was trying this:
ErrorDocument 404 /
ErrorDocument 403 /
RewriteEngine On
RewriteBase /
RewriteRule ^(\w+)(?=\.).html$ index.php?page=$1.html
#if the request is for existent dirs, forbid the request
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !^/?$
RewriteRule ^ - [R=403,L]
RewriteCond %{REQUEST_URI} !^/?$
RewriteRule !^index.php$ - [R,F,L]
Options All -Indexes
And I have server error 500.
Without "Options All -Indexes" js files can't be loaded and styles are not working.
So, my final .htaccess file:
RewriteEngine On
ErrorDocument 403 http://mydomainname
ErrorDocument 404 http://mydomainname
# Don't show directory listings for URLs which map to a directory.
Options -Indexes
# Set the default handler.
DirectoryIndex index.php
# Internal redirect
RewriteRule ^(\w+)(?=\.).html$ index.php?page=$1.html
# Pass all requests not referring directly to files in the filesystem to
# index.php. Clean URLs are handled in drupal_environment_initialize().
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^ / [L,R]
This solution is not deny access to mydomainname/include/myfile.php (if this file is exist), but it cover all other issues.
Search for rewrite condition in .htaccess file. You will get an idea for it. Or add RewriteRule ^(.*).(gif|jpg|png|jpeg|css|js|swf)$ /public/$1.$2 [L,NC] this.

How can I capture a fully qualified local URL path with mod rewrite?

How can I capture a fully qualified local URL path with mod rewrite?
For instance, my project is located in http://{localhost}/projects/mywebsite/index.php
I tried with this RewriteBase /projects/mywebsite/ but it does not work for ErrorDocument.
my .htaccess,
RewriteEngine on
RewriteBase /projects/mywebsite/
ErrorDocument 404 /error.php
I need to do ErrorDocument 404 /projects/mywebsite/error.php but it isn't dynamic. I have to change it in two places everytime for each project.
Any ideas?
ErrorDocument doesn't accept any env variable unlike mod_rewrite rules. Here is what you can do:
Instead of ErrorDocument use mod_rewrite rules to handle 404 issues (see below)
Generate RewriteBase value dynamically using rules
You can use this code in your root .htaccess:
RewriteEngine On
RewriteBase /
# Determine the RewriteBase automatically/dynamically
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
# use %{ENV:BASE} variable set above for routing file/dir not found
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . %{ENV:BASE}error.php?e=404 [L,QSA]
The ErrorDocument is part of the apache core, it isn't affected by the Rewrite stuff which is a completely separate module.
If you need to output the contents of error.php, then output it from the php header() (based on your previous question) and don't rely on ErrorModule. Maybe something like:
header("HTTP/10 404 Not Found");
include("error.php");

how can I set .htaccess for existing files and folders

Can any one help me in .htaccess.
My use case is, if there is index.php in the directory http://domain_name/user/ then load index.php else set rewriteRule to call forbidden.php.
I did a bit but not succeed yet. .htaccess code on my server is-
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond ^(.*)$/index.php !-d
RewriteCond %{REQUEST_URI} (.*)/$
RewriteRule ^(.*)$ forbidden.php?handle=$1
</IfModule>
I think there is an easier way to do what you want. There is no need for rewriting, simply define which page acts as the entry page. In the .htaccess file you can define:
DirectoryIndex index.php
ErrorDocument 404 /forbidden.html
Now, if anybody calls your directory http://www.example.com/user/, the page http://www.example.com/user/index.php will be shown.
If the file index.html does not exist, the server will return an error, so you can define an appropriate error page. With a leading /, you can define a single error page in the root directory, without the / it will look in the relative directory http://www.example.com/user/forbidden.php.

Categories