Apache RewriteRule Issues - Different behaviour local compared to server - apache

I'm having some very weird issues with a simple RewriteRule that is working as it should locally but when deployed to the server I'm getting 500 errors with the text:
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.
The following is the code that I am using:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/(foo|bar|baz)/?
RewriteCond %{REQUEST_URI} !^/410/index.php$
RewriteRule ^.*$ /410/index.php? [L]
</IfModule>
What I want is anything other than /foo, /bar, or /baz to show the page located at /410/index.php
Yes, mod_rewrite.c is installed/enabled on the server.

Since this is for an .htaccess file try removing the slash preceding the "410" in the rewrite rule. Also if you check to see if it's a real file that should stop the endless redirects back to the index page.
I'm going to take a guess and say there is the slight chance (and I couldn't find documentation on this) that the request string you're rewriting with the ? to flush the existing query string might not being matched.
RewriteEngine On
#check if it's a not a real file
RewriteCond %{REQUEST_FILENAME} !-f
#Check if the request doesn't start with foo, bar, or baz
RewriteCond %{REQUEST_URI} !^/(foo|bar|baz)
#Check if uri doesn't only contain the /410/index.php
RewriteCond %{REQUEST_URI} !^/410/index.php\??$
#rewrite the file
RewriteRule ^.*$ 410/index.php? [L]

Related

htaccess pretty urls not working

Folder structure:
- assets
- all css / js
- calsses
- all models, db ant etc
- views
- admin
- app
- index.php
- customers.php
.......
my .htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^(www.)?localhost:8080$
RewriteRule ^(.*)$ /views/$1
RewriteRule ^(/)?$ /views/index.php [L]
address : localhost:8080/app/ - working fine, but then I try to add pretty url for example in my customers.php - localhost:8080/app/customers.php?id=5 change to localhost:8080/app/customers/id/5
htaccess added new line:
RewriteRule /id/(.*) customers.php?id=$1
It's not working, it always return 500 Internal Server Error there could be the problem?
plus Need all urls without .php extend
You'd have to include those conditions for every rule. You'd be better off just rewriting everything to, say views/router.php then using PHP to include the different controllers, or serve a 404 when the URL isn't valid.
RewriteRule !^views/router\.php$ views/router.php [NS,L,DPI]
I agree with Walf in that handling routes through a router class is a better idea (especially in the long run!) than using .htaccess redirects.
However, as your question seems to be more about why is this not working than about how you should do it, here is an explanation for what is going on.
I will be using these URLs as examples:
localhost:8080
localhost:8080/app
localhost:8080/app/customers/id/5
Your first rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^(www.)?localhost:8080$
RewriteRule ^(.*)$ /views/$1
As you intended, this RewriteRule will match any URL which is not a file, not a directory, and made to localhost:8080.
localhost:8080 # not matched because it leads to a directory.
localhost:8080/app -> localhost:8080/views/app
localhost:8080/app/customers/id/5 -> localhost:8080/views/app/customers/id/5
Your next rule:
RewriteRule ^(/)?$ /views/index.php [L]
It is important to realize that RewriteCond statements apply only to the first RewriteRule following them, thus all that is being checked here is the path.
Side note: ^(/)?$, as you are not using $1, can be simplified to ^/?$.
localhost:8080 -> localhost:8080/views/index.php
localhost:8080/views/app # not matched
localhost:8080/views/app/customers/id/5 # not matched
As the L flag is specified, Apache will immediately stop the current iteration and start matching again from the top. The documentation is badly worded. Thus, localhost:8080/views/index.php will be run through the first rule, fail to match, be run through this rule, fail to match, and then as no other rules exist to check (yet) no rewrite will be done.
Now lets look at what happens when you add your broken rule.
RewriteRule /id/(.*) customers.php?id=$1
There are a few problems here. First, as you don't require that the URL start with /id/ the rule will always match a URL that contains /id/, even if you have already rewritten the URL. If you amended this by using ^/id/(.*), then you would still have issues as the string that the rewrite RegEx is tested against has leading slashes removed. Lastly and most importantly, customers.php does not exist in your root directory.
localhost:8080/views/index.php # not matched
localhost:8080/views/app # not matched
localhost:8080/views/app/customers/id/5 -> localhost:8080/customers.php?id=5
This is the last rule in your file currently, so now Apache will start over. customers.php does not exist in your directory, so it will be rewritten to views/customers.php. No other rules matched, but the URL has changed and so Apache will start over again, as /views/customers.php does not exist, it will be rewritten to /views/views/customers.php ... This pattern will repeat until you hit the maximum iteration limit and Apache responds with a 500 error.
You can solve this several ways. Here would be my preferred method, but only if you cannot use a router.
RewriteEngine on
# Rewrite the main page, even though it is a directory
RewriteRule ^/?$ views/index.php [END]
# Don't rewrite any existing files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .? - [S=999,END]
RewriteRule ^app/?$ views/app/index.php [END]
RewriteRule ^app/id/(.*)$ views/app/customers.php?id=$1 [END]
TL;DR Use a PHP based router. .htaccess rules can be incredibly confusing.
Please refer to the question, How to make Clean URLs
I think this is what you needed.
you can use RewriteRule ^(.*)$ index.php [QSA,L]
Having another crack.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{HTTP_HOST} !^(?:www\.)?localhost:8080$ [OR]
RewriteCond $0 =views
RewriteRule [^/]* - [END]
RewriteRule ^(app|admin)/([^/]+) views/$1/$2.php [DPI,END]
RewriteRule ^(app|admin)/?$ views/$1/index.php [DPI,END]
You may have to use L instead of END flags if your Apache is older. Set up an ErrorDocument for 404s, too.
Don't muck around with query strings, just parse $_SERVER['REQUEST_URI'] in PHP, e.g. start by exploding it on /. Then you'll have all the parameters of the original pretty URL. You can do that part in an include so each controller can reuse the same code.
I tried your structure and .htaccess file myself and found an endless loop in the apache logs. I bet you got something like this:
Mon Nov 28 19:57:32.527765 2016] [core:error] [pid 10] [client 172.18.0.1:35048] AH00124: 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.
I could fix it by adding the last rule like:
RewriteRule id/(.*) /views/app/customers.php?id=$1
The leading / is not needed for the match and the target needs the full path. Note that I got the id double (e.g. 123/123) on the url: http://localhost:8080/id/123.
This is caused by one of the 2 previous rules (removing them fixes it) so you might need to change them.
Here is what you want :
RewriteEngine On
RewriteBase /app/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^\/?$ views/index.php [L]
RewriteRule ^([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)\/([a-zA-Z0-9]+)\/?$ views/$1.php?$2=$3 [L]
RewriteRule ^([a-zA-Z0-9]+)\/?$ views/$1.php [L]

Why does this RewriteRule produce infinite recursion?

I am trying to do rather basic URL rewriting but cannot get it running properly.
I want to redirect all requests to wordpress.foobar.com to a local symlinked WordPress installation via my .htaccess file:
RewriteEngine On
RewriteCond %{SERVER_NAME} ^wordpress\.foobar\.com$
RewriteRule ^(.*) /html/wordpress/$1 [L]
While I can perfectly access foobar.com/html/wordpress, visiting wordpress.foobar.com will raise a 500 Internal Server Error.
Apache's error log will contain the following:
[error] [client 12.123.123.123] 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.
When I enable debug LogLevel I can see that Apache is trying to rewrite favicon.ico infinitely, always appending another layer of /html/wordpress/ until the recursion limit is reached.
What's wrong with this rewrite?
Use:
RewriteCond %{SERVER_NAME} ^wordpress\.foobar\.com$
RewriteCond %{REQUEST_URI} !/html/wordpress/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /html/wordpress/$1 [L]
With -f and -d test, you do not redirect existing files and directories. This way, you avoid the problems with favicon.ico (if you have that file, I suggest you add if this is not the case).
When you get the error Request exceeded the limit of 10 internal redirects due to
probable configuration error., ask yourself the question: How did I design my rules to terminate at some point, and why does it not terminate.
In your case, your rule matches everything. The status of the condition will not change either, so if your rule matches one time, it will match an infinite amount of times. This might work on some setups if you rewrite to a file that does exist. It is a safer bet to just prevent it from rewriting more than once by testing if /html/wordpress/ already is in the url:
RewriteCond %{SERVER_NAME} ^wordpress\.foobar\.com$
RewriteCond %{REQUEST_URI} !/html/wordpress/
RewriteRule ^(.*)$ /html/wordpress/$1 [L]
Besides this, I am not sure if wordpress will recognize your rewritten url. That is for you to figure out.

Why does mod_rewrite process the rules after the [L] flag

There are the rules:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) dir/index.php?$1 [L]
RewriteRule dir/index\.php.* - [F]
Why the last rule is processed and it returns Forbidden for all requests?
I need that if file or directory is not found then the next rule shouldn't be processed.
The next example isn't working for me as well:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? - [S=1]
RewriteRule dir/index\.php.* - [F]
RewriteRule (.+) dir/index.php?$1
It still returns Forbidden for all requests.
Why the last rule is processed and it returns Forbidden for all requests?
When the URL foobar is requested:
The two conditions (line 2, 3) match
Pattern matches, the resulting URL becomes dir/index.php?foobar (line 4)
The [L] flag causes the rewriting to stop -- it does not stop Apache from having another go at the rewritten URL since it has changed (see below).
With dir/index.php as the input URL:
The condition does not match (line 2) since file exists
Jumps to line 5
Pattern matches, hence the Forbidden error
When directory or filename changes, Apache has to re-evaluate various configuration sections (e.g. Directory and Files) and the .htaccess file for the "re-written" path. This is why Apache might perform another iteration even when the previous one was ended by [L] flag.
The last string supposes to restrict the direct access to UFL handler.
Direct access means requesting the file through a link like: domain.com/dir/index.php
I think adding another condition before line 5 should work:
RewriteCond %{THE_REQUEST} dir/index\.php\x20HTTP/\d\.\d$
RewriteRule . - [F]
The THE_REQUEST server variable contains the request sent by the browser without any rewriting applied. This could be useful to detect what page was originally requested by the browser.
THE_REQUEST
The full HTTP request line sent by the browser to the server (e.g.,
"GET /index.html HTTP/1.1"). This does not include any additional
headers sent by the browser. This value has not been unescaped
(decoded), unlike most other variables below.
I am not exactly sure of what you meant by "the next rule".
But if you don't want some rules to be executed when a non-existent file is requested, then using the following structure may help. (The following piece of code is copied from the Apache RewriteRule Flags Page)
# Is the request for a non-existent file?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# If so, skip these two RewriteRules
RewriteRule .? - [S=2]
RewriteRule (.*\.gif) images.php?$1
RewriteRule (.*\.html) docs.php?$1
And also using [R] for redirecting instead of [L] might help with the problem of returning Forbidden for all requests.

Mod rewrite - redirect issue - local server is fine, live server isn't

Having a bit of a problem with the below:
RewriteEngine On
RewriteOptions Inherit
RewriteBase /
#Add trailing slash if not a directory or file, but not if it contains a dot
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.
RewriteRule .*[^/]$ $0/ [L,R=301]
# Don't redirect these directories
RewriteRule ^/?_images/.+$ - [L]
RewriteRule ^/?_lib/.+$ - [L]
RewriteRule ^/?_scripts/.+$ - [L]
RewriteRule ^/?_temp/uploads/.+$ - [L]
RewriteRule ^/?_template/.+$ - [L]
# Redirect via router, but not these files
RewriteCond %{REQUEST_URI} !^(\/!favicon.ico|robots.txt|sitemap.xml).*$
RewriteCond %{REQUEST_URI} !^\/$
RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]
The problem I'm having is the 'not redirecting directories' - basically files in these folders should still show, - this was working correctly, but I'm having a bit of trouble displaying something from the /_lib/images/ directory - for some reason I always get a 404 error thrown up (possibly because it goes via the router).
On closer examination by displaying the error number, it actually seems to be a 406 error (which I've not come across before) and the 404 probably results from not having a 406 error page.
The weird thing is, it works perfectly locally on XAMPP but not on the live server - also, if I rename _lib/images/ to, say, _lib/a/ it will work perfectly ... so the question is, am I completely missing something here? Even a simple 'hello world' results the same....
406 Not Acceptable The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.
Sounds like you don't have the associations for your image file types set up on the server. Move an image to DOCROOT, and then try to display it. If it returns a 406, then you need to set up the correct file associations.

Mediawiki Subdirectory Installation

Possible Duplicate: MediaWiki on SubDirectory and SubDomain (However doesn't have an answer, nor any replies offering help)
Alright, I'm trying to configure MediaWiki to be installed to a sub-directory. I previously had it installed to a primary domain on http://www.example.com/ with a mod_rewrite using a Short URL of /wiki/Main_Title.
As a note, I'm also on HostGator shared hosting which has special rules for short urls.
My directory structure is as such:
/ (site root; location of .htaccess)
/wiki/ (mediawiki root; location of LocalSettings.php)
Here's what I tried,
.htaccess:
RewriteEngine on
RewriteBase /
RewriteRule ^(.*)\&(.*)$ $1\%26$2
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^wiki/(.+)$ ./wiki/index.php?title=$1 [PT,L,QSA]
/wiki/LocalSettings.php:
## The URL base path to the directory containing the wiki;
## defaults for all runtime URL paths are based off of this.
## For more information on customizing the URLs please see:
## http://www.mediawiki.org/wiki/Manual:Short_URL
##
$wgScriptPath = "/wiki";
$wgScriptExtension = ".php";
$wgArticlePath = "$wgScriptPath/$1";
However, I do not get anything. I simply get a 403/Forbidden error; no 500 Internal Server Error, just a 403 - url http://www.example.com/. It's as if there's nothing being done. I've banged my head against the wall trying to figure this out. Any help is appreciated.
Thanks in advance!
What is the purpose of
RewriteRule ^(.*)\&(.*)$ $1\%26$2
You've lost me entirely on this one. Any URI with a second parameter will loop indefinitely and generate a 500 status return.
If you read the Rewrite documentation:
What is matched?
...If you wish to match against the ... query string, use a RewriteCond with the ... %{QUERY_STRING} variables
The & is normally part of the query parameter. It can appear in the RewriteRule pattern in the case of malformed URI (e.g. fred&q=1). By default, mod_rewrite will treat this as fred?q=1, but this converts it to the escaped %26 variant so this would be passed as a title fred&q=1 to MW (which is an invalid MW title by the way). I think that you should get rid of it or at least understand what you are trying to do here.
The last line should be
RewriteRule ^wiki/(.+) wiki/index.php?title=$1 [PT,L,QSA]
and keep the RewriteBase otherwise mod_rewrite can get confused.
This should work OK:-)
You're on the right track... if you're on a shared environment, then try this:
RewriteEngine on
# Comment to force base to be the subdir:
# RewriteBase /
RewriteRule ^(.*)\&(.*)$ $1\%26$2
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^wiki/(.+)$ ./wiki/index.php?title=$1 [PT,L,QSA]
Two hints:
If you're not in a hosted environment (= if it's your own server and you can modify the virtual hosts, not only the .htaccess files), try to use the RewriteLog directive: it helps you to track down such problems:
# Trace:
# (!) file gets big quickly, remove in prod environments:
RewriteLog "/web/logs/mywebsite.rewrite.log"
RewriteLogLevel 9
RewriteEngine On
My favorite tool to check for regexp:
http://www.quanetic.com/Regex (don't forget to choose ereg(POSIX) instead of preg(PCRE)!)
My ticket to HostGator resolved the issue, albeit un-helpfully. I was hoping for a single .htaccess solution, rather than a double .htaccess redirect/rewrite. However, here's my solution.
/:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^.*$ http://www.example.com/wiki/
/wiki/:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?title=$1 [L,QSA]
I tried different solutions and what worked for me was changing .htaccess in mediawiki subfolder to
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wikifolder/index.php [L]
</IfModule>