Subdomain to Folder using Apache mod_rewrite related Problem - apache

I want to map all my subdomain to folder.
For example subdomain.domain.com should display content of domain.com/clients/subdmain (Transparently)
RewriteCond %{HTTP_HOST} ^(.+)\.oomail\.org
RewriteCond %{HTTP_HOST} !^www\.oomail\.org [NC]
RewriteRule ^(.+)$ /var/www/clients/%1/$1
I got 500 Internal Server Error. To check whats the problem I appended [R] flag
RewriteRule ^(.+)$ /var/www/clients/%1/$1 [R]
I got this result in address bar
http://q1.oomail.org/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/var/www/clients/q1/always.html
Then I created a details.php file which dumps the $_GET variable details. Its content is
<pre>
<?php
var_dump($_GET);
?>
</pre>
and modified RewriteRule to (Note: I am sending $1 and %1 into details.php which shows its content)
RewriteRule ^(.+)$ details.php?p=%1&d=$1
And after opening http://subdomain.oomail.org/file.html, I got output as
array(2) {
["p"]=>
string(9) "subdomain"
["d"]=>
string(11) "details.php"
}
Of which variable p is correct (value of %1) which is "subdomain", BUT d (value of $1) is details.php which I was expecting to be file.html which I opened in URL. Where am I going wrong? or How can I fetch file.html (URI) into variable for mapping?

Use this rule:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/clients/
RewriteCond %{HTTP_HOST} ^(.+)\.oomail\.org
RewriteCond %{HTTP_HOST} !^www\.oomail\.org
RewriteRule ^(.*)$ /clients/%1/$1 [L]
In your first attempt you had endless rewrite loop which Apache had to interrupt (by default no more than 10 iterations). In second attempt you are facing limited rewrite loop (2 iterations, I believe). That's how mod_rewrite works and you should count such possibility in your rules -- especially when you use .* as matching pattern .
The very first condition in my rule will prevent rewrite loop from happening (means rule will only work on very first iteration). Unfortunately this means some restrictions: the original URL CANNOT start with /clients/. For example: this URL will not be redirected: http://something.example.com/clients/hello-kitten.php.
Solution -- rename clients folder to something more unique: for example _clients_folder_ (you would have to change that folder in rewrite rules as well, obviously).
Something to read: RewriteRule Last [L] flag not working?

Related

htaccess Redirect URL with GET Parameters

I have a URL that is in the format http://www.example.com/?s=query
I want to redirect this URL to http://www.example.com/search/query
I have the following .htaccess but I wanted to check if there is anything wrong with this. My RewriteRule looks a little wonky and I don't know if it will cause problems for other URLs.
RewriteEngine on
RewriteCond %{QUERY_STRING} ^s=(.*)$ [NC]
RewriteRule ^$ /search/%1? [NC,L,R]
I ran a test Here and it seems to redirect to the correct URL.
RewriteCond %{QUERY_STRING} ^s=(.*)$ [NC]
RewriteRule ^$ /search/%1? [NC,L,R]
You will likely need the NE (noescape) flag on the RewriteRule directive if you are receiving a %-encoded URL parameter value, otherwise the target URL will be doubly-encoded. The QUERY_STRING server variable is not decoded by Apache.
It also depends on how you are rewriting /search/query back to /?s=query (or presumably more like /index.php?s=query?) - presumably you are already doing this later in the config? You only want this redirect to apply to direct requests and not rewritten requests (otherwise you'll get a redirect loop). An easy way to ensure this is to check that the REDIRECT_STATUS env var is empty.
For example:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^s=(.*) [NC]
RewriteRule ^$ /search/%1 [NE,QSD,R,L]
Other points:
The QSD flag would be preferable (on Apache 2.4) to appending ? to the end of the susbtitution string in order to remove the query string.
The regex ^s=(.*) (the trailing $ was superfluous) does assume that s is the only URL parameter at the start of the query string. As it stands, everything is assumed to be part of this value. eg. s=foo&bar=1 will result in /search/foo&bar=1.
The NC flag on the RewriteRule directive is superfluous.
Should you also be checking for /index.php?s=<query>? (Or whatever file/DirectoryIndex is handling the request.)

adding forward slash after rewrite if not exist

I have read a ton and tried a ton of solutions, but can't find one specific to my needs.
In my htaccess I have the following:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^profile/([\w-]+)/?$ profile.php?username=$1 [L,QSA]
RewriteRule ^profile/([\w-]+)/([\w-]+)/?$ profile.php?username=$1&type=$2 [L,QSA]
RewriteRule ^profile/([\w-]+)/([\w-]+)/([\w-]+)/?$ profile.php?username=$1&type=$2&o=$3 [L,QSA]
This works wonderfully, except for 1 small problem.
If profile/username does not have a / the links on the page will break unless absolute urls are used. So <a href="./1"> will end up as profile/1 instead of profile/username/1
If I change the first rewrite to the following:
RewriteRule ^profile/([\w-]+)/$ profile.php?username=$1 [L,QSA]
then https://myurl/username will return a 404 which I do not want - I want it to force the / on the end if it does not exist.
I have tried adding:
RewriteRule ^(.*)([^/])$ /$1$2/ [L,R=301]
I have tried
RewriteRule ^(.*)$ https://nmyurl/$1/ [L,R=301]
Just can't figure out how to do this with the rewrite conditions already in place.
To add an optional traling at the end of your profile URLs you can use this
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/profile/
RewriteRule !/$ %{REQUEST_URI}/ [L,R]
If profile/username does not have a / the links on the page will break unless absolute urls are used. So <a href="./1"> will end up as profile/1 instead of profile/username/1
If the issue only applies to URLs of the form /profile/<username> then I would be specific and only append the trailing slash to these specific URLs, otherwise, you are going to get a lot of redirects (which could be detrimental to SEO).
However, you should ensure that internal links are for the canonical URL (ie. with the trailing slash).
For example, the following should go before your existing rewrites:
RewriteRule ^(profile/[\w-]+)$ /$1/ [R=301,L]
Since the canonical URL requires a trailing slash this should be a 301 (permanent) redirect. (But test with a 302 first.)
Alternatively, instead of redirecting in .htaccess (if you are still linking to the slashless URL internally) then you could add a base element (that includes the trailing slash) to the head section to state what relative URLs should be relative to.
For example:
<base href="/profile/<username>/">
Aside:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^profile/([\w-]+)/?$ profile.php?username=$1 [L,QSA]
RewriteRule ^profile/([\w-]+)/([\w-]+)/?$ profile.php?username=$1&type=$2 [L,QSA]
RewriteRule ^profile/([\w-]+)/([\w-]+)/([\w-]+)/?$ profile.php?username=$1&type=$2&o=$3 [L,QSA]
The two RewriteCond directives would seem to be entirely superfluous. RewriteCond directives only apply to the first RewriteRule that follows. But the RewriteRule patterns are unlikely to match real files anyway (unless you have files without extensions or directories with the same name).
So unfortunately I wasn't able to actually achieve what I was hoping to because there are multiple levels of variables that may or may not exist.
In part I used the solution provided by Amit:
RewriteCond %{REQUEST_URI} ^/profile/
RewriteRule !/$ %{REQUEST_URI}/ [L,R]
However this wasn't enough, because as pointed out by MrWhite there are 3 separate potential url's.
https://myurl/profile/username/
https://myurl/profile/username/type/
https://myurl/profile/username/type/o/
In this sitation username should always exist, but type and o may or may not exist.
So what I did was detect the level of the url and then created conditional . and .. using php.
The variable o is always numeric and variable type is never numeric so this worked for me.
if (isset($_GET['o'])) { $o = strip_tags($_GET['o']); }
elseif (isset($_GET['type']) && is_numeric($_GET['type'])) { $o = strip_tags($_GET['type']); }
Then I detect:
// if o is set or if type is numberic, use ..
if (isset($_GET['o']) || (isset($_GET['type']) && is_numeric($_GET['type']))) {
$dots = '..';
// if o is not set and type is not numeric just use .
} else {
$dots = '.';
}
end result of 1:
if url is https://myurl/profile/username/
result is https://myurl/profile/username/1/
if url is https://myurl/profile/username/3/
result is https://myurl/profile/username/1/
if url is https://myurl/profile/username/type/3/
result is https://myurl/profile/username/type/1/
Which was the desired outcome.

Apache .htaccess rewrite parameter to directory

I've got an application that has been migrated to a newer platform. The tasks are similar and I'd like to redirect a GET parameter to a directory. For example
http://gallery/index.php?gal=ABC => http://photos/gal/ABC
and
http://gallery/?gal=DEF => http://photos/gal/DEF
and the anything that doesn't get caught redirect it to http://photos
I've tried
RewriteEngine on
RewriteCond %{QUERY_STRING} ^(\w+)=(\w+)$
RewriteRule ^(/index.php)$ /%1/%2?
However all I get is a 404 and no redirection. Similarly, I've tried
RedirectMatch ^/index\.php\?=gal(.*) http://photos/gal/$1
but I'm having trouble escaping the ? in the original URL.
What would be the proper way of going about this?
Create a .htaccess file and insert the following code:
RewriteCond %{QUERY_STRING} ^(.+)=(.+)$
RewriteRule ^index.php$ http://photos %1/%2? [L,NC,R=301]
Your order is reversed. Rewrite it in front of you
RewriteRule /(.+)\/(.+) index.php?$1=$2
The question is old but might be still relevant for others, so I suggest a slightly different general approach:
RewriteEngine On
RewriteCond %{QUERY_STRING} key=([0-9a-zA-Z]+) [NC]
RewriteRule (.*) /%1? [R=302,L]
Notes:
QUERY_STRING in the condition checks for a param name "key" and catches it's value
The rewrite rule adds the param value as directory using %1. Note the ? removes the original query part from end result

Mod_rewrite in two directions?

An existing page is called /foo/bar.php. What I have done is a rewrite so that when a user types /foobar, it load the contents of /foo/bar.php (while keeping /foobar in the url bar)
But I also want the opposite - when a user clicks on a link or types /foo/bar.php, I want to have /foobar in the url. The reason is to avoid manually changing all the links.
How could I do that (if possible without an http redirect, but via some rewrite magic)? And is it possible for those two rules to co-exist?
Edit - After the first response, I realized my description of the problem was not proper. /foobar is not supposed to be a concatenation of foo, bar of /foo/bar.php, but an arbitrary string (/whatever).
Edit 2:
I now added RewriteRule ^whetever/?$ /foo/bar.php [L] in the / .htaccess. Then I added RewriteRule bar\.php$ /whetever [R=302,L] in the /foo .htaccess. The problem is it 's a circular reference and fails.
Thanks,
John
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/foo/[^/]+\.php$
RewriteCond %{IS_SUBREQ} !true
RewriteRule ^/foo/([^/]+)\.php$ /foo$1 [R,L]
RewriteCond %{REQUEST_URI} ^/foo[^/]
RewriteRule ^/foo(.*) /foo/$1.php [L]
The first part matches /foo/something.php and transforms them into /foosomething, but only if it is not a sub-request.
The second part takes any /foosometing and transforms it into /foo/something.php, via sub-request
You can try matching against %{THE_REQUEST} and only do the redirect when the actual request is for the php file:
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /foo/bar\.php
RewriteRule bar\.php$ /whatever [R=302,L]
RewriteRule ^whatever/?$ /foo/bar.php [L]

mod_rewrite condition for existing folder

I'm trying to set-up an .htaccess file that will pass every request URL as GET into a file called index.php. The only exception is, when the request URL points to a directory res.
Examples:
/wiki/cool-stuff => index.php?uri=/wiki/cool-stuff
/wiki/cool-stuff?news=on => index.php?uri=/wiki/cool-stuff&news=on
/res/cool-photo.jpg => res/cool-photo.jpg
Two problems:
The GET variable passed to /wiki/cool-stuff in the second example is not passed to index.php
Accessing /res (not /res/!!) suddenly shows me /res/?uri=res in my browser and index.php with uri=res/. Accessing /res/ instead, shows me index.php with uri=res/ and the URL in the browser stays (which is okay).
The .htaccess:
RewriteEngine on
RewriteBase /subthing/
RewriteCond %{REQUEST_URI} !/res/(.+)$
RewriteCond %{REQUEST_URI} !index.php
RewriteRule (.*) index.php?uri=$1
How can I achieve the desired behaviour?
Try using the Query-String-Append flag, QSA
Make the trailing slash optional - in Regex, this is achieved by adding ?.
New .htaccess:
RewriteEngine on
RewriteBase /subthing/
RewriteCond %{REQUEST_URI} !/res(/.*)?$
RewriteCond %{REQUEST_URI} !index.php
RewriteRule (.*) index.php?uri=$1 [QSA]
Note that I have tweaked the Regex on the /res folder to cause /resabc to be redirected (if the slash was the only optional piece, anything beginning with res would match.
Apache Mod_Rewrite Documentation