I have a cookie name=dir and value=test. I want htaccess to check if that value exist as a directory and redirect based on that.
RewriteCond /var/www/whatever/%{HTTP_COOKIE:dir} -d
RewriteRule ^(.*)$ example.com [R]
I know it would be possible with a RewriteMap, but I have no access to the conf file and RewriteMaps must be defined there, not in htaccess. A pure mod_rewrite solution would be best, because the module for setenv isn't enabled either. I've tried and googled, but to no avail.
Something like %{HTTP:header} but for cookies would be ideal, but Apache doesn't do that.
You have to match against %{HTTP_COOKIE} in a seperate RewriteCond
RewriteCond %{HTTP_COOKIE} ^dir=(.+)$
RewriteCond /var/www/whatever/%1 -d
RewriteRule ^(.*)$ example.com [R]
#starkeen: I wasn't aware that i could use %1 in RewriteCond, thought it was for RewriteRule only. Your Answer works perfectly exept for 2 things:
A. Regex. %{HTTP_COOKIE} is a String that can have 3 cases in this Situation:
Case 1: dir=abc - Your Regex works
Case 2: dir=abc; cookie1=v1 - Your Rexex does not work
Case 3: cookie1=v1; dir=abc; cookie2=v2 - Your Rexex does not work
Also important: it might be something like dir_save=v1; x_dir=v2; dir=abs, so something like
RewriteCond %{HTTP_COOKIE} ^.*dir=(.*).*$
will not work either.
So ... Start with [NEWLINE] or ';[SPACE]' and end with [LINE-END] or ';'
RewirteCond %{HTTP_COOKIE} (^|;\ )dir=(.*)(;|$)
RewriteCond %2 -d
RewriteRule ^(.*)$ example.com [R]
B. Also check for strange values of the cookie dir, like empty or '\' or '.' or '..\' and so on. On Windows of cause '\' ...
RewirteCond %{HTTP_COOKIE} (^|\ ;)dir=(.*)(;|$)
# must be a directory
RewriteCond %2 -d
# must not be empty
RewriteCond %2 !^$
# must not contain dot
RewriteCond %2 !^.*\..*$
# must not contain /
RewriteCond %2 !^.*/.*$
# must not contain \
RewriteCond %2 !^.*\\.*$
RewriteRule ^(.*)$ example.com [R]
#all: sorry for answering my own question (also starkeen showed a vital part i wasn't aware of) and also sorry for being so rigorous about regex and strange cookie values, but such things can cost you hours to fiddle out in the worst case. I've allready made such mistakes and learned the hard way.
Related
I need to write an anti-hotlink command for my .htaccess file but it can not be specific to any domain name in particular. Here's what I found on another sites so far but I'm not sure exactly why it doesn't work, can anyone spot the problem?
# Stop hotlinking.
#------------------------------
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} ^https?://([^/]+)/ [NC]
# Note the # is just used as a boundary. It could be any character that isn't used in domain-names.
RewriteCond %1#%{HTTP_HOST} !^(.+)#\1$
RewriteRule \.(bmp|gif|jpe?g|png|swf)$ - [F,L,NC]
Try this.
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} ^https?://(www\.)?([^/]+)/.*$ [NC]
RewriteCond %2#%{HTTP_HOST} !^(.+)#(www\.)?\1$ [NC]
RewriteRule \.(bmp|gif|jpe?g|png|swf)$ - [F,L,NC]
Would even work when only one of the referrer or target url has a leading www.
EDIT : (how does this % thing work?)
%n references the n(th) bracket's matched content from the last matched rewrite condition.
So, in this case
%1 = either www. OR "" blank (because it's optional; used ()? to do that)
%2 = yourdomain.com (without www always)
So, now the rewrite condition actually tries to match
yourdomain.com#stealer.com OR yourdomain.com#www.stealer.com
with ^(.+)#(www\.)?\1$ which means (.+)# anything and everything before # followed by www. (but again optional); followed by \1 the first bracket's matched content (within this regex; not the rewrite condition) i.e. the exact same thing before #.
So, stealer.com would fail the regex while yourdomain.com would pass. But, since we've negated the rule with a !; stealer.com passes the condition and hence the hot-link stopper rule is applied.
I have a hard time understanding htaccess mod_rewrite and while I found several related questions + answers, I unfortunately can't get my very specific situation to work correctly (mod_rewrite is even after hours of searching a book of seven seals to me to be honest)
I have foo.html and bar.html within my root directory. Now, I'd like to have foo.html as the default directory index (solved, easy), but from there I do not get it.
What I want to achieve is:
hiding the .html extensions
user should be able to type /bar to get /bar.html without seeing the .html (for every .html)
301 redirecting .html version
user should be able to type /bar.html and see /bar in the url (avoid duplicate, for every .html)
The most tricky part:
As foo.html is default directory index, typing / already shows (transparently) /foo.html, but I need typing /foo.html to resolve to / as well as typing /foo to resolve to /
Try putting these rules in the htaccess file in your document root:
RewriteEngine
# 1. hiding the .html extensions
RewriteCond %{REQUEST_URI} ^/(.*?)/?$
RewriteCond %{DOCUMENT_ROOT}/%1.html -f
RewriteRule ^ /%1.html [L]
# 2. 301 redirecting .html version
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.html
RewriteCond %1 !foo$
RewriteRule ^ /%1 [L,R=301]
# 3. typing /foo.html to resolve to / as well as typing /foo to resolve to /
RewriteCond %{REQUEST_URI} ^/(.*?/?)foo(\.html)?$
RewriteRule ^ /%1 [L,R=301]
Also, make sure you have Multiviews turned off:
Options -Multiviews
The first rule has 2 conditions, the first groups the URI everything between the first / and a possible last /. The references it using %1 in the next condition which sees if the /path/to/www/document/root/%1.html is a file that exists. If both are true, it internally rewrites the URI to include a .html at the end.
The second rule has 2 conditions, the first matches against the actual request as opposed to the URI (which can change as the rules are being applied and rewrites happen). It sees if there's a request that ends with .html, and if so, the second condition makes sure that it isn't foo.html request (since the last rule handles that). If both are true, then it redirects the browser to the part of the URI without the html, again using %1 to reference the grouping in the match from the first condition ([^\ ]+).
The last rule checks if the request is for a foo or foo.html. If so, redirect removing that part of the URI.
I am using the one below and it works except that, in some strange case when working with a WARRANTY script for a client it just won't do the thing.
However; the other scripts that calls external scripts via iFrame in a sub-folder seems to work with the exception of the WARRANTY script. ...
Options +FollowSymLinks -MultiViews
RewriteEngine on
RewriteBase /
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L,NS]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*?)\.(php|html?)$ $1 [R=301,NC,NS]
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule (.*)$ $1.html [L,E=END:1,NS]
RewriteCond %{REQUEST_FILENAME}\.htm -f
RewriteRule (.*)$ $1.htm [L,E=END:1,NS]
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule (.*)$ $1.php [L,E=END:1,NS]
I hope this Helps.
Hi people#stackoverflow,
Maybe I have a fundamental misconception about the working of RewriteRule. Or maybe not. Nevertheless, I'm trying to figure this out now for two days, without any progress.
This is the currrent situation:
I have a Joomla website with SEF and mod_rewrite turned on.
This results in the URL:
mysite.com/index.php?option=com_remository&Itemid=7
being rewritten to:
mysite.com/sub-directory/sub-directory/0000-Business-files/
These are the lines that are currently used in my .htaccess (all standard Joomla)
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^([^\-]*)\-(.*)$ $1 $2 [N]
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [OR]
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ index.php [F,L]
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{REQUEST_URI} (/|\.php|\.html|\.htm|\.feed|\.pdf|\.raw|/[^.]*)$ [NC]
RewriteRule (.*) index.php
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
This is what I want to achieve:
When a visitor uses this URL
mysite.com/sub directory/sub directory/0000 Business files/
it should lead him to the right page.
Although I know it's not the best idea to use spaces in a URL, I'm confronted with the fact that these 'spacious' URL's are used in a PDF, that's already been issued.
I thought I could use mod_rewrite to rewrite these URL's. But all I get is 'page not found'
I've added this rule on top of the .htaccess file:
RewriteRule ^([^\-]*)\-(.*)$ $1 $2 [N]
But this is not working. What am I doing wrong? Or, also possible, am I missing the point on when and how to use mod_rewrite?
rgds, Eric
First off, the default behavior of apache is usually to allow direct URLs that map to the underlying file system (relative to the document root), and you should use RewriteRule when you want to work around that. Looking at your question, it seems like you want to browse the filesystem and so you should not use a RewriteRule.
If mysite.com/sub+diretory/sub+directory/0000+Business+files/ doesn't work (without your rule), I'm wondering: do you have that directory structure on your server? I.e. does it look like this?
[document root]/index.php
[document root]/sub directory/sub directory/0000 Business files/
If not, I'm not sure I understand what you're trying to achieve, and what you mean by the visitor being "lead to the right page". Could you provide an example URL that the user provides, and the corresponding URL (or file system path) that you want the user to be served.
Regarding your rewrite rule, I'm not even sure that it is allowed, and I'm surprised you don't get a 500 Internal Server Error. RewriteRule takes two arguments (matching pattern and substitution) and optionally some flags, but because of the space between $1 and $2 you're supplying three arguments (+ flags).
EDIT: I got the pattern wrong, but it still doesn't make much sense. It matches against any URL that has at least one dash in it, and then picks out the parts before and after the first dash. So, for a URL like "this-is-a-url-path/to-a-file/on-the-server", $1 would be "this" and $2 would be "is-a-url-path/to-a-file/on-the-server". Again, if I had some example URLs and their corresponding rewrites, I could help you find the right pattern.
On a side note, spaces aren't allowed in URLs, but the browser and server probably does some work behind the scenes, allowing your PDFs to be picked up correctly.
I am using mod_rewrite, to convert subdomains into directory urls. (solution from here). When I explicity write a rule for one subdomain, it works perfectly:
RewriteCond %{HTTP_HOST} ^[www\.]*sub-domain-name.domain-name.com [NC]
RewriteCond %{REQUEST_URI} !^/sub-domain-directory/.*
RewriteRule ^(.*) /sub-domain-directory/$1 [L]
However, if I try to match all subdomains, it results in 500 internal error (log says too many redirects). The code is:
RewriteCond %{HTTP_HOST} ^[www\.]*([a-z0-9-]+).domain-name.com [NC]
RewriteCond %{REQUEST_URI} !^/%1/.*
RewriteRule ^(.*) /%1/$1 [L]
Can anyone suggest what went wrong and how to fix it?
Your second RewriteCond will never return false, because you can't use backreferences within your test clauses (they're compiled during parsing, making this impossible since no variable expansion will take place). You're actually testing for paths beginning with the literal text /%1/, which isn't what you wanted. Given that you're operating in a per-directory context, the rule set will end up being applied again, resulting in a transformation like the following:
path -> sub/path
sub/path -> sub/sub/path
sub/sub/path -> sub/sub/sub/path
...
This goes on for about ten iterations before the server gets upset and throws a 500 error. There are a few different ways to fix this, but I'm going to chose one that most closely resembles the approach you were trying to take. I'd also modify that first RewriteCond, since the regular expression is a bit flawed:
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
RewriteCond %1 !=www
RewriteCond %1#%{REQUEST_URI} !^([^#]+)#/\1/
RewriteRule .* /%1/$0 [L]
First, it checks the HTTP_HOST value and captures the subdomain, whatever it might be. Then, assuming you don't want this transformation to take place in the case of www, it makes sure that the capture does not match that. After that, it uses the regular expression's own internal backreferences to see if the REQUEST_URI begins with the subdomain value. If it doesn't, it prepends the subdomain as a directory, like you have now.
The potential problem with this approach is that it won't work correctly if you access a path beginning with the same name as the subdomain the request is sent to, like sub.example.com/sub/. An alternative is to check the REDIRECT_STATUS environment variable to see if an internal redirect has already been performed (that is, this prepending step has already occurred):
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
RewriteCond %1 !=www
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule .* /%1/$0 [L]
I have a website here on my localhost :
http://localhost/mysite/www/index.php
I have some RewriteRules to redirect like this :
http://localhost/mysite/www/index.php?page=home
-> http://localhost/mysite/www/home.html
And now, I want to do a redirection like this :
http://localhost/mysite/www/
-> http://localhost/mysite/www/home.html
I have an environment variable named REWRITE_BASE containing /mysite/www/. So what I thought to do was to compare {REQUEST_URI} to %{ENV:REWRITE_BASE} ... like this:
RewriteCond {REQUEST_URI} =%{ENV:REWRITE_BASE}
RewriteRule . %{ENV:REWRITE_BASE}home\.html [R=301,L]
But it don't works well.
To help you understand what I want to do, here is the working code in PHP to do what I want:
$rewriteBase = getenv('REWRITE_BASE');
if ($rewriteBase === $_SERVER['REQUEST_URI'])
header('Location: '.$rewriteBase.'home.html');
Thanks for help.
Okay... so, as I can't use a variable for my comparison, here is the way that I made it works :
# Redirect domain.tld/ to domain.tld/home.html
RewriteCond %{REQUEST_URI} =/www/ [OR]
RewriteCond %{REQUEST_URI} =/mysite/www/
RewriteRule ^(.*)$ %{REQUEST_URI}home\.html [R=301,L]
# RewriteBase equivalent - Production environment
RewriteRule . - [E=REWRITE_BASE:/www/]
# RewriteBase equivalent - Development environment
RewriteCond %{HTTP_HOST} ^localhost$
RewriteRule . - [E=REWRITE_BASE:/mysite/www/,E=DEVELOPMENT_ENV:1]
# Website rewritings
RewriteRule ^([^/]*)(?:/([^/]*))?\.html$ %{ENV:REWRITE_BASE}index\.php?page=$1&view=$2 [QSA,L]
Now it's alright. Thanks for your answers! ;)
What you want to do won't work, because mod_rewrite doesn't expand any variables present in its test patterns. Therefore, when you do something like this...
RewriteCond %{REQUEST_URI} =%{ENV:REWRITE_BASE}
...What you're actually doing is comparing the value of %{REQUEST_URI} to the string "%{ENV:REWRITE_BASE}", instead of the value "/mysite/www/" like you wanted. Is there a reason that you can't specify the value directly in your RewriteCond or simply move the rules so that they're relative to the /mysite/www/ directory to begin with?
There might be another way to approach the problem, but unfortunately (and for some good reasons) you cannot perform that kind of comparison using mod_rewrite.