.htaccess infinite loop on 404 in subfolders - .htaccess

I got a little problem concerning a project I'm working on.
I want to maintain only one .htaccess file in the root folder of this project. It is modular, so there are many different subfolders. My current .htacccess looks as follows:
ErrorDocument 401 /401.php
ErrorDocument 404 /404.php
RewriteEngine On
#strip www from domain
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
#ignore existing files and directories
RewriteCond %{REQUEST_FILENAME} -f [NC,OR]
RewriteCond %{REQUEST_FILENAME} -d [NC]
RewriteRule .* - [L]
# Check if query string exists
RewriteCond %{QUERY_STRING} ^$
# Check that the request is not for an existing file
RewriteCond %{REQUEST_FILENAME} !-f
The problem is that every 404 error in a subfolder leads to an infinite loop because it looks for i.e. http://mydomain.tld/modules/index.php?p=404 instead of http://mydomain.tld/index.php?p=404 .
I know I could hardcode the URL in my .htaccess, but the problem is that it's kind of a community-hosting platform, where the community is specified dynamically via the subdomain and I want to keep the request in that specific subdomain.
Is there any possible way to force the .htaccess to use the index.php in the root-folder without giving the absolute url?
Thanks in advance!

Related

Htacess Multi language

Im trying to do a multi language errordocument on my htaccess.
But it doesnt enter to my original 404 error page or it just only goes to one of the error pages.
i just want to check the folder and if the folder is "pt", it goes to the portuguese 404error page, else it goes to the other pages with the correspond language.
i already tryed more example but non have help me.
In below there some code that i had already tryed.
Try #1
ErrorDocument 404 http://www.teleondagroup.com/novosite/Teleonda/
RewriteRule ^([a-z]{2}) $1/404error.php [L]
Try #2
RewriteRule ^(pt)/ /$1/404error.php [R,L]
ErrorDocument 404 http://www.teleondagroup.com/novosite/Teleonda/pt/404error.php
RewriteRule ^(en)/ /$1/404error.php [R,L]
ErrorDocument 404 http://www.teleondagroup.com/novosite/Teleonda/en/404error.php
I already solve the problem with this site.
https://webmasters.stackexchange.com/questions/47974/separate-404-page-for-subdirectory
You can use something like the following :
RewriteEngine on
#if a file or directory doesn't exist in a particular folder
RewriteCond %{DOCUMENT_ROOT}/$0 !-f [OR]
RewriteCond %{DOCUMENT_ROOT}/$0 !-d
#redirect the request to /errorpage.php in that folder
RewriteRule ^([^/]+)/.*$ /$1/errorpage.php [L,R]
This will Redirect a 404 Uri to /errorpage.php file located in the requested directory ie . example.com/demo/brokenlink.php to example.com/demo/errorpage.php .
Or if this is just for a single directory /pt you can use the following :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?pt.*$ /pt/errorpage.php [L,R]

Redirect to subfolder with same name on localhost

I have a webproject saved in a "base" folder of the domain "example.com" which contains a main.php and several subfolders. The second part of the code below redirects all requests (except main.php itself and page404.php) to this main.php and hands over the originally requested URL in the variable "path".
In addition there is a first part which redirects all requests of pages of the baseurl to a subfolder "folder1". So in the end the request of
www.example.com/somepage.php
will lead to
example.com/main.php?path=www.example.com/folder1/somepage.php
(Requests to other subfolders shall only be redirected to the main.php. So www.example.com/somefolder/somepage.php will lead to example.com/main.php?path=www.example.com/somefolder/somepage.php - without adding "folder1".)
The code below actually does what I want:
ErrorDocument 404 /page404.php
Options -Indexes
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine on
#first part: redirect to folder1/
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/*
RewriteCond %{REQUEST_URI} !^page404*
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ folder1/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ index.php
#second part: redirect to main.php
RewriteCond %{REQUEST_FILENAME} (.*)\.php [NC]
RewriteCond %{REQUEST_URI} !main\.php
RewriteCond %{REQUEST_URI} !page404\.php
RewriteRule ^([^?]*)$ /main.php?path=$1 [NC,L,QSA]
</IfModule>
But I have two questions:
Side question: I have the feeling that actually redirecting to "folder1" is way to complicated (even though it works) when I only want to add the "folder1" to the path variable in case a file of the base folder is called. Can you show me a better way to archieve this?
Main question: I have the same project on a localhost where the main folder is named "folder1" which contains the folder "folder1". So there the request of htttp://localhost/folder1/somepage.php shall lead to htttp://localhost/folder1/main.php?path=htttp://localhost/folder1/folder1/somepage.php (I replaced "http" by "htttp" to avoid automatic link recognition of SO) - How do I have to change the code above to have it working in the "localhost/folder1" scenario?
This stuff can be simplified:
ErrorDocument 404 /page404.php
Options -Indexes
DirectoryIndex index.php
RewriteEngine on
# ignore main.php, page404.php OR any files/directory for any rules below
RewriteCond %{REQUEST_URI} ^/(main|page404)\.php
RewriteRule ^ - [L]
#first part: /folder1/path
RewriteRule ^([^/]+?\.php)$ main.php?path=folder1/$1 [L,QSA]
#second part: rewrite to main.php
RewriteRule ^(.+?\.php)$ main.php?path=$1 [L,QSA]

Multilanguage htaccess file (LTD)

I want to have a multi language site. Now, I have 2 domains. The first one is the main domain. That is website.nl. And i have a domain alias, website.org. So the 2 domains share the same public_html folder.
What I want is that:
website.nl will use the file /index.php/$1 and
website.org will use the file /gb/index.php/$1 (So when the url is website.org/test you will use the file /gb/index.php/test (No url redirect)
I found on another topic on stackoverflow the following:
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} website.org
RewriteRule ^(.*)$ /gb/index.php [L]
RewriteRule ^(.*)$ /index.php/$1 [L]
But this htaccess file won't work. I will get a 500 error. That's all.
Can someone see what's going wrong?
Your rules are looping, otherwise the 2 rules will mess with each other and loop indefinitely (e.g. requesting /foo will result in /index.php/index.php/index.php/index.php... etc thus returning 500). You need to add some conditions to stop the looping. Try changing the conditions and rules to:
RewriteCond %{HTTP_HOST} website.org
RewriteCond %{REQUEST_URI} !^/gb/index.php
RewriteRule ^(.*)$ /gb/index.php/$1 [L]
RewriteCond %{REQUEST_URI} !^/gb/index.php
RewriteCond %{REQUEST_URI} !^/index.php
RewriteRule ^(.*)$ /index.php/$1 [L]

mod rewrite to remove file extension, add trailing slash, remove www and redirect to 404 if no file/directory is available

I would like to create rewrite rules in my .htaccess file to do the following:
When accessed via domain.com/abc.php: remove the file extension, append a trailing slash and load the abc.php file. url should look like this after rewrite: domain.com/abc/
When accessed via domain.com/abc/: leave the url as is and load abc.php
When accessed via domain.com/abc: append trailing slash and load abc.php. url should look like this after rewrite: domain.com/abc/
Remove www
Redirect to 404 page (404.php) when accessed url doesn't resolve to folder or file, e.g. when accessing either domain.com/nothingthere.php or domain.com/nothingthere/ or domain.com/nothingthere
Make some permanent 301 redirects from old urls to new ones (e.g. domain.com/abc.html to domain.com/abc/)
All php files sit in the document root directory, but if there is a solution that would make urls such as domain.com/abc/def/ (would load domain.com/abc/def.php) also work it would be great as well, but not necessary
So here is what I have at the moment (thrown together from various sources and samples from around the web
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
# redirect from www to non-www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# remove php file extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
# resolve urls to matching php files
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ $1.php [L]
With this the first four requirements seem to work, whether I enter domain.com/abc.php, domain.com/abc/ or domain.com/abc, the final url always ends up being domain.com/abc/ and domain.com/abc.php is loaded.
When I enter a url that resolves to a file that doesn't exists I'm getting an error 310 (redirect loop), when really a 404 page should be loaded. Additionally I haven't tried if subfolders work, but as I said, that's low priority. I'm pretty sure I can just slap the permanent 301 redirects for legacy urls on top of that without any issues as well, just wanted to mention it. So the real issue is really the non working 404 page.
I've had problems with getting ErrorDocument to work reliably with rewrite errors, so I tend to prefer to handle invalid pages correctly in my rewrite cascade. I've tried to cover a fully range of test vectors with this. Didn't find any gaps.
Some general points:
You need to use the DOCUMENT_ROOT environment variable in this. Unfortunately if you use a shared hosting service then this isn't set up correctly during rewrite execution, so hosting providers set up a shadow variable to do the same job. Mine uses DOCUMENT_ROOT_REAL, but I've also come across PHP_DOCUMENT_ROOT. Do a phpinfo to find out what to use for your service.
There's a debug info rule that you can trim as long as you replace DOCROOT appropriately
You can't always use %{REQUEST_FILENAME} where you'd expect to. This is because if the URI maps to DOCROOT/somePathThatExists/name/theRest then the %{REQUEST_FILENAME} is set to DOCROOT/somePathThatExists/name rather than the full pattern equivalent to the rule match string.
This is "Per Directory" so no leading slashes and we need to realise that the rewrite engine will loop on the .htaccess file until a no-match stop occurs.
This processes all valid combinations and at the very end redirects to the 404.php which I assume sets the 404 Status as well as displaying the error page.
It will currently decode someValidScript.php/otherRubbish in the SEO fashion, but extra logic can pick this one up as well.
So here is the .htaccess fragment:
Options -Indexes -MultiViews
AcceptPathInfo Off
RewriteEngine On
RewriteBase /
## Looping stop. Not needed in Apache 2.3 as this introduces the [END] flag
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L,NS]
## 302 redirections ##
RewriteRule ^ - [E=DOCROOT:%{ENV:DOCUMENT_ROOT_REAL},E=URI:%{REQUEST_URI},E=REQFN:%{REQUEST_FILENAME},E=FILENAME:%{SCRIPT_FILENAME}]
# redirect from HTTP://www to non-www
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# remove php file extension on GETs (no point in /[^?\s]+\.php as rule pattern requires this)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_METHOD} =GET
RewriteRule (.*)\.php$ $1/ [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ $0/ [L,R=301]
# terminate if file exists. Note this match may be after internal redirect.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L,E=END:1]
# terminate if directory index.php exists. Note this match may be after internal redirect.
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{ENV:DOCROOT}/$1/index.php -f
RewriteRule ^(.*)(/?)$ $1/index.php [L,NS,E=END:1]
# resolve urls to matching php files
RewriteCond %{ENV:DOCROOT}/$1.php -f
RewriteRule ^(.*?)/?$ $1.php [L,NS,E=END:1]
# Anything else redirect to the 404 script. This one does have the leading /
RewriteRule ^ /404.php [L,NS,E=END:1]
Enjoy :-)
You'll probably want to check if the php file exists before adding the tailing slash.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
or if you really want a tailing slash for all 404 pages (so /image/error.jpg will become /images/error.jpg/, which I think is weird):
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*[^/]$ /$0/ [L,R=301]
I came up with this:
DirectorySlash Off
RewriteEngine on
Options +FollowSymlinks
ErrorDocument 404 /404.php
#if it's www
# redirect to non-www.
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [L,R=301,QSA]
#else if it has slash at the end, and it's not a directory
# serve the appropriate php
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1.php [L,QSA]
#else if it's an existing file, and it's not php or html
# serve the content without rewrite
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !(\.php)|(\.html?)$
RewriteRule ^ - [L,QSA]
#else
# strip php/html extension, force slash
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*?)((\.php)|(\.html?))?/?$ /$1/ [L,NC,R=301,QSA]
Certainly not very elegant (env:redirect_status is quite a hack), but it passes my modest tests. Unfortunately I can't test the www redirection, as I'm on localhost, and has no real access to a server, but that part should work too.
You see, I used the ErrorDocument directive to specify the error page, and used the DirectorySlash Off request to make sure Apache doesn't interfere with the slash-appending fun. I also used the QSA (Query String Append) flag that, well, appends the query string to the request so that it's not lost. It looks kind of silly after the trailing slash, but anyhow.
Otherwise it's pretty straightforward, and I think the comments explain it pretty well. Let me know if you run into any trouble with it.
Create a folder under the root of the domain
Place a .htaccess in the above folder as RewriteRule ^$ index.php
Parse the URL
With PHP coding you can now strip the URL or file extension as required

Logical AND in htaccess modrewrite?

This is my htaccess file
RewriteBase /
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
RewriteCond %{REQUEST_URI} !^/chat/
RewriteCond %{REQUEST_URI} !^/m/
RewriteCond %{REQUEST_URI} !^/__admin/
RewriteCond %{REQUEST_URI} !^/gzip_headers.php
RewriteCond %{REQUEST_URI} !^/phpfreechat/
RewriteCond %{REQUEST_URI} !^/_temp/
RewriteRule ^.+\.php$ index.php [L]
RewriteRule ^.*\.css gzip_headers.php [L]
RewriteRule ^.*\.js gzip_headers.php [L]
RewriteRule ^classifieds/ /index.php [L]
RewriteCond %{REQUEST_URI} !^/movies/.
RewriteRule ^movies/ /index.php [L]
RewriteCond %{REQUEST_URI} !^/games/.
RewriteRule ^games/ /index.php [L]
RewriteRule ^jntu/ /index.php [L]
RewriteRule ^news/ /index.php [L]
My idea behind this basically is,
forward everything to public_html/index.php (except some directories)
forward all js and css to gzip file, ( i am doing this basically because im not jsut gzipping them but also compressing in tha phpfile)
the problem is when I load images from subdirectories the are redirected to index.php as well, so just creating conditions for those directories and storing images in them like RewriteCond %{REQUEST_URI} !^/games/.
I would like to make it simple to do stuff like this
forward everything to index.php (except some conditions on top)
forward css and js to gzip file
load images and flash and some other mime types straight away only if they exists. (jpg|gif|png|swf|flv|mp4|3gp|mp3|zip|rar|exe)
Something like logical AND REQUEST_URI and -f flag I guess
Try these rules:
RewriteCond %{HTTP_HOST} =example.com [NC]
RewriteRule ^ http://www.example.com%{REQUEST_URI} [L,R=301]
RewriteRule .*\.(js|css)$ gzip_headers.php [L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .+\.(jpg|gif|png|swf|flv|mp4|3gp|mp3|zip|rar|exe)$ - [L]
RewriteCond %{REQUEST_URI} !^/(gzip_headers|index)\.php$
RewriteCond %{REQUEST_URI} !^/(chat|m|__admin|phpfreechat|_temp)/
RewriteRule ^.+\.php$ index.php [L]
I'm not sure why your images are being redirected if your rule only redirects URIs ending with '.php'. That should exclude all other file extensions from the rule.
I'm also not sure what you mean by needing 'logical and'. When you have a number of RewriteCond lines before a RewriteRule those conditions are ANDed together and the rule is only applied if they all are true.
You can't use modrewrite to check for the existance of files and say "if the file exists, don't apply any rules, just serve up the file".
I think the best solution would be to either use a single top-level directory called 'static' or 'images' where you put all your files and exclude it from the rules, or have a wider-matching rule.
So for example you could make 'static' or 'images' a special directory name and exclude any url that contains .*/images/.* from the rules. Then /something/images/image.jpg and /something/else/images/image.jpg would both be excluded and the file would be served up.
Another hacky way would be to serve the files up from PHP. So in PHP you would translate $_SERVER['REQUEST_URI'] into a filename and see if it exists. If it does, you can write the file contents to the PHP output stream, although this won't be as efficient as leaving it up to Apache, and actually I really would not recommend it.
But like I said before, if your rule is only matching files that end with .php then your images should not be getting redirected. I would figure out why this is happening first. There is a way to turn on debug logging for mod_rewrite but you'll have to Google that.

Resources