Redirect Loops and .htaccess - regex

I just moved from a CentOS dedi to an Ubuntu VPS. The site is custom coded PHP.
Frontend works fine (including rewrite rules). The admin backend I can't get rewrite rules to work...
First error:
H00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
Then after using debug level:
AH00122: redirected from r->uri = /admin/index.php
The relevant bits of my htaccess are:
# mod_rewrite set:
Options +Includes
RewriteEngine on
# Administration
RewriteCond %{REQUEST_URI} ^(/+)admin/(.*)$
RewriteRule (.*) %{DOCUMENT_ROOT}/admin/index.php [L,QSA]
# Rewrite orther
RewriteCond %{REQUEST_URI} !^(/+)index.php(.*)$
RewriteCond %{REQUEST_URI} !^(/+)syscmd.php$
RewriteRule ^(.*)$ %{DOCUMENT_ROOT}/index.php?page=$1 [L,QSA]
# If Rewriting Failure, Show error message (Internal backup)
RewriteCond %{REQUEST_URI} !^(/+)index.php$
RewriteCond %{REQUEST_URI} !^(/+)syscmd.php$
RewriteRule (.*) \1 [F]
This was working fine on CentOS too.
Any ideas? I already tried adding the following as the first condition:
RewriteCond %{REQUEST_URI} !/admin/ [NC]
That stopped it rewriting /admin completely.
Thanks

Your rules don't appear correct as %{DOCUMENT_ROOT} represents filesystem path and it shouldn't be used in target URLs.
Try these rules:
Options +Includes +FollowSymLinks
DirectoryIndex index.php
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Administration
RewriteRule ^admin/(.*)$ admin/index.php [L,NC]
# Rewrite other
RewriteCond %{THE_REQUEST} !/syscmd\.php [NC]
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]

Related

removing php extension in htaccess returns an internal server error (500)

I'm trying to create a simple htaccess script which redirects users to the appropriate page. So, as an example, if the file/folder doesn't exist, a user navigating to /listing/id will be shown listing.php?id=id instead, or if they navigate to /username they will be shown profile.php?id=username.
The problem is, when accessing /listing/id, I retrieve an internal server error. But not because of the RewriteRule that handles this part - but because of the .php extension removal part of my htaccess script (I figured this out when I commented it out). I have no idea why this isn't working, as I believe I have the correct flags set, and am using the right block of code.
My Code
Options +FollowSymLinks -Indexes -MultiViews
RewriteEngine On
# no php extension
# (/listing/id will work if this is commented out, but the other pages won't without the .php extension)
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
# redirect to www.*
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ http://www.example.com [R=301,L]
# only allow rewriting to paths that don't exist
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.+) - [PT,L]
# external profile.php?id=$id to /$id
RewriteCond %{THE_REQUEST} /profile\.php\?id=([\w-]+) [NC]
RewriteRule ^ /%1? [R=301,L]
# /listing/$id
RewriteRule ^listing/([\w-]+)/?$ listing.php?id=$1 [L,QSA,NC]
# /$username
RewriteRule ^([\w-]+)/?$ profile.php?id=$1 [L,QSA]
Example cases
/ (index) works
/search works (the file exists so it redirects to search page not a user named search)
/username works (username.php doesn't exist so it redirects to the profile page)
/listing/test returns Internal Server Error 500 (removing the no PHP extension part of my htacess causes this page to work normally, but now all the others will require .php to be appended)
All help is appreciated, Cheers.
Try your rules in this order:
Options +FollowSymLinks -Indexes -MultiViews
RewriteEngine On
# redirect to www.*
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# external profile.php?id=$id to /$id
RewriteCond %{THE_REQUEST} /profile\.php\?id=([\w-]+)\s [NC]
RewriteRule ^ /%1? [R=301,L]
# only allow rewriting to paths that don't exist
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# /listing/$id
RewriteRule ^listing/([\w-]+)/?$ listing.php?id=$1 [L,QSA,NC]
# no php extension
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
# /$username
RewriteRule ^([\w-]+)/?$ profile.php?id=$1 [L,QSA]

force single site to use https, all other http (wordpress)

I found several related questions, but non of theme seem to work, so I have to ask again:
I'm using a wordpress site and I want a single site to use https (/kontakt/). All other sites have to use the http (due to duplicate content and such).
I tried a plugin called Wordpress HTTPS which should do exactly that, but the plugin is outdated (3 years not updated) and also doesn't work as expected.
For this case, I thought about using the .htaccess. These is my htaccess-file:
My URL looks exactly like this: http://www.example.com/kontakt/
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
RewriteCond %{HTTPS} off
RewriteRule ^kontakt/$ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,NE,NC]
# change kontaktform
RewriteCond %{HTTPS} off
RewriteRule ^/kontakt https://www.example.com/kontakt/ [R=301,L,QSA]
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/kontakt/
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L,QSA]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
This attempt was taken from here:
force one page to use HTTPS and the others to use HTTP with .htaccess
but that didn't do the trick. My problem now is:
a) the site is not redirected to https (I can confirm the htaccess is working, since i can produce 500's on demand)
b) once it is on https://, all other sides stay on that protocol (already in the link-preview)
What I actually want:
IF the site = /kontakt/ --> use https
ELSE use HTTP
Try these rules:
RewriteEngine On
RewriteBase /
# add www if missing in domain name
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=302,NE,L]
# if http and /kontakt/ then make it https
RewriteCond %{HTTPS} off
RewriteCond %{THE_REQUEST} /kontakt/ [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,NE,NC]
# if https and NOT /kontakt/ then make it http
RewriteCond %{HTTPS} on
RewriteCond %{THE_REQUEST} !/kontakt/ [NC]
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,NE,NC]
# default WP rules
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
I used %{THE_REQUEST} variable for this. THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some rewrite rules unlike %{REQUEST_URI} variable.
Clear your browser cache before testing it and also test in Chrome dev tool with caching disabled.

Getting .htaccess file to work in subfolders

I finally figured out how to get certain things to work on my website using the .htaccess file.
Redirect all non-www requests to www version. DONE.
Remove all php file extensions and add a trailing slash. DONE.
Prohibit directory views. DONE.
Limit caching. DONE.
Redirect 404 requests to home page. DONE.
This all seems to work well, but only in the ROOT directory.
It doesn't work well in subfolders. PHP extensions aren't removed. Folder paths in URLs disappear.
As I'm new to .htaccess files and regular expressions, and getting to this point took some time and lots of trial and error, I'm hesitant to tamper with the code any further.
I would appreciate any guidance on:
How to optimize this file for subfolders.
How to optimize this file in general.
Thank you.
RewriteEngine On
# redirect non-www requests to www version
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^example\.net [NC]
RewriteRule ^(.*)$ http://www.example.net/$1 [R=301,L]
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^example\.net [NC]
RewriteRule ^(.*)$ https://www.example.net/$1 [R=301,L]
# remove .php file extensions
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^/]+)/$ $1.php
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ /$1/ [R=301,L]
# disable directory view on web pages
Options -Indexes
# cached pages will expire in 5 days
ExpiresActive On
ExpiresDefault "access plus 5 days"
# re-direct 404 pages to home page
ErrorDocument 404 /
Keep your DocumentRoot/.htaccess like this:
# disable directory view on web pages
Options -Indexes
# cached pages will expire in 5 days
ExpiresActive On
ExpiresDefault "access plus 5 days"
# re-direct 404 pages to home page
ErrorDocument 404 /
RewriteEngine On
RewriteBase /
# redirect non-www requests to www (both http and https)
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{HTTPS}s on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=302,L,NE]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ /$1/ [R=301,L]
## hide .php extension
# To externally redirect /dir/file.php to /dir/file
RewriteCond %{THE_REQUEST} \s/+(.*?/)?(?:index)?(.*?)\.php[\s?] [NC]
RewriteRule ^ /%1%2/ [R=302,L,NE]
# To internally forward /dir/file to /dir/file.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
Once you verify it is working fine, replace R=302 to R=301. Avoid using R=301 (Permanent Redirect) while testing your mod_rewrite rules.

Apache non www to www badly re writting arrays on URL

we have the following .htaccess configuration:
RewriteEngine on
allow from all
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
# otherwise forward it to index.php
RewriteRule . index.php
RewriteCond %{HTTP_HOST} ^domain1\.domain2\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.domain1\.domain2\.com$
RewriteRule ^(.*)$ "http\:\/\/www\.domain1\.com\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^domain1.com$
RewriteRule ^/?$ "http\:\/\/www\.domain1\.com\/" [R=301,L]
Between other things we want to redirect all non-www URLs to the ones with the www.
Everything works fine, except for the pages where the URL is like this:
index?Form%5bplace%5d=Caribbean&Form%5bdestination%5d=Virgin+Islands&Form%5btype%5d=A
When we enter the URL without the www our redirect ends up with the following URL:
index?Form%255bplace%255d=Caribbean&Form%255bdestination%255d=Virgin+Islands&Form%255btype%255d=A
Which gives an 404 error because it is not recognized.
Any idea how to avoid this?
Replace your code with this:
allow from all
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# if a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
# otherwise forward it to index.php
RewriteRule . index.php [L]
RewriteCond %{HTTP_HOST} ^domain1\.domain2\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.domain1\.domain2\.com$
RewriteRule ^ http://www.domain1.com%{REQUEST_URI} [NE,R=301,L]
RewriteCond %{HTTP_HOST} ^domain1\.com$
RewriteRule ^/?$ http://www.domain1.com/ [R=301,L]
What's happening is that the % symbol is getting escaped to %25.
You can avoid this using the NE flag on your rules

Remove 'index.php' from URL with .htaccess

I've been trying all sorts of solutions from this site and none seem to work. I'm currently hosting with hostgator. This is my current .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
<IfModule mod_suphp.c>
suPHP_ConfigPath /home/user/php.ini
<Files php.ini>
order allow,deny
deny from all
</Files>
</IfModule>
This is in the root folder of my site. I have also tried adding a ? after index.php and no luck. Does anyone know why this isn't working?
This is the code you can use in your .htaccess (under DOCUMENT_ROOT) to remove index.php from URI:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s(.*)/index\.php [NC]
RewriteRule ^ %1 [R=301,L]
Symfony 2 has an excellent solution:
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by apache
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .? - [L]
RewriteRule .? %{ENV:BASE}/index.php [L]
This accomplishes the following:
RewriteBase is not necessary (useful when the site is in a subdirectory beneath the web root)
index.php is removed if present
The request is routed to the correct index.php with the full query string from the original request
Note that the line:
RewriteRule ^(.*) - [E=BASE:%1]
is responsible for setting the %{ENV:BASE} variable for later on. Refer to Apache documentation on E|env flag.
I tried this and works fine:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# Removes index.php from ExpressionEngine URLs
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteCond %{REQUEST_URI} !/system/.* [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
# Directs all EE web requests through the site index file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
Exceptions
If your site’s system directory (/system/) has been renamed and is still accessible by URL, modify the RewriteCond line above:
RewriteCond %{REQUEST_URI} !/newdirectoryname/.* [NC]
If you are running EE from a sub-directory rather from the root of your domain (e.g. http://example.com/myeesite/ instead of http://example.com/), just remove the slash preceding index.php in the RewriteRule line above, like so:
RewriteRule ^(.*)$ index.php/$1 [L]
If you are running EE from a sub-directory and it still doesn’t work after removing the slash, you may need to specify the sub-directory in your rewrite rule. For example, if your sub-folder is named testing, change:
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
To:
RewriteRule (.*?)index\.php/*(.*) testing/$1$2 [R=301,NE,L]
And change:
RewriteRule ^(.*)$ /index.php/$1 [L]
To:
RewriteRule ^(.*)$ testing/index.php/$1 [L]
If your host requires forcing query strings, try adding a question mark following index.php in the RewriteRule line above, like so:
RewriteRule ^(.*)$ /index.php?/$1 [L]
To remove index.php from urls on apache2.4 you can use the following rule :
RewriteEngine on
RewriteRule ^index\.php/(.+)$ /$1 [L,R]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !index\.php /index.php%{REQUEST_URI} [L,END]
This will change the uri
/index.php/foobar
to
/foobar
This rule will return an internal server error for lower versions of apache as they don't support the END flag. Please see the anubhava's answer above that works almost on all versions.
I've been compelled to join stack overflow.com today to comment here as the answer has solved a long term problem I've had with a Zend Framework website. I've worked on the website around 3 1/2 years and during that time I discovered that it didn't handle index.php correctly and this causes webmaster tools to see duplicate titles etc.
I decided to search again today for a solution, one of many times attempted.
This is the one (the last answer shown above) that solves my problem.
# Removes index.php from ExpressionEngine URLs
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteCond %{REQUEST_URI} !/system/.* [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
As an example. this is what it achieves for me.
http://www.domainname.co.uk/index.php/categories/url-name.html
becomes
http://www.domainname.co.uk/categories/url-name.html
Thank you to everyone who contributed to the original question as it lead to the answer and solution above.
Extra Note: I have other rewrite commands that handles the other aspects but those on their own didn't fix the index.php and the only time this has been fixed is by using.
# Removes index.php from ExpressionEngine URLs
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteCond %{REQUEST_URI} !/system/.* [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
I only hope it helps others whether its ExpressionEngine or Zend Framework, in the future.