My primary web site uses PHP/Zend Framework, and the .htaccess is the common one:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Now I need to bring a forum (in another directory) to the main site. I added an Alias directive inside VirtualHost
Alias /forums "h:/projects/forums"
The forum software uses its own .htaccess. The main URL /forums is accessible but not others. Other URLs (those who do not have corresponding files) are forwarded to the main site. In other words, the .htaccess file of the main site (/) is picked up, not the one under /forums directory.
Try adding a new RewriteCond to tell your main .htaccess file to ignore requests under /forums. After the request passes through that file, it should get picked up by the /forums/.htaccess file, though I'll admit that I'm not really sure if Alias affects this.
The condition would look like this:
RewriteCond %{REQUEST_URI} !^/forums [NC]
This says "only perform the next RewriteRule if the request doesn't begin with /forums". The [NC] at the end says to ignore the casing on /forums so it won't matter if the request is actually for /Forums or /FORUMS.
Related
I am trying to setup my .htaccess file to allow for multiple vanity URLs which is fine, but I'm running into issues with them with the pages being in different directories.
First vanity URL is setup and working fine, which works like this:
example.com/blognumber1 > example.com/inspiration/article.php?id=blognumber1
RewriteBase /inspiration/
RewriteCond %{REQUEST_FILENAME} !-d [NC]
RewriteCond %{REQUEST_FILENAME} !-f [NC]
RewriteRule ^(.*)$ article.php?id=$1 [QSA,L]
I am trying to add another one which would work like this:
example.com/supplier/test1 > example.com/profile.php?id=test1
Because the article.php page is in a different directory, I am having problems trying to code it, any help would be appreciated.
Don't use a RewriteBase directive (which applies to the entire file) and make sure the more specific /supplier/test1 rule is first. For example:
RewriteEngine On
# Abort early if a directory or file is requested directly
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Rewrite "/supplier/<test1>" to "profile.php?id=<test1>"
RewriteRule ^supplier/([^/]*)$ profile.php?id=$1 [QSA,L]
# Rewrite "/<blognumber1>" to "inspiration/article.php?id=<blognumber1>"
RewriteRule ^(.*)$ inspiration/article.php?id=$1 [QSA,L]
Note that the NC flag is not permitted on the RewriteCond directive when used with the filesystem checks -f and -d. If you check your error log you will probably see a stack of warnings.
On the /supplier/test1 rule, it only matches a single path segment after /supplier/, ie. it does not match /supplier/test1/something.
Your existing rule is rather generic as it literally matches anything. Perhaps restrict this to a single path segment also? Or restrict the regex to what constitutes a blognumber.
Optimisation
As a further optimisation you could also abort early if a .php file (or a URL that looks-like a .php file) is requested. Unless you have valid "supplier" or "blog" URLs that end in .php? For example, immediately after the RewriteEngine directive:
# Abort early if any `.php` URL is requested (includes rewritten URLs)
RewriteRule \.php$ - [L]
You can extend this for any URL that looks-like it contains a file extension, which should naturally include your static assets and therefore avoid the filesystem check. For example:
RewriteRule \.\w{2,5}$ - [L]
I've been searching for 4 hours by now and I still can't get this to work.
I have the following directories in my webroot:
- application
- assets
- css
- config
- protected
- .htaccess
- ...
- .htaccess
- framework
- [Yii framework inside]
- .htaccess
The .htaccess in my webroot should redirect/'rewrite' all requests for whatever xxx/xxx to http://www.example.com/application/ as long as the requested file or directory does not exist.
This way requests for .css, .js and other files can still work.
In my config I made sure Yii expects SEO friendly URL's and I don't tend to use the index.php. So it now looks like this:
'urlManager'=>array(
'urlFormat'=>'path',
'showScriptName'=>false,
'rules'=>array(
'' => 'site/index',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),
'request' => array(
'baseUrl' => 'http://www.example.com',
),
The 'request' was added later on because Yii was generating links as example.com/application/site/login. With the request Yii generates example.com/site/login instead.
In the .htaccess in my webroot I tried about everything.
First I was able to 'remove' the subdir from the URL. The index page was shown.
I tried to add a rule so all none existing directories would be redirected to the same url.
My first rule broke, and 'application' was in the URL again, but no css styles were loaded.
At this moment I got the index page with css, but now everything brings me to the index page.
my .htaccess looks like this:
RewriteEngine on
RewriteCond $1 !^application/
# if a directory or a file exists, use it directly
RewriteCond %{DOCUMENT_ROOT}/application/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/application/$1 -d
RewriteRule ^(.*)$ application/$1 [L]
# otherwise forward it to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^.*$ application/index.php
Mod_rewrite is enabled (I know because some things worked before). I looked at examples from the Yii docs.
I tried solutions from other questions on Stack Overflow like this one and many many others.
Still no luck.
Could someone please help me out?
edit:
With the .htaccess above a request to example.com ends at example.com/application .. I however would like to make the 'application' 'invisible' again (worked before, don't know why it broke)
I did change my .htaccess as follows:
RewriteEngine on
RewriteCond $1 !^application/
# if a directory or a file exists, use it directly
RewriteCond %{DOCUMENT_ROOT}/application/$1 -f [OR]
RewriteCond %{DOCUMENT_ROOT}/application/$1 -d
RewriteRule ^(.*)$ application/$1 [L]
# otherwise forward it to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)$ /application/
RewriteCond %{HTTP_HOST} ^(www.)?brainfeeder.be$
RewriteRule ^$ application/$1 [L,QSA]
But still a url like www.brainfeeder.be/site/login brings me to the default controller/action which is the site/index.
I guess my conditions or rules are not exactly correct yet.
Please see my small test application I set up to tackle this issue.
What happens: brainfeeder.be get rewritten to brainfeeder.be/application/ My Yii app is in there so it runs the 'bootstrap' index.php file and gets to the default controller/action, in this case site/index.
Now when you click the 'login' button it should show you a login form. But it stays at the site/index view.
Ok, once again I updated my .htaccess a couple of times. Now I have the following situation:
www.example.com AND example.com are rewritten to www.example.com/application AND example.com/application.
(www.)?example.com/existingfolder just shows content of 'existingfolder'.
(www.)?example.com/var1/var2/../varn get redirected to (www.)?example.com/application/var1/var2/.../varn
Now the only thing I would like to happen is that the latter gets rewritten instead of redirected. So visitors don't know they are in the directory 'application'.
So (www.)?example.com/var1/var2/.../varn would bring the visitor directly to the correct page.
The contents of my .htaccess at the moment:
Options +FollowSymLinks
#IndexIgnore */*
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} ^(www.)?brainfeeder.be$
RewriteRule ^$ /application/ [L]
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [L]
# The directory or file does not exist
RewriteCond %{REQUEST_FILENAME} !-s [OR]
RewriteCond %{REQUEST_FILENAME} !-l [OR]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /application/$1 [L,R]
The thing is, when losing the R flag in the last RewriteRule will bring me to the index.php file inside 'application' but it shows the home page instead of a login form when for example I go to example.com/site/login.
Which, I guess, the script does not see the vars. (if it did site/error would trigger) So it handles this as a request to example.com/application and not as example.com/application/var1/var2
I hope I did explain the problem better this time.
Thanks for the great help 'till now.
Try to check these configuration directives if you just want to rewrite all the unexisting /$var1/$var2 to /application/:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)$ /application/
Now, if you want those unexisting files to redirect, rather than to rewrite them? Then just add a [R] flag at the end of the RewriteRule directive, just don't forget a single " " space before the flag.
Now, if you want to redirect /application to / and then rewrite /index.php to /application and to rewrite also the unexisting /$var1/$var2 to /application/$var1/$var2 then it's quite hard (and need some exact details) but you could still try these configuration directives:
RewriteEngine on
# rewrite index.php
RewriteRule ^index.php$ /application
# rewrite unexisting files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)/?$ /application/$1/$2
# try to remove this if it causes redirection loop
RewriteRule ^application/?$ / [R]
You can also try to use DirectoryIndex application/index.php at the very top of those directives to change the index of your site and remove the line RewriteRule ^index.php$ /application if it causes an error.
Actually, I can't understand your question.. You said:
The .htaccess in my webroot should redirect/'rewrite' all requests for
whatever xxx/xxx to http://www.example.com/application/ as long as the
requested file or directory does not exist. This way requests for
.css, .js and other files can still work.
And now, you said to your comment:
So any link to brainfeeder.be/application/$var1/$var2 should be shown
as brainfeeder.be/$var1/$var2
If you would also like to redirect existing /application/$var1/$var2 to /$var1/$var2 then please try to add these directives, and if it causes an error to your system, just remove it:
# the condition is important as mentioned above
RewriteCond %{REQUEST_URI} !\.css$
RewriteRule ^application/([^/]+)/([^/]+)/?$ /$1/$2 [R]
You can add another condition (as many as you like) at the top of the RewriteRule, just use your thinking if you're a programmer. You could add another condition like RewriteCond %{REQUEST_URI} !\.jpg$ if you doesn't want to redirect the file with an extension like .jpg or else that you want such:
RewriteCond %{REQUEST_URI} !\.css$
RewriteCond %{REQUEST_URI} !\.jpg$
RewriteCond %{REQUEST_URI} !\.png$
RewriteRule ^application/([^/]+)/([^/]+)/?$ /$1/$2 [R]
Please try to change the source of your .htaccess file with this code:
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} ^(www\.)?brainfeeder\.be$
RewriteRule ^/?$ /application/ [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /application/$1 [L]
Not sure what your question is ...
But here is an .htaccess that should accomplish what you want:
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
You dont need to edit .htaccess. You just need to move the Yii entry script (index.php) and the default .htaccess up from the subdirectory to the webroot (so that they reside directly under public_html). After you move index.php and .htaccess to the root directory, all web requests will be routed directly to index.php under webroot (rather than to the subdirectory), thus eliminating the /subdirectory part of the url.
After moving the files, you will need to edit index.php to update the references to the yii.php file (under the Yii framework directory) as well as the Yii config file (main.php). Lastly, you will need to move the assets directory to directly the webroot, since by default, Yii expects the assets directory to be located in the same location as the entry script).
That should be all you need to do, but if you need more details I describe the approach more fully here:
http://muhammadatt.tumblr.com/post/83149364519/modifying-a-yii-application-to-run-from-a-subdirectory
I have the following in my htaccess file:
RewriteEngine On
RewriteRule ^(.*)$ rewrite.php?data=$1 [L,QSA]
From rewrite.php I redirect to the correct pages depending on the url. Problem is that it redirects all files including css and js. I tried including these files but I now realise that was dumb of me. Should I redirect when there is and appropriate extension in the url? If redirecting is the way to go what method would be best? header location or HTTP_redirect?
Or is this not a good idea performance or work involved wise? I could go for something like this but I know next to nothing about apache and would rather not work with it right now.
RewriteRule ^(.*).css$ /includes/compressor.php?i=$1.css [L]
I previously had the following in my htaccess file:
RewriteCond %{REQUEST_FILENAME} !-f
I decided to remove this because:
I would not be able to include the header and other common files in the rewrite.php file. I would also not be able to have a database call in the rewrite file that would determine the page to include and to reuse the data for the page contents.
Unwanted files would be reachable such as service used only by external app.
The compression should be done once, and not for every request. You can then exclude requests from the URL rewriting if the corresponding file exists:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ rewrite.php?data=$1 [L,QSA]
How about redirecting only if the requested file does not exist on the server?
You could use the following rewrite conditions to achieve this.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*)$ rewrite.php?data=$1 [L,QSA]
So if the request is for a CSS/JS/HTML/Image file that already exists on the server then no rewriting takes place and the request for the file is processed. If the file does not exist, it will run your rewrite rule to rewrite.php
I'd like to know if it is possible to add a rule to the htaccess of my ZF app to redirect all the URLs that ends with the segment /index/ (such as http://domain.ext/index/) to the same URL without the /index/ suffix.
I've tried with this simple rule:
RedirectMatch ^(.*)/(index(/)?)$ http://localhost$1
but it doesn't work as expected (with other frameworks such as FuelPHP it works like a charm).
I know that this can be done via PHP using a plugin but I'd like to make the redirect via Apache to improve the performance of the application.
I don't know why nobody jumped in here, it is not that complicated?
A config file is executed from top to bottom and certain rules cause an immediate exit. If the rule defines an external redirect the server will perform that redirect immediately and all following rules are therefore ignored. If the redirect is back to the same server and config file then it is just a new game with the rules! If the redirect rule does not apply anymore it is on to the next rule. If the rule would still apply you get a loop.
Similar thing with a RewriteRule that matches and has [L]. L means "Stop the rewriting process here and don't apply any more rewrite rules". This quote is straight from the manual
Now you simply have to define some logic in what order you want to apply certain rules. Your request about the RedirectMatch for any /index/ path is certainly something you want to have very early to the top of the config. If there is a match your config will end here and perform a redirect! The browser will send a new request and we have a new game.
The RewriteRule to an index.php is something we will add very late at the bottom. It may be our last resort like a if all fails then rule. I does not matter if this is the Zend Framework or any other application you funnel through an index.php or other script for that matter.
The following rules should cover any variation with index, including .php, .htm and .html and finally trigger the index.php file for your ZF application.
RedirectMatch ^(/.*)/(index.(php|html|htm)|index)/?$ $1
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
When testing redirect rules be careful with your browser and use one where you can totally reset all cache and history settings. All current browsers are notorious in "remembering" redirects. If they learned a redirect rule they will perform that redirect internal, i.e. they don't go to the server to see what's new!
Here is your ruleset laid out readably
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RedirectMatch ^(.*)/(index(/)?)$ http://localhost$1
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
RedirectMatch is a mod_alias directive which severs the conds as from their rule. Also it's a lot less fraught not mixing mod_alias and mod_rewrite directives, so try:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(.*?)/index/?$ $1 [R=301,L]
RewriteRule ^.*$ index.php [NC,L]
(updated following posters comments)
More footnotes
I tried this out on my VM which mirrors my hosting service, but having root access I can see the 'production' rewrite logs. This fails because the second rules still falls through to rule (3) which dispatchs to index.php. This then returms the full content but with a 301 status and without issuing a new location. If I change the [R=301] to [R=301,L] then it works fine as the server now issues a 301 with a Location header and the browser now retries with the new location.
The documentation states:
You will almost always want to use [R] in conjunction with [L] (that is, use [R,L]) because on its own, the [R] flag prepends http://thishost[:thisport] to the URI, but then passes this on to the next rule in the ruleset, which can often result in 'Invalid URI in request' warnings.
I resolved my problem with this (horrible) workaround:
- I renamed the "index" action of IndexController to "home"
- I setup a static route for home page (source)
- I changed the htaccess to:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^(.*)home(/)?$ $1 [R=301,L]
RewriteRule ^(.*)index/(.*)$ $1$2 [R=301,L]
RewriteRule ^.*$ index.php [QSA,NC,L]
So now the home page is not duplicated because http://localhost/home/ is redirected to the base domain and for other controllers the index action, if it is called specifying the action name (/controller/index/param/value) is redirected to the desired URL (/controller/param/value/)
RewriteRule ^(.*)/index(?|$)$ $1$2 [R=301,L]
this works with urls
/index => /
/index?page=2 => /?page2
/index/index => /
/index/index?page=2 /?page2
you need remove trailing slash before, for url like /index/, index/index/
RewriteRule ^(.*)/$ /$1 [L,R=301]
url like /index/help will work without changes
I have a domain let's call it newsite.com which is parked to maindomain.com. I use mod-rewrite to direct all requests for newsite.com to a subdirectory on maindomain.com. On newsite.com I have CodeIgniter installed. Which means the urls look like this:
newsite.com/products/shoes/
The above works just fine.
However, if I set up a controller for a page like this:
newsite.com/about/ or newsite.com/about/faqs/
I get a 404 which I believe is being caused because it is looking for the page maindomain.com/about.php which does exist, but does NOT exist on newsite.com.
My question is.... how do I PREVENT urls like newsite.com/about/ from pointing to newsite.com/about.php ? This is the opposite of what many people try to do (they tend to want to allow the file extension to be missing).
I'm wondering if it is and apache or PHP setting that causes it to look for the file first if it exists and the directory does not? Or do I need to add more mod-rewrite rules?
Thanks very much!
Edit - here is my .htaccess file currently. It resides at the web root of the maindomain.com shared hosting account.
# Redirect various urls to subfolders of the format: /site-thename/
RewriteEngine On
# Remove the www for NewSite.
RewriteCond %{HTTP_HOST} ^www.newsite.com$ [NC]
RewriteRule ^(.*)$ http://newsite.com/$1 [R=301,L]
# Handle pages and directories that should not go through CodeIgniter.
RewriteCond %{HTTP_HOST} ^(www\.)?newsite\.com
RewriteCond %{REQUEST_URI} !^/site-newsite/
RewriteCond %{REQUEST_URI} ^/demo/ [OR]
RewriteCond %{REQUEST_URI} ^/robots\.txt [OR]
RewriteCond %{REQUEST_URI} ^/emailform\.php [OR]
RewriteCond %{REQUEST_URI} ^/assets/ [OR]
RewriteCond %{REQUEST_URI} ^/index\.php
Rewriterule ^(.*)$ /site-newsite/$1 [L]
# Handle CodeIgniter URLs.
RewriteCond %{HTTP_HOST} ^(www\.)?newsite\.com
RewriteCond %{REQUEST_URI} !^/site-newsite/
Rewriterule ^(.*)$ /site-newsite/index.php?/$1 [L]
Asked my hosting company's support department what might be causing this... and it turns out that it is caused by Apache MultiViews. This can be turned off via
Options -MultiViews
in the htaccess file. That worked.
Thanks for the suggestions.
If you have no rewrite rules for it, Apache, by default, will reference whatever is on the filesystem. You must have rewrite rules there to tell Apache to use a specific controller to handle requests instead of attempting to reference objects on the filesystem.
I assume that if you are an apache user, you use .htaccess file for redirecting the URL to you 'index' file (let's call it index.php). Also you should have sth like:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php
in your .htaccess file. Note that the RewriteCond condition has a parameter which checks if it is not a file:-) More can be found at http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritecond