Mod rewrite rule for mapping one or two parameters - mod-rewrite

I have the following .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?([^/]+)/?$ /?page=$1 [L,QSA]
RewriteRule ^/?([^/]+)/([^/]+)/?$ /?page=$1&id=$2 [L,QSA]
This rules allow to enter urls like:
example.com/my-account-dashboard
example.com/my-account-dashboard/1
which are pretty urls for:
example.com?page=my-account-dashboard
example.com?page=my-account-dashboard&id=1
This works fine so far. But internaly the links are with those parameters. Is it possible to redirect (or something) to the pretty urls if possible? What are the rewrite rules for that?

First of all, a few remarks about your current code which contains some errors.
1) RewriteCond only applies on the very next RewriteRule. So your second RewriteRule can match without that condition (you can try it, you'll see). You need to put (again) that condition to the other RewriteRule (or use S skip flag to simulate if/else condition but it gets complicated for nothing).
2) I'm pretty sure you don't want to use QSA flag the way you do. By using it, you tell mod_rewrite to append any query string to the rewrite. Example: example.com/my-account-dashboard/?foo=bar will rewrite to /?page=my-account-dashboard&foo=bar. So unless you really want that, you don't need it. A lot of people think that they need QSA when adding some query string directly in the rewrite, just like you do. Again, this is not an error that will make everything crash, but still it's not totally correct.
3) Your rules create duplicate content which is bad for SEO (referencing). For instance, example.com/my-account-dashboard and example.com/my-account-dashboard/ (notice the trailing slash) both lead to the same page. But search engines won't consider them as the same. I invite you to search "duplicate content" on Google (or any other search engine you like) and have a look at it. A simple way to avoid this is to chose either with or without the trailing slash.
Now that the base is clear, let's answer to your question. You can't simply use a redirect R from old-url to new-url because you'd end up with an infinite loop. Something is there for this problem: THE_REQUEST. When mod_rewrite uses it, it is able to know that it comes from a direct client request, not a redirect/rewrite by itself.
All-in-one, here is how your code should look like:
RewriteEngine On
RewriteBase /
# Redirect old-url /?page=XXX to new-url equivalent /XXX
RewriteCond %{THE_REQUEST} \s/\?page=([^/&\s]+)\s [NC]
RewriteRule ^ /%1? [R=301,L]
# Redirect old-url /?page=XXX&id=YYY to new-url equivalent /XXX/YYY
RewriteCond %{THE_REQUEST} \s/\?page=([^/&\s]+)&id=([0-9]+)\s [NC]
RewriteRule ^ /%1/%2? [R=301,L]
# if /XXX is not a file/directory then rewrite to /?page=XXX
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?([^/]+)$ /?page=$1 [L]
# if /XXX/YYY is not a file/directory then rewrite to /?page=XXX&id=YYY
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?([^/]+)/([0-9]+)$ /?page=$1&id=$2 [L]
NB: i chose to use the "without trailing slash" option (e.g. example.com/my-account-dashboard and example.com/my-account-dashboard/1). Feel free to ask if you want with.

Related

Relative path and mod_rewrite issue

Have a trouble with mod_rewrite.
I want :
htp://example.com/a/some_text -> htp://example.com/?p1=some_text and
htp://example.com/b/some_text -> htp://example.com/?p1=some_text
So, I type:
RewriteCond %{REQUEST_URI} ^(.*)\/(a|b)\/(.*)$
RewriteRule ^(.*)$ ?fsearch=$2 [QSA]
and get wrong relative paths in css, such as htp://example.com/a/CSS/main.css instead of htp://example.com/CSS/main.css. And get nothing in $2 too.
Help, please
$2 tries to pick the second capture group of the RewriteRules subject, but there is only one! You probably mean %2 which picks from the RewriteCond...
Since you only append a query string in your RewriteRule the original URI (path) is left untouched.
You can simplify the pattern in the RewriteRule since you are not interested in the subject anyway.
This is probably what you are looking for:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^(.*)\/(a|b)\/(.*)$
RewriteRule ^ /?fsearch=%3 [QSA]
Much better however would be to rewrite directly to whatever script you actually want to process the request to safe another rewriting round to find the index document, so something like:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^(.*)\/(a|b)\/(.*)$
RewriteRule ^ /index.php?fsearch=%3 [QSA]
And unless you decide to use the first capture group in the RewriteCond you can also simplify that further:
RewriteEngine on
RewriteCond %{REQUEST_URI} \/(a|b)\/(.*)$
RewriteRule ^ /index.php?fsearch=%2 [QSA]

Mod rewrite redirection to another domain if file not exist

What I'm trying to do:
I need to redirect a request to a file to another domain if the file not exists. For example:
http://www.mydomain.com/js/foo.js
redirects to (if not exists)
http://www.myanotherdomain.com/js/foo.js
What I do:
I wrote the next lines at the end the htaccess, but they redirect ALL!
RewriteCond %{REQUEST_URI} !-f
RewriteRule ^(.*)$ http://www.myanotherdomain.com/$1 [L,NC]
Before these lines, I have a lot of lines like this (I'm using MVC (Model, View,Controller)):
RewriteRule ^car/brand/?$ ?controller=Car&action=viewBrand [L,NC]
What happens:
It works wells with non existing files, but seems to be imcompatible with the MVC rules. These rules have to match and then stop evaluating rules because de "L" flag. But it seems to continue evaluation of the rules and finally evaluates the redirect rule. The result is this:
http://www.mydomain.com/car/brand/
goes to
http://www.myanotherdomain.com/?controller=Car&action=viewBrand
Please can anyone help me?
Thank you very much,
Jonathan
Try this:
RewriteCond %{REQUEST_FILE} !-f
RewriteRule ^(.*)$ http://www.myanotherdomain.com/$1 [QSA,R,L]
See also: mod rewrite directory if file/folder not found
Try placing these rules after your MVC rules:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.(js|png|jpe?g|gif|css|html?)$ http://www.myanotherdomain.com/$1.$2 [L,R,NC]
If you want all requests, and not just static content like scripts and images then change the RewriteRule line to:
RewriteRule ^(.*)$ http://www.myanotherdomain.com/$1 [L,R,NC]

mod_rewrite precedence

Let's say I want to support urls like twitter where:
twitter.com/username redirects to twitter.com/user_name.php?user=username
I have the following
RewriteRule ^(.*)$ user_name.php?user=$1
And that works fine. But the problem is now that everything, including twitter.com/index.php will of course redirect to user_name.php
How can I either create exceptions or precedence so that "real files" don't get rewritten? I tried adding an explicit rule for index.php before and after that one, but it doesn't seem to take effect.
You need to add RewriteCond for this
RewriteCond %{REQUEST_URI} !-f [OR] # for existing files
RewriteCond %{REQUEST_URI} !-d # for existing directories
RewriteRule ^(.*)$ user_name.php?user=$1

Replace ? in request with RewriteRule

site.com/link?p=2
give $_GET['p']==2 even though i've already made
site.com/link
rewrite to
site.com/index.php?page=link
So, i'm trying to replace site.com/link?p=2
with site.com/link&p=2
RewriteEngine on
RewriteRule (.*)\?(.*) $1\&$2
RewriteCond %{REQUEST_URI} !\....$
RewriteRule ^(.*)$ /index.php?p=$1
It doesn't work!
RewriteRule cannot see query strings (the ? and anything after it) on the left-hand side; it matches only on the path part of the URL.
But the good news is, all you probably need to do is this:
RewriteEngine on
RewriteCond %{REQUEST_URI} !\....$
RewriteRule ^(.*)$ /index.php?p=$1 [QSA]
The QSA option, Query String Add, tells your RewriteRule to add to the query string instead of replacing it (the default behavior, which doubtless prompted the whole issue).

Simple mod rewrite question

Here is my current .htaccess file:
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
As you can see, requests to http://domain.com go to http://domain.com/index.html. I want to change this so that they go to http://domain.com/foo, please note that does not exist as a file or folder, it is handled by rails. How do I do this? Note that I have tried the following and it doesn't work:
RewriteRule ^$ foo [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
Thanks!
You're probably safe to just change the first line to this:
RewriteRule ^$ foo [QSA,L]
The L flag tells mod-rewrite that it shouldn't apply any other rules after that one. The problem right now is that the second rule gets applied after the first one, and you end up at "foo.html", instead of "foo", right?
The difference between you trying to send to "foo" and the original redirect to "index.html" is that the second rule applies to requests that do not include a period. So when the first rule was redirecting to "index.html", after it was used, the second rule was no longer valid. However, now that you're not redirecting to a location with a period in it, the second rule gets applied after the first one, so you get a double-redirect.
In addition, you may be able to drop the QSA flag from the first line, it depends on your site though. If someone accesses the site like http://domain.com/?user=fred, do you want to send them to http://domain.com/foo?user=fred, or just http://domain.com/foo? If you don't need the Query String Appended, you can drop the QSA flag, and just have:
RewriteRule ^$ foo [L]

Resources