Explain .htaccess rules. Doesn't work for me - apache

I have hierarchy structure of file as below:
/public_html/directory/
/public_html/directory/index.php
/public_html/directory/file.php
I want to forward the request to the most appropriate link. For example,
mydomain.com/directory/ to mydomain.com/directory/index.php
mydomain.com/directory/file to mydomain.com/directory/file.php
If 404 or 500 error occurs then forward it to /public_html/error.php
For this I have written following code in .htaccess
Options +SymLinksIfOwnerMatch -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# don't touch /forum URIs
RewriteRule ^forums/ - [L,NC]
# hide .php extension snippet
#To externally redirect /dir/foo.php to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+).php [NC]
RewriteRule ^ %1 [R,L]
# To internally forward /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [L]
ErrorDocument 404 /error.php
ErrorDocument 500 /error.php
It works properly if I make requests as mentioned above. But if I request for page mydomain.com/directory/file/scrap then it generates Internal Server Error
I think its because file is not a directory. But I don't know how to solve this problem here. Please suggest.
Also one more line is mentioned in the error output by server regarding ErrorDocument for 500 in the end. The complete output is as follows:
Internal Server Error
The server encountered an internal error or misconfiguration and was
unable to complete your request.
Please contact the server administrator, root#localhost and inform
them of the time the error occurred, and anything you might have done
that may have caused the error.
More information about this error may be available in the server error
log.
Additionally, a 500 Internal Server Error error was encountered while
trying to use an ErrorDocument to handle the request.

This is happening because the %{REQUEST_FILENAME} -f condition also checks for "path info" style requests. So when you request:
mydomain.com/directory/file/scrap
The rewrite engine will see the file /directory/file.php and assume that you're making a path info style request, e.g. /directory/file.php/scrap
This causes the rewrite engine to loop.
You need to change that condition to:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
Oh, also, as for the ErrorDocument thing, I'm pretty sure that what's happening is the rewrite module is completely ending the URL processing in the pipeline. That means, directives that get applied at the end of the pipeline will never get applied if mod_rewrite flips out and ends all the processing. That's why your ErrorDocument directives aren't being applied. If you fix the rewrite issue, you'll notice that the 500 error document will work again.

Based on the configuration above, I would say there is a problem with /error.php.
Assuming there is no scrap.php, mydomain.com/directory/file/scrap will not get rewritten.
The 500 error also mentions that the error was encountered while trying to use an ErrorDocument.
Try a static error.html instead of a dynamic error.php to narrow the problem down.
You could also log the rewrites to verify that they are working correctly:
RewriteLogLevel 9
RewriteLog /var/log/httpd/rewrite_log

Related

Apache Clean URL Code Causing An Internal Server Error

I'm setting up a 404 page on a project on my localhost (MAMP) and in my .htaccess file I’ve included the following code:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) $1.php [NC,L]
</IfModule>
ErrorDocument 404 http://localhost:8888/project/public/404.php
The 404.php page sits at the same level as .htaccess file in a public folder below the project root:
project
— publicFolder
— privateFolder
The Issue
When I include the code within the <IfModule mod_rewrite.c> it throws an error when I type in a 404 page URL (i.e. a page that doesn't exist). When I remove this <IfModule mod_rewrite.c> code block the problem goes away. The error message is:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at you#example.com to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
When I check the apache error log, as recommended in the above message I get the following:
[core:error] [pid 2575] [client ::1:51038] 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 suspect the issue may be to do with the line that removes the .php file extension on all of the pages, i.e.RewriteRule (.+) $1.php [NC,L]
My Question
How do I get the clean URL code inside the <IfModule mod_rewrite.c> block to stop throwing an internal server error when a user goes to what should be a 404 page?
Any help great appreciated.
Your issue simply is that you indeed implement an endless rewriting loop.
Have a try using that variant with an additional condition:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
You need to understand that the L flag you are using indeed terminates the rewriting, but only for the current cycle . Whenever a rewriting cycle alters (rewrites) the processed request a new cycle is started. Until the request is stable, so is not rewritten again. Since the rewritten target again matches your conditions and the rule's matching pattern you again rewrite the request in your implementation. Which ultimately results in a request to something like /foo.php.php.php.php.php, appending one ".php" for every rewriting cycle.
An alternative would be to use the younger [END]¸ flag here instead of the older [L] flag. The END flag completely terminates the rewriting process, ignoring any other rules. So you need to be sure that rule really is the last that should get applied. Using that flag you won't need the additional condition, since the complete termination obviously prevents an endless rewriting loop.
In general I would advise to not use distributed configuration files for this (".htaccess"). But to implement such rules in the actual http server's central host configuration. And use absolute paths there.
That typically prevents a lot of confusing and side effects.
Certainly there may be other issues here that do not get immediately clear from the question you asked. But above is an obvious issue.
Always test using a fresh anonymous browser window, always make deep reloads in the browser to prevent client side caching effects while testing.

httpd RewriteRule not working as expected

On my server I am running awstats, a script that I can currently access via the following URL:
https://stats.example.com/bin/awstats.pl/?config=global
I am trying to use rewrite rules such that I can just use
https://stats.example.com/global
This is what I have defined for a rewrite rule
RewriteRule ^(.*)$ bin/awstats.pl/?config=$1 [NC,L]
httpd virtual host
# Address
ServerName stats.example.com
# Rewrite
RewriteRule ^(.*)$ bin/awstats.pl/?config=$1 [NC,L]
Options ExecCGI
AddHandler cgi-script .cgi .pl
Alias /awstatsstuff "/path/to/awstatsstuff/"
<Directory "/path/to/awstatsstuff">
Options ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>
The problem is that anything I try and access (besides the index), will give me a 400, and my apache logs show no errors.
Should this rule be working correctly, do I have a different configuration issue? Or am I missing something? Yes, RewriteEngine is on.
edit
Based on Michael Berkowski's comment I determined that is is infact an issue with resources also being directed to the pl script, I have since modified and am using the following:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/([0-9a-z]+\.[0-9a-z]+\.[0-9a-z]+)$ bin/awstats.pl/?config=$1 [NC,L]
I can now load the page again using
https://stats.example.com/bin/awstats.pl/?config=www.example.com
This means that all resources can be loaded correctly, however
https://stats.example.com/www.exmaple.com
will return a 400 ( this does not come from the pl script which will return a 200 and error message if the specified config file can not be found, again, no error messages in the logs.
another edit
In changing [NC,L] to [R=302], I am provided with the correct redirect upon request,
curl -k "https://stats.example.com/a.b.c"
...
<p>The document has moved here.</p>
...
Using [R=403] proves that the rewrite rule is working as expected
The problem that I am now facing is that when using [NC,L], I am still receiving a 400, with no errors available in the httpd log.
I strongly suspect requests for documents other than the index are being mistakenly trapped by the very permissive (.*) and sent to config= in error. The 400 (bad request) probably then results from awstats tripping over values it cannot handle there.
Two things should take place. First, you need to exclude real existing files and directories from the rewrite, conventionally done with a pair of RewriteCond. Then, instead of the very general (.*) matcher, use a matcher more specific to the values that should actually be considered valid for config=.
# If the requested document is not a known
# file or directory on disk...
RewriteCond %{REQUEST_FILENAME} !=f
RewriteCond %{REQUEST_FILENAME} !=d
# Rewrite patterns matching only the expected
# config= values for awstats
RewriteRule ^([a-z0-9]+\.[a-z0-9]+\.[a-z0-9]+)$ bin/awstats.pl?config=$1 [L,NC]
Above I have used [a-z0-9]+\. to match 3 part FQDN strings as mentioned in the comment thread. That may need additional refinement. To also support the string "global" for example, you could expand it to
RewriteRule ^(global|[a-z0-9]+\.[a-z0-9]+\.[a-z0-9]+)$ bin/awstats.pl?config=$1 [L,NC]

.htaccess RewriteRule error in a CGI script

I have following files:
website-folder
- .htaccess
- user.php
the .htaccess looks like:
RewriteRule ^user/([0-9]{1,11})$user.php?user_id=$1
Now I want to give in localhost/website-folder/user/1234 which should take the data from localhost/website-folder/user.php?user_id=1234.
But I am getting following error:
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there was an error in a CGI script.
If you think this is a server error, please contact the webmaster.
Your /website-folder/.htaccess file should look like this:
RewriteEngine on
# Set the base from which to rewrite as the site runs from a subfolder.
# This can be safely removed if you ever move to the root of the domain
RewriteBase /website-folder/
# Rewrite user/{id} to user.php (skip existing files)
RewriteRule %{REQUEST_FILENAME} !-f
RewriteRule %{REQUEST_FILENAME} !-d
RewriteRule ^user/([0-9]{1,11})$ user.php?user_id=$1 [QSA,L]
The error was thrown as you had a code formatting issue (assuming you copy-pasted the code into your question): there was no space between $ and user.php....
I've also added a RewriteBase in your file as you are running from a sub-folder.
Lastly, I've added the Query String Append (QSA) flag, which allows you to add more query parameters to the rewritten URI. You also left out the Last flag (L), which would have introduced potential issues for other rules below it.

Apache 2, Joomla 1.0.x configuration causes malformed response in IE 6+?

A friend of mine has inherited an old Joomla 1.0.x site, that amongst other things has a big problem with IE visitors.
The site is viewable here: http://intellepark.co.za
If you browse the site with Firefox, the GETs / responses bounce around as follows:
1. GET /
2. 302 to /site
3. GET /site
4. 301 to /site/
5. GET /site/
6. 200 (or 304)
Problems in IE
In IE7, the same sequence occurs, but at step 6, IE fails to load the page appropriately and displays the "Internet Explorer cannot display the webpage" error page.
If I load the same page with IE6 (Standalone version) I get intermittent and malformed responses from the server. The document fails to download properly but still displays up until the last byte it received.
Solution?
At first I thought there was something wrong with the output, so:
I checked the HTML: There's a double slash in all asset URLs (e.g. /site//templates/intellepark/js/mootools.js). The doctype is XHTML1, valid, but the charset is Latin.
I disabled JavaScript in IE, but that results in the same behaviour.
So now I suspect it's a configuration issue.
The server is running the following:
Apache 2.2.9
Joomla 1.0.12 Stable
PHP 5.2
What would be causing this bad behaviour in IE? Is it the double slash in the URLs?
What can I recommend to my friend to have this problem fixed?
Thanks for your help - Please let me know if you require any further info!
--nd
edit
Inline paste of the .htacces file
## Can be commented out if causes errors, see notes above.
Options +FollowSymLinks
#
# mod_rewrite in use
RewriteEngine On
# Uncomment following line if your webserver's URL
# is not directly related to physical file paths.
# Update Your Joomla!/MamboDirectory (just / for root)
# RewriteBase /
########## Begin - Joomla! core SEF Section
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (/|\.htm|\.php|\.html|/[^.]*)$ [NC]
RewriteRule ^(content/|component/) index.php
#
########## End - Joomla! core SEF Section
# Block out any script trying to set a mosConfig value through the URL
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
# Block out any script trying to base64_encode crap to send via URL
RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [OR]
# Block out any script that includes a <script> tag in URL
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
# Block out any script trying to set a PHP GLOBALS variable via URL
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
# Block out any script trying to modify a _REQUEST variable via URL
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
# Send all blocked request to homepage with 403 Forbidden error!
RewriteRule ^(.*)$ index.php [F,L]
I notice 2 things, but I'm not sure if either is the problem.
1) The site flushes the output early. This is fine (actually good). Other resources can start downloading before the index.php is fully loaded. However, depending on how this is configured it might be causing some problems for IE (and may be related to 2 below).
To diagnose, turn off any early output flushing, and see what happens.
2) The second thing that I notice is that the calculated checksum is different than the stored checksum, and since the content is gzip compressed, IE6 may not decompress after a failed checksum (I don't know what IE's default behavior is in that scenario).
Anyway, turn off compression, and see what happens.
Hope that helps, and let us know when what happens when you disable each of those (individually and both together).

How can I rewrite all but my IP address to the std. Apache 503 temporarily down error message?

I'm about to do some server maintenance and would like to rewrite requests to Apache's standard 503 temporarily unavailable message.
I've Googled and found a few mod_rewrite snippets, but they all involve doing an [R=503] to a PHP script which then sends its own 503 headers and a hand-written message... which just seems ugly to me, when Apache's default is there for me to use.
So, how can I rewrite all request to Apache's standard 503 error message?
Thanks for your help
(Long time Coding Horror RSS subscriber here... Just in a bit of a rush!)
To add a little bit more, I often have the following:
RewriteEngine on
RewriteCond -f path/to/my-custom-error-document
RewriteRule !^path/to/my-custom-error-document$ - [L,R=503]
What this does is check to see if the error document exists. If it does, it serves up the error page. What this allows me to do is throw up the custom error without having to restart apache. To put it back in place, I just remove (or rename) the error page.
I don’t know exactly since when mod_rewrite allows other status codes than 3xx for the R flag. But this should do it:
RewriteEngine on
RewriteRule ^ - [L,R=503]
And if you’ve set a custom error document, use this to prevent additional internal errors:
RewriteEngine on
RewriteRule !^path/to/my-custom-error-document$ - [L,R=503]
Edit   Found a better solution using the REDIRECT_STATUS environment variable:
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} !=503
RewriteRule ^ - [L,R=503]
Thanks guys - worked perfectly.
Here's the exact .htaccess configuration I used (sans my IP address) during maintenance:
RewriteEngine on
RewriteCond %{REMOTE_HOST} !^123\.456\.789\.012$
RewriteCond %{ENV:REDIRECT_STATUS} !=503
RewriteRule ^ - [L,R=503]