Apache RewriteRule for Two URLs - apache

I'm trying to redirect the following two URLs:
https://www.example.com/blog/content/Das.com
https://www.example.com/blog/content/page/2
To:
https://www.example.com/blog/content
Using:
RewriteEngine on
RewriteRule (blog/content/Das.com|blog/content/page/2) /blog/content [L,R=301]
But it's not working. What am I doing wrong?

Are you sure you want to redirect different requested URLs to the same target URL? That means you will loose the information which URL has originally been requested. So you cannot differ between the two requests any more. If you actually only want to internally rewrite those URLs, so that they can be processed by the same controller, then just leave away the R=301 flags below...
I personally would suggest to implement two separate rules. Readability of code is of high importance, it should be possible to immedately understand what code does even for someone who did not write the code:
RewriteEngine on
RewriteRule ^/?blog/content/Das\.com$ /blog/content [R=301,END]
RewriteRule ^/?blog/content/page/2$ /blog/content [R=301,END]
But if you prefer a single rule you certainly can combine that:
RewriteEngine on
RewriteRule ^/?blog/content/(?:Das\.com|page/)$ /blog/content [R=301,END]
For this to work the rewriting module needs to be loaded into the http server obviously. You should prefer to implement such rules in the actual http server's host configuration. You can use a distributed configuration file (".htaccess") in case you do not have control over the normal configuration, but that comes with a performance penalty. And obviously also needs to be enabled first. You'd need to place that file in the top folder of your DOCUMENT_ROOT in that case.
In general it is a good idea to start out with a R=302 temporary redirection and only to change that to a R=301 permanent redirection once you are sure things work as expected. That prevents annoying caching issues.

Related

.htaccess redirects if the condition doe not match/ negative condition

I am modifying the .htaccess file of a legacy PHP web application. I am not familiar with apache .htaccess syntax. I found this tutorial. What I am trying to do is that I am trying to redirect all the requests to a URL/ path if the request URL is not a specific URL/ path. For example, all the requests to the website will be redirected to localhost/my-custom-page unless the request URL is localhost/my-custom-page.
I know how to redirect mapping 1 to 1 as follows:
RewriteEngine on
RewriteRule ^my-old-url.html$ /my-new-url.html [R=301,L]
But, what I am trying to do is that redirecting all the requests to the specific page unless the request is to that page. Even the home page will be redirected to that page. How can I do that?
When I tried the following solution
RewriteEngine on
RewriteCond %{REQUEST_URI} !/my-new-url\.html
RewriteRule ^ /my-new-url.html [R=301]
I get the error
I want to check using OR condition as well. For example, if the path is not path-one or path-two, redirect all the requests to path-one.
Your question is a bit vague, due to your wording. But I assume this is what you are actually looking for:
RewriteEngine on
RewriteCond %{REQUEST_URI} !/my-new-url\.html
RewriteRule ^ /my-new-url.html [R=301]
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
It is a good idea to start out with a 302 temporary redirection and only change that to a 301 permanent redirection later, once you are certain everything is correctly set up. That prevents caching issues while trying things out...
This rule will work likewise in the http servers host configuration or inside a dynamic configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a dynamic configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using dynamic configuration files (".htaccess"). Those dynamic configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).
RewriteCond %{REQUEST_URI} !/my-new-url\.html
RewriteRule ^ /my-new-url.html [R=301]
There are a few potential issues with this, particularly since you hint in a comment that you are perhaps using a front-controller to "route" the URL.
This redirect satisfies the conditions outlined in the question, but does assume that you have no other rewrites, have an essentially "static site" and are not linking to any static resources.
You are missing an L (last) flag, so processing will continue through the file and possibly be rewritten if you have later rewrites.
If you are rewriting the URL to a front-controller in order to route the URL (as you suggest in comments) then this redirect will break, as it will redirect away from the front-controller. You need to only redirect direct requests, ie. when the REDIRECT_STATUS environment variable is empty.
If you are linking to any static resources in the same file space then these will also be redirected. You need to create an exception for any static resources you are using, either by file extension (eg. (css|js|jpg|png)) or by location (eg. /static).
So, try the following instead:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !\.(js|css|jpg|png)$
RewriteRule !^my-custom-url$ /my-custom-url [R=302,L]
You don't need a separate condition to implement the exception for the URL you are redirecting to. It is more efficient to do this directly in the RewriteRule pattern.
The first condition ensures we are only redirecting direct requests and not rewritten requests to your front-controller.
The second condition avoids any static resources also being redirected. You could alternatively check the filesystem path if all your resources are stored under a common root. Or, as a last resort, implement filesystem checks (ie. RewriteCond %{REQUEST_FILENAME} !-f) if your static resources are too varied - but note that this is less efficient.
You will need to clear your browser cache before testing, since any earlier (erroneous) 301s are cached persistently by the browser.

Redirect to a specific page from any dir or subdir in htaccess

Is it possible to use an universal rule to redirect to a specific page from whatever directory or subdirectory using .htaccess?
To be more precise, if I want to have an URL like example.com/login that redirects to example.com/login.php?action=login, I use the following line in my .htaccess file:
RewriteRule ^login$ /login.php?action=login [L]
But is it possible to to have a rule that lets me redirect from example.com/any_directory/login to example.com/login.php?action=login? So from anywhere down the example.com subdirectories to ``example.com/login.php?action=login`. And if yes, how can I do this
Certainly that is possible. Easiest is to use a rewrite condition since that operates on the absolute request path even inside a dynamic configuration file. Rewrite rules operate on a relative path i such location which makes matching complicated...
Take a look at this simple example:
RewriteEngine on
RewriteCond %{REQUEST_URI} /login$
RewriteRule ^ /login.php?action=login [L]
If you do the rewriting in the http servers host configuration instead you can simplify that. Reason is that it is always absolute paths the rules work on in that location:
RewriteEngine on
RewriteRule /login$ /login.php?action=login [L]
The main approach in both variants is to rely on the slash preceding the login key word. It always is present in an absolute request path and clearly left-delimits the key word. And not to insist on matching at the line start.
And a general hint: you should always prefer to place such rules inside the http servers host configuration instead of using dynamic configuration files (".htaccess"). Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).
You need to adjust your regex pattern .Simply remove the ^ ,so that it can match anychars before login/ in uri ie : /foobar/login .
RewriteRule /login/?$ /login.php?action=login [L]

Apache 301 redirect with get parameters

I am trying to do a 301 redirect with lightspeed webserver htaccess with no luck.
I need to do a url to url redirect without any related parameters.
for example:
from: http://www.example.com/?cat=123
to: http://www.example.com/some_url
I have tried:
RewriteRule http://www.example.com/?cat=123 http://www.example.com/some_url/ [R=301,L,NC]
Any help will be appreciated.
Thanks for adding your code to your question. Once more we see how important that is:
your issue is that a RewriteRule does not operate on URLs, but on paths. So you need something like that instead:
RewriteEngine on
RewriteRule ^/?$ /some_url/ [R=301,L,NC,QSD]
From your question it is not clear if you want to ignore any GET parameters or if you only want to redirect if certain parameters are set. So here is a variant that will only get applied if some parameter is actually set in the request:
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)cat=123(?:&|$)
RewriteRule ^/?$ /some_url/ [R=301,L,NC,QSD]
Another thing that does not really get clear is if you want all URLs below http://www.example.com/ (so below the path /) to be rewritten, or only that exact URL. If you want to keep any potential further path component of a request and still rewrite (for example http://www.example.com/foo => http://www.example.com/some_url/foo), then you need to add a capture in your regular expression and reuse the captured path components:
RewriteEngine on
RewriteRule ^/?(.*)$ /some_url/$1 [R=301,L,NC,QSD]
For either of this to work you need to have the interpretation of .htaccess style files enabled by means of the AllowOverride command. See the official documentation of the rewriting module for details. And you have to take care that that -htaccess style file is actually readable by the http server process and that it is located right inside the http hosts DOCUMENT_ROOT folder in the local file system.
And a general hint: you should always prefer to place such rules inside the http servers host configuration instead of using .htaccess style files. Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).

Domain handling with a controller

Im running an MVC based application on my mainsite, I have 2 other domains (for the sake of an example, www.a.com & www.b.com)
I'd like to be able to handle all a.com's requests with mainsite.com/a/ and similarly b.com with mainsite.com/b/
However I do not want the url to be redirected/changed in the browser.
I've been trying with mod_rewrite, however it seems to be clashing with my existing .htaccess rules set for mainsite.com
this is my existing .htaccess
Could anyone please suggest the best way to do this?
In the existing .htaccess, I don't see any rules redirecting the domains a.com or b.com. To do that is pretty straightforward, though.
A condition for selecting the proper host www.a.com or a.com
RewriteCond %{HTTP_HOST} ^(?:www\.)?a\.com$
prevent an endless loop
RewriteCond %{REQUEST_URI} !^/a/
and do the actual rewrite
RewriteRule ^ /a%{REQUEST_URI} [L]
As long as you don't use the R flag, the URL shouldn't change in the browser.
The rule for host b.com is analogous.
Update:
Since you already have a very large .htaccess file, the performance impact shouldn't matter too much. If you want to know for sure, there's no substitute for measuring.
If you want to reduce the performance hit nevertheless, you have two options
Move the directives in the .htaccess file to your main config or virtual config file, see When (not) to use .htaccess files for an explanation.
Do some custom rewriting with PHP in your front controller. This depends on the framework or routing mechanism you use, of course.

Using .htaccess rewrite rules to reflect a "fake" directory structure in the addres bar

I'm working with an online encyclopedia and I am trying to achieve the following:
Given the physical location of a file in http://example.com/articles/c/a/t/Cat.html,
Get the location in the address bar to show http://example.com/encyclopedia/Cat.html
This also needs to work so that if a link is clicked or someone types in "example.com/encyclopedia/Cat.html", the server will look for the file in "/articles/c/a/t/Cat.html", yet still serve the shorter URI in the address bar.
I understand this may involve some heavy .htaccess voodoo to accomplish, or perhaps that it would be better to use a PHP script to serve this purpose.
So far I have the following in my .htaccess:
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^encyclopedia/(.*)\.html$ articles/$1.html [NC]
RewriteCond %{THE_REQUEST} ^GET\ articles/(.*)
RewriteRule ^articles/(.*) /encyclopedia/$1 [L,R=301]
</IfModule>
However with this code, it only works by going to "example.com/encyclopedia/c/a/t/Cat.html" and showing the proper page, and when you go to "/articles/c/a/t/Cat.html it still doesn't rewrite it as "/encyclopedia/", it just stays the same.
Edit - By removing the GET\ part from the RewriteCond and removing the leading forward-slash from /encyclopedia/$1 in the following line, any requests to "/articles/c/a/t/Cat.html" are correctly redirected to "/encyclopedia/c/a/t/Cat.html". I am still at a loss trying to remove the "/c/a/t" part though. **
I've tried using the following two rules to remove the "c/a/t/" part:
RewriteRule ^encyclopedia/((.)(.)(.).*)\.html$ articles/$2/$3/$4/$1.html [NC]
RewriteRule ^articles/(.)/(.)/(.)/(.*) /encyclopedia/$4 [L,R=301]
But with no success as I'm sure what's happening is I'm getting the capital "C" from "Cat.html" and putting that in as "/articles/C/a/t/Cat.html" which will obviously not work.
I've been looking around studying .htaccess RewriteRule and RewriteCond for days but I still haven't been able to figure this out and been BHOK enough to cause a few migraines.
Would this be better accomplished using a PHP script? Or can this voodoo be easily enough accomplished via only .htaccess rules?
First thing, forget about .htaccess files. .htaccess files is just an extension of Apache configuration files that you can put in some directories. They're really slowing down your apache server, he needs to check part of his configuration at runtime. It's done to allow some configuration on hosted environments.
Put everything you have in .htaccess files in <Directory> sections on your VirtualHost and use AllowOverride None to tell Apache to forget about trying to read .htaccess files.
So what you need is mod-rewrite voodoo, not .htaccess voodoo :-)
Now your rewrite problem is quite complex. If you need some mod-rewrite help do not forget to read this ServFault article : Everything You Ever Wanted to Know about Mod_Rewrite Rules but Were Afraid to Ask?
I assume that your Cat.html -> c/a/t/Cat.html is just an example and that you can have more than 3 letters : CatAndDogs.html -> c/a/t/a/n/d/d/o/g/s/CatAndDogs.html.
The part of mod-reqrite you need is (I think) RewriteMap. There you will find some helpers like lowercase: that coudl help you, but you will also find the prg: which means using an external program to perform the mapping. I would use perl examples of such rewriteMaps examples available via google and make some transformations. Should be quite easy and Fast in Perl to transform CatAndDogs.html in c/a/t/a/n/d/d/o/g/s/CatAndDogs.html.
Note that RewriteMap will never work inside a .htaccess. Forget .htaccess files. The prg: keyword will launch your perl program as a parallel daemon and will feed him with quite a lot of data, you shoudl really write something robust & fast. Do not forget to use the RewriteLock directive to avoid mixing results (some prg: mappers do not care about mixing results, think about load balancers for examples, but you do want to avoid mixing results for parallel queries)