Directory index page precedes htaccess - apache

What I want is that only if my root domain is accessed meaning URI is empty, it gets rewritten without redirect, otherwise rewrite to index.php if not accessing file or folder. My .htaccess looks like this:
RewriteEngine On
RewriteBase /
RewriteRule ^/?$ /mypages/landing_page.html [QSA,L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
It works as expected on some servers but on another it works only if there is no index.php file in folder. Something like directory indexing preceding htaccess rules? If I delete the index.php or rename it to index2.php and change my htaccess rules accordingly rewrite works as expected.
Any ideas what might be causing the server to behave like that?

There was a bug introduced in Apache 2.4.2 (#53929) that has the same symptom you're describing:
"The issue is caused by the DirectoryIndex directive. mod_dir is not
respecting the result of the rewrite execution. If DirectoryIndex is
set to disabled, it starts working correctly."
The issue is fixed in Apache 2.4.9.
If you have a mixed environment (i.e. pre and post Apache 2.4.2 versions), this could also explain why your Rewrite is working correctly on some servers, but not others.
If upgrading is not an option, you can also workaround the issue using a conditional SetHandler (based on an env var set in your RewriteRule). This will disable DirectoryIndex for just those requests.
The bug itself (and workaround example) is documented in the following link:
https://bz.apache.org/bugzilla/show_bug.cgi?id=53929

Related

Redirect all to index.php using htaccess

I am writing a simple PHP-based MVC-ish framework. I want this framework to be able to be installed in any directory.
My PHP script grabs the request uri and breaks it off into segments. It makes segment 1 the controller and segment 2 the action. This goes all fine when I do this:
http://www.example.com/mvc/module/test/
It will go to the specific module controller and method. Now I have a default controller, the home controller, which is in folder home.
Now when I access this folder directly http://www.example.com/mvc/home/
It will display a 403 forbidden , because this folder does exist, instead it should also go back to http://www.example.com/mvc/index.php
If I would have installed the framework in a different folder, lets say folder framework it has to redirect back to http://www.example.com/framework/index.php
I would like to redirect every folder and php file back to the index.php, leaving everything else the way it is.
My first problem I encountered was it never redirects to the right folder, always to the domain root folder.
This is what I tried :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
Your rewrite rule looks almost ok.
First make sure that your .htaccess file is in your document root (the same place as index.php) or it'll only affect the sub-folder it's in (and any sub-folders within that - recursively).
Next make a slight change to your rule so it looks something like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?path=$1 [NC,L,QSA]
At the moment you're just matching on . which is one instance of any character, you need at least .* to match any number of instances of any character.
The $_GET['path'] variable will contain the fake directory structure, so /mvc/module/test for instance, which you can then use in index.php to determine the Controller and actions you want to perform.
If you want the whole shebang installed in a sub-directory, such as /mvc/ or /framework/ the least complicated way to do it is to change the rewrite rule slightly to take that into account.
RewriteRule ^(.*)$ /mvc/index.php?path=$1 [NC,L,QSA]
And ensure that your index.php is in that folder whilst the .htaccess file is in the document root.
Alternative to $_GET['path'] (updated Feb '18 and Jan '19)
It's not actually necessary (nor even common now) to set the path as a $_GET variable, many frameworks will rely on $_SERVER['REQUEST_URI'] to retrieve the same information - normally to determine which Controller to use - but the principle is exactly the same.
This does simplify the RewriteRule slightly as you don't need to create the path parameter (which means the OP's original RewriteRule will now work):
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]
However, the rule about installing in a sub-directory still applies, e.g.
RewriteRule ^.*$ /mvc/index.php [L,QSA]
The flags:
NC = No Case (not case sensitive, not really necessary since there are no characters in the pattern)
L = Last (it'll stop rewriting at after this Rewrite so make sure it's the last thing in your list of rewrites)
QSA = Query String Append, just in case you've got something like ?like=penguins on the end which you want to keep and pass to index.php.
To redirect everything that doesnt exist to index.php , you can also use the FallBackResource directive
FallbackResource /index.php
It works same as the ErrorDocument , when you request a non-existent path or file on the server, the directive silently forwords the request to index.php .
If you want to redirect everything (including existant files or folders ) to index.php , you can use something like the following :
RewriteEngine on
RewriteRule ^((?!index\.php).+)$ /index.php [L]
Note the pattern ^((?!index\.php).+)$ matches any uri except index.php we have excluded the destination path to prevent infinite looping error.
There is one "trick" for this problem that fits all scenarios, a so obvious solution that you will have to try it to believe it actually works... :)
Here it is...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>
Basically, you are asking MOD_REWRITE to forward to index.php the URI request always when a file exists AND always when the requested file doesn't exist!
When investigating the source code of MOD-REWRITE to understand how it works I realized that all its checks always happen after the verification if the referenced file exists or not. Only then the RegEx are processed. Even when your URI points to a folder, Apache will enforce the check for the index files listed in its configuration file.
Based on that simple discovery, turned obvious a simple file validation would be enough for all possible calls, as far as we double-tap the file presence check and route both results to the same end-point, covering 100% of the possibilities.
IMPORTANT: Notice there is no "/" in index.php. By default, MOD_REWRITE will use the folder it is set as "base folder" for the forwarding. The beauty of it is that it doesn't necessarily need to be the "root folder" of the site, allowing this solution work for localhost/ and/or any subfolder you apply it.
Ultimately, some other solutions I tested before (the ones that appeared to be working fine) broke the PHP ability to "require" a file via its relative path, which is a bummer. Be careful.
Some people may say this is an inelegant solution. It may be, actually, but as far as tests, in several scenarios, several servers, several different Apache versions, etc., this solution worked 100% on all cases!
You can use something like this:
RewriteEngine on
RewriteRule ^.+$ /index.php [L]
This will redirect every query to the root directory's index.php. Note that it will also redirect queries for files that exist, such as images, javascript files or style sheets.
Silly answer but if you can't figure out why its not redirecting check that the following is enabled for the web folder ..
AllowOverride All
This will enable you to run htaccess which must be running! (there are alternatives but not on will cause problems https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride)
just in case you were still wondering how to redirect all request either if the directory exists (for core framework folders and files) to the framework index handler, after some error/success attempts just noticed I just needed to change the RewriteCond in the .htaccess file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
the above condition states "not found files" and "not found directories", ok, what if just remove "not found" (!-d) line, and ended with something like the below:
RewriteEngine on
RewriteBase /framework/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /framework/index.php [L,QSA]
It worked for me like a charm
I just had to face the same kind of issue with my Laravel 7 project, in Debian 10 shared hosting. I have to add RewriteBase / to my .htaccess within /public/ directory. So the .htaccess looks a like
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L,QSA]
After doing that don't forget to change your href in,
home
Example:
.htaccess file
RewriteEngine On
RewriteRule ^about/$ /about.php
PHP file:
about

My htaccess RewriteRule works on localhost/mysite but not at mysite.com on a 1&1 shared host

Solved:
unfortunately, the solution is not a satisfying one. This morning, when trying #Wige's Suggestion, I found, to my suprise, that the Expected values WERE infact sent to the page as a GET query. Apparently, 1&1 (who I know have been making changes to their environment this last couple weeks), did something behind the scenes which magically fixed my problem, and now all of my previously unworking code is working as originally expected.
New info: The Apache version of the production server is 1.3.34 vs 2.2.21 on my localhost.
I'm having trouble figuring out why my RewriteRule is not working properly in production.
RewriteRule ^page/pretty-url/(.*)$ page.php?query=$1 [L]
In my local testing environment (localhost/mysite/page/pretty-url/{...}) it works fine, but on mysite.com/page/pretty-url/{...} it doesn't work properly. It loads page.php as expected but apparently the ?query=$1 piece is ignored ($_GET is empty)
I imagine that the problem is somehow related to the server configuration. I'm on a 1&1 shared hosting account with no httpd.conf access.
What that RewriteRule does (or should do):
I want urls like
*example.com/page/pretty-url/{{info_for_dynamic_content}}
to be rewritten to
*/page.php?query={{info_for_dynamic_content}}
So I can access info_for_dynamic_content
within php as $_GET['query']
The full .htaccess file for reference:
AddHandler x-mapp-php6 .php
DirectoryIndex index.php
ErrorDocument 404 /index.php
Options +FollowSymLinks
# per #Jacques Chester's suggestion
Options -MultiViews
RewriteEngine on
RewriteBase /
# the rule in question
RewriteRule ^page/pretty-url/(.*)$ page.php?query=$1 [L]
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php !-f
RewriteRule (.*) /index.php [L]
Most likely, your host is storing the variables somewhere else. I would add a call to phpinfo(); into your script and go through the environment variables there to see if you can find the values that should have been in get.
Seems to be connected to 1&1's hosting environment.
See this question, in particular, this answer.
Basically it appears that 1&1 enable "MultiViews". By adding
Options -MultiViews
You disable that setting for your website and according to various reports, this resolves the issue.
I struggled with RewriteRule issues on a 1&1 / 1and1 / IONOS shared server for WEEKS and eventually I found the perfect setup for a 1 and 1 shared server, start your .htaccess file like this
Options -MultiViews
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
I hope this helps someone as 1&1 are useless when it comes to htaccess support

strange trailing slash issue

I have a folder under document_root in Apache server.
When I type in http://www.example.com/help, it does not redirect to http://www.example.com/help/, but goes to http://www.exmaple.com//help/. Note that there are two slashes after the domain name.
I couldn't find any mod-rewrite rule set up for this kind of redirect. Can anyone think of any other possible reason?
Also, in Apache, redirecting from http://www.example.com/help to http://www.example.com/help/ is done by what? (Note 'help' is real folder, and there is not a file named 'help').
Thanks!
Finally I found out that this is a bug of Apache.
https://issues.apache.org/bugzilla/show_bug.cgi?id=51982
First guess is that your application configuration has an item for its base URL, and in your case, it ends with /, causing the application's internal routing system to add the extra slash.
Replying to asker comment:
Look in your .htaccess file.
If it looks something like this (this is the one used by WordPress installations by default, by the way):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Then it will attempt to load from the actual directory /help.
But if it does not contain the !-f and !-d lines, it will load every request via the application entry point, whether the requested item exists in the file system or not.

.htaccess RewriteRule adds drive path to URL

I am using Zend Server CE (v.5.1.0) installed on C: on a Win7 machine. I have added one project to httpd.conf by adding:
Alias /project "D:\Homepages\project"
<Directory "D:\Homepages\project">
Options Indexes FollowSymLinks
AllowOverride all
Order allow,deny
Allow from all
</Directory>
My .htaccess file in the project directory contains the following:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} ^/\w*\.(css|js) [NC]
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Now to the problem; if I go to
http://localhost/project/index.php
everything seems to be working fine. I reach the index.php file and get my contents.
However, if I go to any other page that would trigger the RewriteRule, it seems to be adding the directory path. FireFox outputs the following Not Found message:
The requested URL /Homepages/project/index.php was not found on this server.
I tried to find a similar question/answer here, but failed. Any idea?
Ps. Me accepting of an answer might be delayed as I will be out for a while on an errand.
You need to set the RewriteBase directive; otherwise, mod_rewrite automatically, and by default, prepends the file path to the resulting rewrite rule.
From: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
When a substitution occurs for a new URL, this module has to re-inject the URL into the server processing. To be able to do this it needs to know what the corresponding URL-prefix or URL-base is. By default this prefix is the corresponding filepath itself. However, for most websites, URLs are NOT directly related to physical filename paths, so this assumption will often be wrong! Therefore, you can use the RewriteBase directive to specify the correct URL-prefix.
If your webserver's URLs are not directly related to physical file paths, you will need to use RewriteBase in every .htaccess file where you want to use RewriteRule directives.
Have your last line like this:
RewriteRule ^.*$ /index.php [NC,L]
However I think this is infinite loop so I would suggest this rule instead:
RewriteCond %{THE_REQUEST} !\s/index.php [NC]
RewriteCond %{REQUEST_URI} !^/index.php [NC]
RewriteRule . /index.php [L]
which prevents going to index.php if it is already /index.php.

Use symfony 1.4 without changing apache configuration

Is it possible to set the /web directory as webroot without changing apache configuration file?
I tried using the following .htaccess code, but if i go to localhost/module/, it displays 404 error. But if i go to localhost/web/module/ then everything works.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule sf/(.*) lib/vendor/symfony/data/web/sf/$1 [L]
RewriteRule ^$ web/ [L]
RewriteRule (.*) web/$1 [L]
</IfModule>
i do like this on the root :
RewriteEngine On
RewriteBase /
RewriteRule (.*) ./web/$1 [L]
And edit web/.htaccess uncommented the 'RewriteBase /' line.
this make all the mysite.com/aaaa/bbbb works like mysite.com/web/aaaa/bbbb
Short answer: no.
Bit longer: you will have to edit the apache config at least to give it permission to access the web/ directory, so even if you symlink your web folder to /var/www, it will not work.
This is quiet similar to my question Symfony on virtual host (document root problem).
This is my .htaccess in the project root directory:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/images/ [OR]
RewriteCond %{REQUEST_URI} ^/js/ [OR]
RewriteCond %{REQUEST_URI} ^/css/
RewriteRule ^(.*)$ /web/$1 [L]
RewriteCond %{REQUEST_URI} !^/web/
RewriteRule ^(.*)$ /web/index.php [QSA,L]
This solved my problem but symfony tries to generate every url (eg. using url_for) from the document root so instead of url like domain.com/my-article it generates domain.com/web/my-article.
I had to slightly modify my PatternRouting class to trim the /web prefix from each url. I think this is not the best solution but it works.
Also if I want to access backend application I have to call always /web/backend.php/ because I don't want to have so many rewrite rules in the .htaccess.
If you want to see my extended PatternRouting class source code I'll paste it here.
Yes, it is possible. Copy everything from web/ up a level to your document root. Edit index.php to reflect the fact that everything it includes is now one level closer to its current directory than it used to be (one less ../). You won't have to edit a single other Symfony file.