mod_rewrite in .htaccess file for unknown first part of path - apache

I am trying to write a rewrite rule to change path slugs to query parameters. It is for a web service, and should only rewrite this rule if the host starts with api. There are two slugs that I am trying to capture and rewrite. The first is optional and is a version (i.e. v1.2) and the second is the service domain (i.e. customers, transactions, etc.).
http://api.domain.com/v2.5/customers should rewrite to ?version=2.5&domain=customers
I also want to support a default version so that
http://api.domain.com/customers should rewrite to ?version=&domain=customers
Here is what my .htaccess file looks like:
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^api\..*
RewriteRule ^v([\d\.]*)?\/?([^\/]*)$ ?version=$1&domain=$2
The first example above works fine, but I can't get the default version path to work. I have tried a ton of different things. I thought starting with ^.*v would help, but it didn't. Anybody know how to make it match when you don't know the starting characters?

Try:
RewriteCond %{HTTP_HOST} ^api\..*
RewriteCond %{QUERY_STRING} !version=
RewriteRule ^(v([\d\.]*))?\/?([^\/]*)$ /?version=$2&domain=$3 [L]
This makes the /v part optional:
/v2.5/foo -> /?version=2.5&domain=foo
/foo -> /?version=&domain=foo
/v/foo -> /?version=&domain=foo

Related

Windows 10 Xampp Apache - htaccess rewriterule not working

I am using apache XAMPP on Windows 10 and am trying to get htaccess working. I have this so far...
RewriteEngine On
RewriteRule ^noexist/?$ /folder/
I want someone to go to
www.mysite.com/noexist/test.php -> www.mysite.com/folder/test.php
But I still want the URL to be www.mysite.com/noexist/test.php
I am just getting a 404, where am I going wrong? I have confirmed the htaccess file is being loaded by putting invalid code in and it throws an error so I am certain the file is being used.
RewriteRule ^noexist/?$ /folder/
The regex ^noexist/?$ matches noexist or noexist/ only, so /noexist/test.php is ignored by this rule. It also only rewrites to /folder/ only.
In other words, this rewrites /noexist (or /noexist/) to /folder/ only.
To rewrite /noexist/<something> to /folder/<something> then you need to capture the <something> part and pass this through to the target URL (i.e the substitution string). For example:
RewriteRule ^noexist/(.*) /folder/$1 [L]
The $1 backreference in the substitution string contains the URL-path captured by the parenthesised subpattern (ie. (.*)) in the RewriteRule pattern.
Don't forget the L (last) flag. (This is important if you have other directives later in the file.)
Note that this rewrite is unconditional, regardless of whether /folder/<something> exists or not. If you want to check that /folder/<something> exists before rewriting then add an additional condition. For example:
RewriteCond %{DOCUMENT_ROOT}/folder/$1 -f
RewriteRule ^noexist/(.*) /folder/$1 [L]
This assumes your .htaccess file is located in the document root.

Looking for a RewriteBase equivalent using RewriteRule

I'm facing an Apache configuration issue which can be summarized like follows.
On a unique hosting system I have a lot of different test sites, each one in its own subdirectory, so they are accessible through an url like myhostname.fr/sitename.
Hence in the corresponding .htaccess, the common practice is to have a RewriteBase /sitename before any of the RewriteCond+RewriteRule sets, and it works fine.
Now for one of these sites (say in the specialsite subdirectory) I had to create a dedicated domain so the url looks like domainname.myhostname.fr.
Then for this site to work the .htaccess now needs RewriteBase / instead of RewriteBase /specialsite, and it works fine too.
Here is the trick: being not so familiar with Apache I decided to experiment and wanted to also keep allowed to access this site through the common url myhostname.fr/specialsite.
So I had to find a way to conditionally use one of the above RewriteBase, depending on which is the current url.
The first way I tried was to work like this:
<If "%(HTTP_HOST) =~ domainname\.myhostname\.fr">
RewriteBase /
</If>
<If "%(HTTP_HOST) =~ myhostname\.fr/specialsite">
RewriteBase /specialsite
</If>
But I got a HTTP 500 error, and I take much time to understand that the <If> directive is available as of Apache 2.4, while my hosting only offers Apache 1.3!
So (thanks to some other SO answers) I thinked to another way, which is to first do:
RewriteCond %{HTTP_HOST} domainname\.myhostname\.fr
RewriteRule ^ - [E=VirtualRewriteBase:/]
RewriteCond %{HTTP_HOST} myhostname\.fr/specialsite
RewriteRule ^ - [E=VirtualRewriteBase:/specialsite/]
Then prepend all further RewriteRule replacement with the given VirtualRewriteBase, like in this one:
RewriteRule ^ %{ENV:VirtualRewriteBase}index.php [L]
But while it works fine for the domain-access version, it gives me an HTTP 404 error for the subdirectory-access version.
So in order to watch at how the replacement applied I changed the above rule for:
RewriteRule ^ %{ENV:VirtualRewriteBase}index.php [R,L]
And I observed that the redirected url looked like this:
http://myhostname.fr/kunden/homepages/7/d265580839/htdocs/specialsite/index.php
where kunden/homepages/7/d265580839/htdocs/ is the full document-root of my hosting.
You can notice that the document-root has been inserted between the two parts of the original url.
Moreover, the result is exactly the same whatever I put in place of /specialsite/ in my VirtualRewriteBase!
So here is my main question: why and how does this happen?
Also I'm obviously interested to a possible alternative solution to achieve the double-access availibility.
But above all I would like to understand...
But while it works fine for the domain-access version, it gives me an
HTTP 404 error for the subdirectory-access version.
That's because your second condition is never matched. Indeed, HTTP_HOST only contains the... http host ! The /specialsite is part of the REQUEST_URI (or can also be matched in RewriteRule directly).
This code should work (anyway, i don't know if it would solve totally your problem, but that's a first step)
RewriteCond %{HTTP_HOST} ^domainname\.myhostname\.fr$ [NC]
RewriteRule ^ - [E=VirtualRewriteBase:/]
RewriteCond %{HTTP_HOST} ^myhostname\.fr$ [NC]
RewriteCond %{REQUEST_URI} ^/specialsite(?:/|$) [NC]
RewriteRule ^ - [E=VirtualRewriteBase:/specialsite/]

I Cannot get rewriterule to work

I'm using VertrigoServ 2.27 on my laptop (localhost:8080).
Rewrite module is enabled and i tested it with alice.html and bob.html example
(http://stackoverflow.com/questions/6944521/url-rewriting-on-localhost)
and it works with .htacces inside www-subfolder. And I also put rubbish text inside .htaccess and
I got error from Apcheserver so rewrite mod is running and I cab use rules.
here is the rule: (inside /www/folder1/.htaccess)
Options +FollowSymLinks
RewriteEngine On
RewriteRule /(.*) /index.php?disp=$1 [QSA,L]
So when I put this url into browser my index page loaded ok.
http://localhost:8080/folder1/index.php
And the problem is here: When I request login via index.page(login page) and send url to localhost
server by cliking send-button
the url changed localhost:8080/login, it should be localhost:8080/folder1/login
how I can keep subfolder name in url?
and I want convert urls like this: www.best-food-of-the-usa.com/index.php?operation=top&state=arizona&
city=mesa&limit=10
to like this: www.best-food-of-the-usa.com/arizona/mesa/top10.html
Any help is appreciated. Thanks
\Jose
RewriteRule is behaving as the docs say.
From RewriteRule Directive Apache Docs
What is matched?
In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html").
In Directory and htaccess context, the Pattern will initially be matched against the filesystem path, after removing the prefix that lead the server to the current RewriteRule (e.g. "app1/index.html" or "index.html" depending on where the directives are defined).
If you wish to match against the hostname, port, or query string, use a RewriteCond with the %{HTTP_HOST}, %{SERVER_PORT}, or %{QUERY_STRING} variables respectively.
So, when in Directory and htaccess context the prefix /www/folder1/ will be removed. Also remember when matching with RewriteRule in Directory and htaccess context, the pattern will never begin with /.
So, your RewriteRule Should be:
Options +FollowSymLinks
RewriteEngine On
RewriteRule (.*) /index.php?disp=$1 [QSA,L]

Apache .htaccess RewriteRule

Here's my situation. I have a web root and several subdirectories, let's say:
/var/www
/var/www/site1
/var/www/site2
Due to certain limitations, I need the ability to keep one single domain and have separate folders like this. This will work fine for me, but many JS and CSS references in both sites point to things like:
"/js/file.js"
"/css/file.css"
Because these files are referenced absolutely, they are looking for the 'js' and 'css' directories in /var/www, which of course does not exist. Is there a way to use RewriteRules to redirect requests for absolutely referenced files to point to the correct subdirectory? I have tried doing things like:
RewriteEngine on
RewriteRule ^/$ /site1
or
RewriteEngine on
RewriteRule ^/js/(.*)$ /site1/js/$1
RewriteRule ^/css/(.*)$ /site1/css/$1
But neither of these work, even redirecting to only one directory, not to mention handling both site1 and site2. Is what I'm trying possible?
EDIT: SOLUTION
I ended up adapting Jon's advice to fit my situation. I have the ability to programatically make changes to my .htaccess file whenever a new subdirectory is added or removed. For each "site" that I want, I have the following section in my .htaccess:
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !^/index.php$
RewriteCond %{HTTP_COOKIE} sitename=site1
RewriteCond %{REQUEST_URI} !^/site1/
RewriteRule ^(.*)$ /site1/$1 [L]
Index.php is a file that lists all my sites, deletes the "sitename" cookie, and sets a cookie of "sitename=site#" when a particular one is selected. My RewriteConds check,
If the request is not for /
If the request is not for /index.php
If the request contains the cookie "sitename=site1"
If the request does not start with "/site1/"
If all of these conditions are met, then the request is rewritten to prepend "/site1/" before the request. I tried having a single set of Conds/Rules that would match (\w+) instead of "site1" in the third Condition, and then refer to %1 in the fourth Condition and in the Rule, but this did not work. I gave up and settled for this.
If the RewriteRules are in your .htaccess file, you need to remove the leading slashes in your match (apache strips them before sending it to mod_rewrite). Does this work?
RewriteEngine on
RewriteRule ^js/(.*)$ /site1/js/$1
RewriteRule ^css/(.*)$ /site1/css/$1
EDIT: To address the comment:
Yes, that works, but when I do RewriteRule ^(.*)$ /site1/$1, it causes Apache to issue internal server errors. But to me, it seems like that should just be a generic equivalent of the individual rules!
What's happening with that rule is when /something/ gets rewritten to /site/something/, and apache internally redirects, it gets rewritten again, to /site/site/something/, then again, then again, etc.
You'd need to add a condition to that, something like:
RewriteCond %{REQUEST_URI} !^/site/
RewirteRule ^(.*)$ /site/$1 [L]
You need to set up symlinks, which the rewrite rules will use so your absolute links at the server level can follow the symbolic links to the central site hosting account.

Apache mod_rewrite redirect all requests for files not named x to this domain

Ok, I'm trying to achieve this:
Redirect all files of a particular filetype (except particular exceptions) to be loaded from another server, right now I'm using this rewrite rule:
RewriteEngine on
RewriteRule \.(swf|jpg|png)$ http://example.com%{REQUEST_URI} [NC,R=302,L]
And it will redirect all the swf,jpg, or png files to another hostname to serve them.
So how can I add exceptions to this rule for specific files? I've tried adding:
RewriteCond %{REQUEST_URI} ^!(log22.swf|packer.swf|sos.swf|aeVisual.swf|newBubbleSystem.swf|e.swf)$
But when I did this it completely stopped the rule from doing anything at all to the other files. Any ideas? I'm a newbie at using mod_rewrite.
You have to preprend ! to the condition's regex:
RewriteCond %{REQUEST_URI} !^(log22.swf|packer.swf|sos.swf|aeVisual.swf|newBubbleSystem.swf|e.swf)$
Note that ! and ^ are in different order than in your code, as you can negate the expression, but adding the ! before.
The reason the rule does not work is that it does never match.