Zend Framework setting up the htaccess file - apache

I have been using the Zend Framework for years but have realised some crucial problems with our error handling that we are now fixing.
(I posted a different question here: Why my site is always using the ErrorController for all types of errors irrespective of HTTP Status code? explaining the story there).
My question here is a quick one. What does a common .htaccess file of Zend Framework look like?
According to the latest ZF documentation,
SetEnv APPLICATION_ENV development
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
However, the above is new to me - can someone explain what it does exactly?
My current .htaccess file has a lot of 301 redirect code but for the purpose of this post I'll only paste the relevant information here:
ErrorDocument 404 http://www.mydomain.com/pagenotfound/
ErrorDocument 503 http://www.mydomain.com/service-unavailable/
RewriteCond %{REQUEST_URI} !^/liveagent
RewriteCond %{REQUEST_URI} !^/blog
RewriteRule !\.(js|ico|gif|GIF|jpg|JPG|jpeg|png|PNG|pdf|css|html|xml|swf|php|mp3|mp4|webm|ogv|f4v|flv|txt|wsdl|css3|ttf|eot|svg|woff)$ index.php
The above has been working fine for us, and basically disallows the "liveagent" and "blog" (Wordpress) directories from running with Zend, but I realise I now need to make the following change:
ErrorDocument 404 definitely has to be removed from the code, as Zend Framework should handle all errors. However, when I remove this, going to a URL like www.mydomain.com/this-does-not-exist.php results in a 404 error standard Apache page - it does not load the ZF or the ErrorController. This is because of the "php" exclusion in the above RewriteRule. I do not simply want to remove this since we sometimes want to be able to access php files on the root, such as a separate "holding.php" file which we use for putting the site on maintenance mode.
What is the standard practice? Should I remove the php extension? However this will not solve other 404's like
www.mydomain.com/this-does-not-exist.css
which is also an exclusion (i.e. CSS) in the above RewriteRule.
Therefore, should I completely change the above to Zend's new code for .htaccess as I mentioned above?
If so, I'm a sort of beginner at htaccess - how can I modify that .htaccess code to allow CSS, JS, video files etc. and the blog and liveagent directories to be excluded from the Zend Framework?

I'd switch to the standard ZF rewrite rules instead of the one you have which uses a long regex to redirect to index.php.
Here is an explanation of what the standard .htaccess rules do:
RewriteCond %{REQUEST_FILENAME} -s [OR] # The request is a regular file with size > 0
RewriteCond %{REQUEST_FILENAME} -l [OR] # The request is to a file that is a symlink
RewriteCond %{REQUEST_FILENAME} -d [OR] # The request is to a directory that exists
# if any of the above conditions are true, then simply handle the request as-is
RewriteRule ^.*$ - [NC,L]
# if none of the above match, then rewrite to index.php
RewriteRule ^.*$ index.php [NC,L]
These default ZF rules don't prevent you from accessing existing php files or any other files that are accessible from your document root. If the file requested exists, then the request for that file is served as is. If the file requested does not exist, then the request is forwarded to index.php
Once the request is forwarded to ZF, if there is no matching route, then the ZF ErrorHandler is called and a 404 page (from ZF) is served.
Using the stock ZF rules won't prevent you from having the desired behavior in your application and server settings, and should be a bit more efficient that the regex you currently have. The only things that will really change is that now requests for files that don't exist will be handled by ZF's error handler and no longer by Apache.
Hopefully that answered your question, if not feel free to comment for clarification.

Related

Apache mod_rewrite - unwanted redirect instead of rewrite

I have an issue with mod_rewrite and I can't seem to solve it. I stripped the example down to the bare bones and I don't understand why a specific rule forces my browser to redirect instead of rewrite:
RewriteEngine on
#if request is for a physical-file OR for one of the language paths - skip (return as-is)
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{REQUEST_URI} ^/de [OR]
RewriteCond %{REQUEST_URI} ^/en-US
RewriteRule ^ - [L]
#otherwise: rewrite to en-US folder
RewriteRule ^(.*)$ /en-US/$1 [NC,L,QSA]
I read the documentation very carefully and it seems like this should actually rewrite every call, so https://example.com/fuBar.html should actually retrieve the file /en-US/fuBar.html from my server - the users browser shouldn't know about it.
What's really happening is that for some reason the browser is redirected to https://example.com/en-US/fuBar.html. While this does display the correct content, it's just not what I want or what I thought this RewriteRule should do. What am I doing wrong?
*add - the .htaccess of the subfolders de and en-US:
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
There's nothing in the code you've posted that would trigger an external "redirect".
Make sure you have cleared your browser (and any intermediary) cache(s) to ensure you are not seeing an earlier/erroneous 301 (permanent) redirect. (301 redirects are cached persistently by the browser.)
Check the "network traffic" in the browser's developer tools to see the precise nature of this redirect to see what it redirects from/to, and well as the 3xx HTTP status code of the redirect (if indeed this is an external redirect).
It would seem the front-end (JavaScript/Angular) is manipulating the URL in the address bar (there is no redirect). From comments:
Actually there was no redirect happening at all! Rather since I set <base href="/en-US"> somehow my frontend (Angular) seems to have outsmarted me, manipulating the address without me realizing it. Turns out I don't even need to change the base href, I just need the rewrites.

Apache Mod_Rewrite Seems to be Causing Javascript Reloads

I'm setting up URL rewrite rules for an application I'm developing so that I can use nice clean URLs. I want the URLs to look like http://app.com/page/agency/ and to be equivalent to http://app.com/index.php?p=page&agency=agency. The agency selector is optional, so I want the URLs to redirect, even if the agency is not present. I have created the following mod_rewrite rules for this purpose:
RewriteRule ^/?([a-z]+)/$ /index.php?p=$1 [PT]
RewriteRule ^/?([a-z]+)/([a-z]+)/$ /index.php?p=$1&agency=$2 [PT]
This is working fine for redirecting the pages. However, it seems to me that my javascript files are being re-loaded with each page, as if the browser thinks that it's in a different directory and needs to re-load the JS files. The JS files are linked using a hard-coded URL, such as http://app.com/scripts/dostuff.js.
Is it possible that the browser is reloading the javascript files each time? If so, have I done something wrong?
Try this code:
RewriteEngine On
# skip rewrite rules below it is a valid file or a valid directory
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# write single path
RewriteRule ^([a-z]+)/?$ /index.php?p=$1 [L,QSA]
# write 2 paths
RewriteRule ^([a-z]+)/([a-z]+)/?$ /index.php?p=$1&agency=$2 [L,QSA]

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

Mod-Rewrite rules are breaking 404 routing

I am using the following mod-rewrite in my .htaccess file:
RewriteRule ^$ pages/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ pages/$1 [L]
The intention is to hide the subdirectory called /pages/ from displaying in the URL.
So this: http://mysite.com/pages/home.html
Will look like this: http://mysite.com/home.html
It works but there are some unintended consequences.
As a direct result of the .htaccess code I posted above, my 404 routing is no longer working at all. Anything that should trigger a 404 error page is instead generating a 500 Server Error.
How to fix?
EDIT:
As implied above, it does not matter if a custom 404 page is defined in the .htaccess or not. Without it, or a bad path to the error page, the server should still route to its default 404 page, and not give a 500 Server Error.
Surely, there must be a standard way to suppress sections of a URL without breaking the normal routing of 404 errors. From my online research it seems that my method above commonly breaks the 404 routing, and yet so far, I've seen no applicable solution. (This is not a Wordpress installation; just static HTML content)
EDIT 2:
Since I'm only wanting to suppress the one directory from the URL, I never mentioned that I also have other files & directories which are siblings to /pages/ that cannot be pointed at /pages/, such as /graphics/, /includes/, /css/, /cgi-bin/, robots.txt, favicon.ico, etc.
Maybe this is all an exercise in futility or more trouble than it's worth?
Looking for a definitive answer either way.
Following config will look for your static pages inside the pages/ and if found, it'll display them. This shouldn't break 404.
Put it in root folder of your web in .htaccess
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /pages/$1
This should achieve what you are trying to do.
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/([a-zA-Z0-9\_\-]+)\.html$
RewriteRule (.*) /pages/$1 [L]
Thank-you to #Kamil Šrot for getting the closest working solution. However, I needed to add another test ( -d ) to see if the requesting URI is a directory.
This is working great and the 404 error page is again routing properly.
RewriteEngine On
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/pages/%{REQUEST_URI} -d
RewriteRule ^(.*)$ /pages/$1
How about adding an error page direction to your htaccess file to handle the 404 page:
ErrorDocument 404 /path/to/your/404.html

.htaccess Apache on cPanel only working in some cases

I'm using the Zend Framework, so I'm bootstrapping into a file called index.php. Naturally, I don't want images to be bootstrapped, so I've added a .htaccess file. Here's what it looks like
/application
/library
/public (this is the root of the site)
/images
/js
.htaccess
index.php
This is what's written in my .htaccess:
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|mp3|mov|css)$ index.php
This is basically saying if it doesn't end in .js / .ico / etc, then send the request to index.php. It works just fine on my localhost, but when I get up to actually putting it online, it doesn't. It just routes everything to index.php, regardless of the ending of the request. When mywebsite.com/images/wizard.gif should just show the picture, it tries to load the images controller, which is not what I want it to do.
What could be going wrong? I know it's reading the .htaccess. Is it reading my regex wrong? Why would one apache server read it wrong, while another reads it correctly? Any help would be great.
Here is my .htaccess if you would like to give it a try:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /index.php [NC,L]
Basically it checks to make sure the request is not a directory, symlink or a real file, and then sends it to index.php. Otherwise it will provide direct access to the file/directory